Add the machinery to GrDrawTarget to enable topological sorting

This relies on https://codereview.chromium.org/1414503003/ (Add SkTTopoSort) landing first.

BUG=skia:4094

Review URL: https://codereview.chromium.org/1414773002
diff --git a/src/gpu/GrContext.cpp b/src/gpu/GrContext.cpp
index e5bbb8f..f05d8e6 100644
--- a/src/gpu/GrContext.cpp
+++ b/src/gpu/GrContext.cpp
@@ -45,7 +45,7 @@
 #include "SkTLazy.h"
 #include "SkTLS.h"
 #include "SkTraceEvent.h"
-
+#include "SkTTopoSort.h"
 
 #include "batches/GrBatch.h"
 
@@ -95,9 +95,21 @@
 }
 
 void GrDrawingManager::flush() {
+    SkDEBUGCODE(bool result =) 
+                        SkTTopoSort<GrDrawTarget, GrDrawTarget::TopoSortTraits>(&fDrawTargets);
+    SkASSERT(result);
+
     for (int i = 0; i < fDrawTargets.count(); ++i) {
         fDrawTargets[i]->flush();
     }
+
+#ifndef ENABLE_MDB
+    // When MDB is disabled we keep reusing the same drawTarget
+    if (fDrawTargets.count()) {
+        SkASSERT(fDrawTargets.count() == 1);
+        fDrawTargets[0]->resetFlag(GrDrawTarget::kWasOutput_Flag);
+    }
+#endif
 }
 
 GrTextContext* GrDrawingManager::textContext(const SkSurfaceProps& props,
@@ -131,8 +143,8 @@
 GrDrawTarget* GrDrawingManager::newDrawTarget(GrRenderTarget* rt) {
     SkASSERT(fContext);
 
-    // When MDB is disabled we always just return the single drawTarget
 #ifndef ENABLE_MDB
+    // When MDB is disabled we always just return the single drawTarget
     if (fDrawTargets.count()) {
         SkASSERT(fDrawTargets.count() == 1);
         // DrawingManager gets the creation ref - this ref is for the caller
diff --git a/src/gpu/GrDrawTarget.cpp b/src/gpu/GrDrawTarget.cpp
index 323599d..7f84f8e 100644
--- a/src/gpu/GrDrawTarget.cpp
+++ b/src/gpu/GrDrawTarget.cpp
@@ -38,7 +38,7 @@
     , fFlushState(fGpu, fResourceProvider, 0)
     , fFlushing(false)
     , fFirstUnpreparedBatch(0)
-    , fClosed(false) {
+    , fFlags(0) {
     // TODO: Stop extracting the context (currently needed by GrClipMaskManager)
     fContext = fGpu->getContext();
     fClipMaskManager.reset(new GrClipMaskManager(this));
@@ -50,6 +50,35 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 
+// Add a GrDrawTarget-based dependency
+void GrDrawTarget::addDependency(GrDrawTarget* dependedOn) {
+    SkASSERT(!dependedOn->dependsOn(this));  // loops are bad
+
+    if (this->dependsOn(dependedOn)) {
+        return;  // don't add duplicate dependencies
+    }
+
+    *fDependencies.push() = dependedOn;
+}
+
+// Convert from a GrSurface-based dependency to a GrDrawTarget one
+void GrDrawTarget::addDependency(GrSurface* dependedOn) {
+    if (dependedOn->asRenderTarget() && dependedOn->asRenderTarget()->getLastDrawTarget()) {
+        // If it is still receiving dependencies, this DT shouldn't be closed
+        SkASSERT(!this->isClosed());
+
+        GrDrawTarget* dt = dependedOn->asRenderTarget()->getLastDrawTarget();
+        if (dt == this) {
+            // self-read - presumably for dst reads
+        } else {
+            this->addDependency(dt);
+
+            // Can't make it closed in the self-read case
+            dt->makeClosed();
+        }
+    }
+}
+
 bool GrDrawTarget::setupDstReadIfNecessary(const GrPipelineBuilder& pipelineBuilder,
                                            const GrProcOptInfo& colorPOI,
                                            const GrProcOptInfo& coveragePOI,
@@ -414,7 +443,7 @@
 
 void GrDrawTarget::recordBatch(GrBatch* batch) {
     // A closed drawTarget should never receive new/more batches
-    SkASSERT(!fClosed);
+    SkASSERT(!this->isClosed());
 
     // Check if there is a Batch Draw we can batch with by linearly searching back until we either
     // 1) check every draw
diff --git a/src/gpu/GrDrawTarget.h b/src/gpu/GrDrawTarget.h
index db637d5..925c03e 100644
--- a/src/gpu/GrDrawTarget.h
+++ b/src/gpu/GrDrawTarget.h
@@ -53,10 +53,22 @@
         // We only close drawTargets When MDB is enabled. When MDB is disabled there is only
         // ever one drawTarget and all calls will be funnelled into it.
 #ifdef ENABLE_MDB
-        fClosed = true;
+        this->setFlag(kClosed_Flag);
 #endif
     }
-    bool isClosed() const { return fClosed; }
+    bool isClosed() const { return this->isSetFlag(kClosed_Flag); }
+
+    /*
+     * Notify this drawTarget that it relies on the contents of 'dependedOn'
+     */
+    void addDependency(GrSurface* dependedOn);
+
+    /*
+     * Does this drawTarget depend on 'dependedOn'?
+     */
+    bool dependsOn(GrDrawTarget* dependedOn) const {
+        return fDependencies.find(dependedOn) >= 0;
+    }
 
     /**
      * Empties the draw buffer of any queued up draws.
@@ -204,7 +216,53 @@
 
     const CMMAccess cmmAccess() { return CMMAccess(this); }
 
+
 private:
+    friend class GrDrawingManager; // for resetFlag & TopoSortTraits
+
+    enum Flags {
+        kClosed_Flag    = 0x01,   //!< This drawTarget can't accept any more batches
+
+        kWasOutput_Flag = 0x02,   //!< Flag for topological sorting
+        kTempMark_Flag  = 0x04,   //!< Flag for topological sorting
+    };
+
+    void setFlag(uint32_t flag) {
+        fFlags |= flag;
+    }
+
+    void resetFlag(uint32_t flag) {
+        fFlags &= ~flag;
+    }
+
+    bool isSetFlag(uint32_t flag) const {
+        return SkToBool(fFlags & flag);
+    }
+
+    struct TopoSortTraits {
+        static void Output(GrDrawTarget* dt, int /* index */) {
+            dt->setFlag(GrDrawTarget::kWasOutput_Flag);
+        }
+        static bool WasOutput(const GrDrawTarget* dt) {
+            return dt->isSetFlag(GrDrawTarget::kWasOutput_Flag);
+        }
+        static void SetTempMark(GrDrawTarget* dt) {
+            dt->setFlag(GrDrawTarget::kTempMark_Flag);
+        }
+        static void ResetTempMark(GrDrawTarget* dt) {
+            dt->resetFlag(GrDrawTarget::kTempMark_Flag);
+        }
+        static bool IsTempMarked(const GrDrawTarget* dt) {
+            return dt->isSetFlag(GrDrawTarget::kTempMark_Flag);
+        }
+        static int NumDependencies(const GrDrawTarget* dt) {
+            return dt->fDependencies.count();
+        }
+        static GrDrawTarget* Dependency(GrDrawTarget* dt, int index) {
+            return dt->fDependencies[index];
+        }
+    };
+
     void recordBatch(GrBatch*);
     bool installPipelineInDrawBatch(const GrPipelineBuilder* pipelineBuilder,
                                     const GrScissorState* scissor,
@@ -231,6 +289,8 @@
                            GrScissorState*,
                            const SkRect* devBounds);
 
+    void addDependency(GrDrawTarget* dependedOn);
+
     // Used only by CMM.
     void clearStencilClip(const SkIRect&, bool insideClip, GrRenderTarget*);
 
@@ -244,7 +304,10 @@
     bool                                        fFlushing;
     int                                         fFirstUnpreparedBatch;
 
-    bool                                        fClosed;
+    uint32_t                                    fFlags;
+
+    // 'this' drawTarget relies on the output of the drawTargets in 'fDependencies'
+    SkTDArray<GrDrawTarget*>                    fDependencies;
 
     typedef SkRefCnt INHERITED;
 };