// 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_SERVICE_SHARED_IMAGE_SHARED_IMAGE_REPRESENTATION_H_
#define GPU_COMMAND_BUFFER_SERVICE_SHARED_IMAGE_SHARED_IMAGE_REPRESENTATION_H_

#include <dawn/dawn_proc_table.h>
#include <dawn/webgpu_cpp.h>

#include <memory>

#include "base/functional/callback.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_refptr.h"
#include "base/types/pass_key.h"
#include "build/build_config.h"
#include "gpu/command_buffer/common/shared_image_usage.h"
#include "gpu/command_buffer/service/shared_image/shared_image_backing.h"
#include "gpu/gpu_gles2_export.h"
#include "gpu/vulkan/buildflags.h"
#include "skia/buildflags.h"
#include "third_party/skia/include/core/SkImage.h"
#include "third_party/skia/include/core/SkSurface.h"
#include "third_party/skia/include/gpu/ganesh/GrDirectContext.h"
#include "third_party/skia/include/gpu/ganesh/SkImageGanesh.h"
#include "third_party/skia/include/gpu/graphite/BackendTexture.h"
#include "third_party/skia/include/private/chromium/GrPromiseImageTexture.h"
#include "ui/gfx/color_space.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/size.h"
#include "ui/gfx/gpu_fence.h"

#if BUILDFLAG(ENABLE_VULKAN)
#include <vulkan/vulkan_core.h>

namespace gpu {
class VulkanDeviceQueue;
class VulkanImage;
class VulkanImplementation;
}  // namespace gpu
#endif  // BUILDFLAG(ENABLE_VULKAN)

#if BUILDFLAG(IS_WIN)
#include <d3d11.h>
#include <d3d12.h>
#include <wrl/client.h>

#include "ui/gl/dc_layer_overlay_image.h"
#endif  // BUILDFLAG(IS_WIN)

#if BUILDFLAG(IS_APPLE)
#include "ui/gfx/mac/io_surface.h"
#include "ui/gfx/mac/mtl_shared_event_fence.h"
#endif  // BUILDFLAG(IS_APPLE)

#if BUILDFLAG(IS_ANDROID)
#include "base/android/scoped_hardware_buffer_fence_sync.h"

extern "C" typedef struct AHardwareBuffer AHardwareBuffer;
#endif  // BUILDFLAG(IS_ANDROID)

typedef unsigned int GLenum;
namespace skgpu {
class MutableTextureState;
}

namespace cc {
class PaintOpBuffer;
}  // namespace cc

namespace gfx {
class NativePixmap;
}  // namespace gfx

namespace gpu {
class SharedImageManager;
class TextureBase;

namespace gles2 {
class Texture;
class TexturePassthrough;
}  // namespace gles2

enum class RepresentationAccessMode {
  kNone,
  kRead,
  kWrite,
};

///////////////////////////////////////////////////////////////////////////////
// SharedImageRepresentation

// A representation of a SharedImageBacking for use with a specific use case /
// api.
class GPU_GLES2_EXPORT SharedImageRepresentation {
 public:
  using AccessMode = RepresentationAccessMode;

  // Used by derived classes.
  enum class AllowUnclearedAccess { kYes, kNo };

  SharedImageRepresentation(SharedImageManager* manager,
                            SharedImageBacking* backing,
                            MemoryTypeTracker* tracker);
  virtual ~SharedImageRepresentation();

  viz::SharedImageFormat format() const { return backing_->format(); }
  const gfx::Size& size() const { return backing_->size(); }
  const gfx::ColorSpace& color_space() const { return backing_->color_space(); }
  GrSurfaceOrigin surface_origin() const { return backing_->surface_origin(); }
  SkAlphaType alpha_type() const { return backing_->alpha_type(); }
  SharedImageUsageSet usage() const { return backing_->usage(); }
  const gpu::Mailbox& mailbox() const { return backing_->mailbox(); }
  const std::string& debug_label() const { return backing_->debug_label(); }
  const char* backing_name() const { return backing_->GetName(); }
  MemoryTypeTracker* tracker() { return tracker_; }
  bool IsCleared() const;
  void SetCleared();
  virtual gfx::Rect ClearedRect() const;
  virtual void SetClearedRect(const gfx::Rect& cleared_rect);

  // Indicates that the underlying graphics context has been lost, and the
  // backing should be treated as destroyed.
  virtual void OnContextLost();

  // Returns the number of image planes expected based on the backing format.
  size_t NumPlanesExpected() const;

 protected:
  SharedImageManager* manager() const { return manager_; }
  SharedImageBacking* backing() const { return backing_; }
  bool has_context() const { return has_context_; }

  // Helper class for derived classes' Scoped*Access objects. Has tracking to
  // ensure a Scoped*Access does not outlive the representation it's associated
  // with.
  template <typename RepresentationClass>
  class ScopedAccessBase {
   public:
    ScopedAccessBase(RepresentationClass* representation,
                     AccessMode access_mode)
        : representation_(representation) {
      CHECK_EQ(representation_->access_mode_, AccessMode::kNone);
      representation_->access_mode_ = access_mode;
    }

    ScopedAccessBase(const ScopedAccessBase&) = delete;
    ScopedAccessBase& operator=(const ScopedAccessBase&) = delete;

    ~ScopedAccessBase() {
      CHECK_NE(representation_->access_mode_, AccessMode::kNone);
      representation_->access_mode_ = AccessMode::kNone;
    }

    RepresentationClass* representation() { return representation_; }
    const RepresentationClass* representation() const {
      return representation_;
    }

   private:
    // Uses UnprotectedInRelease for performance reasons (based on analysis of
    // MotionMark).
    const raw_ptr<RepresentationClass, UnprotectedInRelease> representation_ =
        nullptr;
  };

 private:
  // Uses UnprotectedInRelease for performance reasons (based on analysis of
  // MotionMark).
  const raw_ptr<SharedImageManager, UnprotectedInRelease> manager_ = nullptr;
  raw_ptr<SharedImageBacking, DanglingUntriaged | UnprotectedInRelease>
      backing_ = nullptr;
  const raw_ptr<MemoryTypeTracker, UnprotectedInRelease> tracker_ = nullptr;
  bool has_context_ = true;
  AccessMode access_mode_ = AccessMode::kNone;
};

///////////////////////////////////////////////////////////////////////////////
// SharedImageRepresentationFactoryRef
class SharedImageRepresentationFactoryRef : public SharedImageRepresentation {
 public:
  SharedImageRepresentationFactoryRef(SharedImageManager* manager,
                                      SharedImageBacking* backing,
                                      MemoryTypeTracker* tracker,
                                      bool is_primary);

  ~SharedImageRepresentationFactoryRef() override;

  const Mailbox& mailbox() const { return backing()->mailbox(); }
  bool CopyToGpuMemoryBuffer() { return backing()->CopyToGpuMemoryBuffer(); }
  void CopyToGpuMemoryBufferAsync(base::OnceCallback<void(bool)> callback) {
    backing()->CopyToGpuMemoryBufferAsync(std::move(callback));
  }
  void GetGpuMemoryBufferHandleInfo(gfx::GpuMemoryBufferHandle& handle,
                                    gfx::BufferUsage& buffer_usage) {
    handle = backing()->GetGpuMemoryBufferHandle();
    buffer_usage = backing()->buffer_usage().value();
  }
  void SetSharedImagePoolId(SharedImagePoolId pool_id) {
    backing()->SetSharedImagePoolId(std::move(pool_id));
  }

 private:
  const bool is_primary_;
};

///////////////////////////////////////////////////////////////////////////////
// GLTextureImageRepresentationBase

class GPU_GLES2_EXPORT GLTextureImageRepresentationBase
    : public SharedImageRepresentation {
 public:
  static constexpr GLenum kReadAccessMode = 0x8AF6;

  class ScopedAccess
      : public ScopedAccessBase<GLTextureImageRepresentationBase> {
   public:
    ScopedAccess(base::PassKey<GLTextureImageRepresentationBase> pass_key,
                 GLTextureImageRepresentationBase* representation,
                 AccessMode access_mode)
        : ScopedAccessBase(representation, access_mode) {}
    ~ScopedAccess() {
      representation()->UpdateClearedStateOnEndAccess();
      representation()->EndAccess();
    }
  };

  GLTextureImageRepresentationBase(SharedImageManager* manager,
                                   SharedImageBacking* backing,
                                   MemoryTypeTracker* tracker)
      : SharedImageRepresentation(manager, backing, tracker) {}

  std::unique_ptr<ScopedAccess> BeginScopedAccess(
      GLenum mode,
      AllowUnclearedAccess allow_uncleared);

  // Gets the texture associated with the `plane_index` for SharedImageFormat.
  virtual gpu::TextureBase* GetTextureBase(size_t plane_index) = 0;
  // Calls GetTextureBase with `plane_index` = 0 for single planar formats eg.
  // RGB.
  gpu::TextureBase* GetTextureBase();

 protected:
  friend class SkiaGLImageRepresentation;
  friend class DawnEGLImageRepresentation;
  friend class DawnGLTextureRepresentation;
  friend class GLTextureGLCommonRepresentation;

  // Can be overridden to handle clear state tracking when GL access begins or
  // ends.
  virtual void UpdateClearedStateOnBeginAccess() {}
  virtual void UpdateClearedStateOnEndAccess() {}

  virtual bool BeginAccess(GLenum mode) = 0;
  virtual void EndAccess() = 0;

  virtual bool SupportsMultipleConcurrentReadAccess();
};

///////////////////////////////////////////////////////////////////////////////
// GLTextureImageRepresentation

class GPU_GLES2_EXPORT GLTextureImageRepresentation
    : public GLTextureImageRepresentationBase {
 public:
  GLTextureImageRepresentation(SharedImageManager* manager,
                               SharedImageBacking* backing,
                               MemoryTypeTracker* tracker)
      : GLTextureImageRepresentationBase(manager, backing, tracker) {}

  // Gets the texture associated with the `plane_index` for SharedImageFormat.
  virtual gles2::Texture* GetTexture(size_t plane_index) = 0;
  // Calls GetTexture with `plane_index` = 0 for single planar formats eg. RGB.
  gles2::Texture* GetTexture();

  gpu::TextureBase* GetTextureBase(size_t plane_index) override;

 protected:
  friend class WrappedGLTextureCompoundImageRepresentation;

  void UpdateClearedStateOnBeginAccess() override;
  void UpdateClearedStateOnEndAccess() override;
};

///////////////////////////////////////////////////////////////////////////////
// GLTexturePassthroughImageRepresentation

class GPU_GLES2_EXPORT GLTexturePassthroughImageRepresentation
    : public GLTextureImageRepresentationBase {
 public:
  GLTexturePassthroughImageRepresentation(SharedImageManager* manager,
                                          SharedImageBacking* backing,
                                          MemoryTypeTracker* tracker)
      : GLTextureImageRepresentationBase(manager, backing, tracker) {}

  // Gets the passthrough texture associated with the `plane_index` for
  // SharedImageFormat.
  virtual const scoped_refptr<gles2::TexturePassthrough>& GetTexturePassthrough(
      size_t plane_index) = 0;
  // Calls GetTexturePassthrough with `plane_index` = 0 for single planar
  // formats eg. RGB.
  const scoped_refptr<gles2::TexturePassthrough>& GetTexturePassthrough();

  gpu::TextureBase* GetTextureBase(size_t plane_index) override;

  // Returns true if access must be suspended in between GL decoder tasks due to
  // DXGI keyed mutex. Only implemented for D3D GL representation.
  virtual bool NeedsSuspendAccessForDXGIKeyedMutex() const;

 private:
  friend class WrappedGLTexturePassthroughCompoundImageRepresentation;
};

///////////////////////////////////////////////////////////////////////////////
// SkiaImageRepresentation

class GPU_GLES2_EXPORT SkiaImageRepresentation
    : public SharedImageRepresentation {
 public:
  // Object that holds skgpu::graphite::BackendTexture.
  class GPU_GLES2_EXPORT GraphiteTextureHolder
      : public base::RefCountedThreadSafe<GraphiteTextureHolder> {
   public:
    explicit GraphiteTextureHolder(skgpu::graphite::BackendTexture texture);

    const skgpu::graphite::BackendTexture& texture() { return texture_; }

   protected:
    friend class base::RefCountedThreadSafe<GraphiteTextureHolder>;
    virtual ~GraphiteTextureHolder();

    skgpu::graphite::BackendTexture texture_;
  };

  class GPU_GLES2_EXPORT ScopedWriteAccess
      : public ScopedAccessBase<SkiaImageRepresentation> {
   public:
    virtual ~ScopedWriteAccess();

    // NOTE: All references to the returned SkSurface(s) must be destroyed
    // before ScopedWriteAccess is destroyed.
    bool has_surfaces() const { return !surfaces_.empty(); }
    SkSurface* surface() const {
      // Writes do not support external sampler.
      CHECK(representation()->format().is_single_plane());
      return surface(0);
    }
    SkSurface* surface(size_t plane_index) const {
      return surfaces_[plane_index].get();
    }

    GrPromiseImageTexture* promise_image_texture(size_t plane_index) const {
      return promise_image_textures_[plane_index].get();
    }

    skgpu::graphite::BackendTexture graphite_texture(size_t plane_index) const {
      return graphite_texture_holder(plane_index)->texture();
    }

    const scoped_refptr<GraphiteTextureHolder>& graphite_texture_holder(
        size_t plane_index) const {
      return graphite_texture_holders_[plane_index];
    }

    // Return the representations's implementation.
    bool NeedGraphiteContextSubmit();

    // NOTE: Implemented only for Ganesh.
    // Checks if there's a need to apply skgpu::MutableTextureState.
    virtual bool HasBackendSurfaceEndState() = 0;
    // NOTE: Implemented only for Ganesh.
    // Applies the skgpu::MutableTextureState for Vulkan layout and external
    // queue transitions needed for Vulkan/GL interop.
    virtual void ApplyBackendSurfaceEndState() = 0;

   protected:
    ScopedWriteAccess(SkiaImageRepresentation* representation,
                      std::vector<sk_sp<SkSurface>> surfaces);
    ScopedWriteAccess(
        SkiaImageRepresentation* representation,
        std::vector<sk_sp<GrPromiseImageTexture>> promise_image_textures);
    ScopedWriteAccess(
        SkiaImageRepresentation* representation,
        std::vector<scoped_refptr<GraphiteTextureHolder>> graphite_textures);

    // A vector of surfaces, promise textures and graphite backend textures
    // corresponding to the number of planes in SharedImageFormat.
    std::vector<sk_sp<SkSurface>> surfaces_;
    // NOTE: Used only for Ganesh.
    std::vector<sk_sp<GrPromiseImageTexture>> promise_image_textures_;
    // NOTE: Used only for Graphite.
    std::vector<scoped_refptr<GraphiteTextureHolder>> graphite_texture_holders_;
  };

  class GPU_GLES2_EXPORT ScopedReadAccess
      : public ScopedAccessBase<SkiaImageRepresentation> {
   public:
    virtual ~ScopedReadAccess();

    GrPromiseImageTexture* promise_image_texture() const {
      CHECK_EQ(representation()->NumPlanesExpected(), 1u);
      return promise_image_texture(0);
    }
    GrPromiseImageTexture* promise_image_texture(size_t plane_index) const {
      return promise_image_textures_[plane_index].get();
    }

    skgpu::graphite::BackendTexture graphite_texture() const {
      CHECK_EQ(representation()->NumPlanesExpected(), 1u);
      return graphite_texture(0);
    }
    skgpu::graphite::BackendTexture graphite_texture(size_t plane_index) const {
      return graphite_texture_holder(plane_index)->texture();
    }

    const scoped_refptr<GraphiteTextureHolder>& graphite_texture_holder(
        size_t plane_index) const {
      return graphite_texture_holders_[plane_index];
    }

    // Return the representations's implementation.
    bool NeedGraphiteContextSubmit();

    // Creates an SkImage from BackendTexture for single planar formats or if
    // format prefers external sampler. Creates an SkImage from
    // YUVABackendTexture for multiplanar formats.
    virtual sk_sp<SkImage> CreateSkImage(
        SharedContextState* context_state,
        SkImages::TextureReleaseProc texture_release_proc = nullptr,
        SkImages::ReleaseContext release_context = nullptr) = 0;
    // Creates an SkImage for the given `plane_index` for
    // multiplanar formats.
    virtual sk_sp<SkImage> CreateSkImageForPlane(
        size_t plane_index,
        SharedContextState* context_state,
        SkImages::TextureReleaseProc texture_release_proc = nullptr,
        SkImages::ReleaseContext release_context = nullptr) = 0;

    // NOTE: Implemented only for Ganesh.
    // Checks if there's a need to apply skgpu::MutableTextureState.
    virtual bool HasBackendSurfaceEndState() = 0;
    // Applies the skgpu::MutableTextureState for Vulkan layout and external
    // queue transitions needed for Vulkan/GL interop.
    virtual void ApplyBackendSurfaceEndState() = 0;

   protected:
    ScopedReadAccess(
        SkiaImageRepresentation* representation,
        std::vector<sk_sp<GrPromiseImageTexture>> promise_image_textures);
    ScopedReadAccess(
        SkiaImageRepresentation* representation,
        std::vector<scoped_refptr<GraphiteTextureHolder>> graphite_textures);

    // A vector of promise textures and graphite backend textures corresponding
    // to the number of planes in SharedImageFormat. NOTE: Used only for Ganesh.
    std::vector<sk_sp<GrPromiseImageTexture>> promise_image_textures_;
    // NOTE: Used only for Graphite.
    std::vector<scoped_refptr<GraphiteTextureHolder>> graphite_texture_holders_;
  };

  SkiaImageRepresentation(SharedImageManager* manager,
                          SharedImageBacking* backing,
                          MemoryTypeTracker* tracker,
                          bool is_graphite);
  ~SkiaImageRepresentation() override;

  // Note: See BeginWriteAccess below for a description of the semaphore
  // parameters.
  virtual std::unique_ptr<ScopedWriteAccess> BeginScopedWriteAccess(
      int final_msaa_count,
      const SkSurfaceProps& surface_props,
      const gfx::Rect& update_rect,
      std::vector<GrBackendSemaphore>* begin_semaphores,
      std::vector<GrBackendSemaphore>* end_semaphores,
      AllowUnclearedAccess allow_uncleared,
      bool use_sk_surface = true) = 0;
  virtual std::unique_ptr<ScopedWriteAccess> BeginScopedWriteAccess(
      int final_msaa_count,
      const SkSurfaceProps& surface_props,
      std::vector<GrBackendSemaphore>* begin_semaphores,
      std::vector<GrBackendSemaphore>* end_semaphores,
      AllowUnclearedAccess allow_uncleared,
      bool use_sk_surface = true) = 0;
  virtual std::unique_ptr<ScopedWriteAccess> BeginScopedWriteAccess(
      std::vector<GrBackendSemaphore>* begin_semaphores,
      std::vector<GrBackendSemaphore>* end_semaphores,
      AllowUnclearedAccess allow_uncleared,
      bool use_sk_surface = true) = 0;

  // Note: See BeginReadAccess below for a description of the semaphore
  // parameters.
  virtual std::unique_ptr<ScopedReadAccess> BeginScopedReadAccess(
      std::vector<GrBackendSemaphore>* begin_semaphores,
      std::vector<GrBackendSemaphore>* end_semaphores) = 0;

  // Return whether we need to submit graphite's commands before EndAccess.
  // NOTE: Implemented only for Graphite.
  bool NeedGraphiteContextSubmitBeforeEndAccess();

  virtual bool SupportsMultipleConcurrentReadAccess();

 protected:
  // Return whether the graphite context submission can be deferred even after
  // the backing is destroyed.
  virtual bool SupportsDeferredGraphiteSubmit();

  virtual void EndWriteAccess() = 0;
  virtual void EndReadAccess() = 0;

  const bool is_graphite_;
};

///////////////////////////////////////////////////////////////////////////////
// SkiaGaneshImageRepresentation

class GPU_GLES2_EXPORT SkiaGaneshImageRepresentation
    : public SkiaImageRepresentation {
 public:
  class GPU_GLES2_EXPORT ScopedGaneshWriteAccess : public ScopedWriteAccess {
   public:
    ScopedGaneshWriteAccess(
        base::PassKey<SkiaGaneshImageRepresentation> pass_key,
        SkiaImageRepresentation* representation,
        std::vector<sk_sp<SkSurface>> surfaces,
        std::unique_ptr<skgpu::MutableTextureState> end_state);
    ScopedGaneshWriteAccess(
        base::PassKey<SkiaGaneshImageRepresentation> pass_key,
        SkiaImageRepresentation* representation,
        std::vector<sk_sp<GrPromiseImageTexture>> promise_image_textures,
        std::unique_ptr<skgpu::MutableTextureState> end_state);
    ~ScopedGaneshWriteAccess() override;

    // Checks if there's a need to apply skgpu::MutableTextureState.
    bool HasBackendSurfaceEndState() override;
    // Applies the skgpu::MutableTextureState for Vulkan layout and external
    // queue transitions needed for Vulkan/GL interop.
    void ApplyBackendSurfaceEndState() override;

   private:
    SkiaGaneshImageRepresentation* ganesh_representation() {
      return static_cast<SkiaGaneshImageRepresentation*>(representation());
    }

    std::unique_ptr<skgpu::MutableTextureState> end_state_;
  };

  class GPU_GLES2_EXPORT ScopedGaneshReadAccess : public ScopedReadAccess {
   public:
    ScopedGaneshReadAccess(
        base::PassKey<SkiaGaneshImageRepresentation> pass_key,
        SkiaImageRepresentation* representation,
        std::vector<sk_sp<GrPromiseImageTexture>> promise_image_textures,
        std::unique_ptr<skgpu::MutableTextureState> end_state);
    ~ScopedGaneshReadAccess() override;

    // Creates an SkImage from GrBackendTexture for single planar formats or if
    // format prefers external sampler. Creates an SkImage from
    // GrYUVABackendTexture for multiplanar formats.
    sk_sp<SkImage> CreateSkImage(
        SharedContextState* context_state,
        SkImages::TextureReleaseProc texture_release_proc = nullptr,
        SkImages::ReleaseContext release_context = nullptr) override;
    // Creates an SkImage for the given `plane_index` from GrBackendTexture for
    // multiplanar formats.
    sk_sp<SkImage> CreateSkImageForPlane(
        size_t plane_index,
        SharedContextState* context_state,
        SkImages::TextureReleaseProc texture_release_proc = nullptr,
        SkImages::ReleaseContext release_context = nullptr) override;

    // Checks if there's a need to apply skgpu::MutableTextureState.
    bool HasBackendSurfaceEndState() override;
    // Applies the skgpu::MutableTextureState for Vulkan layout and external
    // queue transitions needed for Vulkan/GL interop.
    void ApplyBackendSurfaceEndState() override;

   private:
    SkiaGaneshImageRepresentation* ganesh_representation() {
      return static_cast<SkiaGaneshImageRepresentation*>(representation());
    }

    std::unique_ptr<skgpu::MutableTextureState> end_state_;
  };

  SkiaGaneshImageRepresentation(GrDirectContext* gr_context,
                                SharedImageManager* manager,
                                SharedImageBacking* backing,
                                MemoryTypeTracker* tracker);

  GrDirectContext* gr_context() const { return gr_context_; }

  // Note: See BeginWriteAccess below for a description of the semaphore
  // parameters.
  std::unique_ptr<ScopedWriteAccess> BeginScopedWriteAccess(
      int final_msaa_count,
      const SkSurfaceProps& surface_props,
      const gfx::Rect& update_rect,
      std::vector<GrBackendSemaphore>* begin_semaphores,
      std::vector<GrBackendSemaphore>* end_semaphores,
      AllowUnclearedAccess allow_uncleared,
      bool use_sk_surface = true) override;

  std::unique_ptr<ScopedWriteAccess> BeginScopedWriteAccess(
      int final_msaa_count,
      const SkSurfaceProps& surface_props,
      std::vector<GrBackendSemaphore>* begin_semaphores,
      std::vector<GrBackendSemaphore>* end_semaphores,
      AllowUnclearedAccess allow_uncleared,
      bool use_sk_surface = true) override;

  std::unique_ptr<ScopedWriteAccess> BeginScopedWriteAccess(
      std::vector<GrBackendSemaphore>* begin_semaphores,
      std::vector<GrBackendSemaphore>* end_semaphores,
      AllowUnclearedAccess allow_uncleared,
      bool use_sk_surface = true) override;

  // Note: See BeginReadAccess below for a description of the semaphore
  // parameters.
  std::unique_ptr<ScopedReadAccess> BeginScopedReadAccess(
      std::vector<GrBackendSemaphore>* begin_semaphores,
      std::vector<GrBackendSemaphore>* end_semaphores) override;

 protected:
  friend class WrappedSkiaGaneshCompoundImageRepresentation;

  // Begin the write access.
  //
  // update_rect is a hint to the backend about the portion of the image that
  // will be drawn to. Callers shouldn't draw outside of this area, but aren't
  // required to overwrite every pixel inside it.
  //
  // The implementations should insert semaphores into begin_semaphores vector
  // which client will wait on before writing the backing. The ownership of
  // begin_semaphores is not passed to client. The implementations can also
  // optionally insert semaphores into end_semaphores. If using end_semaphores,
  // the client must submit them with drawing operations which use the backing.
  // The ownership of end_semaphores are not passed to client. And client must
  // submit the end_semaphores before calling EndWriteAccess().
  //
  // The backing can assign end_state, and the caller must reset backing's state
  // to the end_state before calling EndWriteAccess().
  // Returns an empty vector on failure.
  virtual std::vector<sk_sp<SkSurface>> BeginWriteAccess(
      int final_msaa_count,
      const SkSurfaceProps& surface_props,
      const gfx::Rect& update_rect,
      std::vector<GrBackendSemaphore>* begin_semaphores,
      std::vector<GrBackendSemaphore>* end_semaphores,
      std::unique_ptr<skgpu::MutableTextureState>* end_state) = 0;
  virtual std::vector<sk_sp<GrPromiseImageTexture>> BeginWriteAccess(
      std::vector<GrBackendSemaphore>* begin_semaphores,
      std::vector<GrBackendSemaphore>* end_semaphores,
      std::unique_ptr<skgpu::MutableTextureState>* end_state) = 0;

  // Begin the read access. The implementations should insert semaphores into
  // begin_semaphores vector which client will wait on before reading the
  // backing. The ownership of begin_semaphores is not passed to client.
  // The implementations can also optionally insert semaphores into
  // end_semaphores. If using end_semaphores, the client must submit them with
  // drawing operations which use the backing. The ownership of end_semaphores
  // are not passed to client. And client must submit the end_semaphores before
  // calling EndReadAccess().
  // The backing can assign end_state, and the caller must reset backing's state
  // to the end_state before calling EndReadAccess().
  // Returns an empty vector on failure.
  virtual std::vector<sk_sp<GrPromiseImageTexture>> BeginReadAccess(
      std::vector<GrBackendSemaphore>* begin_semaphores,
      std::vector<GrBackendSemaphore>* end_semaphores,
      std::unique_ptr<skgpu::MutableTextureState>* end_state) = 0;

 private:
  raw_ptr<GrDirectContext> gr_context_ = nullptr;
};

///////////////////////////////////////////////////////////////////////////////
// SkiaGraphiteImageRepresentation

class GPU_GLES2_EXPORT SkiaGraphiteImageRepresentation
    : public SkiaImageRepresentation {
 public:
  class GPU_GLES2_EXPORT ScopedGraphiteWriteAccess : public ScopedWriteAccess {
   public:
    ScopedGraphiteWriteAccess(
        base::PassKey<SkiaGraphiteImageRepresentation> pass_key,
        SkiaImageRepresentation* representation,
        std::vector<sk_sp<SkSurface>> surfaces);
    ScopedGraphiteWriteAccess(
        base::PassKey<SkiaGraphiteImageRepresentation> pass_key,
        SkiaImageRepresentation* representation,
        std::vector<scoped_refptr<GraphiteTextureHolder>> graphite_textures);
    ~ScopedGraphiteWriteAccess() override;

    bool HasBackendSurfaceEndState() override;
    void ApplyBackendSurfaceEndState() override;
  };

  class GPU_GLES2_EXPORT ScopedGraphiteReadAccess : public ScopedReadAccess {
   public:
    ScopedGraphiteReadAccess(
        base::PassKey<SkiaGraphiteImageRepresentation> pass_key,
        SkiaImageRepresentation* representation,
        std::vector<scoped_refptr<GraphiteTextureHolder>> graphite_textures);
    ~ScopedGraphiteReadAccess() override;

    // Creates an SkImage from BackendTexture for single planar formats or if
    // format prefers external sampler. Creates an SkImage from
    // YUVABackendTexture for multiplanar formats.
    sk_sp<SkImage> CreateSkImage(
        SharedContextState* context_state,
        SkImages::TextureReleaseProc texture_release_proc = nullptr,
        SkImages::ReleaseContext release_context = nullptr) override;
    // Creates an SkImage for the given `plane_index` from BackendTexture for
    // multiplanar formats.
    sk_sp<SkImage> CreateSkImageForPlane(
        size_t plane_index,
        SharedContextState* context_state,
        SkImages::TextureReleaseProc texture_release_proc = nullptr,
        SkImages::ReleaseContext release_context = nullptr) override;

    bool HasBackendSurfaceEndState() override;
    void ApplyBackendSurfaceEndState() override;
  };

  SkiaGraphiteImageRepresentation(SharedImageManager* manager,
                                  SharedImageBacking* backing,
                                  MemoryTypeTracker* tracker);

  // Note: See BeginWriteAccess below for a description of the semaphore
  // parameters.
  std::unique_ptr<ScopedWriteAccess> BeginScopedWriteAccess(
      int final_msaa_count,
      const SkSurfaceProps& surface_props,
      const gfx::Rect& update_rect,
      std::vector<GrBackendSemaphore>* begin_semaphores,
      std::vector<GrBackendSemaphore>* end_semaphores,
      AllowUnclearedAccess allow_uncleared,
      bool use_sk_surface = true) override;

  std::unique_ptr<ScopedWriteAccess> BeginScopedWriteAccess(
      int final_msaa_count,
      const SkSurfaceProps& surface_props,
      std::vector<GrBackendSemaphore>* begin_semaphores,
      std::vector<GrBackendSemaphore>* end_semaphores,
      AllowUnclearedAccess allow_uncleared,
      bool use_sk_surface = true) override;

  std::unique_ptr<ScopedWriteAccess> BeginScopedWriteAccess(
      std::vector<GrBackendSemaphore>* begin_semaphores,
      std::vector<GrBackendSemaphore>* end_semaphores,
      AllowUnclearedAccess allow_uncleared,
      bool use_sk_surface = true) override;

  // Note: See BeginReadAccess below for a description of the semaphore
  // parameters.
  std::unique_ptr<ScopedReadAccess> BeginScopedReadAccess(
      std::vector<GrBackendSemaphore>* begin_semaphores,
      std::vector<GrBackendSemaphore>* end_semaphores) override;

 protected:
  friend class WrappedSkiaGraphiteCompoundImageRepresentation;

  std::string WrappedTextureDebugLabel(int plane) const;

  // Begin the write access. Returns an empty vector on failure.
  //
  // update_rect is a hint to the backend about the portion of the image that
  // will be drawn to. Callers shouldn't draw outside of this area, but aren't
  // required to overwrite every pixel inside it.
  virtual std::vector<sk_sp<SkSurface>> BeginWriteAccess(
      const SkSurfaceProps& surface_props,
      const gfx::Rect& update_rect) = 0;

  // Returns a vector of ref counted GraphiteTextureHolder that holds
  // skgpu::graphite::BackendTexture which graphite can use for writing.
  // Notes:
  // - If `NeedGraphiteContextSubmitBeforeEndAccess()` returns true: it's only
  // safe to use the contained BackendTexture within the access' scope.
  // - If `NeedGraphiteContextSubmitBeforeEndAccess()` returns false: the
  // contained BackendTexture is safe to be used as long as the holder is
  // intact. For example, in some scenarios the BackendTexture would be used in
  // a command buffer, but its submission needs to be deferred later, even after
  // the SI's backing is destroyed. In those cases, we can pass
  // refptr<GraphiteTextureHolder> to Graphite's release proc in order to keep
  // the BackendTexture alive until Graphite finishes using it.
  // - This function will return an empty vector on failure.
  virtual std::vector<scoped_refptr<GraphiteTextureHolder>>
  BeginWriteAccess() = 0;

  // Same as above but return holders of skgpu::graphite::BackendTexture for
  // reading in graphite.
  virtual std::vector<scoped_refptr<GraphiteTextureHolder>>
  BeginReadAccess() = 0;
};

///////////////////////////////////////////////////////////////////////////////
// DawnImageRepresentation

class GPU_GLES2_EXPORT DawnImageRepresentation
    : public SharedImageRepresentation {
 public:
  static constexpr wgpu::TextureUsage kWriteUsage =
      wgpu::TextureUsage::CopyDst | wgpu::TextureUsage::RenderAttachment |
      wgpu::TextureUsage::StorageBinding;

  DawnImageRepresentation(SharedImageManager* manager,
                          SharedImageBacking* backing,
                          MemoryTypeTracker* tracker)
      : SharedImageRepresentation(manager, backing, tracker) {}

  class GPU_GLES2_EXPORT ScopedAccess
      : public ScopedAccessBase<DawnImageRepresentation> {
   public:
    ScopedAccess(base::PassKey<DawnImageRepresentation> pass_key,
                 DawnImageRepresentation* representation,
                 wgpu::Texture texture,
                 AccessMode access_mode);
    ~ScopedAccess();

    // Get the unowned texture handle. The caller should take a reference
    // if necessary by doing wgpu::Texture texture(access->texture());
    const wgpu::Texture& texture() const { return texture_; }

   private:
    wgpu::Texture texture_;
  };

  // Calls BeginAccess and returns a ScopedAccess object which will EndAccess
  // when it goes out of scope. The Representation must outlive the returned
  // ScopedAccess.
  std::unique_ptr<ScopedAccess> BeginScopedAccess(
      wgpu::TextureUsage usage,
      AllowUnclearedAccess allow_uncleared);

  // Allawos passing internal usages to the created Dawn texture.
  std::unique_ptr<ScopedAccess> BeginScopedAccess(
      wgpu::TextureUsage usage,
      wgpu::TextureUsage internal_usage,
      AllowUnclearedAccess allow_uncleared);

  // For write usage, the update_rect is a hint to the backend about the portion
  // of the image that will be drawn to. Callers shouldn't draw outside of this
  // area, but aren't required to overwrite every pixel inside it.
  // For non-write usage, the update_rect can be ignored.
  std::unique_ptr<ScopedAccess> BeginScopedAccess(
      wgpu::TextureUsage usage,
      AllowUnclearedAccess allow_uncleared,
      const gfx::Rect& update_rect);

  std::unique_ptr<ScopedAccess> BeginScopedAccess(
      wgpu::TextureUsage usage,
      wgpu::TextureUsage internal_usage,
      AllowUnclearedAccess allow_uncleared,
      const gfx::Rect& update_rect);

 private:
  friend class WrappedDawnCompoundImageRepresentation;

  // This can return null in case of a Dawn validation error, for example if
  // usage is invalid.
  virtual wgpu::Texture BeginAccess(wgpu::TextureUsage usage,
                                    wgpu::TextureUsage internal_usage) = 0;
  virtual wgpu::Texture BeginAccess(wgpu::TextureUsage usage,
                                    wgpu::TextureUsage internal_usage,
                                    const gfx::Rect& update_rect);
  virtual void EndAccess() = 0;
};

///////////////////////////////////////////////////////////////////////////////
// DawnBufferRepresentation

class GPU_GLES2_EXPORT DawnBufferRepresentation
    : public SharedImageRepresentation {
 public:
  DawnBufferRepresentation(SharedImageManager* manager,
                           SharedImageBacking* backing,
                           MemoryTypeTracker* tracker)
      : SharedImageRepresentation(manager, backing, tracker) {}

  class GPU_GLES2_EXPORT ScopedAccess
      : public ScopedAccessBase<DawnBufferRepresentation> {
   public:
    ScopedAccess(base::PassKey<DawnBufferRepresentation> pass_key,
                 DawnBufferRepresentation* representation,
                 wgpu::Buffer buffer,
                 AccessMode access_mode);
    ~ScopedAccess();

    std::unique_ptr<ScopedAccess> BeginScopedAccess(wgpu::BufferUsage usage);

    const wgpu::Buffer& buffer() const { return buffer_; }

   private:
    wgpu::Buffer buffer_;
  };

  // Allows passing usages to the created Dawn buffer.
  std::unique_ptr<ScopedAccess> BeginScopedAccess(wgpu::BufferUsage usage);

 protected:
  friend class WrappedDawnBufferCompoundImageRepresentation;
  virtual wgpu::Buffer BeginAccess(wgpu::BufferUsage usage) = 0;
  virtual void EndAccess() = 0;
};

///////////////////////////////////////////////////////////////////////////////
// WebNNTensorRepresentation

class GPU_GLES2_EXPORT WebNNTensorRepresentation
    : public SharedImageRepresentation {
 public:
  WebNNTensorRepresentation(SharedImageManager* manager,
                            SharedImageBacking* backing,
                            MemoryTypeTracker* tracker)
      : SharedImageRepresentation(manager, backing, tracker) {}

  class GPU_GLES2_EXPORT ScopedAccess
      : public ScopedAccessBase<WebNNTensorRepresentation> {
   public:
    ScopedAccess(base::PassKey<WebNNTensorRepresentation> pass_key,
                 WebNNTensorRepresentation* representation,
                 AccessMode access_mode);
    ~ScopedAccess();

#if BUILDFLAG(IS_WIN)
    scoped_refptr<gfx::D3DSharedFence> GetAcquireFence() const;
    void SetReleaseFence(scoped_refptr<gfx::D3DSharedFence> release_fence);
#endif
  };

  bool is_thread_safe() const;

  std::unique_ptr<ScopedAccess> BeginScopedAccess();

#if BUILDFLAG(IS_WIN)
  virtual Microsoft::WRL::ComPtr<ID3D12Resource> GetD3D12Buffer() const;
  virtual base::win::ScopedHandle GetD3D12HeapHandle() const;
#endif  // BUILDFLAG(IS_WIN)
#if BUILDFLAG(IS_APPLE)
  virtual IOSurfaceRef GetIOSurface() const;
#endif  // BUILDFLAG(IS_APPLE)
 protected:
  friend class WrappedWebNNTensorCompoundImageRepresentation;

#if BUILDFLAG(IS_WIN)
  virtual scoped_refptr<gfx::D3DSharedFence> GetAcquireFence() const = 0;
  virtual void SetReleaseFence(
      scoped_refptr<gfx::D3DSharedFence> release_fence) = 0;
#endif  // BUILDFLAG(IS_WIN)
  virtual bool BeginAccess() = 0;
  virtual void EndAccess() = 0;
};

///////////////////////////////////////////////////////////////////////////////
// OverlayImageRepresentation

class GPU_GLES2_EXPORT OverlayImageRepresentation
    : public SharedImageRepresentation {
 public:
  OverlayImageRepresentation(SharedImageManager* manager,
                             SharedImageBacking* backing,
                             MemoryTypeTracker* tracker)
      : SharedImageRepresentation(manager, backing, tracker) {}

  class GPU_GLES2_EXPORT ScopedReadAccess
      : public ScopedAccessBase<OverlayImageRepresentation> {
   public:
    ScopedReadAccess(base::PassKey<OverlayImageRepresentation> pass_key,
                     OverlayImageRepresentation* representation,
                     gfx::GpuFenceHandle acquire_fence);
    ~ScopedReadAccess();

#if BUILDFLAG(IS_ANDROID)
    AHardwareBuffer* GetAHardwareBuffer() {
      return representation()->GetAHardwareBuffer();
    }
    // Deprecated. All code should use GetAHardwareBuffer() above, this function
    // will be deleted when GLSurfaceEGLSurface control will be able to deliver
    // fences via EndAccess.
    std::unique_ptr<base::android::ScopedHardwareBufferFenceSync>
    GetAHardwareBufferFenceSync() {
      return representation()->GetAHardwareBufferFenceSync();
    }
#elif BUILDFLAG(IS_OZONE)
    scoped_refptr<gfx::NativePixmap> GetNativePixmap() {
      return representation()->GetNativePixmap();
    }
#elif BUILDFLAG(IS_WIN)
    std::optional<gl::DCLayerOverlayImage> GetDCLayerOverlayImage() {
      return representation()->GetDCLayerOverlayImage();
    }
#elif BUILDFLAG(IS_APPLE)
    gfx::ScopedIOSurface GetIOSurface() const {
      return representation()->GetIOSurface();
    }
    std::vector<gfx::MTLSharedEventFence> GetBackpressureFences() const {
      return representation()->GetBackpressureFences();
    }
    bool IsInUseByWindowServer() const {
      return representation()->IsInUseByWindowServer();
    }
#endif

    gfx::GpuFenceHandle TakeAcquireFence() { return std::move(acquire_fence_); }
    void SetReleaseFence(gfx::GpuFenceHandle release_fence) {
      // Note: We overwrite previous fence. In case if window manager uses fence
      // for each frame we schedule overlay and the same image is scheduled for
      // multiple frames this will be updated after each frame. It's safe to
      // wait only for the last frame's fence.
      release_fence_ = std::move(release_fence);
    }

   private:
    gfx::GpuFenceHandle acquire_fence_;
    gfx::GpuFenceHandle release_fence_;
  };

  std::unique_ptr<ScopedReadAccess> BeginScopedReadAccess();

 protected:
  friend class WrappedOverlayCompoundImageRepresentation;

  // Notifies the backing that an access will start. Returns false if there is a
  // conflict. Otherwise, returns true and:
  // - Set a gpu fence to |acquire_fence| that should be waited on before the
  // SharedImage is ready to be displayed. This fence is fired when the gpu
  // has finished writing.
  virtual bool BeginReadAccess(gfx::GpuFenceHandle& acquire_fence) = 0;

  // |release_fence| is a fence that will be signaled when the image can be
  // safely re-used. Note, on some platforms window manager doesn't support
  // release fences and return image when it's already safe to re-use.
  // |release_fence| will be null in that case.
  virtual void EndReadAccess(gfx::GpuFenceHandle release_fence) = 0;

#if BUILDFLAG(IS_ANDROID)
  virtual AHardwareBuffer* GetAHardwareBuffer();
  virtual std::unique_ptr<base::android::ScopedHardwareBufferFenceSync>
  GetAHardwareBufferFenceSync();
#elif BUILDFLAG(IS_OZONE)
  scoped_refptr<gfx::NativePixmap> GetNativePixmap();
#elif BUILDFLAG(IS_WIN)
  virtual std::optional<gl::DCLayerOverlayImage> GetDCLayerOverlayImage();
#elif BUILDFLAG(IS_APPLE)
  virtual gfx::ScopedIOSurface GetIOSurface() const;
  virtual std::vector<gfx::MTLSharedEventFence> GetBackpressureFences() const;
  // Return true if the macOS WindowServer is currently using the underlying
  // storage for the image.
  virtual bool IsInUseByWindowServer() const;
#endif
};

///////////////////////////////////////////////////////////////////////////////
// LegacyOverlayImageRepresentation

#if BUILDFLAG(IS_ANDROID)
class GPU_GLES2_EXPORT LegacyOverlayImageRepresentation
    : public SharedImageRepresentation {
 public:
  LegacyOverlayImageRepresentation(SharedImageManager* manager,
                                   SharedImageBacking* backing,
                                   MemoryTypeTracker* tracker)
      : SharedImageRepresentation(manager, backing, tracker) {}

  // Renders shared image to SurfaceView/Dialog overlay. Should only be called
  // if the image already promoted to overlay.
  virtual void RenderToOverlay() = 0;

  // Notifies legacy overlay system about overlay promotion.
  virtual void NotifyOverlayPromotion(bool promotion,
                                      const gfx::Rect& bounds) = 0;
};
#endif

///////////////////////////////////////////////////////////////////////////////
// MemoryImageRepresentation

class GPU_GLES2_EXPORT MemoryImageRepresentation
    : public SharedImageRepresentation {
 public:
  class GPU_GLES2_EXPORT ScopedReadAccess
      : public ScopedAccessBase<MemoryImageRepresentation> {
   public:
    ScopedReadAccess(base::PassKey<MemoryImageRepresentation> pass_key,
                     MemoryImageRepresentation* representation,
                     SkPixmap pixmap);
    ~ScopedReadAccess();

    SkPixmap pixmap() { return pixmap_; }

   private:
    SkPixmap pixmap_;
  };

  MemoryImageRepresentation(SharedImageManager* manager,
                            SharedImageBacking* backing,
                            MemoryTypeTracker* tracker)
      : SharedImageRepresentation(manager, backing, tracker) {}

  std::unique_ptr<ScopedReadAccess> BeginScopedReadAccess();

 protected:
  friend class WrappedMemoryCompoundImageRepresentation;

  virtual SkPixmap BeginReadAccess() = 0;
};

///////////////////////////////////////////////////////////////////////////////
// RasterImageRepresentation

// Representation of a SharedImageBacking for raster work.
// This representation is used for raster work and compositor. The raster work
// will be converted to a cc::PaintOpBuffer and stored in the
// SharedImageBacking. And then the the compositor will access the stored
// cc::PaintOpBuffer and execute paint ops in it.
class GPU_GLES2_EXPORT RasterImageRepresentation
    : public SharedImageRepresentation {
 public:
  class GPU_GLES2_EXPORT ScopedReadAccess
      : public ScopedAccessBase<RasterImageRepresentation> {
   public:
    ScopedReadAccess(base::PassKey<RasterImageRepresentation> pass_key,
                     RasterImageRepresentation* representation,
                     const cc::PaintOpBuffer* paint_op_buffer,
                     const std::optional<SkColor4f>& clear_color);
    ~ScopedReadAccess();

    const cc::PaintOpBuffer* paint_op_buffer() const {
      return paint_op_buffer_;
    }
    const std::optional<SkColor4f>& clear_color() const { return clear_color_; }

   private:
    const raw_ptr<const cc::PaintOpBuffer> paint_op_buffer_;
    std::optional<SkColor4f> clear_color_;
  };

  class GPU_GLES2_EXPORT ScopedWriteAccess
      : public ScopedAccessBase<RasterImageRepresentation> {
   public:
    ScopedWriteAccess(base::PassKey<RasterImageRepresentation> pass_key,
                      RasterImageRepresentation* representation,
                      cc::PaintOpBuffer* paint_op_buffer);
    ~ScopedWriteAccess();

    cc::PaintOpBuffer* paint_op_buffer() { return paint_op_buffer_; }
    // An optional callback which will be called when the all paint ops in the
    // |paint_op_buffer_| are released.
    void set_callback(base::OnceClosure callback) {
      DCHECK(!callback_);
      DCHECK(callback);
      callback_ = std::move(callback);
    }

   private:
    const raw_ptr<cc::PaintOpBuffer> paint_op_buffer_;
    base::OnceClosure callback_;
  };

  RasterImageRepresentation(SharedImageManager* manager,
                            SharedImageBacking* backing,
                            MemoryTypeTracker* tracker)
      : SharedImageRepresentation(manager, backing, tracker) {}

  std::unique_ptr<ScopedReadAccess> BeginScopedReadAccess();

  std::unique_ptr<ScopedWriteAccess> BeginScopedWriteAccess(
      scoped_refptr<SharedContextState> context_state,
      int final_msaa_count,
      const SkSurfaceProps& surface_props,
      const std::optional<SkColor4f>& clear_color,
      bool visible);

 protected:
  virtual cc::PaintOpBuffer* BeginReadAccess(
      std::optional<SkColor4f>& clear_color) = 0;
  virtual void EndReadAccess() = 0;
  virtual cc::PaintOpBuffer* BeginWriteAccess(
      scoped_refptr<SharedContextState> context_state,
      int final_msaa_count,
      const SkSurfaceProps& surface_props,
      const std::optional<SkColor4f>& clear_color,
      bool visible) = 0;
  virtual void EndWriteAccess(base::OnceClosure callback) = 0;
};

///////////////////////////////////////////////////////////////////////////////
// VideoImageRepresentation

#if BUILDFLAG(IS_WIN)
// Holds a D3D11 texture array, and index into it.
struct GPU_GLES2_EXPORT D3D11TextureAndArrayIndex {
  D3D11TextureAndArrayIndex(Microsoft::WRL::ComPtr<ID3D11Texture2D> texture,
                            size_t array_index);
  D3D11TextureAndArrayIndex(const D3D11TextureAndArrayIndex& other);
  D3D11TextureAndArrayIndex(D3D11TextureAndArrayIndex&& other);

  ~D3D11TextureAndArrayIndex();

  Microsoft::WRL::ComPtr<ID3D11Texture2D> texture;
  size_t array_index = 0;
};
#endif  // BUILDFLAG(IS_WIN)

class GPU_GLES2_EXPORT VideoImageRepresentation
    : public SharedImageRepresentation {
 public:
  class GPU_GLES2_EXPORT ScopedWriteAccess
      : public ScopedAccessBase<VideoImageRepresentation> {
   public:
    ScopedWriteAccess(base::PassKey<VideoImageRepresentation> pass_key,
                      VideoImageRepresentation* representation);
    ~ScopedWriteAccess();

#if BUILDFLAG(IS_WIN)
    D3D11TextureAndArrayIndex GetD3D11Texture() const {
      return representation()->GetD3D11Texture();
    }
#endif  // BUILDFLAG(IS_WIN)
  };

  class GPU_GLES2_EXPORT ScopedReadAccess
      : public ScopedAccessBase<VideoImageRepresentation> {
   public:
    ScopedReadAccess(base::PassKey<VideoImageRepresentation> pass_key,
                     VideoImageRepresentation* representation);
    ~ScopedReadAccess();

#if BUILDFLAG(IS_WIN)
    D3D11TextureAndArrayIndex GetD3D11Texture() const {
      return representation()->GetD3D11Texture();
    }
#endif  // BUILDFLAG(IS_WIN)

#if BUILDFLAG(IS_ANDROID)
    AHardwareBuffer* GetAHardwareBuffer() const {
      return representation()->GetAHardwareBuffer();
    }
#endif  // BUILDFLAG(IS_ANDROID)
  };

  VideoImageRepresentation(SharedImageManager* manager,
                           SharedImageBacking* backing,
                           MemoryTypeTracker* tracker);
  ~VideoImageRepresentation() override;

  virtual std::unique_ptr<ScopedWriteAccess> BeginScopedWriteAccess();
  virtual std::unique_ptr<ScopedReadAccess> BeginScopedReadAccess();

 protected:
  friend class WrappedVideoCompoundImageRepresentation;

#if BUILDFLAG(IS_WIN)
  virtual D3D11TextureAndArrayIndex GetD3D11Texture() const = 0;
#endif  // BUILDFLAG(IS_WIN)

#if BUILDFLAG(IS_ANDROID)
  virtual AHardwareBuffer* GetAHardwareBuffer() const = 0;
#endif  // BUILDFLAG(IS_ANDROID)

  virtual bool BeginWriteAccess() = 0;
  virtual void EndWriteAccess() = 0;
  virtual bool BeginReadAccess() = 0;
  virtual void EndReadAccess() = 0;
};

///////////////////////////////////////////////////////////////////////////////
// VulkanImageRepresentation

#if BUILDFLAG(ENABLE_VULKAN)
class GPU_GLES2_EXPORT VulkanImageRepresentation
    : public SharedImageRepresentation {
 public:
  VulkanImageRepresentation(SharedImageManager* manager,
                            SharedImageBacking* backing,
                            MemoryTypeTracker* tracker,
                            std::unique_ptr<gpu::VulkanImage> vulkan_image,
                            gpu::VulkanDeviceQueue* vulkan_device_queue,
                            gpu::VulkanImplementation& vulkan_impl);
  ~VulkanImageRepresentation() override;

  class ScopedAccess : public ScopedAccessBase<VulkanImageRepresentation> {
   public:
    ScopedAccess(
        VulkanImageRepresentation* representation,
        AccessMode access_mode,
        std::vector<base::RawPtrIfPtrT<VkSemaphore, DanglingUntriaged>>
            begin_semaphores,
        base::RawPtrIfPtrT<VkSemaphore, DanglingUntriaged> end_semaphore);
    ~ScopedAccess();

    gpu::VulkanImage& GetVulkanImage();

   private:
    bool is_read_only_;
    std::vector<base::RawPtrIfPtrT<VkSemaphore, DanglingUntriaged>>
        begin_semaphores_;
    base::RawPtrIfPtrT<VkSemaphore, DanglingUntriaged> end_semaphore_;
  };

  std::unique_ptr<ScopedAccess> BeginScopedAccess(
      AccessMode access_mode,
      std::vector<VkSemaphore>& begin_semaphores,
      std::vector<VkSemaphore>& end_semaphores);

  virtual bool BeginAccess(
      AccessMode access_mode,
      std::vector<base::RawPtrIfPtrT<VkSemaphore, DanglingUntriaged>>&
          begin_semaphores,
      std::vector<base::RawPtrIfPtrT<VkSemaphore, DanglingUntriaged>>&
          end_semaphores) = 0;

  virtual void EndAccess(bool is_read_only, VkSemaphore end_semaphore) = 0;

  virtual gpu::VulkanImage& GetVulkanImage();

 protected:
  friend class WrappedVulkanCompoundImageRepresentation;

  std::unique_ptr<gpu::VulkanImage> vulkan_image_;
  raw_ptr<gpu::VulkanDeviceQueue> vulkan_device_queue_;
  raw_ref<VulkanImplementation> vulkan_impl_;
};
#endif

}  // namespace gpu

#endif  // GPU_COMMAND_BUFFER_SERVICE_SHARED_IMAGE_SHARED_IMAGE_REPRESENTATION_H_
