| // Copyright 2018 The Chromium Authors | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| #ifndef GPU_COMMAND_BUFFER_CLIENT_SHARED_IMAGE_INTERFACE_H_ | |
| #define GPU_COMMAND_BUFFER_CLIENT_SHARED_IMAGE_INTERFACE_H_ | |
| #include <cstdint> | |
| #include <optional> | |
| #include "base/compiler_specific.h" | |
| #include "base/containers/span.h" | |
| #include "base/memory/raw_ptr.h" | |
| #include "base/memory/ref_counted.h" | |
| #include "base/memory/scoped_refptr.h" | |
| #include "build/build_config.h" | |
| #include "components/viz/common/resources/shared_image_format.h" | |
| #include "gpu/command_buffer/client/client_shared_image.h" | |
| #include "gpu/command_buffer/client/gpu_command_buffer_client_export.h" | |
| #include "gpu/command_buffer/common/mailbox.h" | |
| #include "gpu/command_buffer/common/shared_image_info.h" | |
| #include "gpu/command_buffer/common/shared_image_pool_id.h" | |
| #include "gpu/command_buffer/common/shared_image_usage.h" | |
| #include "gpu/command_buffer/common/sync_token.h" | |
| #include "gpu/ipc/common/shared_image_pool_client_interface.mojom.h" | |
| #include "gpu/ipc/common/surface_handle.h" | |
| #include "mojo/public/cpp/bindings/pending_remote.h" | |
| #include "third_party/skia/include/core/SkImageInfo.h" | |
| #include "third_party/skia/include/gpu/ganesh/GrTypes.h" | |
| #include "ui/gfx/buffer_types.h" | |
| #include "ui/gfx/color_space.h" | |
| #include "ui/gfx/gpu_memory_buffer_handle.h" | |
| #include "ui/gfx/native_pixmap.h" | |
| #include "ui/gfx/native_pixmap_handle.h" | |
| #if BUILDFLAG(IS_FUCHSIA) | |
| #include <lib/zx/channel.h> | |
| #include <lib/zx/eventpair.h> | |
| #endif // BUILDFLAG(IS_FUCHSIA) | |
| namespace gfx { | |
| class GpuFence; | |
| class Size; | |
| #if BUILDFLAG(IS_WIN) | |
| class D3DSharedFence; | |
| #endif | |
| } // namespace gfx | |
| namespace media { | |
| class MockSharedImageInterface; | |
| } | |
| namespace gpu { | |
| class ArcSharedImageInterface; | |
| class ClientSharedImageInterface; | |
| struct ExportedSharedImage; | |
| class GpuChannelLostObserver; | |
| struct SharedImageCapabilities; | |
| class SharedImageInterfaceHolder; | |
| class SharedImageInterfaceInProcessBase; | |
| class TestSharedImageInterface; | |
| // An interface to create shared images and swap chains that can be imported | |
| // into other APIs. This interface is thread-safe and (essentially) stateless. | |
| // It is asynchronous in the same sense as GLES2Interface or RasterInterface in | |
| // that commands are executed asynchronously on the service side, but can be | |
| // synchronized using SyncTokens. See //docs/design/gpu_synchronization.md. | |
| class GPU_COMMAND_BUFFER_CLIENT_EXPORT SharedImageInterface | |
| : public base::RefCountedThreadSafe<SharedImageInterface> { | |
| public: | |
| // Creates a shared image of requested |format|, |size| and |color_space|. | |
| // |usage| is a combination of |SharedImageUsage| bits that describes which | |
| // API(s) the image will be used with. | |
| // Returns a non-null scoped_refptr to ClientSharedImage. The | |
| // ClientSharedImage struct contains a mailbox that can be imported into said | |
| // APIs using their corresponding shared image functions (e.g. | |
| // GLES2Interface::CreateAndTexStorage2DSharedImageCHROMIUM or | |
| // RasterInterface::CopySharedImage). | |
| // The |SharedImageInterface| keeps ownership of the image until | |
| // |DestroySharedImage| is called or the interface itself is destroyed (e.g. | |
| // the GPU channel is lost). | |
| // |debug_label| is retained for heap dumps and passed to graphics APIs for | |
| // tracing tools. Pick a name that is unique to the allocation site. | |
| virtual scoped_refptr<ClientSharedImage> CreateSharedImage( | |
| const SharedImageInfo& si_info, | |
| gpu::SurfaceHandle surface_handle, | |
| std::optional<SharedImagePoolId> pool_id /*=std::nullopt*/) = 0; | |
| scoped_refptr<ClientSharedImage> CreateSharedImage( | |
| const SharedImageInfo& si_info, | |
| gpu::SurfaceHandle surface_handle) { | |
| return CreateSharedImage(si_info, surface_handle, std::nullopt); | |
| } | |
| // Same behavior as the above, except that this version takes |pixel_data| | |
| // which is used to populate the SharedImage. |pixel_data| should have the | |
| // same format which would be passed to glTexImage2D to populate a similarly | |
| // specified texture. | |
| // May return null if |pixel_data| is too big for IPC. | |
| // TODO(crbug.com/40268891): Have the caller specify a row span for | |
| // |pixel_data| explicitly. Some backings have different row alignment | |
| // requirements which the caller has to match exactly or it won't work. | |
| virtual scoped_refptr<ClientSharedImage> CreateSharedImage( | |
| const SharedImageInfo& si_info, | |
| base::span<const uint8_t> pixel_data) = 0; | |
| // Same behavior as above methods, except that this version is specifically | |
| // used by clients which intend to create a shared image back by either a | |
| // native buffer (if supported) or shared memory which are CPU mappable. | |
| // We are currently passing BufferUsage to this method for simplicity since | |
| // as of now we dont have a clear way to map BufferUsage to SharedImageUsage. | |
| // May return null if GPU memory buffer creation fails. | |
| // TODO(crbug.com/40276844): Merge this method to above existing methods once | |
| // we figure out mapping between BufferUsage and SharedImageUsage and | |
| // eliminate all usages of BufferUsage. | |
| virtual scoped_refptr<ClientSharedImage> CreateSharedImage( | |
| const SharedImageInfo& si_info, | |
| gpu::SurfaceHandle surface_handle, | |
| gfx::BufferUsage buffer_usage, | |
| std::optional<SharedImagePoolId> pool_id /*=std::nullopt*/); | |
| scoped_refptr<ClientSharedImage> CreateSharedImage( | |
| const SharedImageInfo& si_info, | |
| gpu::SurfaceHandle surface_handle, | |
| gfx::BufferUsage buffer_usage) { | |
| return CreateSharedImage(si_info, surface_handle, buffer_usage, | |
| std::nullopt); | |
| } | |
| // Creates a shared image out an existing buffer. The buffer described by | |
| // `buffer_handle` must hold all planes based on `format` and `size`. This | |
| // version is specifically used by clients that need access to the buffer on | |
| // the client side. It ensures that | |
| // ClientSharedImage::CloneGpuMemoryBufferHandle() can be invoked on the | |
| // returned ClientSharedImage. | |
| // NOTE: We are currently passing BufferUsage to this method for simplicity | |
| // since as of now we dont have a clear way to map BufferUsage to | |
| // SharedImageUsage. | |
| // TODO(crbug.com/40276844): Merge this method to above existing methods once | |
| // we figure out mapping between BufferUsage and SharedImageUsage and | |
| // eliminate all usages of BufferUsage. | |
| virtual scoped_refptr<ClientSharedImage> CreateSharedImage( | |
| const SharedImageInfo& si_info, | |
| gpu::SurfaceHandle surface_handle, | |
| gfx::BufferUsage buffer_usage, | |
| gfx::GpuMemoryBufferHandle buffer_handle) = 0; | |
| // Creates a shared image out an existing buffer. The buffer described by | |
| // `buffer_handle` must hold all planes based `format` and `size. `usage` is a | |
| // combination of |SharedImageUsage| bits that describes which API(s) the | |
| // image will be used with. | |
| // | |
| // SharedImageInterface keeps ownership of the image until | |
| // `DestroySharedImage()` is called or the interface itself is destroyed (e.g. | |
| // the GPU channel is lost). | |
| virtual scoped_refptr<ClientSharedImage> CreateSharedImage( | |
| const SharedImageInfo& si_info, | |
| gfx::GpuMemoryBufferHandle buffer_handle) = 0; | |
| // Creates a shared image for an existing MLTensor. | |
| // Tensors store numeric values in multiple dimensions. | |
| // |size| is calculated from the tensor's shape: the product of all dimensions | |
| // except the last determines the height, and the last dimension becomes the | |
| // width. |usage| must include gpu::SHARED_IMAGE_USAGE_WEBNN_SHARED_TENSOR. | |
| // |format| should be valid and correspond to the equivalent dataType. | |
| virtual scoped_refptr<ClientSharedImage> CreateSharedImageForMLTensor( | |
| std::string debug_label, | |
| viz::SharedImageFormat format, | |
| const gfx::Size& size, | |
| gpu::SharedImageUsageSet usage) = 0; | |
| // Creates a shared image with the usage of | |
| // gpu::SHARED_IMAGE_USAGE_CPU_WRITE_ONLY only. A shared memory buffer is | |
| // created internally and a shared image is created out of this buffer. This | |
| // method is used by the software compositor only. | |
| virtual scoped_refptr<ClientSharedImage> | |
| CreateSharedImageForSoftwareCompositor(const SharedImageInfo& si_info) = 0; | |
| // Updates a shared image after its GpuMemoryBuffer (if any) was modified on | |
| // the CPU or through external devices, after |sync_token| has been released. | |
| virtual void UpdateSharedImage(const SyncToken& sync_token, | |
| const Mailbox& mailbox) = 0; | |
| // Updates a shared image after its GpuMemoryBuffer (if any) was modified on | |
| // the CPU or through external devices, after |sync_token| has been released. | |
| // If |acquire_fence| is not null, the fence is inserted in the GPU command | |
| // stream and a server side wait is issued before any GPU command referring | |
| // to this shared imaged is executed on the GPU. | |
| virtual void UpdateSharedImage(const SyncToken& sync_token, | |
| std::unique_ptr<gfx::GpuFence> acquire_fence, | |
| const Mailbox& mailbox) = 0; | |
| // Update the GpuMemoryBuffer associated with the shared image |mailbox| after | |
| // all |sync_tokens| have been released. This is needed when the | |
| // GpuMemoryBuffer is backed by shared memory on platforms like Windows where | |
| // the renderer cannot create native GMBs. | |
| virtual void CopyToGpuMemoryBuffer(std::vector<SyncToken> sync_tokens, | |
| const Mailbox& mailbox); | |
| // Update the GpuMemoryBuffer associated with the shared image |mailbox| after | |
| // all |sync_tokens| have been released. The |callback| is run denoting if the | |
| // copy was successful and the GpuMemoryBuffer is ready to be mapped by the | |
| // client. This is needed when the GpuMemoryBuffer is backed by shared memory | |
| // on platforms like Windows where the renderer cannot create native GMBs. | |
| virtual void CopyToGpuMemoryBufferAsync( | |
| std::vector<SyncToken> sync_tokens, | |
| const Mailbox& mailbox, | |
| base::OnceCallback<void(bool)> callback); | |
| // On windows, native GMB can not be mapped in any process other than the GPU | |
| // process. So during GpuMemoryBuffer::Map() operation, an IPC to GPU process | |
| // is done to copy the content of |buffer_handle| into a shared memory | |
| // |memory_region| via below methods. This shared memory is mappable in any | |
| // process and is used internally during GpuMemoryBuffer::Map(). | |
| // The |callback| will be run when the copy is done. | |
| virtual void CopyNativeGmbToSharedMemoryAsync( | |
| gfx::GpuMemoryBufferHandle buffer_handle, | |
| base::UnsafeSharedMemoryRegion memory_region, | |
| base::OnceCallback<void(bool)> callback); | |
| // Destroys the shared image, unregistering its mailbox, after all | |
| // |sync_tokens| have been released. After this call, the mailbox can't be | |
| // used to reference the image any more, however if the image was imported | |
| // into other APIs, those may keep a reference to the underlying data. | |
| virtual void DestroySharedImage(std::vector<SyncToken> sync_tokens, | |
| const Mailbox& mailbox) = 0; | |
| // Imports SharedImage to this interface and returns an owning reference. It | |
| // must be released via DestroySharedImage in the same way as for SharedImages | |
| // created via CreateSharedImage(). | |
| virtual scoped_refptr<ClientSharedImage> ImportSharedImage( | |
| ExportedSharedImage exported_shared_image) = 0; | |
| #if BUILDFLAG(IS_FUCHSIA) | |
| // Registers a sysmem buffer collection. `service_handle` contains a handle | |
| // for the eventpair that controls the lifetime of the collection. The | |
| // collection will be destroyed when all peer handles for that eventpair are | |
| // destroyed (i.e. when `ZX_EVENTPAIR_PEER_CLOSED` is signaled on that | |
| // handle). The caller can use CreateSharedImage() to create shared images | |
| // from the buffer in the collection by setting `buffer_collection_handle` and | |
| // `buffer_index` fields in NativePixmapHandle, wrapping it in | |
| // GpuMemoryBufferHandle and then creating a GpuMemoryBuffer from that handle. | |
| // If `register_with_image_pipe` field is set, the collection is shared with a | |
| // new ImagePipe, which allows it to display these images as overlays. | |
| virtual void RegisterSysmemBufferCollection( | |
| zx::eventpair service_handle, | |
| zx::channel sysmem_token, | |
| const viz::SharedImageFormat& format, | |
| gfx::BufferUsage usage, | |
| bool register_with_image_pipe) = 0; | |
| #endif // BUILDFLAG(IS_FUCHSIA) | |
| #if BUILDFLAG(IS_WIN) | |
| // Update fence between processes. Register D3DSharedFence in GPU process | |
| // first and then use DXGIHandleToken to identify the fence between processes | |
| // and pass signaled fence value from current process to GPU process. | |
| virtual void UpdateSharedImage( | |
| const SyncToken& sync_token, | |
| scoped_refptr<gfx::D3DSharedFence> d3d_shared_fence, | |
| const Mailbox& mailbox); | |
| #endif // BUILDFLAG(IS_WIN) | |
| // Generates an unverified SyncToken that is released after all previous | |
| // commands on this interface have executed on the service side. | |
| virtual SyncToken GenUnverifiedSyncToken() = 0; | |
| // Generates a verified SyncToken that is released after all previous | |
| // commands on this interface have executed on the service side. | |
| virtual SyncToken GenVerifiedSyncToken() = 0; | |
| // Verifies the SyncToken. | |
| virtual void VerifySyncToken(gpu::SyncToken& sync_token) = 0; | |
| // Check if a token is able to be verified by this client | |
| virtual bool CanVerifySyncToken(const gpu::SyncToken& sync_token) = 0; | |
| // Runs a synchronous round trip mojo IPC to ensure everything up this point | |
| // is visible to the service | |
| virtual void VerifyFlush() = 0; | |
| // Verifies a range of SyncTokens. Will trigger a synchronous round trip IPC | |
| // if there is anything to sync. | |
| // | |
| // The `proj` parameter allows using this function with ranges containing | |
| // elements other than gpu::SyncToken references. For example to handle a | |
| // vector of unique_ptrs, use: | |
| // `[](const auto& p) { return *p.get(); }` | |
| template <std::ranges::input_range Range, typename Proj = std::identity> | |
| requires std::convertible_to< | |
| std::invoke_result_t<Proj&, std::ranges::range_reference_t<Range>>, | |
| gpu::SyncToken&> | |
| void VerifySyncTokens(Range&& sync_token_range, Proj proj = {}) { | |
| bool flush_required = false; | |
| for (auto& element : sync_token_range) { | |
| gpu::SyncToken& sync_token = proj(element); | |
| if (sync_token.verified_flush()) { | |
| continue; | |
| } | |
| if (!sync_token.HasData()) { | |
| sync_token.SetVerifyFlush(); | |
| continue; | |
| } | |
| if (CanVerifySyncToken(sync_token)) { | |
| flush_required = true; | |
| sync_token.SetVerifyFlush(); | |
| } | |
| } | |
| if (flush_required) { | |
| VerifyFlush(); | |
| } | |
| } | |
| // Wait on this SyncToken to be released before executing new commands on | |
| // this interface on the service side. This is an async wait for all the | |
| // previous commands which will be sent to server on the next flush(). | |
| virtual void WaitSyncToken(const gpu::SyncToken& sync_token) = 0; | |
| // Asynchronously waits until all `sync_tokens` are signaled, then runs | |
| // `callback` on the calling thread. | |
| virtual void SignalSyncToken(std::vector<SyncToken> sync_tokens, | |
| base::OnceClosure callback); | |
| // Informs that existing |mailbox| with the specified metadata can be passed | |
| // to DestroySharedImage(). | |
| virtual scoped_refptr<ClientSharedImage> NotifyMailboxAdded( | |
| const Mailbox& mailbox, | |
| viz::SharedImageFormat format, | |
| const gfx::Size& size, | |
| const gfx::ColorSpace& color_space, | |
| GrSurfaceOrigin surface_origin, | |
| SkAlphaType alpha_type, | |
| SharedImageUsageSet usage, | |
| uint32_t texture_target, | |
| std::string_view debug_label); | |
| // Returns true if the backing context has been lost. | |
| virtual bool IsLost() const; | |
| // Adds an observer that will be notified when the backing GPU channel is | |
| // lost. Returns true if the observer was added successfully. | |
| virtual bool AddGpuChannelLostObserver(GpuChannelLostObserver* observer); | |
| // Removes a GPU channel lost observer. | |
| virtual void RemoveGpuChannelLostObserver(GpuChannelLostObserver* observer); | |
| virtual const SharedImageCapabilities& GetCapabilities() = 0; | |
| void Release() const; | |
| // Used by client side shared image pool aka SharedImagePool to | |
| // create a service side pool. It also creates a new mojo IPC connection | |
| // between the client and the service side pool so that service side pool | |
| // can communicate with client side pool when needed. | |
| virtual void CreateSharedImagePool( | |
| const SharedImagePoolId& pool_id, | |
| mojo::PendingRemote<mojom::SharedImagePoolClientInterface> client_remote); | |
| // Called when client side SharedImagePool is destroyed. It will | |
| // in turn destroy the corresponding GPU service side SharedImagePool. | |
| virtual void DestroySharedImagePool(const SharedImagePoolId& pool_id); | |
| protected: | |
| friend class base::RefCountedThreadSafe<SharedImageInterface>; | |
| virtual ~SharedImageInterface(); | |
| // Creates a WritableSharedMemoryRegion corresponding to the format/size | |
| // passed in `si_info` and populates `mapping` and `handle` from the created | |
| // shmem region. Fails if the shmem region cannot be created or mapped. For | |
| // usage in implementing APIs that create mappable SharedImages without | |
| // holding on to a handle on the client side for usage with the software | |
| // compositor. As such, verifies that `si_info`'s usage is | |
| // `SHARED_IMAGE_USAGE_CPU_WRITE_ONLY`. | |
| static void CreateSharedMemoryRegionFromSIInfo( | |
| const SharedImageInfo& si_info, | |
| base::WritableSharedMemoryMapping& mapping, | |
| gfx::GpuMemoryBufferHandle& handle); | |
| // Returns CPU read | write shared image usages based on BufferUsage passed | |
| // in. | |
| gpu::SharedImageUsageSet GetCpuSIUsage(gfx::BufferUsage buffer_usage); | |
| scoped_refptr<SharedImageInterfaceHolder> holder_; | |
| private: | |
| friend class ArcSharedImageInterface; | |
| friend class ClientSharedImageInterface; | |
| friend class SharedImageInterfaceInProcessBase; | |
| friend class TestSharedImageInterface; | |
| friend class media::MockSharedImageInterface; | |
| // Make the constructor private to ensure that any new subclassing of this | |
| // interface gets explicit approval from //gpu OWNERS (by adding to the list | |
| // of friends above). In particular, do not subclass this interface for | |
| // testing purposes - use (and extend if necessary) TestSharedImageInterface | |
| // instead. | |
| SharedImageInterface(); | |
| }; | |
| // |SharedImageInterfaceHolder| provides thread-safe access to | |
| // |SharedImageInterface| via a weak reference. | |
| class GPU_COMMAND_BUFFER_CLIENT_EXPORT SharedImageInterfaceHolder | |
| : public base::RefCountedThreadSafe<SharedImageInterfaceHolder> { | |
| public: | |
| SharedImageInterfaceHolder(SharedImageInterface* sii); | |
| scoped_refptr<SharedImageInterface> Get(); | |
| private: | |
| friend base::RefCountedThreadSafe<SharedImageInterfaceHolder>; | |
| friend SharedImageInterface; | |
| ~SharedImageInterfaceHolder(); | |
| void OnDestroy(); | |
| mutable base::Lock lock_; | |
| raw_ptr<SharedImageInterface> sii_ GUARDED_BY(lock_); | |
| }; | |
| } // namespace gpu | |
| #endif // GPU_COMMAND_BUFFER_CLIENT_SHARED_IMAGE_INTERFACE_H_ |