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;
};