7b253591创建于 2023年12月16日历史提交
// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// This file contains the GLES2DecoderPassthroughImpl class.

#ifndef GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_DECODER_PASSTHROUGH_H_
#define GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_DECODER_PASSTHROUGH_H_

#include <algorithm>
#include <memory>
#include <vector>

#include "base/containers/circular_deque.h"
#include "base/containers/flat_map.h"
#include "base/containers/flat_set.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/ref_counted.h"
#include "build/build_config.h"
#include "gpu/command_buffer/common/debug_marker_manager.h"
#include "gpu/command_buffer/common/discardable_handle.h"
#include "gpu/command_buffer/common/gles2_cmd_format.h"
#include "gpu/command_buffer/common/gles2_cmd_utils.h"
#include "gpu/command_buffer/common/mailbox.h"
#include "gpu/command_buffer/common/sync_token.h"
#include "gpu/command_buffer/service/client_service_map.h"
#include "gpu/command_buffer/service/context_group.h"
#include "gpu/command_buffer/service/gles2_cmd_decoder.h"
#include "gpu/command_buffer/service/logger.h"
#include "gpu/command_buffer/service/mailbox_manager.h"
#include "gpu/command_buffer/service/shared_context_state.h"
#include "gpu/command_buffer/service/shared_image/shared_image_representation.h"
#include "gpu/command_buffer/service/texture_manager.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
#include "ui/gl/gl_bindings.h"
#include "ui/gl/gl_context.h"
#include "ui/gl/gl_fence.h"
#include "ui/gl/gl_surface.h"
#include "ui/gl/gpu_switching_observer.h"

#if !BUILDFLAG(IS_ANDROID)
#include "gpu/command_buffer/service/passthrough_abstract_texture_impl.h"
#endif

namespace gl {
class GLFence;
class GLImage;
class ProgressReporter;
}

namespace gpu {
class GLTexturePassthroughImageRepresentation;

namespace gles2 {

class ContextGroup;
class GPUTracer;
class PassthroughAbstractTextureImpl;
class MultiDrawManager;
class GLES2DecoderPassthroughImpl;
class GLES2ExternalFramebuffer;

struct MappedBuffer {
  GLsizeiptr size;
  GLbitfield original_access;
  GLbitfield filtered_access;
  raw_ptr<uint8_t, AllowPtrArithmetic> map_ptr;
  int32_t data_shm_id;
  uint32_t data_shm_offset;
};

struct PassthroughResources {
  PassthroughResources();
  ~PassthroughResources();

  // api is null if we don't have a context (e.g. lost).
  void Destroy(gl::GLApi* api, gl::ProgressReporter* progress_reporter);

#if !BUILDFLAG(IS_ANDROID)
  // Resources stores a shared list of textures pending deletion.
  // If we have don't context when this function is called, we can mark
  // these textures as lost context and drop all references to them.
  // NOTE: This functionality is exercised only when the decoder is asked to
  // create textures via CreateAbstractTexture(), an API that does not exist on
  // Android.
  void DestroyPendingTextures(bool has_context);

  // If there are any textures pending destruction.
  bool HasTexturesPendingDestruction() const;
#endif

  void SuspendSharedImageAccessIfNeeded();
  bool ResumeSharedImageAccessIfNeeded(gl::GLApi* api);

  // Mappings from client side IDs to service side IDs.
  ClientServiceMap<GLuint, GLuint> texture_id_map;
  ClientServiceMap<GLuint, GLuint> buffer_id_map;
  ClientServiceMap<GLuint, GLuint> renderbuffer_id_map;
  ClientServiceMap<GLuint, GLuint> sampler_id_map;
  ClientServiceMap<GLuint, GLuint> program_id_map;
  ClientServiceMap<GLuint, GLuint> shader_id_map;

  static_assert(sizeof(uintptr_t) == sizeof(GLsync),
                "GLsync not the same size as uintptr_t");
  ClientServiceMap<GLuint, uintptr_t> sync_id_map;

  // Mapping of client texture IDs to TexturePassthrough objects used to make
  // sure all textures used by mailboxes are not deleted until all textures
  // using the mailbox are deleted
  ClientServiceMap<GLuint, scoped_refptr<TexturePassthrough>>
      texture_object_map;

  class SharedImageData {
   public:
    SharedImageData();
    explicit SharedImageData(
        const GLES2DecoderPassthroughImpl*,
        std::unique_ptr<GLTexturePassthroughImageRepresentation>);
    SharedImageData(SharedImageData&& other);

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

    ~SharedImageData();
    SharedImageData& operator=(SharedImageData&& other);

    GLTexturePassthroughImageRepresentation* representation() const {
      return representation_.get();
    }

    // Returns true between a successful BeginAccess and the following EndAccess
    // even if access is currently suspended.
    bool is_being_accessed() const { return access_mode_.has_value(); }

    void EnsureClear(const GLES2DecoderPassthroughImpl*);

    bool BeginAccess(GLenum mode, gl::GLApi* api);
    void EndAccess();

    bool ResumeAccessIfNeeded(gl::GLApi* api);
    void SuspendAccessIfNeeded();

   private:
    std::unique_ptr<GLTexturePassthroughImageRepresentation> representation_;
    std::unique_ptr<GLTexturePassthroughImageRepresentation::ScopedAccess>
        scoped_access_;
    absl::optional<GLenum> access_mode_;
  };
  // Mapping of client texture IDs to GLTexturePassthroughImageRepresentations.
  // TODO(ericrk): Remove this once TexturePassthrough holds a reference to
  // the GLTexturePassthroughImageRepresentation itself.
  base::flat_map<GLuint, SharedImageData> texture_shared_image_map;

#if !BUILDFLAG(IS_ANDROID)
  // A set of yet-to-be-deleted TexturePassthrough, which should be tossed
  // whenever a context switch happens or the resources is destroyed.
  // NOTE: The concept of "textures pending destruction" is relevant only when
  // the decoder is asked to create textures via CreateAbstractTexture(), an API
  // that does not exist on Android.
  base::flat_set<scoped_refptr<TexturePassthrough>>
      textures_pending_destruction;
#endif

  // Mapping of client buffer IDs that are mapped to the shared memory used to
  // back the mapping so that it can be flushed when the buffer is unmapped
  base::flat_map<GLuint, MappedBuffer> mapped_buffer_map;
};

// Impose an upper bound on the number ANGLE_shader_pixel_local_storage planes
// so we can stack-allocate load/store ops.
static constexpr GLsizei kPassthroughMaxPLSPlanes = 8;

class GPU_GLES2_EXPORT GLES2DecoderPassthroughImpl
    : public GLES2Decoder,
      public ui::GpuSwitchingObserver {
 public:
  GLES2DecoderPassthroughImpl(DecoderClient* client,
                              CommandBufferServiceBase* command_buffer_service,
                              Outputter* outputter,
                              ContextGroup* group);
  ~GLES2DecoderPassthroughImpl() override;

  Error DoCommands(unsigned int num_commands,
                   const volatile void* buffer,
                   int num_entries,
                   int* entries_processed) override;

  template <bool DebugImpl>
  Error DoCommandsImpl(unsigned int num_commands,
                       const volatile void* buffer,
                       int num_entries,
                       int* entries_processed);

  base::WeakPtr<DecoderContext> AsWeakPtr() override;

  gpu::ContextResult Initialize(
      const scoped_refptr<gl::GLSurface>& surface,
      const scoped_refptr<gl::GLContext>& context,
      bool offscreen,
      const DisallowedFeatures& disallowed_features,
      const ContextCreationAttribs& attrib_helper) override;

  // Destroys the graphics context.
  void Destroy(bool have_context) override;

  // Set the surface associated with the default FBO.
  void SetSurface(const scoped_refptr<gl::GLSurface>& surface) override;

  // Releases the surface associated with the GL context.
  // The decoder should not be used until a new surface is set.
  void ReleaseSurface() override;

  void TakeFrontBuffer(const Mailbox& mailbox) override;

  void ReturnFrontBuffer(const Mailbox& mailbox, bool is_lost) override;

  void SetDefaultFramebufferSharedImage(const Mailbox& mailbox,
                                        int samples,
                                        bool preserve,
                                        bool needs_depth,
                                        bool needs_stencil) override;

  // Resize an offscreen frame buffer.
  bool ResizeOffscreenFramebuffer(const gfx::Size& size) override;

  // Make this decoder's GL context current.
  bool MakeCurrent() override;

  gl::GLApi* api() const { return api_; }

  // Gets the GLES2 Util which holds info.
  GLES2Util* GetGLES2Util() override;

  // Gets the associated GLContext and GLSurface.
  gl::GLContext* GetGLContext() override;
  gl::GLSurface* GetGLSurface() override;

  // Gets the associated ContextGroup
  ContextGroup* GetContextGroup() override;

  const FeatureInfo* GetFeatureInfo() const override;

  Capabilities GetCapabilities() override;

  // Restores all of the decoder GL state.
  void RestoreState(const ContextState* prev_state) override;

  // Restore States.
  void RestoreActiveTexture() const override;
  void RestoreAllTextureUnitAndSamplerBindings(
      const ContextState* prev_state) const override;
  void RestoreActiveTextureUnitBinding(unsigned int target) const override;
  void RestoreBufferBinding(unsigned int target) override;
  void RestoreBufferBindings() const override;
  void RestoreFramebufferBindings() const override;
  void RestoreRenderbufferBindings() override;
  void RestoreGlobalState() const override;
  void RestoreProgramBindings() const override;
  void RestoreTextureState(unsigned service_id) override;
  void RestoreTextureUnitBindings(unsigned unit) const override;
  void RestoreVertexAttribArray(unsigned index) override;
  void RestoreAllExternalTextureBindingsIfNeeded() override;
  void RestoreDeviceWindowRectangles() const override;

  void ClearAllAttributes() const override;
  void RestoreAllAttributes() const override;

  void SetIgnoreCachedStateForTest(bool ignore) override;
  void SetForceShaderNameHashingForTest(bool force) override;
  size_t GetSavedBackTextureCountForTest() override;
  size_t GetCreatedBackTextureCountForTest() override;

  // Gets the QueryManager for this context.
  QueryManager* GetQueryManager() override;

  // Set a callback to be called when a query is complete.
  void SetQueryCallback(unsigned int query_client_id,
                        base::OnceClosure callback) override;

  // Gets the GpuFenceManager for this context.
  GpuFenceManager* GetGpuFenceManager() override;

  // Gets the FramebufferManager for this context.
  FramebufferManager* GetFramebufferManager() override;

  // Gets the TransformFeedbackManager for this context.
  TransformFeedbackManager* GetTransformFeedbackManager() override;

  // Gets the VertexArrayManager for this context.
  VertexArrayManager* GetVertexArrayManager() override;

  // Returns false if there are no pending queries.
  bool HasPendingQueries() const override;

  // Process any pending queries.
  void ProcessPendingQueries(bool did_finish) override;

  // Returns false if there is no idle work to be made.
  bool HasMoreIdleWork() const override;

  // Perform any idle work that needs to be made.
  void PerformIdleWork() override;

  bool HasPollingWork() const override;
  void PerformPollingWork() override;

  bool GetServiceTextureId(uint32_t client_texture_id,
                           uint32_t* service_texture_id) override;
  TextureBase* GetTextureBase(uint32_t client_id) override;

  // Provides detail about a lost context if one occurred.
  // Clears a level sub area of a texture
  // Returns false if a GL error should be generated.
  bool ClearLevel(Texture* texture,
                  unsigned target,
                  int level,
                  unsigned format,
                  unsigned type,
                  int xoffset,
                  int yoffset,
                  int width,
                  int height) override;

  // Clears a level sub area of a compressed 2D texture.
  // Returns false if a GL error should be generated.
  bool ClearCompressedTextureLevel(Texture* texture,
                                   unsigned target,
                                   int level,
                                   unsigned format,
                                   int width,
                                   int height) override;

  // Clears a level sub area of a compressed 3D texture.
  // Returns false if a GL error should be generated.
  bool ClearCompressedTextureLevel3D(Texture* texture,
                                     unsigned target,
                                     int level,
                                     unsigned format,
                                     int width,
                                     int height,
                                     int depth) override;

  // Indicates whether a given internal format is one for a compressed
  // texture.
  bool IsCompressedTextureFormat(unsigned format) override;

  // Clears a level of a 3D texture.
  // Returns false if a GL error should be generated.
  bool ClearLevel3D(Texture* texture,
                    unsigned target,
                    int level,
                    unsigned format,
                    unsigned type,
                    int width,
                    int height,
                    int depth) override;

  ErrorState* GetErrorState() override;

#if !(BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_OHOS))
  std::unique_ptr<AbstractTexture> CreateAbstractTexture(
      unsigned target,
      unsigned internal_format,
      int width,
      int height,
      int depth,
      int border,
      unsigned format,
      unsigned type) override;
#endif

  void WaitForReadPixels(base::OnceClosure callback) override;

  // Returns true if the context was lost either by GL_ARB_robustness, forced
  // context loss or command buffer parse error.
  bool WasContextLost() const override;

  // Returns true if the context was lost specifically by GL_ARB_robustness.
  bool WasContextLostByRobustnessExtension() const override;

  // Lose this context.
  void MarkContextLost(error::ContextLostReason reason) override;

  // Update lost context state for use when making calls to the GL context
  // directly, and needing to know if they failed due to loss.
  bool CheckResetStatus() override;

  // Implement GpuSwitchingObserver.
  void OnGpuSwitched(gl::GpuPreference active_gpu_heuristic) override;

  Logger* GetLogger() override;

  void BeginDecoding() override;
  void EndDecoding() override;

  const ContextState* GetContextState() override;
  scoped_refptr<ShaderTranslatorInterface> GetTranslator(GLenum type) override;

#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_APPLE)
  void AttachImageToTextureWithDecoderBinding(uint32_t client_texture_id,
                                              uint32_t texture_target,
                                              gl::GLImage* image) override;
#elif !BUILDFLAG(IS_ANDROID)
  void AttachImageToTextureWithClientBinding(uint32_t client_texture_id,
                                             uint32_t texture_target,
                                             gl::GLImage* image) override;
#endif

  void OnDebugMessage(GLenum source,
                      GLenum type,
                      GLuint id,
                      GLenum severity,
                      GLsizei length,
                      const GLchar* message);

  void SetCopyTextureResourceManagerForTest(
      CopyTextureCHROMIUMResourceManager* copy_texture_resource_manager)
      override;
  void SetCopyTexImageBlitterForTest(
      CopyTexImageResourceManager* copy_tex_image_blit) override;

#if !BUILDFLAG(IS_ANDROID)
  void OnAbstractTextureDestroyed(PassthroughAbstractTextureImpl*,
                                  scoped_refptr<TexturePassthrough>);
#endif

  const FeatureInfo::FeatureFlags& features() const {
    return feature_info_->feature_flags();
  }

  class ScopedPixelLocalStorageInterrupt {
   public:
    ScopedPixelLocalStorageInterrupt(const GLES2DecoderPassthroughImpl*);
    ~ScopedPixelLocalStorageInterrupt();

   private:
    raw_ptr<const GLES2DecoderPassthroughImpl> impl_;
  };

 private:
  // Allow unittests to inspect internal state tracking
  friend class GLES2DecoderPassthroughTestBase;

#if !BUILDFLAG(IS_ANDROID)
  // Attaches |image| to the texture referred to by |client_texture_id|, marking
  // the image as needing on-demand binding by the decoder if
  // |can_bind_to_sampler| is false and as not needing on-demand binding by the
  // decoder otherwise. |can_bind_to_sampler| is always false on Mac/Win and
  // always true on all other platforms.
  void BindImageInternal(uint32_t client_texture_id,
                         uint32_t texture_target,
                         gl::GLImage* image,
                         bool can_bind_to_sampler);
#endif

  const char* GetCommandName(unsigned int command_id) const;

  void SetOptionalExtensionsRequestedForTesting(bool request_extensions);

  void InitializeFeatureInfo(ContextType context_type,
                             const DisallowedFeatures& disallowed_features,
                             bool force_reinitialize);

  template <typename T, typename GLGetFunction>
  error::Error GetNumericHelper(GLenum pname,
                                GLsizei bufsize,
                                GLsizei* length,
                                T* params,
                                GLGetFunction get_call) {
    get_call(pname, bufsize, length, params);

    // Update the results of the query, if needed
    const error::Error error = PatchGetNumericResults(pname, *length, params);
    if (error != error::kNoError) {
      *length = 0;
      return error;
    }

    return error::kNoError;
  }

  template <typename T>
  error::Error PatchGetNumericResults(GLenum pname, GLsizei length, T* params);
  error::Error PatchGetFramebufferAttachmentParameter(GLenum target,
                                                      GLenum attachment,
                                                      GLenum pname,
                                                      GLsizei length,
                                                      GLint* params);

  template <typename T>
  error::Error PatchGetBufferResults(GLenum target,
                                     GLenum pname,
                                     GLsizei bufsize,
                                     GLsizei* length,
                                     T* params);

  error::Error PatchGetFramebufferPixelLocalStorageParameterivANGLE(
      GLint plane,
      GLenum pname,
      GLsizei length,
      GLint* params);

  void InsertError(GLenum error, const std::string& message);
  GLenum PopError();
  bool FlushErrors();

  bool IsIgnoredCap(GLenum cap) const;

  bool IsEmulatedQueryTarget(GLenum target) const;
  error::Error ProcessQueries(bool did_finish);
  void RemovePendingQuery(GLuint service_id);

  struct BufferShadowUpdate;
  // BufferShadowUpdateMap's key is a buffer client id.
  using BufferShadowUpdateMap = base::flat_map<GLuint, BufferShadowUpdate>;
  void ReadBackBuffersIntoShadowCopies(const BufferShadowUpdateMap& updates);

  error::Error ProcessReadPixels(bool did_finish);

  // Checks to see if the inserted fence has completed.
  void ProcessDescheduleUntilFinished();

  void UpdateTextureBinding(GLenum target,
                            GLuint client_id,
                            TexturePassthrough* texture);
  void RebindTexture(TexturePassthrough* texture);

  void UpdateTextureSizeFromTexturePassthrough(TexturePassthrough* texture,
                                               GLuint client_id);
  void UpdateTextureSizeFromTarget(GLenum target);
  void UpdateTextureSizeFromClientID(GLuint client_id);

  // Some operations like binding a VAO will update the element array buffer
  // binding without an explicit glBindBuffer. This function is extremely
  // expensive, and it is crucial that it be called only when the command
  // decoder's notion of the element array buffer absolutely has to be
  // up-to-date.
  void LazilyUpdateCurrentlyBoundElementArrayBuffer();

  void VerifyServiceTextureObjectsExist();

  bool IsEmulatedFramebufferBound(GLenum target) const;

  void ExitCommandProcessingEarly() override;

  void CheckSwapBuffersAsyncResult(const char* function_name,
                                   uint64_t swap_id,
                                   gfx::SwapCompletionResult result);
  error::Error CheckSwapBuffersResult(gfx::SwapResult result,
                                      const char* function_name);

  // Textures can be marked as needing binding only on Windows/Mac, so all
  // functionality related to binding textures is relevant only on those
  // platforms.
#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_APPLE)
  // Issue BindTexImage calls for |passthrough_texture|, if
  // they're pending.
  void BindOnePendingImage(GLenum target, TexturePassthrough* texture);

  // Issue BindTexImage calls for any GLImages that
  // requested it in BindImage, and are currently bound to textures that
  // are bound to samplers (i.e., are in |textures_pending_binding_|).
  void BindPendingImagesForSamplers();

  // Fail-fast inline version of BindPendingImagesForSamplers.
  inline void BindPendingImagesForSamplersIfNeeded() {
    if (!textures_pending_binding_.empty())
      BindPendingImagesForSamplers();
  }

  // Fail-fast version of BindPendingImages that operates on a single texture
  // that's specified by |client_id|.
  inline void BindPendingImageForClientIDIfNeeded(int client_id) {
    scoped_refptr<TexturePassthrough> texture;

    // We could keep track of the number of |is_bind_pending| textures in
    // |resources_|, and elide all of this if it's zero.
    if (!resources_->texture_object_map.GetServiceID(client_id, &texture))
      return;

    if (texture && texture->is_bind_pending())
      BindOnePendingImage(texture->target(), texture.get());
  }

  inline void RemovePendingBindingTexture(GLenum target, GLuint unit) {
    // Note that this code was found to be faster than running base::EraseIf.
    size_t num_pending = textures_pending_binding_.size();
    for (size_t index = 0; index < num_pending; ++index) {
      TexturePendingBinding& pending = textures_pending_binding_[index];
      if (pending.target == target && pending.unit == unit) {
        textures_pending_binding_.erase(textures_pending_binding_.begin() +
                                        index);
        return;
      }
    }
  }
#endif

  bool OnlyHasPendingProgramCompletionQueries();

#if !BUILDFLAG(IS_ANDROID)
  // A set of raw pointers to currently living PassthroughAbstractTextures
  // which allow us to properly signal to them when we are destroyed.
  base::flat_set<PassthroughAbstractTextureImpl*> abstract_textures_;
#endif

  int commands_to_process_;

  DebugMarkerManager debug_marker_manager_;
  Logger logger_;

#define GLES2_CMD_OP(name) \
  Error Handle##name(uint32_t immediate_data_size, const volatile void* data);

  GLES2_COMMAND_LIST(GLES2_CMD_OP)
#undef GLES2_CMD_OP

  using CmdHandler =
      Error (GLES2DecoderPassthroughImpl::*)(uint32_t immediate_data_size,
                                             const volatile void* data);

  // A struct to hold info about each command.
  struct CommandInfo {
    CmdHandler cmd_handler;
    uint8_t arg_flags;   // How to handle the arguments for this scommand
    uint8_t cmd_flags;   // How to handle this command
    uint16_t arg_count;  // How many arguments are expected for this command.
  };

  // A table of CommandInfo for all the commands.
  static const CommandInfo command_info[kNumCommands - kFirstGLES2Command];

  // Creates lazily and holds a SharedContextState on a GLContext that is in the
  // same share group as the command decoder's context. This is done so that
  // skia operations can be performed on textures from the context and not worry
  // about state tracking.
  class LazySharedContextState {
   public:
    static std::unique_ptr<LazySharedContextState> Create(
        GLES2DecoderPassthroughImpl* impl);

    explicit LazySharedContextState(GLES2DecoderPassthroughImpl* impl);
    ~LazySharedContextState();

    SharedContextState* shared_context_state() {
      return shared_context_state_.get();
    }

   private:
    bool Initialize();

    raw_ptr<GLES2DecoderPassthroughImpl> impl_ = nullptr;
    scoped_refptr<SharedContextState> shared_context_state_;
  };

  std::unique_ptr<LazySharedContextState> lazy_context_;

  // The GLApi to make the gl calls on.
  raw_ptr<gl::GLApi> api_ = nullptr;

  // The GL context this decoder renders to on behalf of the client.
  scoped_refptr<gl::GLSurface> surface_;
  scoped_refptr<gl::GLContext> context_;
  bool offscreen_;

  // The ContextGroup for this decoder uses to track resources.
  scoped_refptr<ContextGroup> group_;
  scoped_refptr<FeatureInfo> feature_info_;

  // By default, all requestable extensions should be loaded at initialization
  // time. Can be disabled for testing with only specific extensions enabled.
  bool request_optional_extensions_ = true;

  // Some objects may generate resources when they are bound even if they were
  // not generated yet: texture, buffer, renderbuffer, framebuffer, transform
  // feedback, vertex array
  bool bind_generates_resource_;

  // Mappings from client side IDs to service side IDs for shared objects
  raw_ptr<PassthroughResources> resources_ = nullptr;

  // Mappings from client side IDs to service side IDs for per-context objects
  ClientServiceMap<GLuint, GLuint> framebuffer_id_map_;
  ClientServiceMap<GLuint, GLuint> transform_feedback_id_map_;
  ClientServiceMap<GLuint, GLuint> query_id_map_;
  ClientServiceMap<GLuint, GLuint> vertex_array_id_map_;

  // Mailboxes
  raw_ptr<MailboxManager> mailbox_manager_ = nullptr;

  std::unique_ptr<GpuFenceManager> gpu_fence_manager_;

  std::unique_ptr<MultiDrawManager> multi_draw_manager_;

  // State tracking of currently bound 2D textures (client IDs)
  size_t active_texture_unit_;

  enum class TextureTarget : uint8_t {
    k2D = 0,
    kCubeMap = 1,
    k2DArray = 2,
    k3D = 3,
    k2DMultisample = 4,
    kExternal = 5,
    kRectangle = 6,

    kUnkown = 7,
    kCount = kUnkown,
  };
  static TextureTarget GLenumToTextureTarget(GLenum target);

  struct BoundTexture {
    BoundTexture();
    ~BoundTexture();
    BoundTexture(const BoundTexture&);
    BoundTexture(BoundTexture&&);
    BoundTexture& operator=(const BoundTexture&);
    BoundTexture& operator=(BoundTexture&&);

    GLuint client_id = 0;
    scoped_refptr<TexturePassthrough> texture;
  };

  // Tracked viewport and scissor state for surface offset
  GLint viewport_[4] = {0, 0, 0, 0};
  GLint scissor_[4] = {0, 0, 0, 0};
  gfx::Vector2d GetSurfaceDrawOffset() const;
  void ApplySurfaceDrawOffset();

  // Use a limit that is at least ANGLE's IMPLEMENTATION_MAX_ACTIVE_TEXTURES
  // constant
  static constexpr size_t kMaxTextureUnits = 64;
  static constexpr size_t kNumTextureTypes =
      static_cast<size_t>(TextureTarget::kCount);
  std::array<std::array<BoundTexture, kMaxTextureUnits>, kNumTextureTypes>
      bound_textures_;

  // [target, texture unit, texture] where texture has a bound GLImage that
  // requires binding before draw.
  struct TexturePendingBinding {
    TexturePendingBinding(GLenum target,
                          GLuint unit,
                          base::WeakPtr<TexturePassthrough> texture);
    TexturePendingBinding(const TexturePendingBinding& other);
    TexturePendingBinding(TexturePendingBinding&& other);
    ~TexturePendingBinding();

    TexturePendingBinding& operator=(const TexturePendingBinding& other);
    TexturePendingBinding& operator=(TexturePendingBinding&& other);

    GLenum target;
    GLuint unit;
    base::WeakPtr<TexturePassthrough> texture;
  };
#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_APPLE)
  std::vector<TexturePendingBinding> textures_pending_binding_;
#endif

  // State tracking of currently bound buffers
  base::flat_map<GLenum, GLuint> bound_buffers_;
  // Lazy tracking of the bound element array buffer when changing VAOs.
  bool bound_element_array_buffer_dirty_;

  // Track the service-id to type of all queries for validation
  struct QueryInfo {
    GLenum type = GL_NONE;
  };
  base::flat_map<GLuint, QueryInfo> query_info_map_;

  // All queries that are waiting for their results to be ready
  struct PendingQuery {
    PendingQuery();
    ~PendingQuery();
    PendingQuery(const PendingQuery&) = delete;
    PendingQuery(PendingQuery&&);
    PendingQuery& operator=(const PendingQuery&) = delete;
    PendingQuery& operator=(PendingQuery&&);

    GLenum target = GL_NONE;
    GLuint service_id = 0;

    scoped_refptr<gpu::Buffer> shm;
    raw_ptr<QuerySync> sync = nullptr;
    base::subtle::Atomic32 submit_count = 0;

    std::unique_ptr<gl::GLFence> commands_completed_fence;
    base::TimeDelta commands_issued_time;
    base::TimeTicks commands_issued_timestamp;

    std::vector<base::OnceClosure> callbacks;
    std::unique_ptr<gl::GLFence> buffer_shadow_update_fence;
    BufferShadowUpdateMap buffer_shadow_updates;
    GLuint program_service_id = 0u;
  };
  base::circular_deque<PendingQuery> pending_queries_;

  // Currently active queries
  struct ActiveQuery {
    ActiveQuery();
    ~ActiveQuery();
    ActiveQuery(const ActiveQuery&) = delete;
    ActiveQuery(ActiveQuery&&);
    ActiveQuery& operator=(const ActiveQuery&) = delete;
    ActiveQuery& operator=(ActiveQuery&&);

    GLuint service_id = 0;
    scoped_refptr<gpu::Buffer> shm;
    raw_ptr<QuerySync> sync = nullptr;

    // Time at which the commands for this query started processing. This is
    // used to ensure we only include the time when the decoder is scheduled in
    // the |active_time|. Used for GL_COMMANDS_ISSUED_CHROMIUM type query.
    base::TimeTicks command_processing_start_time;
    base::TimeDelta active_time;
  };
  base::flat_map<GLenum, ActiveQuery> active_queries_;

  // Pending async ReadPixels calls
  struct PendingReadPixels {
    PendingReadPixels();

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

    PendingReadPixels(PendingReadPixels&&);
    PendingReadPixels& operator=(PendingReadPixels&&);

    ~PendingReadPixels();

    std::unique_ptr<gl::GLFence> fence;
    GLuint buffer_service_id = 0;
    uint32_t pixels_size = 0;
    uint32_t pixels_shm_id = 0;
    uint32_t pixels_shm_offset = 0;
    uint32_t result_shm_id = 0;
    uint32_t result_shm_offset = 0;

    // Service IDs of GL_ASYNC_PIXEL_PACK_COMPLETED_CHROMIUM queries waiting for
    // this read pixels operation to complete
    base::flat_set<GLuint> waiting_async_pack_queries;
  };
  base::circular_deque<PendingReadPixels> pending_read_pixels_;

  struct BufferShadowUpdate {
    BufferShadowUpdate();

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

    BufferShadowUpdate(BufferShadowUpdate&&);
    BufferShadowUpdate& operator=(BufferShadowUpdate&&);

    ~BufferShadowUpdate();

    scoped_refptr<gpu::Buffer> shm;
    GLuint shm_offset = 0;
    GLuint size = 0;
  };
  BufferShadowUpdateMap buffer_shadow_updates_;

  // Error state
  base::flat_set<GLenum> errors_;

  // Checks if an error has been generated since the last call to
  // CheckErrorCallbackState
  bool CheckErrorCallbackState();
  bool had_error_callback_ = false;

  // Default framebuffer emulation
  struct EmulatedDefaultFramebufferFormat {
    GLenum color_renderbuffer_internal_format = GL_NONE;
    GLenum color_texture_internal_format = GL_NONE;
    GLenum color_texture_format = GL_NONE;
    GLenum color_texture_type = GL_NONE;
    GLenum depth_stencil_internal_format = GL_NONE;
    GLenum depth_internal_format = GL_NONE;
    GLenum stencil_internal_format = GL_NONE;
    GLint samples = 0;
  };

  struct EmulatedColorBuffer {
    explicit EmulatedColorBuffer(const GLES2DecoderPassthroughImpl*);

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

    ~EmulatedColorBuffer();

    gl::GLApi* api() const { return impl_->api(); }

    void Resize(const gfx::Size& new_size);
    void Destroy(bool have_context);

    raw_ptr<const GLES2DecoderPassthroughImpl> impl_;

    scoped_refptr<TexturePassthrough> texture;

    gfx::Size size;
  };

  struct EmulatedDefaultFramebuffer {
    EmulatedDefaultFramebuffer(const GLES2DecoderPassthroughImpl*);

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

    ~EmulatedDefaultFramebuffer();

    gl::GLApi* api() const { return impl_->api(); }

    // Set a new color buffer, return the old one
    std::unique_ptr<EmulatedColorBuffer> SetColorBuffer(
        std::unique_ptr<EmulatedColorBuffer> new_color_buffer);

    // Blit this framebuffer into another same-sized color buffer
    void Blit(EmulatedColorBuffer* target);

    bool Resize(const gfx::Size& new_size);
    void Destroy(bool have_context);

    raw_ptr<const GLES2DecoderPassthroughImpl> impl_;

    // Service ID of the framebuffer
    GLuint framebuffer_service_id = 0;

    // Service ID of the color renderbuffer (if multisampled)
    GLuint color_buffer_service_id = 0;

    // Color buffer texture (if not multisampled)
    std::unique_ptr<EmulatedColorBuffer> color_texture;

    // Service ID of the depth stencil renderbuffer
    GLuint depth_stencil_buffer_service_id = 0;

    // Service ID of the depth renderbuffer
    GLuint depth_buffer_service_id = 0;

    // Service ID of the stencil renderbuffer (
    GLuint stencil_buffer_service_id = 0;

    gfx::Size size;
  };
  EmulatedDefaultFramebufferFormat emulated_default_framebuffer_format_;
  std::unique_ptr<EmulatedDefaultFramebuffer> emulated_back_buffer_;
  std::unique_ptr<EmulatedColorBuffer> emulated_front_buffer_;
  bool offscreen_single_buffer_;
  bool offscreen_target_buffer_preserved_;
  std::vector<std::unique_ptr<EmulatedColorBuffer>> in_use_color_textures_;
  std::vector<std::unique_ptr<EmulatedColorBuffer>> available_color_textures_;
  size_t create_color_buffer_count_for_test_ = 0;
  std::unique_ptr<GLES2ExternalFramebuffer> external_default_framebuffer_;

  // Maximum 2D resource sizes for limiting offscreen framebuffer sizes
  GLint max_renderbuffer_size_ = 0;
  GLint max_offscreen_framebuffer_size_ = 0;

  // State tracking of currently bound draw and read framebuffers (client IDs)
  GLuint bound_draw_framebuffer_;
  GLuint bound_read_framebuffer_;

  // If this context supports both read and draw framebuffer bindings
  bool supports_separate_fbo_bindings_ = false;

  // Tracks if the context has ever called glBeginPixelLocalStorageANGLE. If it
  // has, we need to start using the pixel local storage interrupt mechanism.
  bool has_activated_pixel_local_storage_ = false;

  // Tracing
  std::unique_ptr<GPUTracer> gpu_tracer_;
  const unsigned char* gpu_decoder_category_ = nullptr;
  int gpu_trace_level_;
  bool gpu_trace_commands_;
  bool gpu_debug_commands_;

  // Context lost state
  bool context_lost_;
  bool reset_by_robustness_extension_;
  bool lose_context_when_out_of_memory_;

  // After a second fence is inserted, both the GpuChannelMessageQueue and
  // CommandExecutor are descheduled. Once the first fence has completed, both
  // get rescheduled.
  base::circular_deque<std::unique_ptr<gl::GLFence>>
      deschedule_until_finished_fences_;

  GLuint linking_program_service_id_ = 0u;

  base::WeakPtrFactory<GLES2DecoderPassthroughImpl> weak_ptr_factory_{this};

  class ScopedEnableTextureRectangleInShaderCompiler;

// Include the prototypes of all the doer functions from a separate header to
// keep this file clean.
#include "base/time/time.h"
#include "gpu/command_buffer/service/gles2_cmd_decoder_passthrough_doer_prototypes.h"
};

}  // namespace gles2
}  // namespace gpu

#endif  // GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_DECODER_PASSTHROUGH_H_