#ifndef GPU_COMMAND_BUFFER_CLIENT_CLIENT_SHARED_IMAGE_H_
#define GPU_COMMAND_BUFFER_CLIENT_CLIENT_SHARED_IMAGE_H_
#include <optional>
#include "base/byte_count.h"
#include "base/containers/span.h"
#include "base/gtest_prod_util.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/raw_ptr_exclusion.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_refptr.h"
#include "base/memory/unsafe_shared_memory_pool.h"
#include "base/task/single_thread_task_runner.h"
#include "gpu/command_buffer/client/gpu_command_buffer_client_export.h"
#include "gpu/command_buffer/client/internal/mappable_buffer.h"
#include "gpu/command_buffer/common/mailbox.h"
#include "gpu/command_buffer/common/shared_image_trace_utils.h"
#include "gpu/command_buffer/common/shared_image_usage.h"
#include "gpu/command_buffer/common/sync_token.h"
#include "gpu/ipc/common/exported_shared_image.mojom-forward.h"
#include "gpu/ipc/common/gpu_memory_buffer_handle_info.h"
#include "third_party/skia/include/core/SkImageInfo.h"
#include "third_party/skia/include/core/SkPixmap.h"
#include "third_party/skia/include/gpu/ganesh/GrTypes.h"
#include "ui/gfx/color_space.h"
#include "ui/gfx/gpu_memory_buffer_handle.h"
namespace base::trace_event {
class ProcessMemoryDump;
class MemoryAllocatorDumpGuid;
}
namespace media {
class VideoFrame;
}
namespace viz {
class CopyOutputSharedImageResult;
}
namespace wgpu::dawn::wire::client {
class Device;
class Texture;
class Buffer;
struct TextureDescriptor;
struct BufferDescriptor;
}
namespace gpu {
namespace gles2 {
class GLES2Interface;
}
namespace webgpu {
class WebGPUInterface;
enum MailboxFlags : uint32_t;
}
class SharedImageInterface;
class ClientSharedImageInterface;
class GpuChannelSharedImageInterface;
class GpuChannelSharedImageInterfaceExt;
class MappableBuffer;
class InterfaceBase;
class RasterScopedAccess;
struct SharedImageInfo;
class SharedImageInterfaceHolder;
class SharedImageTexture;
class TestSharedImageInterface;
class WebGPUTextureScopedAccess;
class WebGPUBufferScopedAccess;
struct ExportedSharedImage;
struct SharedImageMetadata {
viz::SharedImageFormat format;
gfx::Size size;
gfx::ColorSpace color_space;
GrSurfaceOrigin surface_origin;
SkAlphaType alpha_type;
SharedImageUsageSet usage;
};
class GPU_COMMAND_BUFFER_CLIENT_EXPORT ClientSharedImage
: public base::RefCountedThreadSafe<ClientSharedImage> {
public:
class GPU_COMMAND_BUFFER_CLIENT_EXPORT ScopedMapping {
public:
ScopedMapping(const gfx::Size& size, viz::SharedImageFormat format);
~ScopedMapping();
base::span<uint8_t> GetMemoryForPlane(const uint32_t plane_index);
SkPixmap GetSkPixmapForPlane(const uint32_t plane_index,
SkImageInfo sk_image_info);
size_t Stride(const uint32_t plane_index);
gfx::Size Size();
bool IsSharedMemory();
private:
friend class ClientSharedImage;
static std::unique_ptr<ScopedMapping> Create(
SharedImageMetadata metadata_,
MappableBuffer* mappable_buffer,
bool is_already_mapped);
static void StartCreateAsync(
SharedImageMetadata metadata_,
MappableBuffer* mappable_buffer,
base::OnceCallback<void(std::unique_ptr<ScopedMapping>)> result_cb);
static void FinishCreateAsync(
SharedImageMetadata metadata_,
MappableBuffer* mappable_buffer,
base::OnceCallback<void(std::unique_ptr<ScopedMapping>)> result_cb,
bool success);
bool Init(MappableBuffer* mappable_buffer, bool is_already_mapped);
RAW_PTR_EXCLUSION MappableBuffer* buffer_ = nullptr;
gfx::Size size_;
viz::SharedImageFormat format_;
};
ClientSharedImage(const Mailbox& mailbox,
const SharedImageInfo& info,
const SyncToken& sync_token,
scoped_refptr<SharedImageInterfaceHolder> sii_holder,
gfx::GpuMemoryBufferType gmb_type);
ClientSharedImage(const Mailbox& mailbox,
const SharedImageInfo& info,
const SyncToken& sync_token,
scoped_refptr<SharedImageInterfaceHolder> sii_holder,
base::WritableSharedMemoryMapping mapping);
ClientSharedImage(
const Mailbox& mailbox,
const SharedImageInfo& info,
const SyncToken& sync_token,
GpuMemoryBufferHandleInfo handle_info,
scoped_refptr<SharedImageInterfaceHolder> sii_holder,
scoped_refptr<base::UnsafeSharedMemoryPool> shared_memory_pool = nullptr);
const Mailbox& mailbox() const { return mailbox_; }
viz::SharedImageFormat format() const { return metadata_.format; }
base::ByteCount EstimatedSizeInBytes() const {
return base::ByteCount(format().EstimatedSizeInBytes(size()));
}
gfx::Size size() const { return metadata_.size; }
const gfx::ColorSpace& color_space() const { return metadata_.color_space; }
GrSurfaceOrigin surface_origin() const { return metadata_.surface_origin; }
SkAlphaType alpha_type() const { return metadata_.alpha_type; }
SharedImageUsageSet usage() const { return metadata_.usage; }
std::optional<gfx::BufferUsage> buffer_usage() const { return buffer_usage_; }
std::string debug_label() const { return debug_label_; }
bool is_software() const { return is_software_; }
bool HasHolder() { return sii_holder_ != nullptr; }
gfx::GpuMemoryBufferHandle CloneGpuMemoryBufferHandle() const;
uint32_t GetTextureTarget();
base::trace_event::MemoryAllocatorDumpGuid GetGUIDForTracing() {
return gpu::GetSharedImageGUIDForTracing(mailbox_);
}
std::unique_ptr<ScopedMapping> Map();
void MapAsync(
base::OnceCallback<void(std::unique_ptr<ScopedMapping>)> result_cb);
scoped_refptr<ClientSharedImage> MakeUnowned();
ExportedSharedImage Export(bool with_buffer_handle = false);
static scoped_refptr<ClientSharedImage> ImportUnowned(
ExportedSharedImage exported_shared_image);
void UpdateDestructionSyncToken(const gpu::SyncToken& sync_token) {
destruction_sync_token_ = sync_token;
}
gpu::SyncToken BackingWasExternallyUpdated(const gpu::SyncToken& sync_token);
static scoped_refptr<ClientSharedImage> CreateForTesting();
static scoped_refptr<ClientSharedImage> CreateSoftwareForTesting();
static scoped_refptr<ClientSharedImage> CreateForTesting(
viz::SharedImageFormat format,
uint32_t texture_target);
static scoped_refptr<ClientSharedImage> CreateForTesting(
SharedImageUsageSet usage);
static scoped_refptr<ClientSharedImage> CreateForTesting(
const SharedImageMetadata& metadata);
static scoped_refptr<ClientSharedImage> CreateForTesting(
const SharedImageMetadata& metadata,
uint32_t texture_target);
using AsyncMapCompletionCallback = base::OnceCallback<void(bool)>;
static scoped_refptr<ClientSharedImage> CreateForTesting(
const Mailbox& mailbox,
const SharedImageMetadata& metadata,
const SyncToken& sync_token,
uint32_t texture_target,
bool is_software = false);
using AsyncMapInvokedCallback =
base::RepeatingCallback<void(AsyncMapCompletionCallback)>;
static scoped_refptr<ClientSharedImage> CreateForTesting(
const Mailbox& mailbox,
const SharedImageMetadata& metadata,
const SyncToken& sync_token,
bool premapped,
const AsyncMapInvokedCallback& callback,
gfx::BufferUsage buffer_usage,
scoped_refptr<SharedImageInterfaceHolder> sii_holder);
const SyncToken& creation_sync_token() const { return creation_sync_token_; }
void OnMemoryDump(
base::trace_event::ProcessMemoryDump* pmd,
const base::trace_event::MemoryAllocatorDumpGuid& buffer_dump_guid,
int importance);
std::unique_ptr<SharedImageTexture> CreateGLTexture(
gles2::GLES2Interface* gl);
std::unique_ptr<RasterScopedAccess> BeginRasterAccess(
InterfaceBase* raster_interface,
const SyncToken& sync_token,
bool readonly);
std::unique_ptr<RasterScopedAccess> BeginGLAccessForCopySharedImage(
InterfaceBase* gl_interface,
const SyncToken& sync_token,
bool readonly);
std::unique_ptr<WebGPUTextureScopedAccess> BeginWebGPUTextureAccess(
webgpu::WebGPUInterface* webgpu,
const SyncToken& sync_token,
const wgpu::dawn::wire::client::Device& device,
const wgpu::dawn::wire::client::TextureDescriptor& desc,
uint64_t usage,
webgpu::MailboxFlags mailbox_flags);
std::unique_ptr<WebGPUBufferScopedAccess> BeginWebGPUBufferAccess(
webgpu::WebGPUInterface* webgpu,
const SyncToken& sync_token,
const wgpu::dawn::wire::client::Device& device,
const wgpu::dawn::wire::client::BufferDescriptor& desc,
uint64_t usage,
webgpu::MailboxFlags mailbox_flags);
#if BUILDFLAG(IS_WIN)
void SetUsePreMappedMemory(bool use_premapped_memory);
#endif
private:
friend class base::RefCountedThreadSafe<ClientSharedImage>;
friend class SharedImageTexture;
~ClientSharedImage();
std::unique_ptr<MappableBuffer> CreateMappableBufferFromHandle(
gfx::GpuMemoryBufferHandle handle,
const gfx::Size& size,
viz::SharedImageFormat format,
gfx::BufferUsage usage,
gpu::SharedImageUsageSet si_usage,
MappableBuffer::CopyNativeBufferToShMemCallback
copy_native_buffer_to_shmem_callback =
MappableBuffer::CopyNativeBufferToShMemCallback(),
scoped_refptr<base::UnsafeSharedMemoryPool> pool = nullptr);
friend class ClientSharedImageInterface;
friend class GpuChannelSharedImageInterface;
friend class GpuChannelSharedImageInterfaceExt;
friend class RasterScopedAccess;
friend class TestSharedImageInterface;
friend class media::VideoFrame;
friend class WebGPUTextureScopedAccess;
friend class WebGPUBufferScopedAccess;
ClientSharedImage(const Mailbox& mailbox,
const SharedImageInfo& info,
const SyncToken& sync_token,
scoped_refptr<SharedImageInterfaceHolder> sii_holder,
uint32_t texture_target);
ClientSharedImage(ExportedSharedImage exported_si,
scoped_refptr<SharedImageInterfaceHolder> sii_holder);
explicit ClientSharedImage(ExportedSharedImage exported_si);
friend class ::viz::CopyOutputSharedImageResult;
explicit ClientSharedImage(const Mailbox& mailbox,
const SharedImageInfo& info);
size_t GetStrideForVideoFrame(uint32_t plane_index) const;
bool IsSharedMemoryForVideoFrame() const;
bool AsyncMappingIsNonBlocking() const;
void CopyNativeGmbToSharedMemoryAsync(
gfx::GpuMemoryBufferHandle buffer_handle,
base::UnsafeSharedMemoryRegion memory_region,
base::OnceCallback<void(bool)> callback);
void BeginAccess(bool readonly);
void EndAccess(bool readonly);
void FinishMapAsyncForTests(
base::OnceCallback<void(std::unique_ptr<ScopedMapping>)> result_cb,
bool success);
const Mailbox mailbox_;
const SharedImageMetadata metadata_;
const std::string debug_label_;
SyncToken creation_sync_token_;
SyncToken destruction_sync_token_;
std::unique_ptr<MappableBuffer> mappable_buffer_;
std::optional<gfx::BufferUsage> buffer_usage_;
scoped_refptr<SharedImageInterfaceHolder> sii_holder_;
scoped_refptr<base::SingleThreadTaskRunner>
copy_native_buffer_to_shmem_task_runner_;
uint32_t texture_target_ = 0;
bool is_software_ = false;
AsyncMapInvokedCallback async_map_invoked_callback_for_testing_;
bool premapped_for_testing_;
unsigned int num_readers_ GUARDED_BY(lock_) = 0;
bool has_writer_ GUARDED_BY(lock_) = false;
base::Lock lock_;
};
struct GPU_COMMAND_BUFFER_CLIENT_EXPORT ExportedSharedImage {
public:
ExportedSharedImage();
~ExportedSharedImage();
ExportedSharedImage(const ExportedSharedImage& other) = delete;
ExportedSharedImage& operator=(const ExportedSharedImage& other) = delete;
ExportedSharedImage(ExportedSharedImage&& other);
ExportedSharedImage& operator=(ExportedSharedImage&& other);
ExportedSharedImage Clone() const;
private:
friend class ClientSharedImage;
friend class SharedImageInterface;
friend class ClientSharedImageInterface;
friend class TestSharedImageInterface;
friend struct mojo::StructTraits<gpu::mojom::ExportedSharedImageDataView,
ExportedSharedImage>;
FRIEND_TEST_ALL_PREFIXES(ClientSharedImageTest, ImportUnowned);
ExportedSharedImage(const Mailbox& mailbox,
const SharedImageMetadata& metadata,
const SyncToken& sync_token,
std::string debug_label,
std::optional<gfx::GpuMemoryBufferHandle> buffer_handle,
std::optional<gfx::BufferUsage> buffer_usage,
uint32_t texture_target,
bool is_software);
Mailbox mailbox_;
SharedImageMetadata metadata_;
SyncToken creation_sync_token_;
std::string debug_label_;
std::optional<gfx::GpuMemoryBufferHandle> buffer_handle_;
std::optional<gfx::BufferUsage> buffer_usage_;
uint32_t texture_target_ = 0;
bool is_software_ = false;
};
class GPU_COMMAND_BUFFER_CLIENT_EXPORT SharedImageTexture {
public:
class GPU_COMMAND_BUFFER_CLIENT_EXPORT ScopedAccess {
public:
ScopedAccess(const ScopedAccess&) = delete;
ScopedAccess& operator=(const ScopedAccess&) = delete;
ScopedAccess(ScopedAccess&&) = delete;
ScopedAccess& operator=(ScopedAccess&&) = delete;
~ScopedAccess();
unsigned int texture_id() { return texture_->id(); }
static SyncToken EndAccess(
std::unique_ptr<ScopedAccess> scoped_shared_image);
private:
friend class SharedImageTexture;
ScopedAccess(SharedImageTexture* texture,
const SyncToken& sync_token,
bool readonly);
void DidEndAccess();
const raw_ptr<SharedImageTexture> texture_;
const bool readonly_;
bool is_access_ended_ = false;
};
SharedImageTexture(const SharedImageTexture&) = delete;
SharedImageTexture& operator=(const SharedImageTexture&) = delete;
SharedImageTexture(SharedImageTexture&&) = delete;
SharedImageTexture& operator=(SharedImageTexture&&) = delete;
~SharedImageTexture();
std::unique_ptr<ScopedAccess> BeginAccess(const SyncToken& sync_token,
bool readonly);
void DidEndAccess(bool readonly);
unsigned int id() { return id_; }
private:
friend class ClientSharedImage;
SharedImageTexture(gles2::GLES2Interface* gl,
ClientSharedImage* shared_image);
const raw_ptr<gles2::GLES2Interface> gl_;
const raw_ptr<gpu::ClientSharedImage> shared_image_;
unsigned int id_ = 0;
bool has_active_access_ = false;
};
class GPU_COMMAND_BUFFER_CLIENT_EXPORT RasterScopedAccess {
public:
RasterScopedAccess(const RasterScopedAccess&) = delete;
RasterScopedAccess& operator=(const RasterScopedAccess&) = delete;
RasterScopedAccess(RasterScopedAccess&&) = delete;
RasterScopedAccess& operator=(RasterScopedAccess&&) = delete;
~RasterScopedAccess() = default;
static SyncToken EndAccess(
std::unique_ptr<RasterScopedAccess> scoped_shared_image);
private:
friend class ClientSharedImage;
RasterScopedAccess(InterfaceBase* raster_interface,
ClientSharedImage* shared_image,
const SyncToken& sync_token,
bool readonly);
const raw_ptr<InterfaceBase> raster_interface_;
const raw_ptr<ClientSharedImage> shared_image_;
bool readonly_;
};
class GPU_COMMAND_BUFFER_CLIENT_EXPORT WebGPUTextureScopedAccess {
public:
WebGPUTextureScopedAccess(const WebGPUTextureScopedAccess&) = delete;
WebGPUTextureScopedAccess& operator=(const WebGPUTextureScopedAccess&) =
delete;
WebGPUTextureScopedAccess(WebGPUTextureScopedAccess&&) = delete;
WebGPUTextureScopedAccess& operator=(WebGPUTextureScopedAccess&&) = delete;
~WebGPUTextureScopedAccess();
static SyncToken EndAccess(
std::unique_ptr<WebGPUTextureScopedAccess> scoped_access);
void SetNeedsPresent(bool needs_present);
const wgpu::dawn::wire::client::Texture& texture();
void ClearContext();
private:
friend class ClientSharedImage;
WebGPUTextureScopedAccess(
webgpu::WebGPUInterface* webgpu,
ClientSharedImage* shared_image,
const SyncToken& sync_token,
const wgpu::dawn::wire::client::Device& device,
const wgpu::dawn::wire::client::TextureDescriptor& desc,
uint64_t usage,
webgpu::MailboxFlags mailbox_flags);
raw_ptr<webgpu::WebGPUInterface> webgpu_;
std::unique_ptr<wgpu::dawn::wire::client::Texture> texture_;
raw_ptr<gpu::ClientSharedImage> shared_image_;
uint32_t device_id_ = 0;
uint32_t device_generation_ = 0;
uint32_t texture_id_ = 0;
uint32_t texture_generation_ = 0;
bool needs_present_ = false;
bool readonly_;
};
class GPU_COMMAND_BUFFER_CLIENT_EXPORT WebGPUBufferScopedAccess {
public:
WebGPUBufferScopedAccess(const WebGPUBufferScopedAccess&) = delete;
WebGPUBufferScopedAccess& operator=(const WebGPUBufferScopedAccess&) = delete;
WebGPUBufferScopedAccess(WebGPUBufferScopedAccess&&) = delete;
WebGPUBufferScopedAccess& operator=(WebGPUBufferScopedAccess&&) = delete;
~WebGPUBufferScopedAccess();
static SyncToken EndAccess(
std::unique_ptr<WebGPUBufferScopedAccess> scoped_access);
const wgpu::dawn::wire::client::Buffer& buffer();
private:
friend class ClientSharedImage;
WebGPUBufferScopedAccess(
webgpu::WebGPUInterface* webgpu,
ClientSharedImage* shared_image,
const SyncToken& sync_token,
const wgpu::dawn::wire::client::Device& device,
const wgpu::dawn::wire::client::BufferDescriptor& desc,
uint64_t usage,
webgpu::MailboxFlags mailbox_flags);
const raw_ptr<webgpu::WebGPUInterface> webgpu_;
std::unique_ptr<wgpu::dawn::wire::client::Buffer> buffer_;
raw_ptr<gpu::ClientSharedImage> shared_image_;
uint32_t buffer_id_ = 0;
uint32_t buffer_generation_ = 0;
};
}
#endif