blob: 97f083d5399b274aba67947bf425db178d9aceff [file] [log] [blame]
// 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));
// 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