Loosen requirement that there be only one GrDrawTarget
BUG=skia:4094
Review URL: https://codereview.chromium.org/1406173003
diff --git a/include/gpu/GrContext.h b/include/gpu/GrContext.h
index 91ae2d1..904a041 100644
--- a/include/gpu/GrContext.h
+++ b/include/gpu/GrContext.h
@@ -188,6 +188,12 @@
return fDrawingMgr.textContext(surfaceProps, rt);
}
+ // The caller automatically gets a ref on the returned drawTarget. It must
+ // be balanced by an unref call.
+ GrDrawTarget* newDrawTarget(GrRenderTarget* rt) {
+ return fDrawingMgr.newDrawTarget(rt);
+ }
+
///////////////////////////////////////////////////////////////////////////
// Misc.
@@ -426,7 +432,10 @@
// each GrRenderTarget/GrDrawTarget and manage the DAG.
class DrawingMgr {
public:
- DrawingMgr() : fDrawTarget(nullptr), fNVPRTextContext(nullptr) {
+ DrawingMgr()
+ : fContext(nullptr)
+ , fAbandoned(false)
+ , fNVPRTextContext(nullptr) {
sk_bzero(fTextContexts, sizeof(fTextContexts));
}
@@ -435,7 +444,7 @@
void init(GrContext* context);
void abandon();
- bool abandoned() const { return NULL == fDrawTarget; }
+ bool abandoned() const { return fAbandoned; }
void reset();
void flush();
@@ -445,6 +454,8 @@
GrDrawContext* drawContext(GrRenderTarget* rt, const SkSurfaceProps* surfaceProps);
GrTextContext* textContext(const SkSurfaceProps& props, GrRenderTarget* rt);
+
+ GrDrawTarget* newDrawTarget(GrRenderTarget* rt);
private:
void cleanup();
@@ -455,7 +466,9 @@
static const int kNumDFTOptions = 2; // DFT or no DFT
GrContext* fContext;
- GrDrawTarget* fDrawTarget;
+
+ bool fAbandoned;
+ SkTDArray<GrDrawTarget*> fDrawTargets;
GrTextContext* fNVPRTextContext;
GrTextContext* fTextContexts[kNumPixelGeometries][kNumDFTOptions];
diff --git a/include/gpu/GrDrawContext.h b/include/gpu/GrDrawContext.h
index 5e1dc07..86a0efe 100644
--- a/include/gpu/GrDrawContext.h
+++ b/include/gpu/GrDrawContext.h
@@ -256,7 +256,7 @@
SkDEBUGCODE(void validate() const;)
- GrDrawContext(GrContext*, GrRenderTarget*, GrDrawTarget*, const SkSurfaceProps* surfaceProps);
+ GrDrawContext(GrContext*, GrRenderTarget*, const SkSurfaceProps* surfaceProps);
void internalDrawPath(GrDrawTarget*,
GrPipelineBuilder*,
@@ -270,8 +270,13 @@
// the drawTarget.
void drawBatch(GrPipelineBuilder* pipelineBuilder, GrDrawBatch* batch);
+ GrDrawTarget* getDrawTarget();
+
GrContext* fContext; // owning context -> no ref
GrRenderTarget* fRenderTarget;
+
+ // In MDB-mode the drawTarget can be closed by some other drawContext that has picked
+ // it up. For this reason, the drawTarget should only ever be accessed via 'getDrawTarget'.
GrDrawTarget* fDrawTarget;
GrTextContext* fTextContext; // lazily gotten from GrContext::DrawingMgr
diff --git a/include/gpu/GrRenderTarget.h b/include/gpu/GrRenderTarget.h
index 2309dbd..b5fc6f0 100644
--- a/include/gpu/GrRenderTarget.h
+++ b/include/gpu/GrRenderTarget.h
@@ -11,6 +11,7 @@
#include "GrSurface.h"
#include "SkRect.h"
+class GrDrawTarget;
class GrStencilAttachment;
class GrRenderTargetPriv;
@@ -151,12 +152,16 @@
GrRenderTargetPriv renderTargetPriv();
const GrRenderTargetPriv renderTargetPriv() const;
+ void setLastDrawTarget(GrDrawTarget* dt);
+ GrDrawTarget* getLastDrawTarget() { return fLastDrawTarget; }
+
protected:
GrRenderTarget(GrGpu* gpu, LifeCycle lifeCycle, const GrSurfaceDesc& desc,
SampleConfig sampleConfig, GrStencilAttachment* stencil = nullptr)
: INHERITED(gpu, lifeCycle, desc)
, fStencilAttachment(stencil)
- , fSampleConfig(sampleConfig) {
+ , fSampleConfig(sampleConfig)
+ , fLastDrawTarget(nullptr) {
fResolveRect.setLargestInverted();
}
@@ -178,6 +183,14 @@
SkIRect fResolveRect;
+ // The last drawTarget that wrote to or is currently going to write to this renderTarget
+ // The drawTarget can be closed (e.g., no draw context is currently bound
+ // to this renderTarget).
+ // This back-pointer is required so that we can add a dependancy between
+ // the drawTarget used to create the current contents of this renderTarget
+ // and the drawTarget of a destination renderTarget to which this one is being drawn.
+ GrDrawTarget* fLastDrawTarget;
+
typedef GrSurface INHERITED;
};
diff --git a/src/gpu/GrContext.cpp b/src/gpu/GrContext.cpp
index 82550d0..a691da7 100644
--- a/src/gpu/GrContext.cpp
+++ b/src/gpu/GrContext.cpp
@@ -62,13 +62,18 @@
void GrContext::DrawingMgr::init(GrContext* context) {
fContext = context;
- fDrawTarget = new GrDrawTarget(context->getGpu(), context->resourceProvider());
}
void GrContext::DrawingMgr::cleanup() {
- SkSafeSetNull(fDrawTarget);
+ for (int i = 0; i < fDrawTargets.count(); ++i) {
+ fDrawTargets[i]->unref();
+ }
+
+ fDrawTargets.reset();
+
delete fNVPRTextContext;
fNVPRTextContext = nullptr;
+
for (int i = 0; i < kNumPixelGeometries; ++i) {
delete fTextContexts[i][0];
fTextContexts[i][0] = nullptr;
@@ -82,18 +87,19 @@
}
void GrContext::DrawingMgr::abandon() {
+ fAbandoned = true;
this->cleanup();
}
void GrContext::DrawingMgr::reset() {
- if (fDrawTarget) {
- fDrawTarget->reset();
+ for (int i = 0; i < fDrawTargets.count(); ++i) {
+ fDrawTargets[i]->reset();
}
}
void GrContext::DrawingMgr::flush() {
- if (fDrawTarget) {
- fDrawTarget->flush();
+ for (int i = 0; i < fDrawTargets.count(); ++i) {
+ fDrawTargets[i]->flush();
}
}
@@ -125,13 +131,33 @@
return fTextContexts[props.pixelGeometry()][useDIF];
}
+GrDrawTarget* GrContext::DrawingMgr::newDrawTarget(GrRenderTarget* rt) {
+ SkASSERT(fContext);
+
+ // When MDB is disabled we always just return the single drawTarget
+#ifndef ENABLE_MDB
+ if (fDrawTargets.count()) {
+ SkASSERT(fDrawTargets.count() == 1);
+ // DrawingMgr gets the creation ref - this ref is for the caller
+ return SkRef(fDrawTargets[0]);
+ }
+#endif
+
+ GrDrawTarget* dt = new GrDrawTarget(fContext->getGpu(), fContext->resourceProvider());
+
+ *fDrawTargets.append() = dt;
+
+ // DrawingMgr gets the creation ref - this ref is for the caller
+ return SkRef(dt);
+}
+
GrDrawContext* GrContext::DrawingMgr::drawContext(GrRenderTarget* rt,
const SkSurfaceProps* surfaceProps) {
if (this->abandoned()) {
return nullptr;
}
- return new GrDrawContext(fContext, rt, fDrawTarget, surfaceProps);
+ return new GrDrawContext(fContext, rt, surfaceProps);
}
////////////////////////////////////////////////////////////////////////////////
diff --git a/src/gpu/GrDrawContext.cpp b/src/gpu/GrDrawContext.cpp
index dcf148f..1aec92e 100644
--- a/src/gpu/GrDrawContext.cpp
+++ b/src/gpu/GrDrawContext.cpp
@@ -37,34 +37,52 @@
GrContext* fContext;
};
+// In MDB mode the reffing of the 'getLastDrawTarget' call's result allows in-progress
+// drawTargets to be picked up and added to by drawContexts lower in the call
+// stack. When this occurs with a closed drawTarget, a new one will be allocated
+// when the drawContext attempts to use it (via getDrawTarget).
GrDrawContext::GrDrawContext(GrContext* context,
GrRenderTarget* rt,
- GrDrawTarget* drawTarget,
const SkSurfaceProps* surfaceProps)
: fContext(context)
, fRenderTarget(rt)
- , fDrawTarget(SkRef(drawTarget))
+ , fDrawTarget(SkSafeRef(rt->getLastDrawTarget()))
, fTextContext(nullptr)
, fSurfaceProps(SkSurfacePropsCopyOrDefault(surfaceProps)) {
SkDEBUGCODE(this->validate();)
}
-GrDrawContext::~GrDrawContext() {
- SkSafeUnref(fDrawTarget);
-}
-
#ifdef SK_DEBUG
void GrDrawContext::validate() const {
SkASSERT(fRenderTarget);
ASSERT_OWNED_RESOURCE(fRenderTarget);
+
+ if (fDrawTarget && !fDrawTarget->isClosed()) {
+ SkASSERT(fRenderTarget->getLastDrawTarget() == fDrawTarget);
+ }
}
#endif
+GrDrawContext::~GrDrawContext() {
+ SkSafeUnref(fDrawTarget);
+}
+
+GrDrawTarget* GrDrawContext::getDrawTarget() {
+ SkDEBUGCODE(this->validate();)
+
+ if (!fDrawTarget || fDrawTarget->isClosed()) {
+ fDrawTarget = fContext->newDrawTarget(fRenderTarget);
+ fRenderTarget->setLastDrawTarget(fDrawTarget);
+ }
+
+ return fDrawTarget;
+}
+
void GrDrawContext::copySurface(GrSurface* src, const SkIRect& srcRect, const SkIPoint& dstPoint) {
RETURN_IF_ABANDONED
SkDEBUGCODE(this->validate();)
- fDrawTarget->copySurface(fRenderTarget, src, srcRect, dstPoint);
+ this->getDrawTarget()->copySurface(fRenderTarget, src, srcRect, dstPoint);
}
@@ -126,8 +144,8 @@
RETURN_IF_ABANDONED
SkDEBUGCODE(this->validate();)
- fDrawTarget->drawPathsFromRange(*pipelineBuilder, viewMatrix, localMatrix, color, range, draw,
- (GrPathRendering::FillType) fill);
+ this->getDrawTarget()->drawPathsFromRange(*pipelineBuilder, viewMatrix, localMatrix, color,
+ range, draw, (GrPathRendering::FillType) fill);
}
void GrDrawContext::discard() {
@@ -135,7 +153,7 @@
SkDEBUGCODE(this->validate();)
AutoCheckFlush acf(fContext);
- fDrawTarget->discard(fRenderTarget);
+ this->getDrawTarget()->discard(fRenderTarget);
}
void GrDrawContext::clear(const SkIRect* rect,
@@ -145,7 +163,7 @@
SkDEBUGCODE(this->validate();)
AutoCheckFlush acf(fContext);
- fDrawTarget->clear(rect, color, canIgnoreRect, fRenderTarget);
+ this->getDrawTarget()->clear(rect, color, canIgnoreRect, fRenderTarget);
}
@@ -191,11 +209,11 @@
AutoCheckFlush acf(fContext);
GrPipelineBuilder pipelineBuilder(*paint, fRenderTarget, clip);
- fDrawTarget->drawNonAARect(pipelineBuilder,
- paint->getColor(),
- SkMatrix::I(),
- r,
- localMatrix);
+ this->getDrawTarget()->drawNonAARect(pipelineBuilder,
+ paint->getColor(),
+ SkMatrix::I(),
+ r,
+ localMatrix);
}
}
@@ -253,7 +271,7 @@
// Will it blend?
GrColor clearColor;
if (paint.isConstantBlendedColor(&clearColor)) {
- fDrawTarget->clear(nullptr, clearColor, true, fRenderTarget);
+ this->getDrawTarget()->clear(nullptr, clearColor, true, fRenderTarget);
return;
}
}
@@ -279,7 +297,7 @@
viewMatrix.mapRect(&devBoundRect, rect);
batch.reset(GrRectBatchFactory::CreateAAFill(color, viewMatrix, rect, devBoundRect));
}
- fDrawTarget->drawBatch(pipelineBuilder, batch);
+ this->getDrawTarget()->drawBatch(pipelineBuilder, batch);
return;
}
@@ -294,10 +312,10 @@
// is enabled because it can cause ugly artifacts.
pipelineBuilder.setState(GrPipelineBuilder::kSnapVerticesToPixelCenters_Flag,
snapToPixelCenters);
- fDrawTarget->drawBatch(pipelineBuilder, batch);
+ this->getDrawTarget()->drawBatch(pipelineBuilder, batch);
} else {
// filled BW rect
- fDrawTarget->drawNonAARect(pipelineBuilder, color, viewMatrix, rect);
+ this->getDrawTarget()->drawNonAARect(pipelineBuilder, color, viewMatrix, rect);
}
}
@@ -312,11 +330,11 @@
AutoCheckFlush acf(fContext);
GrPipelineBuilder pipelineBuilder(paint, fRenderTarget, clip);
- fDrawTarget->drawNonAARect(pipelineBuilder,
- paint.getColor(),
- viewMatrix,
- rectToDraw,
- localRect);
+ this->getDrawTarget()->drawNonAARect(pipelineBuilder,
+ paint.getColor(),
+ viewMatrix,
+ rectToDraw,
+ localRect);
}
void GrDrawContext::drawNonAARectWithLocalMatrix(const GrClip& clip,
@@ -330,11 +348,11 @@
AutoCheckFlush acf(fContext);
GrPipelineBuilder pipelineBuilder(paint, fRenderTarget, clip);
- fDrawTarget->drawNonAARect(pipelineBuilder,
- paint.getColor(),
- viewMatrix,
- rectToDraw,
- localMatrix);
+ this->getDrawTarget()->drawNonAARect(pipelineBuilder,
+ paint.getColor(),
+ viewMatrix,
+ rectToDraw,
+ localMatrix);
}
void GrDrawContext::drawVertices(const GrClip& clip,
@@ -376,7 +394,7 @@
indexCount, colors, texCoords,
bounds));
- fDrawTarget->drawBatch(pipelineBuilder, batch);
+ this->getDrawTarget()->drawBatch(pipelineBuilder, batch);
}
///////////////////////////////////////////////////////////////////////////////
@@ -400,7 +418,7 @@
SkAutoTUnref<GrDrawBatch> batch(GrDrawAtlasBatch::Create(geometry, viewMatrix, spriteCount,
xform, texRect, colors));
- fDrawTarget->drawBatch(pipelineBuilder, batch);
+ this->getDrawTarget()->drawBatch(pipelineBuilder, batch);
}
///////////////////////////////////////////////////////////////////////////////
@@ -430,7 +448,7 @@
GrPipelineBuilder pipelineBuilder(paint, fRenderTarget, clip);
GrColor color = paint.getColor();
- if (!GrOvalRenderer::DrawRRect(fDrawTarget,
+ if (!GrOvalRenderer::DrawRRect(this->getDrawTarget(),
pipelineBuilder,
color,
viewMatrix,
@@ -440,7 +458,7 @@
SkPath path;
path.setIsVolatile(true);
path.addRRect(rrect);
- this->internalDrawPath(fDrawTarget, &pipelineBuilder, viewMatrix, color,
+ this->internalDrawPath(this->getDrawTarget(), &pipelineBuilder, viewMatrix, color,
paint.isAntiAlias(), path, strokeInfo);
}
}
@@ -463,7 +481,7 @@
GrPipelineBuilder pipelineBuilder(paint, fRenderTarget, clip);
GrColor color = paint.getColor();
- if (!GrOvalRenderer::DrawDRRect(fDrawTarget,
+ if (!GrOvalRenderer::DrawDRRect(this->getDrawTarget(),
pipelineBuilder,
color,
viewMatrix,
@@ -477,7 +495,7 @@
path.setFillType(SkPath::kEvenOdd_FillType);
GrStrokeInfo fillRec(SkStrokeRec::kFill_InitStyle);
- this->internalDrawPath(fDrawTarget, &pipelineBuilder, viewMatrix, color,
+ this->internalDrawPath(this->getDrawTarget(), &pipelineBuilder, viewMatrix, color,
paint.isAntiAlias(), path, fillRec);
}
}
@@ -509,7 +527,7 @@
GrPipelineBuilder pipelineBuilder(paint, fRenderTarget, clip);
GrColor color = paint.getColor();
- if (!GrOvalRenderer::DrawOval(fDrawTarget,
+ if (!GrOvalRenderer::DrawOval(this->getDrawTarget(),
pipelineBuilder,
color,
viewMatrix,
@@ -519,7 +537,7 @@
SkPath path;
path.setIsVolatile(true);
path.addOval(oval);
- this->internalDrawPath(fDrawTarget, &pipelineBuilder, viewMatrix, color,
+ this->internalDrawPath(this->getDrawTarget(), &pipelineBuilder, viewMatrix, color,
paint.isAntiAlias(), path, strokeInfo);
}
}
@@ -582,7 +600,7 @@
AutoCheckFlush acf(fContext);
GrPipelineBuilder pipelineBuilder(paint, fRenderTarget, clip);
- fDrawTarget->drawBatch(pipelineBuilder, batch);
+ this->getDrawTarget()->drawBatch(pipelineBuilder, batch);
}
void GrDrawContext::drawPath(const GrClip& clip,
@@ -621,7 +639,7 @@
if (is_nested_rects(viewMatrix, path, strokeInfo, rects)) {
SkAutoTUnref<GrDrawBatch> batch(GrRectBatchFactory::CreateAAFillNestedRects(
color, viewMatrix, rects));
- fDrawTarget->drawBatch(pipelineBuilder, batch);
+ this->getDrawTarget()->drawBatch(pipelineBuilder, batch);
return;
}
}
@@ -629,7 +647,7 @@
bool isOval = path.isOval(&ovalRect);
if (isOval && !path.isInverseFillType()) {
- if (GrOvalRenderer::DrawOval(fDrawTarget,
+ if (GrOvalRenderer::DrawOval(this->getDrawTarget(),
pipelineBuilder,
color,
viewMatrix,
@@ -640,8 +658,8 @@
}
}
}
- this->internalDrawPath(fDrawTarget, &pipelineBuilder, viewMatrix, color, paint.isAntiAlias(),
- path, strokeInfo);
+ this->internalDrawPath(this->getDrawTarget(), &pipelineBuilder, viewMatrix, color,
+ paint.isAntiAlias(), path, strokeInfo);
}
void GrDrawContext::internalDrawPath(GrDrawTarget* target,
@@ -736,5 +754,5 @@
RETURN_IF_ABANDONED
SkDEBUGCODE(this->validate();)
- fDrawTarget->drawBatch(*pipelineBuilder, batch);
+ this->getDrawTarget()->drawBatch(*pipelineBuilder, batch);
}
diff --git a/src/gpu/GrDrawTarget.cpp b/src/gpu/GrDrawTarget.cpp
index cd86458..323599d 100644
--- a/src/gpu/GrDrawTarget.cpp
+++ b/src/gpu/GrDrawTarget.cpp
@@ -37,7 +37,8 @@
, fResourceProvider(resourceProvider)
, fFlushState(fGpu, fResourceProvider, 0)
, fFlushing(false)
- , fFirstUnpreparedBatch(0) {
+ , fFirstUnpreparedBatch(0)
+ , fClosed(false) {
// TODO: Stop extracting the context (currently needed by GrClipMaskManager)
fContext = fGpu->getContext();
fClipMaskManager.reset(new GrClipMaskManager(this));
@@ -118,6 +119,12 @@
}
fFlushing = true;
+ // Semi-usually the drawTargets are already closed at this point, but sometimes Ganesh
+ // needs to flush mid-draw. In that case, the SkGpuDevice's drawTargets won't be closed
+ // but need to be flushed anyway. Closing such drawTargets here will mean new
+ // drawTargets will be created to replace them if the SkGpuDevice(s) write to them again.
+ this->makeClosed();
+
// Loop over all batches and generate geometry
for (; fFirstUnpreparedBatch < fBatches.count(); ++fFirstUnpreparedBatch) {
fBatches[fFirstUnpreparedBatch]->prepare(&fFlushState);
@@ -406,6 +413,9 @@
}
void GrDrawTarget::recordBatch(GrBatch* batch) {
+ // A closed drawTarget should never receive new/more batches
+ SkASSERT(!fClosed);
+
// Check if there is a Batch Draw we can batch with by linearly searching back until we either
// 1) check every draw
// 2) intersect with something
diff --git a/src/gpu/GrDrawTarget.h b/src/gpu/GrDrawTarget.h
index 98faffc..db637d5 100644
--- a/src/gpu/GrDrawTarget.h
+++ b/src/gpu/GrDrawTarget.h
@@ -49,6 +49,15 @@
~GrDrawTarget() override;
+ void makeClosed() {
+ // 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;
+#endif
+ }
+ bool isClosed() const { return fClosed; }
+
/**
* Empties the draw buffer of any queued up draws.
*/
@@ -235,6 +244,8 @@
bool fFlushing;
int fFirstUnpreparedBatch;
+ bool fClosed;
+
typedef SkRefCnt INHERITED;
};
diff --git a/src/gpu/GrRenderTarget.cpp b/src/gpu/GrRenderTarget.cpp
index e81a9cf..ad56cf7 100644
--- a/src/gpu/GrRenderTarget.cpp
+++ b/src/gpu/GrRenderTarget.cpp
@@ -11,6 +11,7 @@
#include "GrContext.h"
#include "GrDrawContext.h"
+#include "GrDrawTarget.h"
#include "GrGpu.h"
#include "GrRenderTargetPriv.h"
#include "GrStencilAttachment.h"
@@ -56,16 +57,26 @@
void GrRenderTarget::onRelease() {
SkSafeSetNull(fStencilAttachment);
+ fLastDrawTarget = nullptr;
INHERITED::onRelease();
}
void GrRenderTarget::onAbandon() {
SkSafeSetNull(fStencilAttachment);
+ fLastDrawTarget = nullptr;
INHERITED::onAbandon();
}
+void GrRenderTarget::setLastDrawTarget(GrDrawTarget* dt) {
+ if (fLastDrawTarget) {
+ SkASSERT(fLastDrawTarget->isClosed());
+ }
+
+ fLastDrawTarget = dt;
+}
+
///////////////////////////////////////////////////////////////////////////////
bool GrRenderTargetPriv::attachStencilAttachment(GrStencilAttachment* stencil) {
diff --git a/src/gpu/GrTest.cpp b/src/gpu/GrTest.cpp
index 8d6208d..9096ef8 100644
--- a/src/gpu/GrTest.cpp
+++ b/src/gpu/GrTest.cpp
@@ -54,7 +54,8 @@
// then disconnects. This would help prevent test writers from mixing using the returned
// GrDrawTarget and regular drawing. We could also assert or fail in GrContext drawing methods
// until ~GrTestTarget().
- tar->init(this, fDrawingMgr.fDrawTarget);
+ SkAutoTUnref<GrDrawTarget> dt(fDrawingMgr.newDrawTarget(nullptr));
+ tar->init(this, dt);
}
void GrContext::setTextBlobCacheLimit_ForTesting(size_t bytes) {