From 9954bc38c498f6b9e9d8c0bcc5cd00d45bfc6e23 Mon Sep 17 00:00:00 2001 From: cdalton Date: Wed, 29 Apr 2015 14:17:00 -0700 Subject: 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 --- include/gpu/GrXferProcessor.h | 16 ++++++++++++++++ src/gpu/GrDrawTarget.cpp | 14 +++++++++++++- src/gpu/GrGpu.h | 3 +++ src/gpu/GrTargetCommands.cpp | 25 +++++++++++++++++++++++++ src/gpu/GrTargetCommands.h | 17 +++++++++++++++++ src/gpu/GrTest.cpp | 2 ++ src/gpu/GrXferProcessor.cpp | 13 +++++++++++++ src/gpu/gl/GrGLGpu.cpp | 9 +++++++++ src/gpu/gl/GrGLGpu.h | 2 ++ tests/GLProgramsTest.cpp | 6 ++++++ 10 files changed, 106 insertions(+), 1 deletion(-) 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 @@ -47,6 +47,14 @@ enum GrBlendCoeff { kTotalGrBlendCoeffCount }; +/** + * 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, //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, ©Rect); 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(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(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()); -- cgit v1.2.3