blob: d438573bd3d0a500f48e751e366ed1ad0b76d352 [file] [log] [blame]
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <GLES2/gl2.h>
#include <GLES2/gl2extchromium.h>
#include "base/containers/contains.h"
#include "components/viz/common/resources/shared_image_format_utils.h"
#include "gpu/command_buffer/client/client_shared_image.h"
#include "gpu/command_buffer/common/gpu_memory_buffer_support.h"
#include "gpu/command_buffer/common/shared_image_capabilities.h"
#include "gpu/command_buffer/common/shared_image_usage.h"
#include "gpu/ipc/common/gpu_memory_buffer_support.h"
#include "ui/gfx/buffer_types.h"
namespace gpu {
namespace {
bool GMBIsNative(gfx::GpuMemoryBufferType gmb_type) {
return gmb_type != gfx::EMPTY_BUFFER && gmb_type != gfx::SHARED_MEMORY_BUFFER;
}
} // namespace
BASE_FEATURE(kUseUniversalGetTextureTargetFunction,
"UseUniversalGetTextureTargetFunction",
base::FEATURE_DISABLED_BY_DEFAULT);
ClientSharedImage::ScopedMapping::ScopedMapping() = default;
ClientSharedImage::ScopedMapping::~ScopedMapping() {
if (buffer_) {
buffer_->Unmap();
}
}
// static
std::unique_ptr<ClientSharedImage::ScopedMapping>
ClientSharedImage::ScopedMapping::Create(
gfx::GpuMemoryBuffer* gpu_memory_buffer) {
auto scoped_mapping = base::WrapUnique(new ScopedMapping());
if (!scoped_mapping->Init(gpu_memory_buffer)) {
LOG(ERROR) << "ScopedMapping init failed.";
return nullptr;
}
return scoped_mapping;
}
bool ClientSharedImage::ScopedMapping::Init(
gfx::GpuMemoryBuffer* gpu_memory_buffer) {
if (!gpu_memory_buffer) {
LOG(ERROR) << "No GpuMemoryBuffer.";
return false;
}
if (!gpu_memory_buffer->Map()) {
LOG(ERROR) << "Failed to map the buffer.";
return false;
}
buffer_ = gpu_memory_buffer;
return true;
}
void* ClientSharedImage::ScopedMapping::Memory(const uint32_t plane_index) {
CHECK(buffer_);
return buffer_->memory(plane_index);
}
size_t ClientSharedImage::ScopedMapping::Stride(const uint32_t plane_index) {
CHECK(buffer_);
return buffer_->stride(plane_index);
}
gfx::Size ClientSharedImage::ScopedMapping::Size() {
CHECK(buffer_);
return buffer_->GetSize();
}
gfx::BufferFormat ClientSharedImage::ScopedMapping::Format() {
CHECK(buffer_);
return buffer_->GetFormat();
}
bool ClientSharedImage::ScopedMapping::IsSharedMemory() {
CHECK(buffer_);
return buffer_->GetType() == gfx::GpuMemoryBufferType::SHARED_MEMORY_BUFFER;
}
void ClientSharedImage::ScopedMapping::OnMemoryDump(
base::trace_event::ProcessMemoryDump* pmd,
const base::trace_event::MemoryAllocatorDumpGuid& buffer_dump_guid,
uint64_t tracing_process_id,
int importance) {
buffer_->OnMemoryDump(pmd, buffer_dump_guid, tracing_process_id, importance);
}
ClientSharedImage::ClientSharedImage(
const Mailbox& mailbox,
const SharedImageMetadata& metadata,
const SyncToken& sync_token,
scoped_refptr<SharedImageInterfaceHolder> sii_holder,
gfx::GpuMemoryBufferType gmb_type /*= gfx::EMPTY_BUFFER*/)
: mailbox_(mailbox),
metadata_(metadata),
creation_sync_token_(sync_token),
sii_holder_(std::move(sii_holder)),
client_side_native_buffer_used_(GMBIsNative(gmb_type)) {
CHECK(!mailbox.IsZero());
}
ClientSharedImage::ClientSharedImage(
const Mailbox& mailbox,
const SharedImageMetadata& metadata,
const SyncToken& sync_token,
GpuMemoryBufferHandleInfo handle_info,
scoped_refptr<SharedImageInterfaceHolder> sii_holder)
: mailbox_(mailbox),
metadata_(metadata),
creation_sync_token_(sync_token),
gpu_memory_buffer_(
GpuMemoryBufferSupport().CreateGpuMemoryBufferImplFromHandle(
std::move(handle_info.handle),
handle_info.size,
// Only single planar buffer formats are supported currently.
// Multiplanar will be supported when Multiplanar SharedImages are
// fully implemented.
viz::SinglePlaneSharedImageFormatToBufferFormat(
handle_info.format),
handle_info.buffer_usage,
base::DoNothing())),
sii_holder_(std::move(sii_holder)) {
CHECK(!mailbox.IsZero());
client_side_native_buffer_used_ = GMBIsNative(gpu_memory_buffer_->GetType());
}
ClientSharedImage::~ClientSharedImage() = default;
std::unique_ptr<ClientSharedImage::ScopedMapping> ClientSharedImage::Map() {
auto scoped_mapping = ScopedMapping::Create(gpu_memory_buffer_.get());
if (!scoped_mapping) {
LOG(ERROR) << "Unable to create ScopedMapping";
}
return scoped_mapping;
}
#if BUILDFLAG(IS_APPLE)
void ClientSharedImage::SetColorSpaceOnNativeBuffer(
const gfx::ColorSpace& color_space) {
CHECK(gpu_memory_buffer_);
gpu_memory_buffer_->SetColorSpace(color_space);
}
#endif
uint32_t ClientSharedImage::GetTextureTarget() {
// On Mac, the platform-specific texture target is required if this
// SharedImage is backed by a native buffer. On other platforms, the
// platform-specific target is required if external sampling is used.
#if BUILDFLAG(IS_MAC)
// NOTE: WebGPU usage on Mac results in SharedImages being backed by
// IOSurfaces.
uint32_t usages_requiring_native_buffer = SHARED_IMAGE_USAGE_SCANOUT |
SHARED_IMAGE_USAGE_WEBGPU_READ |
SHARED_IMAGE_USAGE_WEBGPU_WRITE;
bool uses_native_buffer = client_side_native_buffer_used_ ||
(usage() & usages_requiring_native_buffer);
return uses_native_buffer ? GetPlatformSpecificTextureTarget()
: GL_TEXTURE_2D;
#else
bool uses_external_sampler =
format().PrefersExternalSampler() || format().IsLegacyMultiplanar();
// The client should configure an SI to use external sampling only if they
// have provided a native buffer to back that SI.
CHECK(!uses_external_sampler || client_side_native_buffer_used_);
return uses_external_sampler ? GetPlatformSpecificTextureTarget()
: GL_TEXTURE_2D;
#endif
}
uint32_t ClientSharedImage::GetTextureTargetForOverlays() {
if (base::FeatureList::IsEnabled(kUseUniversalGetTextureTargetFunction)) {
return GetTextureTarget();
}
#if BUILDFLAG(IS_MAC)
return GetPlatformSpecificTextureTarget();
#else
return GL_TEXTURE_2D;
#endif
}
uint32_t ClientSharedImage::GetTextureTarget(gfx::BufferFormat format) {
if (base::FeatureList::IsEnabled(kUseUniversalGetTextureTargetFunction)) {
return GetTextureTarget();
}
return NativeBufferNeedsPlatformSpecificTextureTarget(format)
? GetPlatformSpecificTextureTarget()
: GL_TEXTURE_2D;
}
uint32_t ClientSharedImage::GetTextureTarget(gfx::BufferUsage usage,
gfx::BufferFormat format) {
if (base::FeatureList::IsEnabled(kUseUniversalGetTextureTargetFunction)) {
return GetTextureTarget();
}
CHECK(HasHolder());
auto capabilities = sii_holder_->Get()->GetCapabilities();
bool found = base::Contains(capabilities.texture_target_exception_list,
gfx::BufferUsageAndFormat(usage, format));
return found ? gpu::GetPlatformSpecificTextureTarget() : GL_TEXTURE_2D;
}
uint32_t ClientSharedImage::GetTextureTarget(gfx::BufferUsage usage) {
if (base::FeatureList::IsEnabled(kUseUniversalGetTextureTargetFunction)) {
return GetTextureTarget();
}
uint32_t usages_forcing_native_buffer = SHARED_IMAGE_USAGE_SCANOUT;
#if BUILDFLAG(IS_MAC)
// On Mac, WebGPU usage results in SharedImages being backed by IOSurfaces.
usages_forcing_native_buffer = usages_forcing_native_buffer |
SHARED_IMAGE_USAGE_WEBGPU_READ |
SHARED_IMAGE_USAGE_WEBGPU_WRITE;
#endif
bool uses_native_buffer = this->usage() & usages_forcing_native_buffer;
return uses_native_buffer
? GetTextureTarget(usage,
viz::SinglePlaneSharedImageFormatToBufferFormat(
metadata_.format))
: GL_TEXTURE_2D;
}
ExportedSharedImage ClientSharedImage::Export() {
if (creation_sync_token_.HasData() &&
!creation_sync_token_.verified_flush()) {
sii_holder_->Get()->VerifySyncToken(creation_sync_token_);
}
return ExportedSharedImage(mailbox_, metadata_, creation_sync_token_);
}
scoped_refptr<ClientSharedImage> ClientSharedImage::ImportUnowned(
const ExportedSharedImage& exported_shared_image) {
return base::MakeRefCounted<ClientSharedImage>(
exported_shared_image.mailbox_, exported_shared_image.metadata_,
exported_shared_image.sync_token_, nullptr);
}
ExportedSharedImage::ExportedSharedImage(const Mailbox& mailbox,
const SharedImageMetadata& metadata,
const SyncToken& sync_token)
: mailbox_(mailbox), metadata_(metadata), sync_token_(sync_token) {}
} // namespace gpu