aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar cdalton <cdalton@nvidia.com>2015-04-29 14:17:00 -0700
committerGravatar Commit bot <commit-bot@chromium.org>2015-04-29 14:17:00 -0700
commit9954bc38c498f6b9e9d8c0bcc5cd00d45bfc6e23 (patch)
treef88d88bad3884d979e595a6a462e21cf89b4bdc9
parentdbc3cefb0b624808ddb86d444e6103f216e12fa5 (diff)
Use texture barriers to read directly from the RT
Updates GrXferProcessor to read directly from the RT texture when texture barriers are supported and it needs to know the dst color. Also adds the notion of an Xfer barrier and uses it to issue texture barriers when the XP will read the RT. BUG=skia: Review URL: https://codereview.chromium.org/1040303002
-rw-r--r--include/gpu/GrXferProcessor.h16
-rw-r--r--src/gpu/GrDrawTarget.cpp14
-rw-r--r--src/gpu/GrGpu.h3
-rw-r--r--src/gpu/GrTargetCommands.cpp25
-rw-r--r--src/gpu/GrTargetCommands.h17
-rw-r--r--src/gpu/GrTest.cpp2
-rw-r--r--src/gpu/GrXferProcessor.cpp13
-rw-r--r--src/gpu/gl/GrGLGpu.cpp9
-rw-r--r--src/gpu/gl/GrGLGpu.h2
-rw-r--r--tests/GLProgramsTest.cpp6
10 files changed, 106 insertions, 1 deletions
diff --git a/include/gpu/GrXferProcessor.h b/include/gpu/GrXferProcessor.h
index 411231d154..8ef897c232 100644
--- a/include/gpu/GrXferProcessor.h
+++ b/include/gpu/GrXferProcessor.h
@@ -48,6 +48,14 @@ enum GrBlendCoeff {
};
/**
+ * Barriers for blending. When a shader reads the dst directly, an Xfer barrier is sometimes
+ * required after a pixel has been written, before it can be safely read again.
+ */
+enum GrXferBarrierType {
+ kTexture_GrXferBarrierType, //<! Required when a shader reads and renders to the same texture.
+};
+
+/**
* GrXferProcessor is responsible for implementing the xfer mode that blends the src color and dst
* color. It does this by emitting fragment shader code and controlling the fixed-function blend
* state. The inputs to its shader code are the final computed src color and fractional pixel
@@ -124,6 +132,14 @@ public:
GrColor* overrideColor,
const GrDrawTargetCaps& caps) = 0;
+ /**
+ * Returns whether this XP will require an Xfer barrier on the given rt. If true, outBarrierType
+ * is updated to contain the type of barrier needed.
+ */
+ bool willNeedXferBarrier(const GrRenderTarget* rt,
+ const GrDrawTargetCaps& caps,
+ GrXferBarrierType* outBarrierType) const;
+
struct BlendInfo {
void reset() {
fSrcBlend = kOne_GrBlendCoeff;
diff --git a/src/gpu/GrDrawTarget.cpp b/src/gpu/GrDrawTarget.cpp
index e52e4f976b..d868bcb6bd 100644
--- a/src/gpu/GrDrawTarget.cpp
+++ b/src/gpu/GrDrawTarget.cpp
@@ -78,8 +78,20 @@ bool GrDrawTarget::setupDstReadIfNecessary(const GrPipelineBuilder& pipelineBuil
if (!pipelineBuilder.willXPNeedDstCopy(*this->caps(), colorPOI, coveragePOI)) {
return true;
}
- SkIRect copyRect;
+
GrRenderTarget* rt = pipelineBuilder.getRenderTarget();
+
+ if (this->caps()->textureBarrierSupport()) {
+ if (GrTexture* rtTex = rt->asTexture()) {
+ // The render target is a texture, se we can read from it directly in the shader. The XP
+ // will be responsible to detect this situation and request a texture barrier.
+ dstCopy->setTexture(rtTex);
+ dstCopy->setOffset(0, 0);
+ return true;
+ }
+ }
+
+ SkIRect copyRect;
pipelineBuilder.clip().getConservativeBounds(rt, &copyRect);
if (drawBounds) {
diff --git a/src/gpu/GrGpu.h b/src/gpu/GrGpu.h
index 5784781996..b2dbec65fb 100644
--- a/src/gpu/GrGpu.h
+++ b/src/gpu/GrGpu.h
@@ -304,6 +304,9 @@ public:
const SkIRect& srcRect,
const SkIPoint& dstPoint) = 0;
+ // Called before certain draws in order to guarantee coherent results from dst reads.
+ virtual void xferBarrier(GrXferBarrierType) = 0;
+
struct DrawArgs {
typedef GrDrawTarget::DrawInfo DrawInfo;
DrawArgs(const GrPrimitiveProcessor* primProc,
diff --git a/src/gpu/GrTargetCommands.cpp b/src/gpu/GrTargetCommands.cpp
index c448db95b6..24ee32d832 100644
--- a/src/gpu/GrTargetCommands.cpp
+++ b/src/gpu/GrTargetCommands.cpp
@@ -341,6 +341,10 @@ void GrTargetCommands::CopySurface::execute(GrGpu* gpu, const SetState*) {
gpu->copySurface(this->dst(), this->src(), fSrcRect, fDstPoint);
}
+void GrTargetCommands::XferBarrier::execute(GrGpu* gpu, const SetState* state) {
+ gpu->xferBarrier(fBarrierType);
+}
+
GrTargetCommands::Cmd* GrTargetCommands::recordCopySurface(GrSurface* dst,
GrSurface* src,
const SkIRect& srcRect,
@@ -375,6 +379,8 @@ bool GrTargetCommands::setupPipelineAndShouldDraw(GrInOrderDrawBuffer* iodb,
fPrevState = ss;
iodb->recordTraceMarkersIfNecessary(ss);
}
+
+ this->recordXferBarrierIfNecessary(iodb, pipelineInfo);
return true;
}
@@ -398,6 +404,25 @@ bool GrTargetCommands::setupPipelineAndShouldDraw(GrInOrderDrawBuffer* iodb,
fPrevState = ss;
iodb->recordTraceMarkersIfNecessary(ss);
}
+
+ this->recordXferBarrierIfNecessary(iodb, pipelineInfo);
return true;
}
+void GrTargetCommands::recordXferBarrierIfNecessary(GrInOrderDrawBuffer* iodb,
+ const GrDrawTarget::PipelineInfo& info) {
+ SkASSERT(fPrevState);
+ const GrXferProcessor& xp = *fPrevState->getXferProcessor();
+ GrRenderTarget* rt = fPrevState->getRenderTarget();
+
+ GrXferBarrierType barrierType;
+ if (!xp.willNeedXferBarrier(rt, *iodb->caps(), &barrierType)) {
+ return;
+ }
+
+ XferBarrier* xb = GrNEW_APPEND_TO_RECORDER(fCmdBuffer, XferBarrier, ());
+ xb->fBarrierType = barrierType;
+
+ iodb->recordTraceMarkersIfNecessary(xb);
+}
+
diff --git a/src/gpu/GrTargetCommands.h b/src/gpu/GrTargetCommands.h
index cff9898dad..4ab41dbaf1 100644
--- a/src/gpu/GrTargetCommands.h
+++ b/src/gpu/GrTargetCommands.h
@@ -56,6 +56,7 @@ public:
kDrawPath_CmdType = 6,
kDrawPaths_CmdType = 7,
kDrawBatch_CmdType = 8,
+ kXferBarrier_CmdType = 9,
};
Cmd(CmdType type) : fMarkerID(-1), fType(type) {}
@@ -151,6 +152,8 @@ private:
GrBatch*,
const GrDrawTarget::PipelineInfo&);
+ void recordXferBarrierIfNecessary(GrInOrderDrawBuffer*, const GrDrawTarget::PipelineInfo&);
+
struct Draw : public Cmd {
Draw(const GrDrawTarget::DrawInfo& info) : Cmd(kDraw_CmdType), fInfo(info) {}
@@ -276,6 +279,12 @@ private:
const GrPipeline* getPipeline() const {
return reinterpret_cast<const GrPipeline*>(fPipeline.get());
}
+ GrRenderTarget* getRenderTarget() const {
+ return this->getPipeline()->getRenderTarget();
+ }
+ const GrXferProcessor* getXferProcessor() const {
+ return this->getPipeline()->getXferProcessor();
+ }
void execute(GrGpu*, const SetState*) override;
@@ -303,6 +312,14 @@ private:
GrBatchTarget* fBatchTarget;
};
+ struct XferBarrier : public Cmd {
+ XferBarrier() : Cmd(kXferBarrier_CmdType) {}
+
+ void execute(GrGpu*, const SetState*) override;
+
+ GrXferBarrierType fBarrierType;
+ };
+
static const int kCmdBufferInitialSizeInBytes = 8 * 1024;
typedef void* TCmdAlign; // This wouldn't be enough align if a command used long double.
diff --git a/src/gpu/GrTest.cpp b/src/gpu/GrTest.cpp
index 3c5d3dd790..23739f2b2a 100644
--- a/src/gpu/GrTest.cpp
+++ b/src/gpu/GrTest.cpp
@@ -170,6 +170,8 @@ public:
return false;
}
+ void xferBarrier(GrXferBarrierType) override {}
+
private:
void onResetContext(uint32_t resetBits) override {}
diff --git a/src/gpu/GrXferProcessor.cpp b/src/gpu/GrXferProcessor.cpp
index de08ef0ee6..42ac1531c1 100644
--- a/src/gpu/GrXferProcessor.cpp
+++ b/src/gpu/GrXferProcessor.cpp
@@ -32,6 +32,19 @@ void GrXferProcessor::getGLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBu
this->onGetGLProcessorKey(caps, b);
}
+bool GrXferProcessor::willNeedXferBarrier(const GrRenderTarget* rt,
+ const GrDrawTargetCaps& caps,
+ GrXferBarrierType* outBarrierType) const {
+ if (static_cast<const GrSurface*>(rt) == this->getDstCopyTexture()) {
+ // Texture barriers are required when a shader reads and renders to the same texture.
+ SkASSERT(rt);
+ SkASSERT(caps.textureBarrierSupport());
+ *outBarrierType = kTexture_GrXferBarrierType;
+ return true;
+ }
+ return false;
+}
+
///////////////////////////////////////////////////////////////////////////////
GrXferProcessor* GrXPFactory::createXferProcessor(const GrProcOptInfo& colorPOI,
diff --git a/src/gpu/gl/GrGLGpu.cpp b/src/gpu/gl/GrGLGpu.cpp
index 2c46f9b343..4421b3c510 100644
--- a/src/gpu/gl/GrGLGpu.cpp
+++ b/src/gpu/gl/GrGLGpu.cpp
@@ -2727,6 +2727,15 @@ bool GrGLGpu::canCopySurface(const GrSurface* dst,
return false;
}
+void GrGLGpu::xferBarrier(GrXferBarrierType type) {
+ switch (type) {
+ case kTexture_GrXferBarrierType:
+ SkASSERT(this->caps()->textureBarrierSupport());
+ GL_CALL(TextureBarrier());
+ return;
+ }
+}
+
void GrGLGpu::didAddGpuTraceMarker() {
if (this->caps()->gpuTracingSupport()) {
const GrTraceMarkerSet& markerArray = this->getActiveTraceMarkers();
diff --git a/src/gpu/gl/GrGLGpu.h b/src/gpu/gl/GrGLGpu.h
index d833ca5bf1..5357142ec9 100644
--- a/src/gpu/gl/GrGLGpu.h
+++ b/src/gpu/gl/GrGLGpu.h
@@ -105,6 +105,8 @@ public:
const SkIRect& srcRect,
const SkIPoint& dstPoint) override;
+ void xferBarrier(GrXferBarrierType) override;
+
void buildProgramDesc(GrProgramDesc*,
const GrPrimitiveProcessor&,
const GrPipeline&,
diff --git a/tests/GLProgramsTest.cpp b/tests/GLProgramsTest.cpp
index bc3da6d9ee..c12e5e8781 100644
--- a/tests/GLProgramsTest.cpp
+++ b/tests/GLProgramsTest.cpp
@@ -304,6 +304,12 @@ bool GrDrawTarget::programUnitTest(int maxStages) {
if (pipeline.mustSkip()) {
continue;
}
+
+ GrXferBarrierType barrierType;
+ if (pipeline.getXferProcessor()->willNeedXferBarrier(rt, *gpu->caps(), &barrierType)) {
+ gpu->xferBarrier(barrierType);
+ }
+
GrBatchTracker bt;
primProc->initBatchTracker(&bt, pipeline.getInitBatchTracker());