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 GrDrawingManager_DEFINED
  #define GrDrawingManager_DEFINED
  
  #include "GrDeferredUpload.h"
  #include "GrPathRenderer.h"
  #include "GrPathRendererChain.h"
  #include "GrResourceCache.h"
  #include "SkTArray.h"
  #include "text/GrTextContext.h"
  
  class GrContext;
  class GrCoverageCountingPathRenderer;
  class GrOnFlushCallbackObject;
  class GrOpFlushState;
  class GrRenderTargetContext;
  class GrRenderTargetProxy;
  class GrSingleOWner;
  class GrRenderTargetOpList;
  class GrSoftwarePathRenderer;
  class GrTextureContext;
  class GrTextureOpList;
  class SkDeferredDisplayList;
  
  // The GrDrawingManager allocates a new GrRenderTargetContext for each GrRenderTarget
  // but all of them still land in the same GrOpList!
  //
  // In the future this class will allocate a new GrRenderTargetContext for
  // each GrRenderTarget/GrOpList and manage the DAG.
  class GrDrawingManager {
  public:
      ~GrDrawingManager();
  
      bool wasAbandoned() const { return fAbandoned; }
      void freeGpuResources();
  
      sk_sp<GrRenderTargetContext> makeRenderTargetContext(sk_sp<GrSurfaceProxy>,
                                                           sk_sp<SkColorSpace>,
                                                           const SkSurfaceProps*,
                                                           bool managedOpList = true);
      sk_sp<GrTextureContext> makeTextureContext(sk_sp<GrSurfaceProxy>, sk_sp<SkColorSpace>);
  
      // The caller automatically gets a ref on the returned opList. It must
      // be balanced by an unref call.
      // A managed opList is controlled by the drawing manager (i.e., sorted & flushed with the
      // other). An unmanaged one is created and used by the onFlushCallback.
      sk_sp<GrRenderTargetOpList> newRTOpList(GrRenderTargetProxy* rtp, bool managedOpList);
      sk_sp<GrTextureOpList> newTextureOpList(GrTextureProxy* textureProxy);
  
      GrContext* getContext() { return fContext; }
  
      GrTextContext* getTextContext();
  
      GrPathRenderer* getPathRenderer(const GrPathRenderer::CanDrawPathArgs& args,
                                      bool allowSW,
                                      GrPathRendererChain::DrawType drawType,
                                      GrPathRenderer::StencilSupport* stencilSupport = nullptr);
  
      GrPathRenderer* getSoftwarePathRenderer();
  
      // Returns a direct pointer to the coverage counting path renderer, or null if it is not
      // supported and turned on.
      GrCoverageCountingPathRenderer* getCoverageCountingPathRenderer();
  
      void flushIfNecessary();
  
      static bool ProgramUnitTest(GrContext* context, int maxStages, int maxLevels);
  
      GrSemaphoresSubmitted prepareSurfaceForExternalIO(GrSurfaceProxy*,
                                                        int numSemaphores,
                                                        GrBackendSemaphore backendSemaphores[]);
  
      void addOnFlushCallbackObject(GrOnFlushCallbackObject*);
      void testingOnly_removeOnFlushCallbackObject(GrOnFlushCallbackObject*);
  
      void moveOpListsToDDL(SkDeferredDisplayList* ddl);
      void copyOpListsFromDDL(const SkDeferredDisplayList*, GrRenderTargetProxy* newDest);
  
  private:
      // This class encapsulates maintenance and manipulation of the drawing manager's DAG of opLists.
      class OpListDAG {
      public:
          OpListDAG(bool explicitlyAllocating, GrContextOptions::Enable sortOpLists);
          ~OpListDAG();
  
          // Currently, when explicitly allocating resources, this call will topologically sort the
          // opLists.
          // MDB TODO: remove once incremental opList sorting is enabled
          void prepForFlush();
  
          void closeAll(const GrCaps* caps);
  
          // A yucky combination of closeAll and reset
          void cleanup(const GrCaps* caps);
  
          void gatherIDs(SkSTArray<8, uint32_t, true>* idArray) const;
  
          void reset();
  
          // These calls forceably remove an opList from the DAG. They are problematic bc they just
          // remove the opList but don't cleanup any refering pointers (i.e., dependency pointers
          // in the DAG). They work right now bc they are only called at flush time, after the
          // topological sort is complete (so the dangling pointers aren't used).
          void removeOpList(int index);
          void removeOpLists(int startIndex, int stopIndex);
  
          bool empty() const { return fOpLists.empty(); }
          int numOpLists() const { return fOpLists.count(); }
  
          GrOpList* opList(int index) { return fOpLists[index].get(); }
          const GrOpList* opList(int index) const { return fOpLists[index].get(); }
  
          GrOpList* back() { return fOpLists.back().get(); }
          const GrOpList* back() const { return fOpLists.back().get(); }
  
          void add(sk_sp<GrOpList>);
          void add(const SkTArray<sk_sp<GrOpList>>&);
  
          void swap(SkTArray<sk_sp<GrOpList>>* opLists);
  
          bool sortingOpLists() const { return fSortOpLists; }
  
      private:
          SkTArray<sk_sp<GrOpList>> fOpLists;
          bool                      fSortOpLists;
      };
  
      GrDrawingManager(GrContext*, const GrPathRendererChain::Options&,
                       const GrTextContext::Options&, GrSingleOwner*,
                       bool explicitlyAllocating, GrContextOptions::Enable sortRenderTargets,
                       GrContextOptions::Enable reduceOpListSplitting);
  
      void abandon();
      void cleanup();
  
      // return true if any opLists were actually executed; false otherwise
      bool executeOpLists(int startIndex, int stopIndex, GrOpFlushState*, int* numOpListsExecuted);
  
      GrSemaphoresSubmitted flush(GrSurfaceProxy* proxy,
                                  int numSemaphores = 0,
                                  GrBackendSemaphore backendSemaphores[] = nullptr);
  
      SkDEBUGCODE(void validate() const);
  
      friend class GrContext;  // for access to: ctor, abandon, reset & flush
      friend class GrContextPriv; // access to: flush
      friend class GrOnFlushResourceProvider; // this is just a shallow wrapper around this class
  
      static const int kNumPixelGeometries = 5; // The different pixel geometries
      static const int kNumDFTOptions = 2;      // DFT or no DFT
  
      GrContext*                        fContext;
      GrPathRendererChain::Options      fOptionsForPathRendererChain;
      GrTextContext::Options            fOptionsForTextContext;
  
      std::unique_ptr<char[]>           fVertexBufferSpace;
      std::unique_ptr<char[]>           fIndexBufferSpace;
      // In debug builds we guard against improper thread handling
      GrSingleOwner*                    fSingleOwner;
  
      bool                              fAbandoned;
      OpListDAG                         fDAG;
      GrOpList*                         fActiveOpList = nullptr;
      // These are the IDs of the opLists currently being flushed (in internalFlush)
      SkSTArray<8, uint32_t, true>      fFlushingOpListIDs;
      // These are the new opLists generated by the onFlush CBs
      SkSTArray<8, sk_sp<GrOpList>>     fOnFlushCBOpLists;
  
      std::unique_ptr<GrTextContext>    fTextContext;
  
      std::unique_ptr<GrPathRendererChain> fPathRendererChain;
      sk_sp<GrSoftwarePathRenderer>     fSoftwarePathRenderer;
  
      GrTokenTracker                    fTokenTracker;
      bool                              fFlushing;
      bool                              fReduceOpListSplitting;
  
      SkTArray<GrOnFlushCallbackObject*> fOnFlushCBObjects;
  };
  
  #endif
  