910e62b5创建于 1月15日历史提交
// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "gpu/command_buffer/client/client_shared_image.h"

#include <GLES2/gl2.h>
#include <GLES2/gl2extchromium.h>

#include "gpu/command_buffer/client/shared_image_interface.h"
#include "gpu/command_buffer/client/test_shared_image_interface.h"
#include "gpu/command_buffer/common/shared_image_capabilities.h"
#include "gpu/command_buffer/common/shared_image_usage.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/gpu_fence.h"

namespace gpu {

namespace {

constexpr viz::SharedImageFormat kMultiPlaneFormatsWithHardwareGMBs[4] = {
    viz::MultiPlaneFormat::kYV12, viz::MultiPlaneFormat::kNV12,
    viz::MultiPlaneFormat::kNV12A, viz::MultiPlaneFormat::kP010};

}  // namespace

TEST(ClientSharedImageTest, ImportUnowned) {
  auto mailbox = Mailbox::Generate();
  const auto kFormat = viz::SinglePlaneFormat::kRGBA_8888;
  const gfx::Size kSize(256, 256);
  const SharedImageUsageSet kUsage =
      SHARED_IMAGE_USAGE_RASTER_WRITE | SHARED_IMAGE_USAGE_DISPLAY_READ;
  SharedImageMetadata metadata{kFormat,
                               kSize,
                               gfx::ColorSpace(),
                               kTopLeft_GrSurfaceOrigin,
                               kOpaque_SkAlphaType,
                               kUsage};

  auto client_si = ClientSharedImage::ImportUnowned(ExportedSharedImage(
      mailbox, metadata, SyncToken(), "ClientSharedImageTest", std::nullopt,
      std::nullopt, GL_TEXTURE_2D, /*is_software=*/false));

  // Check that the ClientSI's state matches the input parameters.
  EXPECT_EQ(client_si->mailbox(), mailbox);
  EXPECT_EQ(client_si->format(), kFormat);
  EXPECT_EQ(client_si->size(), kSize);
  EXPECT_EQ(client_si->usage(), kUsage);
  EXPECT_EQ(client_si->GetTextureTarget(),
            static_cast<uint32_t>(GL_TEXTURE_2D));
  EXPECT_FALSE(client_si->HasHolder());
}

TEST(ClientSharedImageTest, CreateViaSharedImageInterface) {
  auto sii = base::MakeRefCounted<TestSharedImageInterface>();

  const auto kFormat = viz::SinglePlaneFormat::kRGBA_8888;
  const gfx::Size kSize(256, 256);
  const SharedImageUsageSet kUsage =
      SHARED_IMAGE_USAGE_RASTER_WRITE | SHARED_IMAGE_USAGE_DISPLAY_READ;
  SharedImageInfo si_info{kFormat,
                          kSize,
                          gfx::ColorSpace(),
                          kTopLeft_GrSurfaceOrigin,
                          kOpaque_SkAlphaType,
                          kUsage,
                          ""};

  auto client_si = sii->CreateSharedImage(si_info, kNullSurfaceHandle);

  EXPECT_TRUE(client_si->HasHolder());
  EXPECT_FALSE(client_si->mailbox().IsZero());

  // Check that the ClientSI's state matches the input parameters.
  EXPECT_EQ(client_si->format(), kFormat);
  EXPECT_EQ(client_si->size(), kSize);
  EXPECT_EQ(client_si->usage(), kUsage);

  // With no scanout or WebGPU usage, external sampling not configured, and no
  // client-side native buffer handle passed, the SharedImage should be using
  // the default texture target on all platforms.
  EXPECT_EQ(client_si->GetTextureTarget(),
            static_cast<uint32_t>(GL_TEXTURE_2D));
}

TEST(ClientSharedImageTest, BackingWasExternallyUpdatedForwardsToSII) {
  auto sii = base::MakeRefCounted<TestSharedImageInterface>();

  const auto kFormat = viz::SinglePlaneFormat::kRGBA_8888;
  const gfx::Size kSize(256, 256);
  const SharedImageUsageSet kUsage =
      SHARED_IMAGE_USAGE_RASTER_WRITE | SHARED_IMAGE_USAGE_DISPLAY_READ;
  SharedImageInfo si_info{kFormat,
                          kSize,
                          gfx::ColorSpace(),
                          kTopLeft_GrSurfaceOrigin,
                          kOpaque_SkAlphaType,
                          kUsage,
                          ""};

  auto client_si = sii->CreateSharedImage(si_info, kNullSurfaceHandle);

  ASSERT_EQ(0u, sii->num_update_shared_image_no_fence_calls());
  client_si->BackingWasExternallyUpdated(gpu::SyncToken());
  EXPECT_EQ(1u, sii->num_update_shared_image_no_fence_calls());
}

// Verifies that invoking BackingWasExternallyUpdated() on a
// ClientSharedImage after its SharedImageInterface has been lost does not cause
// a crash.
TEST(ClientSharedImageTest, BackingWasExternallyUpdatedAfterLossOfSII) {
  auto sii = base::MakeRefCounted<TestSharedImageInterface>();

  const auto kFormat = viz::SinglePlaneFormat::kRGBA_8888;
  const gfx::Size kSize(256, 256);
  const SharedImageUsageSet kUsage =
      SHARED_IMAGE_USAGE_RASTER_WRITE | SHARED_IMAGE_USAGE_DISPLAY_READ;
  SharedImageInfo si_info{kFormat,
                          kSize,
                          gfx::ColorSpace(),
                          kTopLeft_GrSurfaceOrigin,
                          kOpaque_SkAlphaType,
                          kUsage,
                          ""};

  auto client_si = sii->CreateSharedImage(si_info, kNullSurfaceHandle);

  sii.reset();
  client_si->BackingWasExternallyUpdated(gpu::SyncToken());
}

TEST(ClientSharedImageTest, ExportAndImport) {
  auto sii = base::MakeRefCounted<TestSharedImageInterface>();

  const auto kFormat = viz::SinglePlaneFormat::kRGBA_8888;
  const gfx::Size kSize(256, 256);
  const SharedImageUsageSet kUsage =
      SHARED_IMAGE_USAGE_RASTER_WRITE | SHARED_IMAGE_USAGE_DISPLAY_READ;
  SharedImageInfo si_info{kFormat,
                          kSize,
                          gfx::ColorSpace(),
                          kTopLeft_GrSurfaceOrigin,
                          kOpaque_SkAlphaType,
                          kUsage,
                          ""};

  auto client_si = sii->CreateSharedImage(si_info, kNullSurfaceHandle);
  auto exported_si = client_si->Export();
  auto imported_client_si =
      ClientSharedImage::ImportUnowned(std::move(exported_si));

  EXPECT_EQ(imported_client_si->mailbox(), client_si->mailbox());
  EXPECT_EQ(imported_client_si->format(), kFormat);
  EXPECT_EQ(imported_client_si->size(), kSize);
  EXPECT_EQ(imported_client_si->usage(), kUsage);
  EXPECT_EQ(imported_client_si->GetTextureTarget(),
            static_cast<uint32_t>(GL_TEXTURE_2D));
}

TEST(ClientSharedImageTest, MakeUnowned) {
  auto sii = base::MakeRefCounted<TestSharedImageInterface>();

  const auto kFormat = viz::SinglePlaneFormat::kRGBA_8888;
  const gfx::Size kSize(256, 256);
  const SharedImageUsageSet kUsage =
      SHARED_IMAGE_USAGE_RASTER_WRITE | SHARED_IMAGE_USAGE_DISPLAY_READ;
  SharedImageInfo si_info{kFormat,
                          kSize,
                          gfx::ColorSpace(),
                          kTopLeft_GrSurfaceOrigin,
                          kOpaque_SkAlphaType,
                          kUsage,
                          ""};

  auto client_si = sii->CreateSharedImage(si_info, kNullSurfaceHandle);
  auto unowned_si = client_si->MakeUnowned();

  EXPECT_EQ(unowned_si->mailbox(), client_si->mailbox());
  EXPECT_EQ(unowned_si->format(), kFormat);
  EXPECT_EQ(unowned_si->size(), kSize);
  EXPECT_EQ(unowned_si->usage(), kUsage);
  EXPECT_EQ(unowned_si->GetTextureTarget(),
            static_cast<uint32_t>(GL_TEXTURE_2D));
  EXPECT_FALSE(unowned_si->HasHolder());
}

// The default target should be set for single-planar formats with no
// native buffer used.
TEST(ClientSharedImageTest,
     GetTextureTarget_SinglePlaneFormats_NoNativeBuffer) {
  auto sii = base::MakeRefCounted<TestSharedImageInterface>();
  const gfx::Size kSize(256, 256);
  const SharedImageUsageSet kUsage =
      SHARED_IMAGE_USAGE_RASTER_WRITE | SHARED_IMAGE_USAGE_DISPLAY_READ;

  for (auto format : viz::SinglePlaneFormat::kAll) {
    SharedImageInfo si_info{format,
                            kSize,
                            gfx::ColorSpace(),
                            kTopLeft_GrSurfaceOrigin,
                            kOpaque_SkAlphaType,
                            kUsage,
                            ""};

    auto client_si = sii->CreateSharedImage(si_info, kNullSurfaceHandle);
    EXPECT_EQ(client_si->GetTextureTarget(),
              static_cast<uint32_t>(GL_TEXTURE_2D));
  }
}

// When the client provides a native buffer with a single-plane format,
// GL_TEXTURE_2D should be used as the texture target on all platforms other
// than Mac, where the target for IO surfaces should be used.
TEST(ClientSharedImageTest,
     GetTextureTarget_SinglePlaneFormats_ClientNativeBuffer) {
  auto sii = base::MakeRefCounted<TestSharedImageInterface>();
  sii->emulate_client_provided_native_buffer();

#if BUILDFLAG(IS_MAC)
  // Explicitly set the texture target for IO surfaces to a target other than
  // GL_TEXTURE_2D to ensure that the test is meaningful on Mac.
  const uint32_t kTargetForIOSurfaces = GL_TEXTURE_RECTANGLE_ARB;
  sii->set_texture_target_for_io_surfaces(kTargetForIOSurfaces);
#endif

  const gfx::Size kSize(256, 256);
  const SharedImageUsageSet kUsage =
      SHARED_IMAGE_USAGE_RASTER_WRITE | SHARED_IMAGE_USAGE_DISPLAY_READ;

  for (auto format : viz::SinglePlaneFormat::kAll) {
    SharedImageInfo si_info{format,
                            kSize,
                            gfx::ColorSpace(),
                            kTopLeft_GrSurfaceOrigin,
                            kOpaque_SkAlphaType,
                            kUsage,
                            ""};

    auto client_si = sii->CreateSharedImage(si_info, kNullSurfaceHandle);

#if BUILDFLAG(IS_MAC)
    const uint32_t expected_texture_target = kTargetForIOSurfaces;
#else
    const uint32_t expected_texture_target = GL_TEXTURE_2D;
#endif
    EXPECT_EQ(client_si->GetTextureTarget(), expected_texture_target);
  }
}

// When the client asks for SCANOUT usage, GL_TEXTURE_2D should be used as the
// texture target on all platforms other than Mac, where the target for IO
// surfaces should be used.
TEST(ClientSharedImageTest, GetTextureTarget_ScanoutUsage) {
  auto sii = base::MakeRefCounted<TestSharedImageInterface>();

#if BUILDFLAG(IS_MAC)
  // Explicitly set the texture target for IO surfaces to a target other than
  // GL_TEXTURE_2D to ensure that the test is meaningful on Mac.
  const uint32_t kTargetForIOSurfaces = GL_TEXTURE_RECTANGLE_ARB;
  sii->set_texture_target_for_io_surfaces(kTargetForIOSurfaces);
#endif

  const gfx::Size kSize(256, 256);
  const SharedImageUsageSet kUsage = SHARED_IMAGE_USAGE_SCANOUT;

  // Test all single-plane formats as well as multiplane formats for which
  // hardware GMBs are supported.
  std::vector<viz::SharedImageFormat> formats_to_test;
  for (auto format : viz::SinglePlaneFormat::kAll) {
    formats_to_test.push_back(format);
  }
  for (auto format : kMultiPlaneFormatsWithHardwareGMBs) {
    formats_to_test.push_back(format);
  }

  for (auto format : formats_to_test) {
    SharedImageInfo si_info{format,
                            kSize,
                            gfx::ColorSpace(),
                            kTopLeft_GrSurfaceOrigin,
                            kOpaque_SkAlphaType,
                            kUsage,
                            ""};

    auto client_si = sii->CreateSharedImage(si_info, kNullSurfaceHandle);

#if BUILDFLAG(IS_MAC)
    const uint32_t expected_texture_target = kTargetForIOSurfaces;
#else
    const uint32_t expected_texture_target = GL_TEXTURE_2D;
#endif
    EXPECT_EQ(client_si->GetTextureTarget(), expected_texture_target);
  }
}

// When the client asks for WEBGPU usage, GL_TEXTURE_2D should be used as the
// texture target on all platforms other than Mac, where the target for IO
// surfaces should be used.
TEST(ClientSharedImageTest, GetTextureTarget_WebGPUUsage) {
  auto sii = base::MakeRefCounted<TestSharedImageInterface>();

#if BUILDFLAG(IS_MAC)
  // Explicitly set the texture target for IO surfaces to a target other than
  // GL_TEXTURE_2D to ensure that the test is meaningful on Mac.
  const uint32_t kTargetForIOSurfaces = GL_TEXTURE_RECTANGLE_ARB;
  sii->set_texture_target_for_io_surfaces(kTargetForIOSurfaces);
#endif

  // Test all single-plane formats as well as multiplane formats for which
  // hardware GMBs are supported.
  std::vector<viz::SharedImageFormat> formats_to_test;
  for (auto format : viz::SinglePlaneFormat::kAll) {
    formats_to_test.push_back(format);
  }
  for (auto format : kMultiPlaneFormatsWithHardwareGMBs) {
    formats_to_test.push_back(format);
  }

  for (SharedImageUsageSet webgpu_usage :
       {SHARED_IMAGE_USAGE_WEBGPU_READ, SHARED_IMAGE_USAGE_WEBGPU_WRITE}) {
    const gfx::Size kSize(256, 256);
    const SharedImageUsageSet kUsage = webgpu_usage;

    for (auto format : formats_to_test) {
      SharedImageInfo si_info{format,
                              kSize,
                              gfx::ColorSpace(),
                              kTopLeft_GrSurfaceOrigin,
                              kOpaque_SkAlphaType,
                              kUsage,
                              ""};

      auto client_si = sii->CreateSharedImage(si_info, kNullSurfaceHandle);

#if BUILDFLAG(IS_MAC)
      const uint32_t expected_texture_target = kTargetForIOSurfaces;
#else
      const uint32_t expected_texture_target = GL_TEXTURE_2D;
#endif
      EXPECT_EQ(client_si->GetTextureTarget(), expected_texture_target);
    }
  }
}

// On all platforms, the default target should be used for multi-planar
// formats if external sampling is not set and scanout/WebGPU usage are not
// specified.
TEST(ClientSharedImageTest,
     GetTextureTarget_MultiplanarFormats_NoScanoutOrWebGPUUsage) {
  auto sii = base::MakeRefCounted<TestSharedImageInterface>();
  const gfx::Size kSize(256, 256);
  const SharedImageUsageSet kUsage =
      SHARED_IMAGE_USAGE_RASTER_WRITE | SHARED_IMAGE_USAGE_DISPLAY_READ;

  // Pass all the multiplanar formats that are used with hardware GMBs.
  for (auto format : kMultiPlaneFormatsWithHardwareGMBs) {
    SharedImageInfo si_info{format,
                            kSize,
                            gfx::ColorSpace(),
                            kTopLeft_GrSurfaceOrigin,
                            kOpaque_SkAlphaType,
                            kUsage,
                            ""};

    auto client_si = sii->CreateSharedImage(si_info, kNullSurfaceHandle);

    // Since the format does not have external sampling enabled, the default
    // target should be used.
    EXPECT_EQ(client_si->GetTextureTarget(),
              static_cast<uint32_t>(GL_TEXTURE_2D));
  }
}

#if BUILDFLAG(IS_OZONE)
// On Ozone, the target for native buffers should be used if a
// multiplanar format with external sampling is passed.
TEST(ClientSharedImageTest,
     GetTextureTarget_MultiplanarFormatsWithExternalSampling) {
  auto sii = base::MakeRefCounted<TestSharedImageInterface>();
  sii->emulate_client_provided_native_buffer();

  const gfx::Size kSize(256, 256);
  const SharedImageUsageSet kUsage =
      SHARED_IMAGE_USAGE_RASTER_WRITE | SHARED_IMAGE_USAGE_DISPLAY_READ;

  // Pass all the multiplanar formats that are used with hardware GMBs.
  for (auto format :
       {viz::MultiPlaneFormat::kYV12, viz::MultiPlaneFormat::kNV12,
        viz::MultiPlaneFormat::kNV12A, viz::MultiPlaneFormat::kP010}) {
    format.SetPrefersExternalSampler();
    SharedImageInfo si_info{format,
                            kSize,
                            gfx::ColorSpace(),
                            kTopLeft_GrSurfaceOrigin,
                            kOpaque_SkAlphaType,
                            kUsage,
                            ""};

    auto client_si = sii->CreateSharedImage(si_info, kNullSurfaceHandle);

    // Since the format has external sampling enabled, the platform-specific
    // target for native buffers should be used.
#if BUILDFLAG(IS_FUCHSIA)
    EXPECT_EQ(client_si->GetTextureTarget(), 0u);
#else
    EXPECT_EQ(client_si->GetTextureTarget(),
              static_cast<uint32_t>(GL_TEXTURE_EXTERNAL_OES));
#endif
  }
}
#endif

}  // namespace gpu