text: /*
   * Copyright 2015 Google Inc.
   *
   * Use of this source code is governed by a BSD-style license that can be
   * found in the LICENSE file.
   */
  
  #ifndef GrOpFlushState_DEFINED
  #define GrOpFlushState_DEFINED
  
  #include <utility>
  #include "GrAppliedClip.h"
  #include "GrBufferAllocPool.h"
  #include "GrDeferredUpload.h"
  #include "GrDeinstantiateProxyTracker.h"
  #include "GrRenderTargetProxy.h"
  #include "SkArenaAlloc.h"
  #include "SkArenaAllocList.h"
  #include "ops/GrMeshDrawOp.h"
  
  class GrGpu;
  class GrGpuCommandBuffer;
  class GrGpuRTCommandBuffer;
  class GrResourceProvider;
  
  /** Tracks the state across all the GrOps (really just the GrDrawOps) in a GrOpList flush. */
  class GrOpFlushState final : public GrDeferredUploadTarget, public GrMeshDrawOp::Target {
  public:
      // vertexSpace and indexSpace may either be null or an alloation of size
      // GrBufferAllocPool::kDefaultBufferSize. If the latter, then CPU memory is only allocated for
      // vertices/indices when a buffer larger than kDefaultBufferSize is required.
      GrOpFlushState(GrGpu*, GrResourceProvider*, GrResourceCache*, GrTokenTracker*,
                     sk_sp<GrBufferAllocPool::CpuBufferCache> = nullptr);
  
      ~GrOpFlushState() final { this->reset(); }
  
      /** This is called after each op has a chance to prepare its draws and before the draws are
          executed. */
      void preExecuteDraws();
  
      void doUpload(GrDeferredTextureUploadFn&);
  
      /** Called as ops are executed. Must be called in the same order as the ops were prepared. */
      void executeDrawsAndUploadsForMeshDrawOp(
              const GrOp* op, const SkRect& chainBounds, GrProcessorSet&&,
              GrPipeline::InputFlags = GrPipeline::InputFlags::kNone,
              const GrUserStencilSettings* = &GrUserStencilSettings::kUnused);
  
      GrGpuCommandBuffer* commandBuffer() { return fCommandBuffer; }
      // Helper function used by Ops that are only called via RenderTargetOpLists
      GrGpuRTCommandBuffer* rtCommandBuffer();
      void setCommandBuffer(GrGpuCommandBuffer* buffer) { fCommandBuffer = buffer; }
  
      GrGpu* gpu() { return fGpu; }
  
      void reset();
  
      /** Additional data required on a per-op basis when executing GrOps. */
      struct OpArgs {
          GrSurfaceOrigin origin() const { return fProxy->origin(); }
          GrRenderTarget* renderTarget() const { return fProxy->peekRenderTarget(); }
  
          GrOp* fOp;
          // TODO: do we still need the dst proxy here?
          GrRenderTargetProxy* fProxy;
          GrAppliedClip* fAppliedClip;
          GrXferProcessor::DstProxy fDstProxy;
      };
  
      void setOpArgs(OpArgs* opArgs) { fOpArgs = opArgs; }
  
      const OpArgs& drawOpArgs() const {
          SkASSERT(fOpArgs);
          SkASSERT(fOpArgs->fOp);
          return *fOpArgs;
      }
  
      /** Overrides of GrDeferredUploadTarget. */
  
      const GrTokenTracker* tokenTracker() final { return fTokenTracker; }
      GrDeferredUploadToken addInlineUpload(GrDeferredTextureUploadFn&&) final;
      GrDeferredUploadToken addASAPUpload(GrDeferredTextureUploadFn&&) final;
  
      /** Overrides of GrMeshDrawOp::Target. */
      void recordDraw(
              sk_sp<const GrGeometryProcessor>, const GrMesh[], int meshCnt,
              const GrPipeline::FixedDynamicState*, const GrPipeline::DynamicStateArrays*) final;
      void* makeVertexSpace(size_t vertexSize, int vertexCount, sk_sp<const GrBuffer>*,
                            int* startVertex) final;
      uint16_t* makeIndexSpace(int indexCount, sk_sp<const GrBuffer>*, int* startIndex) final;
      void* makeVertexSpaceAtLeast(size_t vertexSize, int minVertexCount, int fallbackVertexCount,
                                   sk_sp<const GrBuffer>*, int* startVertex,
                                   int* actualVertexCount) final;
      uint16_t* makeIndexSpaceAtLeast(int minIndexCount, int fallbackIndexCount,
                                      sk_sp<const GrBuffer>*, int* startIndex,
                                      int* actualIndexCount) final;
      void putBackIndices(int indexCount) final;
      void putBackVertices(int vertices, size_t vertexStride) final;
      GrRenderTargetProxy* proxy() const final { return fOpArgs->fProxy; }
      const GrAppliedClip* appliedClip() final { return fOpArgs->fAppliedClip; }
      GrAppliedClip detachAppliedClip() final;
      const GrXferProcessor::DstProxy& dstProxy() const final { return fOpArgs->fDstProxy; }
      GrDeferredUploadTarget* deferredUploadTarget() final { return this; }
      const GrCaps& caps() const final;
      GrResourceProvider* resourceProvider() const final { return fResourceProvider; }
  
      GrStrikeCache* glyphCache() const final;
  
      // At this point we know we're flushing so full access to the GrAtlasManager is required (and
      // permissible).
      GrAtlasManager* atlasManager() const final;
  
      GrDeinstantiateProxyTracker* deinstantiateProxyTracker() { return &fDeinstantiateProxyTracker; }
  
  private:
      /** GrMeshDrawOp::Target override. */
      SkArenaAlloc* allocator() override { return &fArena; }
  
      struct InlineUpload {
          InlineUpload(GrDeferredTextureUploadFn&& upload, GrDeferredUploadToken token)
                  : fUpload(std::move(upload)), fUploadBeforeToken(token) {}
          GrDeferredTextureUploadFn fUpload;
          GrDeferredUploadToken fUploadBeforeToken;
      };
  
      // A set of contiguous draws that share a draw token, geometry processor, and pipeline. The
      // meshes for the draw are stored in the fMeshes array. The reason for coalescing meshes
      // that share a geometry processor into a Draw is that it allows the Gpu object to setup
      // the shared state once and then issue draws for each mesh.
      struct Draw {
          ~Draw();
          sk_sp<const GrGeometryProcessor> fGeometryProcessor;
          const GrPipeline::FixedDynamicState* fFixedDynamicState;
          const GrPipeline::DynamicStateArrays* fDynamicStateArrays;
          const GrMesh* fMeshes = nullptr;
          const GrOp* fOp = nullptr;
          int fMeshCnt = 0;
      };
  
      // Storage for ops' pipelines, draws, and inline uploads.
      SkArenaAlloc fArena{sizeof(GrPipeline) * 100};
  
      // Store vertex and index data on behalf of ops that are flushed.
      GrVertexBufferAllocPool fVertexPool;
      GrIndexBufferAllocPool fIndexPool;
  
      // Data stored on behalf of the ops being flushed.
      SkArenaAllocList<GrDeferredTextureUploadFn> fASAPUploads;
      SkArenaAllocList<InlineUpload> fInlineUploads;
      SkArenaAllocList<Draw> fDraws;
  
      // All draws we store have an implicit draw token. This is the draw token for the first draw
      // in fDraws.
      GrDeferredUploadToken fBaseDrawToken = GrDeferredUploadToken::AlreadyFlushedToken();
  
      // Info about the op that is currently preparing or executing using the flush state or null if
      // an op is not currently preparing of executing.
      OpArgs* fOpArgs = nullptr;
  
      GrGpu* fGpu;
      GrResourceProvider* fResourceProvider;
      GrTokenTracker* fTokenTracker;
      GrGpuCommandBuffer* fCommandBuffer = nullptr;
  
      // Variables that are used to track where we are in lists as ops are executed
      SkArenaAllocList<Draw>::Iter fCurrDraw;
      SkArenaAllocList<InlineUpload>::Iter fCurrUpload;
  
      // Used to track the proxies that need to be deinstantiated after we finish a flush
      GrDeinstantiateProxyTracker fDeinstantiateProxyTracker;
  };
  
  #endif
  