blob: 0e0da67cb4d76c762f4903927eaa9470ec57d2b0 [file] [log] [blame]
// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <string>
#include "base/check_op.h"
#include "base/dcheck_is_on.h"
#include "base/memory/shared_memory_mapping.h"
#include "base/memory/weak_ptr.h"
#include "base/notreached.h"
#include "base/task/single_thread_task_runner.h"
#include "components/viz/common/resources/release_callback.h"
#include "components/viz/common/resources/shared_image_format.h"
#include "components/viz/common/resources/transferable_resource.h"
#include "gpu/command_buffer/client/client_shared_image.h"
#include "gpu/command_buffer/client/gles2_interface.h"
#include "gpu/command_buffer/client/shared_image_interface.h"
#include "gpu/command_buffer/common/mailbox.h"
#include "gpu/command_buffer/common/shared_image_usage.h"
#include "gpu/command_buffer/common/sync_token.h"
#include "skia/buildflags.h"
#include "third_party/blink/public/platform/web_graphics_shared_image_interface_provider.h"
#include "third_party/blink/renderer/platform/graphics/canvas_high_entropy_op_type.h"
#include "third_party/blink/renderer/platform/graphics/canvas_resource_provider.h"
#include "third_party/blink/renderer/platform/graphics/web_graphics_context_3d_provider_wrapper.h"
#include "third_party/blink/renderer/platform/scheduler/public/thread.h"
#include "third_party/blink/renderer/platform/wtf/thread_safe_ref_counted.h"
#include "third_party/skia/include/core/SkImageInfo.h"
#include "third_party/skia/include/core/SkRefCnt.h"
#include "ui/gfx/buffer_types.h"
#include "ui/gfx/geometry/size.h"
class SkSurface;
#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_CANVAS_RESOURCE_H_
#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_CANVAS_RESOURCE_H_
namespace gfx {
class ColorSpace;
} // namespace gfx
namespace gpu::raster {
class RasterInterface;
} // namespace gpu::raster
namespace blink {
class CanvasResourceProviderSharedImage;
class StaticBitmapImage;
// Generic resource interface, used for locking (RAII) and recycling pixel
// buffers of any type.
// Note that this object may be accessed across multiple threads but not
// concurrently. The caller is responsible to call Transfer on the object before
// using it on a different thread.
class PLATFORM_EXPORT CanvasResource
: public ThreadSafeRefCounted<CanvasResource> {
public:
using ReleaseCallback = base::OnceCallback<void(
scoped_refptr<blink::CanvasResource>&& canvas_resource,
const gpu::SyncToken& sync_token,
bool is_lost)>;
using LastUnrefCallback = base::OnceCallback<void(
scoped_refptr<blink::CanvasResource> canvas_resource)>;
virtual ~CanvasResource();
static void OnPlaceholderReleasedResource(
scoped_refptr<CanvasResource> resource);
// Returns true if this instance creates TransferableResources for usage with
// GPU compositing.
virtual bool CreatesAcceleratedTransferableResources() const = 0;
virtual void OnRefReturned(scoped_refptr<CanvasResource>&& resource) {}
// Returns true if the resource is still usable. It maybe not be valid in the
// case of a context loss or if we fail to initialize the memory backing for
// the resource.
virtual bool IsValid() const = 0;
// The bounds for this resource.
gfx::Size Size() const { return GetClientSharedImage()->size(); }
base::ByteCount EstimatedSizeInBytes() const {
return GetClientSharedImage()->EstimatedSizeInBytes();
}
// The ClientSharedImage containing information on the SharedImage
// attached to the resource.
virtual const scoped_refptr<gpu::ClientSharedImage>& GetClientSharedImage()
const = 0;
// A CanvasResource is not thread-safe and does not allow concurrent usage
// from multiple threads. But it maybe used from any thread. It remains bound
// to the current thread until Transfer is called. Note that while the
// resource maybe used for reads on any thread, it can be written to only on
// the thread where it was created.
virtual void Transfer() {}
// Provides a TransferableResource representation of this resource to share it
// with the compositor.
bool PrepareTransferableResource(viz::TransferableResource*,
ReleaseCallback*,
bool needs_verified_synctoken);
// Issues a wait for this sync token on the context used by this resource for
// rendering.
virtual void WaitSyncToken(const gpu::SyncToken&) = 0;
bool OriginClean() const { return is_origin_clean_; }
void SetOriginClean(bool flag) { is_origin_clean_ = flag; }
HighEntropyCanvasOpType HighEntropyCanvasOpTypes() const {
return high_entropy_canvas_op_types_;
}
void SetHighEntropyCanvasOpTypes(HighEntropyCanvasOpType types) {
high_entropy_canvas_op_types_ = types;
}
// Provides a StaticBitmapImage wrapping this resource. Commonly used for
// snapshots not used in compositing (for instance to draw to another canvas).
virtual scoped_refptr<StaticBitmapImage> Bitmap() = 0;
// Called when the resource is marked lost. Losing a resource does not mean
// that the backing memory has been destroyed, since the resource itself keeps
// a ref on that memory.
// It means that the consumer (commonly the compositor) can not provide a sync
// token for the resource to be safely recycled and its the GL state may be
// inconsistent with when the resource was given to the compositor. So it
// should not be recycled for writing again but can be safely read from.
virtual void NotifyResourceLost() = 0;
bool is_cross_thread() const {
return base::PlatformThread::CurrentRef() != owning_thread_ref_;
}
protected:
CanvasResource();
virtual gfx::HDRMetadata GetHDRMetadata() const { return gfx::HDRMetadata(); }
virtual viz::TransferableResource::ResourceSource
GetTransferableResourceSource() const {
return viz::TransferableResource::ResourceSource::kCanvas;
}
gpu::InterfaceBase* InterfaceBase() const;
gpu::gles2::GLES2Interface* ContextGL() const;
gpu::raster::RasterInterface* RasterInterface() const;
gpu::webgpu::WebGPUInterface* WebGPUInterface() const;
virtual base::WeakPtr<WebGraphicsContext3DProviderWrapper>
ContextProviderWrapper() const = 0;
const base::PlatformThreadRef owning_thread_ref_;
const scoped_refptr<base::SingleThreadTaskRunner> owning_thread_task_runner_;
private:
friend class CanvasResourceProviderTest;
friend class WebGPUMailboxTexture;
static void OnPlaceholderReleasedResourceOnOwningThread(
scoped_refptr<CanvasResource> resource);
// Returns true if the resource is rastered via the GPU.
virtual bool UsesAcceleratedRaster() const = 0;
// Verify the sync token that indicates when all writes to the current
// resource are finished on the GPU thread. Note that in some subclasses the
// token is already verified by GetSyncToken() so this function is no-op for
// those classes.
virtual void VerifySyncToken() {}
virtual const gpu::SyncToken& sync_token() const = 0;
bool is_origin_clean_ = true;
HighEntropyCanvasOpType high_entropy_canvas_op_types_ =
HighEntropyCanvasOpType::kNone;
};
// Resource type for SharedImage
class PLATFORM_EXPORT CanvasResourceSharedImage final : public CanvasResource {
public:
static scoped_refptr<CanvasResourceSharedImage> CreateSoftware(
gfx::Size size,
viz::SharedImageFormat format,
SkAlphaType alpha_type,
const gfx::ColorSpace& color_space,
base::WeakPtr<CanvasResourceProviderSharedImage>,
base::WeakPtr<WebGraphicsSharedImageInterfaceProvider>);
static scoped_refptr<CanvasResourceSharedImage> Create(
gfx::Size size,
viz::SharedImageFormat format,
SkAlphaType alpha_type,
const gfx::ColorSpace& color_space,
base::WeakPtr<WebGraphicsContext3DProviderWrapper>,
base::WeakPtr<CanvasResourceProviderSharedImage>,
bool is_accelerated,
gpu::SharedImageUsageSet shared_image_usage_flags);
~CanvasResourceSharedImage() override;
bool CreatesAcceleratedTransferableResources() const override {
return !GetClientSharedImage()->is_software();
}
void OnRefReturned(scoped_refptr<CanvasResource>&& resource) final;
bool IsValid() const final;
scoped_refptr<StaticBitmapImage> Bitmap() final;
void Transfer() final;
// Save (and wait on) this sync token on the context used by this resource for
// rendering.
// TODO(crbug.com/40286368): completely defer the waiting to the
// zero-parameter variant of WaitSyncToken().
void WaitSyncToken(const gpu::SyncToken&) override;
std::unique_ptr<gpu::RasterScopedAccess> BeginAccess(bool readonly);
void EndAccess(std::unique_ptr<gpu::RasterScopedAccess> access);
void NotifyResourceLost() final;
bool IsLost() const { return owning_thread_data().is_lost; }
const scoped_refptr<gpu::ClientSharedImage>& GetClientSharedImage()
const override;
void OnMemoryDump(base::trace_event::ProcessMemoryDump* pmd,
const std::string& parent_path) const;
SkImageInfo CreateSkImageInfo() const;
// Signals that an external write has completed, passing the token that should
// be waited on to ensure that the service-side operations of the external
// write have completed. Ensures that the next read of this resource (whether
// via raster or the compositor) waits on this token.
void EndExternalWrite(const gpu::SyncToken& external_write_sync_token);
// Uploads the contents of |sk_surface| to the resource's backing memory.
// Should be called only if the resource is using software raster.
void UploadSoftwareRenderingResults(SkSurface* sk_surface);
void PrepareForWebGPUDummyMailbox();
private:
friend class CanvasResourceProviderSharedImage;
// These members are either only accessed on the owning thread, or are only
// updated on the owning thread and then are read on a different thread.
// We ensure to correctly update their state in Transfer, which is called
// before a resource is used on a different thread.
struct OwningThreadData {
scoped_refptr<gpu::ClientSharedImage> client_shared_image;
gpu::SyncToken sync_token;
bool is_lost = false;
};
base::WeakPtr<WebGraphicsContext3DProviderWrapper> ContextProviderWrapper()
const override;
void VerifySyncToken() override;
bool UsesAcceleratedRaster() const final { return is_accelerated_; }
CanvasResourceProviderSharedImage* Provider();
CanvasResourceSharedImage(
gfx::Size size,
viz::SharedImageFormat format,
SkAlphaType alpha_type,
const gfx::ColorSpace& color_space,
base::WeakPtr<CanvasResourceProviderSharedImage>,
base::WeakPtr<WebGraphicsSharedImageInterfaceProvider>);
CanvasResourceSharedImage(gfx::Size size,
viz::SharedImageFormat format,
SkAlphaType alpha_type,
const gfx::ColorSpace& color_space,
base::WeakPtr<WebGraphicsContext3DProviderWrapper>,
base::WeakPtr<CanvasResourceProviderSharedImage>,
bool is_accelerated,
gpu::SharedImageUsageSet shared_image_usage_flags);
OwningThreadData& owning_thread_data() {
DCHECK(!is_cross_thread());
return owning_thread_data_;
}
const OwningThreadData& owning_thread_data() const {
DCHECK(!is_cross_thread());
return owning_thread_data_;
}
const gpu::SyncToken& sync_token() const override {
return owning_thread_data_.sync_token;
}
SkAlphaType GetAlphaType() const { return alpha_type_; }
// This should only be de-referenced on the owning thread but may be copied
// on a different thread.
base::WeakPtr<WebGraphicsContext3DProviderWrapper> context_provider_wrapper_;
gpu::SyncToken acquire_sync_token_;
// Accessed on any thread.
const bool is_accelerated_;
const SkAlphaType alpha_type_;
OwningThreadData owning_thread_data_;
base::WeakPtr<CanvasResourceProviderSharedImage> provider_;
};
// Resource type for a given opaque external resource described on construction
// via a TransferableResource. This CanvasResource should only be used with
// context that support GL.
class PLATFORM_EXPORT ExternalCanvasResource final : public CanvasResource {
public:
static scoped_refptr<ExternalCanvasResource> Create(
scoped_refptr<gpu::ClientSharedImage> client_si,
const gpu::SyncToken& sync_token,
viz::TransferableResource::ResourceSource resource_source,
gfx::HDRMetadata hdr_metadata,
viz::ReleaseCallback release_callback,
base::WeakPtr<WebGraphicsContext3DProviderWrapper>);
~ExternalCanvasResource() override;
bool IsValid() const override;
bool CreatesAcceleratedTransferableResources() const override { return true; }
void NotifyResourceLost() override { resource_is_lost_ = true; }
const scoped_refptr<gpu::ClientSharedImage>& GetClientSharedImage()
const final {
return client_si_;
}
void WaitSyncToken(const gpu::SyncToken&) override;
void GetSyncToken();
scoped_refptr<StaticBitmapImage> Bitmap() override;
private:
gfx::HDRMetadata GetHDRMetadata() const final { return hdr_metadata_; }
viz::TransferableResource::ResourceSource GetTransferableResourceSource()
const final {
return resource_source_;
}
bool UsesAcceleratedRaster() const final { return true; }
base::WeakPtr<WebGraphicsContext3DProviderWrapper> ContextProviderWrapper()
const override;
void VerifySyncToken() override;
ExternalCanvasResource(
scoped_refptr<gpu::ClientSharedImage> client_si,
const gpu::SyncToken& sync_token,
viz::TransferableResource::ResourceSource resource_source,
gfx::HDRMetadata hdr_metadata,
viz::ReleaseCallback out_callback,
base::WeakPtr<WebGraphicsContext3DProviderWrapper>);
SkAlphaType GetAlphaType() const { return alpha_type_; }
const gpu::SyncToken& sync_token() const override { return sync_token_; }
scoped_refptr<gpu::ClientSharedImage> client_si_;
const base::WeakPtr<WebGraphicsContext3DProviderWrapper>
context_provider_wrapper_;
gpu::SyncToken sync_token_;
viz::TransferableResource::ResourceSource resource_source_;
gfx::HDRMetadata hdr_metadata_;
viz::ReleaseCallback release_callback_;
bool resource_is_lost_ = false;
const SkAlphaType alpha_type_;
};
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_CANVAS_RESOURCE_H_