diff options
author | bsalomon <bsalomon@google.com> | 2015-09-09 09:48:06 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-09-09 09:48:06 -0700 |
commit | 1fcc01c4158bd68c679569e6c7cfbb302d0ce170 (patch) | |
tree | 2d3d41bf771e9433ed6a26b0e2e710f1c87a5391 | |
parent | 5ca4fa3846067a47e88d35ace895df3ebe3ec2a5 (diff) |
GrPathRangeBatch
BUG=skia:
Review URL: https://codereview.chromium.org/1315563003
-rw-r--r-- | gyp/gpu.gypi | 1 | ||||
-rw-r--r-- | include/gpu/GrDrawContext.h | 19 | ||||
-rw-r--r-- | src/gpu/GrBufferedDrawTarget.cpp | 62 | ||||
-rw-r--r-- | src/gpu/GrBufferedDrawTarget.h | 69 | ||||
-rw-r--r-- | src/gpu/GrCommandBuilder.h | 14 | ||||
-rw-r--r-- | src/gpu/GrDrawContext.cpp | 20 | ||||
-rw-r--r-- | src/gpu/GrDrawTarget.cpp | 84 | ||||
-rw-r--r-- | src/gpu/GrDrawTarget.h | 46 | ||||
-rw-r--r-- | src/gpu/GrGeometryProcessor.h | 8 | ||||
-rw-r--r-- | src/gpu/GrImmediateDrawTarget.h | 14 | ||||
-rw-r--r-- | src/gpu/GrInOrderCommandBuilder.cpp | 75 | ||||
-rw-r--r-- | src/gpu/GrInOrderCommandBuilder.h | 12 | ||||
-rw-r--r-- | src/gpu/GrPathProcessor.cpp | 6 | ||||
-rw-r--r-- | src/gpu/GrPathProcessor.h | 6 | ||||
-rw-r--r-- | src/gpu/GrPrimitiveProcessor.h | 4 | ||||
-rw-r--r-- | src/gpu/GrReorderCommandBuilder.h | 17 | ||||
-rw-r--r-- | src/gpu/GrStencilAndCoverTextContext.cpp | 78 | ||||
-rw-r--r-- | src/gpu/GrStencilAndCoverTextContext.h | 15 | ||||
-rw-r--r-- | src/gpu/GrTargetCommands.cpp | 23 | ||||
-rw-r--r-- | src/gpu/GrTargetCommands.h | 84 | ||||
-rw-r--r-- | src/gpu/batches/GrDrawPathBatch.cpp | 138 | ||||
-rw-r--r-- | src/gpu/batches/GrDrawPathBatch.h | 170 |
22 files changed, 376 insertions, 589 deletions
diff --git a/gyp/gpu.gypi b/gyp/gpu.gypi index 58687a7014..818f2b20e6 100644 --- a/gyp/gpu.gypi +++ b/gyp/gpu.gypi @@ -229,6 +229,7 @@ '<(skia_src_path)/gpu/batches/GrDrawBatch.h', '<(skia_src_path)/gpu/batches/GrDrawAtlasBatch.cpp', '<(skia_src_path)/gpu/batches/GrDrawAtlasBatch.h', + '<(skia_src_path)/gpu/batches/GrDrawPathBatch.cpp', '<(skia_src_path)/gpu/batches/GrDrawPathBatch.h', '<(skia_src_path)/gpu/batches/GrDrawVerticesBatch.cpp', '<(skia_src_path)/gpu/batches/GrDrawVerticesBatch.h', diff --git a/include/gpu/GrDrawContext.h b/include/gpu/GrDrawContext.h index 552cfd3dc8..aae4bf00b3 100644 --- a/include/gpu/GrDrawContext.h +++ b/include/gpu/GrDrawContext.h @@ -18,7 +18,7 @@ class GrDrawBatch; class GrDrawTarget; class GrPaint; class GrPathProcessor; -class GrPathRange; +class GrPathRangeDraw; class GrPipelineBuilder; class GrRenderTarget; class GrStrokeInfo; @@ -61,17 +61,12 @@ public: SkScalar x, SkScalar y, SkDrawFilter*, const SkIRect& clipBounds); - // drawPaths is thanks to GrStencilAndCoverTextContext - // TODO: remove - void drawPaths(GrPipelineBuilder* pipelineBuilder, - const GrPathProcessor* pathProc, - const GrPathRange* pathRange, - const void* indices, - int /*GrDrawTarget::PathIndexType*/ indexType, - const float transformValues[], - int /*GrDrawTarget::PathTransformType*/ transformType, - int count, - int /*GrPathRendering::FillType*/ fill); + // drawPathsFromRange is thanks to GrStencilAndCoverTextContext + // TODO: remove once path batches can be created external to GrDrawTarget. + void drawPathsFromRange(const GrPipelineBuilder*, + const GrPathProcessor*, + GrPathRangeDraw* draw, + int /*GrPathRendering::FillType*/ fill); /** * Provides a perfomance hint that the render target's contents are allowed diff --git a/src/gpu/GrBufferedDrawTarget.cpp b/src/gpu/GrBufferedDrawTarget.cpp index 7ba6a2d70f..0b6e885db3 100644 --- a/src/gpu/GrBufferedDrawTarget.cpp +++ b/src/gpu/GrBufferedDrawTarget.cpp @@ -16,9 +16,6 @@ static inline bool allow_reordering(const GrCaps* caps) { GrBufferedDrawTarget::GrBufferedDrawTarget(GrContext* context) : INHERITED(context) , fCommands(GrCommandBuilder::Create(context->getGpu(), allow_reordering(context->caps()))) - , fPathIndexBuffer(kPathIdxBufferMinReserve * sizeof(char)/4) - , fPathTransformBuffer(kPathXformBufferMinReserve * sizeof(float)/4) - , fPipelineBuffer(kPipelineBufferMinReserve) , fDrawID(0) { } @@ -30,66 +27,11 @@ void GrBufferedDrawTarget::onDrawBatch(GrBatch* batch) { fCommands->recordDrawBatch(batch, *this->caps()); } -void GrBufferedDrawTarget::onDrawPaths(const GrPathProcessor* pathProc, - const GrPathRange* pathRange, - const void* indices, - PathIndexType indexType, - const float transformValues[], - PathTransformType transformType, - int count, - const GrStencilSettings& stencilSettings, - const PipelineInfo& pipelineInfo) { - GrPipelineOptimizations opts; - StateForPathDraw* state = this->createStateForPathDraw(pathProc, pipelineInfo, &opts); - if (!state) { - return; - } - fCommands->recordDrawPaths(state, this, pathProc, pathRange, indices, indexType, - transformValues, transformType, count, stencilSettings, - opts); -} - -void GrBufferedDrawTarget::onReset() { - fCommands->reset(); - fPathIndexBuffer.rewind(); - fPathTransformBuffer.rewind(); - - fPrevState.reset(nullptr); - // Note, fPrevState points into fPipelineBuffer's allocation, so we have to reset first. - // Furthermore, we have to reset fCommands before fPipelineBuffer too. - if (fDrawID % kPipelineBufferHighWaterMark) { - fPipelineBuffer.rewind(); - } else { - fPipelineBuffer.reset(); - } -} - void GrBufferedDrawTarget::onFlush() { fCommands->flush(this->getGpu(), this->getContext()->resourceProvider()); ++fDrawID; } -GrTargetCommands::StateForPathDraw* -GrBufferedDrawTarget::createStateForPathDraw(const GrPrimitiveProcessor* primProc, - const GrDrawTarget::PipelineInfo& pipelineInfo, - GrPipelineOptimizations* opts) { - StateForPathDraw* state = this->allocState(primProc); - if (!GrPipeline::CreateAt(state->pipelineLocation(), pipelineInfo.pipelineCreateArgs(), opts)) { - this->unallocState(state); - return nullptr; - } - - state->fPrimitiveProcessor->initBatchTracker(&state->fBatchTracker, *opts); - - if (fPrevState && fPrevState->fPrimitiveProcessor.get() && - fPrevState->fPrimitiveProcessor->canMakeEqual(fPrevState->fBatchTracker, - *state->fPrimitiveProcessor, - state->fBatchTracker) && - GrPipeline::AreEqual(*fPrevState->getPipeline(), *state->getPipeline(), false)) { - this->unallocState(state); - } else { - fPrevState.reset(state); - } - - return fPrevState; +void GrBufferedDrawTarget::onReset() { + fCommands->reset(); } diff --git a/src/gpu/GrBufferedDrawTarget.h b/src/gpu/GrBufferedDrawTarget.h index 5a80a3ccfb..79b1a71cfe 100644 --- a/src/gpu/GrBufferedDrawTarget.h +++ b/src/gpu/GrBufferedDrawTarget.h @@ -20,7 +20,6 @@ */ class GrBufferedDrawTarget : public GrClipTarget { public: - /** * Creates a GrBufferedDrawTarget * @@ -31,82 +30,14 @@ public: ~GrBufferedDrawTarget() override; protected: - void appendIndicesAndTransforms(const void* indexValues, PathIndexType indexType, - const float* transformValues, PathTransformType transformType, - int count, char** indicesLocation, float** xformsLocation) { - int indexBytes = GrPathRange::PathIndexSizeInBytes(indexType); - *indicesLocation = (char*) fPathIndexBuffer.alloc(count * indexBytes, - SkChunkAlloc::kThrow_AllocFailType); - SkASSERT(SkIsAlign4((uintptr_t)*indicesLocation)); - memcpy(*indicesLocation, reinterpret_cast<const char*>(indexValues), count * indexBytes); - - const int xformBytes = GrPathRendering::PathTransformSize(transformType) * sizeof(float); - *xformsLocation = nullptr; - - if (0 != xformBytes) { - *xformsLocation = (float*) fPathTransformBuffer.alloc(count * xformBytes, - SkChunkAlloc::kThrow_AllocFailType); - SkASSERT(SkIsAlign4((uintptr_t)*xformsLocation)); - memcpy(*xformsLocation, transformValues, count * xformBytes); - } - } - void onDrawBatch(GrBatch*) override; private: - friend class GrInOrderCommandBuilder; - friend class GrTargetCommands; - - typedef GrTargetCommands::StateForPathDraw StateForPathDraw; - - StateForPathDraw* allocState(const GrPrimitiveProcessor* primProc = nullptr) { - void* allocation = fPipelineBuffer.alloc(sizeof(StateForPathDraw), - SkChunkAlloc::kThrow_AllocFailType); - return new (allocation) StateForPathDraw(primProc); - } - - void unallocState(StateForPathDraw* state) { - state->unref(); - fPipelineBuffer.unalloc(state); - } - void onReset() override; void onFlush() override; - void onDrawPaths(const GrPathProcessor*, - const GrPathRange*, - const void* indices, - PathIndexType, - const float transformValues[], - PathTransformType, - int count, - const GrStencilSettings&, - const PipelineInfo&) override; - - bool isIssued(uint32_t drawID) override { return drawID != fDrawID; } - - StateForPathDraw* SK_WARN_UNUSED_RESULT createStateForPathDraw( - const GrPrimitiveProcessor*, - const PipelineInfo&, - GrPipelineOptimizations* opts); - - // TODO: Use a single allocator for commands and records - enum { - kPathIdxBufferMinReserve = 2 * 64, // 64 uint16_t's - kPathXformBufferMinReserve = 2 * 64, // 64 two-float transforms - kPipelineBufferMinReserve = 32 * sizeof(StateForPathDraw), - }; - - // every 100 flushes we should reset our fPipelineBuffer to prevent us from holding at a - // highwater mark - static const int kPipelineBufferHighWaterMark = 100; - SkAutoTDelete<GrCommandBuilder> fCommands; - SkChunkAlloc fPathIndexBuffer; - SkChunkAlloc fPathTransformBuffer; - SkChunkAlloc fPipelineBuffer; uint32_t fDrawID; - SkAutoTUnref<StateForPathDraw> fPrevState; typedef GrClipTarget INHERITED; }; diff --git a/src/gpu/GrCommandBuilder.h b/src/gpu/GrCommandBuilder.h index 876e9b1c50..29dcb3339a 100644 --- a/src/gpu/GrCommandBuilder.h +++ b/src/gpu/GrCommandBuilder.h @@ -17,7 +17,6 @@ class GrBufferedDrawTarget; class GrCommandBuilder : ::SkNoncopyable { public: typedef GrTargetCommands::Cmd Cmd; - typedef GrTargetCommands::StateForPathDraw State; static GrCommandBuilder* Create(GrGpu* gpu, bool reorder); @@ -27,22 +26,9 @@ public: void flush(GrGpu* gpu, GrResourceProvider* rp) { fCommands.flush(gpu, rp); } virtual Cmd* recordDrawBatch(GrBatch*, const GrCaps&) = 0; - virtual Cmd* recordDrawPaths(State*, - GrBufferedDrawTarget*, - const GrPathProcessor*, - const GrPathRange*, - const void*, - GrDrawTarget::PathIndexType, - const float transformValues[], - GrDrawTarget::PathTransformType , - int, - const GrStencilSettings&, - const GrPipelineOptimizations&) = 0; protected: typedef GrTargetCommands::DrawBatch DrawBatch; - typedef GrTargetCommands::DrawPath DrawPath; - typedef GrTargetCommands::DrawPaths DrawPaths; GrCommandBuilder() {} diff --git a/src/gpu/GrDrawContext.cpp b/src/gpu/GrDrawContext.cpp index e03075e41f..8068403e4b 100644 --- a/src/gpu/GrDrawContext.cpp +++ b/src/gpu/GrDrawContext.cpp @@ -111,20 +111,12 @@ void GrDrawContext::drawTextBlob(GrRenderTarget* rt, const GrClip& clip, const S clip, skPaint, viewMatrix, blob, x, y, filter, clipBounds); } -void GrDrawContext::drawPaths(GrPipelineBuilder* pipelineBuilder, - const GrPathProcessor* pathProc, - const GrPathRange* pathRange, - const void* indices, - int /*GrDrawTarget::PathIndexType*/ indexType, - const float transformValues[], - int /*GrDrawTarget::PathTransformType*/ transformType, - int count, - int /*GrPathRendering::FillType*/ fill) { - fDrawTarget->drawPaths(*pipelineBuilder, pathProc, pathRange, - indices, (GrDrawTarget::PathIndexType) indexType, - transformValues, - (GrDrawTarget::PathTransformType) transformType, - count, (GrPathRendering::FillType) fill); +void GrDrawContext::drawPathsFromRange(const GrPipelineBuilder* pipelineBuilder, + const GrPathProcessor* pathProc, + GrPathRangeDraw* draw, + int /*GrPathRendering::FillType*/ fill) { + fDrawTarget->drawPathsFromRange(*pipelineBuilder, pathProc, draw, + (GrPathRendering::FillType) fill); } void GrDrawContext::discard(GrRenderTarget* renderTarget) { diff --git a/src/gpu/GrDrawTarget.cpp b/src/gpu/GrDrawTarget.cpp index 3f472d0948..0e7e6bce90 100644 --- a/src/gpu/GrDrawTarget.cpp +++ b/src/gpu/GrDrawTarget.cpp @@ -224,8 +224,23 @@ void GrDrawTarget::drawPath(const GrPipelineBuilder& pipelineBuilder, SkASSERT(path); SkASSERT(this->caps()->shaderCaps()->pathRenderingSupport()); - GrDrawPathBatch* batch = GrDrawPathBatch::Create(pathProc, path); + GrDrawPathBatchBase* batch = GrDrawPathBatch::Create(pathProc, path); + this->drawPathBatch(pipelineBuilder, batch, fill); + batch->unref(); +} + +void GrDrawTarget::drawPathsFromRange(const GrPipelineBuilder& pipelineBuilder, + const GrPathProcessor* pathProc, + GrPathRangeDraw* draw, + GrPathRendering::FillType fill) { + GrDrawPathBatchBase* batch = GrDrawPathRangeBatch::Create(pathProc, draw); + this->drawPathBatch(pipelineBuilder, batch, fill); + batch->unref(); +} +void GrDrawTarget::drawPathBatch(const GrPipelineBuilder& pipelineBuilder, + GrDrawPathBatchBase* batch, + GrPathRendering::FillType fill) { // This looks like drawBatch() but there is an added wrinkle that stencil settings get inserted // after setupClip() but before onDrawBatch(). TODO: Figure out a better model for handling // stencil settings WRT interactions between pipeline(builder), clipmaskmanager, and batches. @@ -244,11 +259,8 @@ void GrDrawTarget::drawPath(const GrPipelineBuilder& pipelineBuilder, this->getPathStencilSettingsForFilltype(fill, sb, &stencilSettings); batch->setStencilSettings(stencilSettings); - // Don't compute a bounding box for dst copy texture, we'll opt - // instead for it to just copy the entire dst. Realistically this is a moot - // point, because any context that supports NV_path_rendering will also - // support NV_blend_equation_advanced. - GrDrawTarget::PipelineInfo pipelineInfo(&pipelineBuilder, &scissorState, batch, nullptr, this); + GrDrawTarget::PipelineInfo pipelineInfo(&pipelineBuilder, &scissorState, batch, + &batch->bounds(), this); if (!pipelineInfo.valid()) { return; @@ -258,50 +270,6 @@ void GrDrawTarget::drawPath(const GrPipelineBuilder& pipelineBuilder, } this->onDrawBatch(batch); - batch->unref(); -} - -void GrDrawTarget::drawPaths(const GrPipelineBuilder& pipelineBuilder, - const GrPathProcessor* pathProc, - const GrPathRange* pathRange, - const void* indices, - PathIndexType indexType, - const float transformValues[], - PathTransformType transformType, - int count, - GrPathRendering::FillType fill) { - SkASSERT(this->caps()->shaderCaps()->pathRenderingSupport()); - SkASSERT(pathRange); - SkASSERT(indices); - SkASSERT(0 == reinterpret_cast<intptr_t>(indices) % - GrPathRange::PathIndexSizeInBytes(indexType)); - SkASSERT(transformValues); - - // Setup clip - GrScissorState scissorState; - GrPipelineBuilder::AutoRestoreFragmentProcessorState arfps; - GrPipelineBuilder::AutoRestoreStencil ars; - if (!this->setupClip(pipelineBuilder, &arfps, &ars, &scissorState, nullptr)) { - return; - } - - // set stencil settings for path - GrStencilSettings stencilSettings; - GrRenderTarget* rt = pipelineBuilder.getRenderTarget(); - GrStencilAttachment* sb = rt->renderTargetPriv().attachStencilAttachment(); - this->getPathStencilSettingsForFilltype(fill, sb, &stencilSettings); - - // Don't compute a bounding box for dst copy texture, we'll opt - // instead for it to just copy the entire dst. Realistically this is a moot - // point, because any context that supports NV_path_rendering will also - // support NV_blend_equation_advanced. - GrDrawTarget::PipelineInfo pipelineInfo(&pipelineBuilder, &scissorState, pathProc, nullptr, this); - if (!pipelineInfo.valid()) { - return; - } - - this->onDrawPaths(pathProc, pathRange, indices, indexType, transformValues, - transformType, count, stencilSettings, pipelineInfo); } void GrDrawTarget::drawNonAARect(const GrPipelineBuilder& pipelineBuilder, @@ -406,22 +374,6 @@ void GrDrawTarget::copySurface(GrSurface* dst, GrDrawTarget::PipelineInfo::PipelineInfo(const GrPipelineBuilder* pipelineBuilder, const GrScissorState* scissor, - const GrPrimitiveProcessor* primProc, - const SkRect* devBounds, - GrDrawTarget* target) { - fArgs.fPipelineBuilder = pipelineBuilder; - fArgs.fCaps = target->caps(); - fArgs.fScissor = scissor; - fArgs.fColorPOI = fArgs.fPipelineBuilder->colorProcInfo(primProc); - fArgs.fCoveragePOI = fArgs.fPipelineBuilder->coverageProcInfo(primProc); - if (!target->setupDstReadIfNecessary(*fArgs.fPipelineBuilder, fArgs.fColorPOI, - fArgs.fCoveragePOI, &fArgs.fDstTexture, devBounds)) { - fArgs.fPipelineBuilder = nullptr; - } -} - -GrDrawTarget::PipelineInfo::PipelineInfo(const GrPipelineBuilder* pipelineBuilder, - const GrScissorState* scissor, const GrDrawBatch* batch, const SkRect* devBounds, GrDrawTarget* target) { diff --git a/src/gpu/GrDrawTarget.h b/src/gpu/GrDrawTarget.h index 572e4cbf3b..13f35ac768 100644 --- a/src/gpu/GrDrawTarget.h +++ b/src/gpu/GrDrawTarget.h @@ -33,8 +33,9 @@ class GrBatch; class GrClip; class GrCaps; class GrPath; -class GrPathRange; class GrDrawBatch; +class GrDrawPathBatchBase; +class GrPathRangeDraw; class GrDrawTarget : public SkRefCnt { public: @@ -81,6 +82,8 @@ public: /** * Draws a path. Fill must not be a hairline. It will respect the HW * antialias flag on the GrPipelineBuilder (if possible in the 3D API). + * + * TODO: Remove this function and construct the batch outside GrDrawTarget. */ void drawPath(const GrPipelineBuilder&, const GrPathProcessor*, const GrPath*, GrPathRendering::FillType); @@ -90,23 +93,17 @@ public: * always be equivalent to back-to-back calls to drawPath(). It will respect * the HW antialias flag on the GrPipelineBuilder (if possible in the 3D API). * - * @param pathRange Source paths to draw from - * @param indices Array of path indices to draw - * @param indexType Data type of the array elements in indexBuffer - * @param transformValues Array of transforms for the individual paths - * @param transformType Type of transforms in transformBuffer - * @param count Number of paths to draw + * TODO: Remove this function and construct the batch outside GrDrawTarget. + * + * @param draw The range, transforms, and indices for the draw. + * This object must only be drawn once. The draw + * may modify its contents. * @param fill Fill type for drawing all the paths */ - void drawPaths(const GrPipelineBuilder&, - const GrPathProcessor*, - const GrPathRange* pathRange, - const void* indices, - PathIndexType indexType, - const float transformValues[], - PathTransformType transformType, - int count, - GrPathRendering::FillType fill); + void drawPathsFromRange(const GrPipelineBuilder&, + const GrPathProcessor*, + GrPathRangeDraw* draw, + GrPathRendering::FillType fill); /** * Helper function for drawing rects. @@ -187,10 +184,6 @@ public: struct PipelineInfo { PipelineInfo(const GrPipelineBuilder* pipelineBuilder, const GrScissorState* scissor, - const GrPrimitiveProcessor* primProc, - const SkRect* devBounds, GrDrawTarget* target); - - PipelineInfo(const GrPipelineBuilder* pipelineBuilder, const GrScissorState* scissor, const GrDrawBatch* batch, const SkRect* devBounds, GrDrawTarget* target); @@ -225,18 +218,9 @@ private: virtual void onFlush() = 0; - virtual void onDrawPaths(const GrPathProcessor*, - const GrPathRange*, - const void* indices, - PathIndexType, - const float transformValues[], - PathTransformType, - int count, - const GrStencilSettings&, - const PipelineInfo&) = 0; - + void drawPathBatch(const GrPipelineBuilder& pipelineBuilder, GrDrawPathBatchBase* batch, + GrPathRendering::FillType fill); // Check to see if this set of draw commands has been sent out - virtual bool isIssued(uint32_t drawID) { return true; } void getPathStencilSettingsForFilltype(GrPathRendering::FillType, const GrStencilAttachment*, GrStencilSettings*); diff --git a/src/gpu/GrGeometryProcessor.h b/src/gpu/GrGeometryProcessor.h index 72f4d24bf9..232b73ef07 100644 --- a/src/gpu/GrGeometryProcessor.h +++ b/src/gpu/GrGeometryProcessor.h @@ -29,14 +29,6 @@ public: // TODO delete when paths are in batch void initBatchTracker(GrBatchTracker*, const GrPipelineOptimizations&) const override {} - // TODO delete this when paths are in batch - bool canMakeEqual(const GrBatchTracker& mine, - const GrPrimitiveProcessor& that, - const GrBatchTracker& theirs) const override { - SkFAIL("Unsupported\n"); - return false; - } - // TODO Delete when paths are in batch void getInvariantOutputColor(GrInitInvariantOutput* out) const override { SkFAIL("Unsupported\n"); diff --git a/src/gpu/GrImmediateDrawTarget.h b/src/gpu/GrImmediateDrawTarget.h index 1fabce4a98..4791de9841 100644 --- a/src/gpu/GrImmediateDrawTarget.h +++ b/src/gpu/GrImmediateDrawTarget.h @@ -33,20 +33,6 @@ private: void onReset() override; void onFlush() override; - void onDrawPaths(const GrPathProcessor*, - const GrPathRange*, - const void* indices, - PathIndexType, - const float transformValues[], - PathTransformType, - int count, - const GrStencilSettings&, - const PipelineInfo&) override { - SkFAIL("Only batch implemented\n"); - } - - bool isIssued(uint32_t drawID) override { return drawID != fDrawID; } - uint32_t fDrawID; typedef GrClipTarget INHERITED; diff --git a/src/gpu/GrInOrderCommandBuilder.cpp b/src/gpu/GrInOrderCommandBuilder.cpp index b9387e9486..bbe42a6de5 100644 --- a/src/gpu/GrInOrderCommandBuilder.cpp +++ b/src/gpu/GrInOrderCommandBuilder.cpp @@ -12,19 +12,6 @@ #include "GrColor.h" #include "SkPoint.h" -static bool path_fill_type_is_winding(const GrStencilSettings& pathStencilSettings) { - static const GrStencilSettings::Face pathFace = GrStencilSettings::kFront_Face; - bool isWinding = kInvert_StencilOp != pathStencilSettings.passOp(pathFace); - if (isWinding) { - // Double check that it is in fact winding. - SkASSERT(kIncClamp_StencilOp == pathStencilSettings.passOp(pathFace)); - SkASSERT(kIncClamp_StencilOp == pathStencilSettings.failOp(pathFace)); - SkASSERT(0x1 != pathStencilSettings.writeMask(pathFace)); - SkASSERT(!pathStencilSettings.isTwoSided()); - } - return isWinding; -} - GrTargetCommands::Cmd* GrInOrderCommandBuilder::recordDrawBatch(GrBatch* batch, const GrCaps& caps) { GrBATCH_INFO("In-Recording (%s, %u)\n", batch->name(), batch->uniqueID()); @@ -40,65 +27,3 @@ GrTargetCommands::Cmd* GrInOrderCommandBuilder::recordDrawBatch(GrBatch* batch, return GrNEW_APPEND_TO_RECORDER(*this->cmdBuffer(), DrawBatch, (batch)); } - -GrTargetCommands::Cmd* -GrInOrderCommandBuilder::recordDrawPaths(State* state, - GrBufferedDrawTarget* bufferedDrawTarget, - const GrPathProcessor* pathProc, - const GrPathRange* pathRange, - const void* indexValues, - GrDrawTarget::PathIndexType indexType, - const float transformValues[], - GrDrawTarget::PathTransformType transformType, - int count, - const GrStencilSettings& stencilSettings, - const GrPipelineOptimizations& opts) { - SkASSERT(pathRange); - SkASSERT(indexValues); - SkASSERT(transformValues); - - char* savedIndices; - float* savedTransforms; - - bufferedDrawTarget->appendIndicesAndTransforms(indexValues, indexType, - transformValues, transformType, - count, &savedIndices, &savedTransforms); - - if (!this->cmdBuffer()->empty() && - Cmd::kDrawPaths_CmdType == this->cmdBuffer()->back().type()) { - // Try to combine this call with the previous DrawPaths. We do this by stenciling all the - // paths together and then covering them in a single pass. This is not equivalent to two - // separate draw calls, so we can only do it if there is no blending (no overlap would also - // work). Note that it's also possible for overlapping paths to cancel each other's winding - // numbers, and we only partially account for this by not allowing even/odd paths to be - // combined. (Glyphs in the same font tend to wind the same direction so it works out OK.) - DrawPaths* previous = static_cast<DrawPaths*>(&this->cmdBuffer()->back()); - if (pathRange == previous->pathRange() && - indexType == previous->fIndexType && - transformType == previous->fTransformType && - stencilSettings == previous->fStencilSettings && - path_fill_type_is_winding(stencilSettings) && - previous->fState == state && - !opts.willColorBlendWithDst()) { - - const int indexBytes = GrPathRange::PathIndexSizeInBytes(indexType); - const int xformSize = GrPathRendering::PathTransformSize(transformType); - if (&previous->fIndices[previous->fCount * indexBytes] == savedIndices && - (0 == xformSize || - &previous->fTransforms[previous->fCount * xformSize] == savedTransforms)) { - // Combine this DrawPaths call with the one previous. - previous->fCount += count; - return nullptr; - } - } - } - - DrawPaths* dp = GrNEW_APPEND_TO_RECORDER(*this->cmdBuffer(), DrawPaths, (state, pathRange)); - dp->fIndices = savedIndices; - dp->fIndexType = indexType; - dp->fTransforms = savedTransforms; - dp->fTransformType = transformType; - dp->fCount = count; - dp->fStencilSettings = stencilSettings; - return dp; -} diff --git a/src/gpu/GrInOrderCommandBuilder.h b/src/gpu/GrInOrderCommandBuilder.h index dbc978dd3a..e205ae49eb 100644 --- a/src/gpu/GrInOrderCommandBuilder.h +++ b/src/gpu/GrInOrderCommandBuilder.h @@ -13,22 +13,10 @@ class GrInOrderCommandBuilder : public GrCommandBuilder { public: typedef GrCommandBuilder::Cmd Cmd; - typedef GrCommandBuilder::State State; GrInOrderCommandBuilder() : INHERITED() { } Cmd* recordDrawBatch(GrBatch*, const GrCaps&) override; - Cmd* recordDrawPaths(State*, - GrBufferedDrawTarget*, - const GrPathProcessor*, - const GrPathRange*, - const void*, - GrDrawTarget::PathIndexType, - const float transformValues[], - GrDrawTarget::PathTransformType , - int, - const GrStencilSettings&, - const GrPipelineOptimizations&) override; private: typedef GrCommandBuilder INHERITED; diff --git a/src/gpu/GrPathProcessor.cpp b/src/gpu/GrPathProcessor.cpp index 3a5ab44da1..b6f174d801 100644 --- a/src/gpu/GrPathProcessor.cpp +++ b/src/gpu/GrPathProcessor.cpp @@ -46,9 +46,9 @@ void GrPathProcessor::initBatchTracker(GrBatchTracker* bt, const GrPipelineOptim local->fUsesLocalCoords = opt.readsLocalCoords(); } -bool GrPathProcessor::canMakeEqual(const GrBatchTracker& m, - const GrPrimitiveProcessor& that, - const GrBatchTracker& t) const { +bool GrPathProcessor::isEqual(const GrBatchTracker& m, + const GrPrimitiveProcessor& that, + const GrBatchTracker& t) const { if (this->classID() != that.classID() || !this->hasSameTextureAccesses(that)) { return false; } diff --git a/src/gpu/GrPathProcessor.h b/src/gpu/GrPathProcessor.h index 57c5a8ba12..2a101107f2 100644 --- a/src/gpu/GrPathProcessor.h +++ b/src/gpu/GrPathProcessor.h @@ -31,9 +31,9 @@ public: void initBatchTracker(GrBatchTracker*, const GrPipelineOptimizations&) const override; - bool canMakeEqual(const GrBatchTracker& mine, - const GrPrimitiveProcessor& that, - const GrBatchTracker& theirs) const override; + bool isEqual(const GrBatchTracker& mine, + const GrPrimitiveProcessor& that, + const GrBatchTracker& theirs) const; const char* name() const override { return "PathProcessor"; } diff --git a/src/gpu/GrPrimitiveProcessor.h b/src/gpu/GrPrimitiveProcessor.h index f6ad6b17b2..cba869eb3f 100644 --- a/src/gpu/GrPrimitiveProcessor.h +++ b/src/gpu/GrPrimitiveProcessor.h @@ -174,10 +174,6 @@ class GrPrimitiveProcessor : public GrProcessor { public: virtual void initBatchTracker(GrBatchTracker*, const GrPipelineOptimizations&) const = 0; - virtual bool canMakeEqual(const GrBatchTracker& mine, - const GrPrimitiveProcessor& that, - const GrBatchTracker& theirs) const = 0; - virtual void getInvariantOutputColor(GrInitInvariantOutput* out) const = 0; virtual void getInvariantOutputCoverage(GrInitInvariantOutput* out) const = 0; diff --git a/src/gpu/GrReorderCommandBuilder.h b/src/gpu/GrReorderCommandBuilder.h index a5d6e487dc..4670f1b176 100644 --- a/src/gpu/GrReorderCommandBuilder.h +++ b/src/gpu/GrReorderCommandBuilder.h @@ -13,30 +13,13 @@ class GrReorderCommandBuilder : public GrCommandBuilder { public: typedef GrCommandBuilder::Cmd Cmd; - typedef GrCommandBuilder::State State; GrReorderCommandBuilder() : INHERITED() {} Cmd* recordDrawBatch(GrBatch*, const GrCaps&) override; - Cmd* recordDrawPaths(State*, - GrBufferedDrawTarget*, - const GrPathProcessor*, - const GrPathRange*, - const void*, - GrDrawTarget::PathIndexType, - const float transformValues[], - GrDrawTarget::PathTransformType , - int, - const GrStencilSettings&, - const GrPipelineOptimizations&) override { - SkFAIL("Unsupported\n"); - return nullptr; - } - private: typedef GrCommandBuilder INHERITED; - }; #endif diff --git a/src/gpu/GrStencilAndCoverTextContext.cpp b/src/gpu/GrStencilAndCoverTextContext.cpp index 479213b21c..7325f155cf 100644 --- a/src/gpu/GrStencilAndCoverTextContext.cpp +++ b/src/gpu/GrStencilAndCoverTextContext.cpp @@ -21,12 +21,13 @@ #include "SkTextMapStateProc.h" #include "SkTextFormatParams.h" +#include "batches/GrDrawPathBatch.h" + GrStencilAndCoverTextContext::GrStencilAndCoverTextContext(GrContext* context, const SkSurfaceProps& surfaceProps) - : GrTextContext(context, surfaceProps) - , fStroke(SkStrokeRec::kFill_InitStyle) - , fQueuedGlyphCount(0) - , fFallbackGlyphsIdx(kGlyphBufferSize) { + : INHERITED(context, surfaceProps) + , fDraw(nullptr) + , fStroke(SkStrokeRec::kFill_InitStyle) { } GrStencilAndCoverTextContext* @@ -154,7 +155,7 @@ void GrStencilAndCoverTextContext::onDrawText(GrDrawContext* dc, GrRenderTarget* const SkGlyph& glyph = glyphCacheProc(fGlyphCache, &text, 0, 0); fx += SkFixedMul(autokern.adjust(glyph), fixedSizeRatio); if (glyph.fWidth) { - this->appendGlyph(dc, glyph, SkPoint::Make(SkFixedToScalar(fx), SkFixedToScalar(fy))); + this->appendGlyph(glyph, SkPoint::Make(SkFixedToScalar(fx), SkFixedToScalar(fy))); } fx += SkFixedMul(glyph.fAdvanceX, fixedSizeRatio); @@ -208,7 +209,7 @@ void GrStencilAndCoverTextContext::onDrawPosText(GrDrawContext* dc, GrRenderTarg SkPoint loc; alignProc(tmsLoc, glyph, &loc); - this->appendGlyph(dc, glyph, loc); + this->appendGlyph(glyph, loc); } pos += scalarsPerPosition; } @@ -398,20 +399,22 @@ bool GrStencilAndCoverTextContext::mapToFallbackContext(SkMatrix* inverse) { return true; } -inline void GrStencilAndCoverTextContext::appendGlyph(GrDrawContext* dc, - const SkGlyph& glyph, - const SkPoint& pos) { - if (fQueuedGlyphCount >= fFallbackGlyphsIdx) { - SkASSERT(fQueuedGlyphCount == fFallbackGlyphsIdx); - this->flush(dc); +inline void GrStencilAndCoverTextContext::appendGlyph(const SkGlyph& glyph, const SkPoint& pos) { + // Stick the glyphs we can't draw into the fallback arrays. + if (SkMask::kARGB32_Format == glyph.fMaskFormat) { + fFallbackIndices.push_back(glyph.getGlyphID()); + fFallbackPositions.push_back().set(fTextInverseRatio * pos.x(), + -fTextInverseRatio * pos.y()); + } else { + // TODO: infer the reserve count from the text length. + if (!fDraw) { + fDraw = GrPathRangeDraw::Create(fGlyphs, + GrPathRendering::kTranslate_PathTransformType, + 64); + } + float translate[] = { fTextInverseRatio * pos.x(), -fTextInverseRatio * pos.y() }; + fDraw->append(glyph.getGlyphID(), translate); } - - // Stick the glyphs we can't draw at the end of the buffer, growing backwards. - int index = (SkMask::kARGB32_Format == glyph.fMaskFormat) ? - --fFallbackGlyphsIdx : fQueuedGlyphCount++; - - fGlyphIndices[index] = glyph.getGlyphID(); - fGlyphPositions[index].set(fTextInverseRatio * pos.x(), -fTextInverseRatio * pos.y()); } static const SkScalar* get_xy_scalar_array(const SkPoint* pointArray) { @@ -422,7 +425,8 @@ static const SkScalar* get_xy_scalar_array(const SkPoint* pointArray) { } void GrStencilAndCoverTextContext::flush(GrDrawContext* dc) { - if (fQueuedGlyphCount > 0) { + if (fDraw) { + SkASSERT(fDraw->count()); SkAutoTUnref<GrPathProcessor> pp(GrPathProcessor::Create(fPaint.getColor(), fViewMatrix, fLocalMatrix)); @@ -443,20 +447,13 @@ void GrStencilAndCoverTextContext::flush(GrDrawContext* dc) { *pipelineBuilder.stencil() = kStencilPass; - SkASSERT(kGlyphBufferSize == fFallbackGlyphsIdx); - - dc->drawPaths(&pipelineBuilder, pp, fGlyphs, - fGlyphIndices, GrPathRange::kU16_PathIndexType, - get_xy_scalar_array(fGlyphPositions), - GrPathRendering::kTranslate_PathTransformType, - fQueuedGlyphCount, GrPathRendering::kWinding_FillType); - - fQueuedGlyphCount = 0; + dc->drawPathsFromRange(&pipelineBuilder, pp, fDraw, GrPathRendering::kWinding_FillType); + fDraw->unref(); + fDraw = nullptr; } - if (fFallbackGlyphsIdx < kGlyphBufferSize) { - int fallbackGlyphCount = kGlyphBufferSize - fFallbackGlyphsIdx; - + if (fFallbackIndices.count()) { + SkASSERT(fFallbackPositions.count() == fFallbackIndices.count()); GrPaint paintFallback(fPaint); SkPaint skPaintFallback(fSkPaint); @@ -468,22 +465,26 @@ void GrStencilAndCoverTextContext::flush(GrDrawContext* dc) { SkMatrix inverse; if (this->mapToFallbackContext(&inverse)) { - inverse.mapPoints(&fGlyphPositions[fFallbackGlyphsIdx], fallbackGlyphCount); + inverse.mapPoints(fFallbackPositions.begin(), fFallbackPositions.count()); } fFallbackTextContext->drawPosText(dc, fRenderTarget, fClip, paintFallback, skPaintFallback, - fViewMatrix, (char*)&fGlyphIndices[fFallbackGlyphsIdx], - 2 * fallbackGlyphCount, - get_xy_scalar_array(&fGlyphPositions[fFallbackGlyphsIdx]), + fViewMatrix, (char*)fFallbackIndices.begin(), + sizeof(uint16_t) * fFallbackIndices.count(), + get_xy_scalar_array(fFallbackPositions.begin()), 2, SkPoint::Make(0, 0), fRegionClipBounds); - - fFallbackGlyphsIdx = kGlyphBufferSize; + fFallbackIndices.reset(); + fFallbackPositions.reset(); } } void GrStencilAndCoverTextContext::finish(GrDrawContext* dc) { this->flush(dc); + SkASSERT(!fDraw); + SkASSERT(!fFallbackIndices.count()); + SkASSERT(!fFallbackPositions.count()); + fGlyphs->unref(); fGlyphs = nullptr; @@ -492,4 +493,3 @@ void GrStencilAndCoverTextContext::finish(GrDrawContext* dc) { fViewMatrix = fContextInitialMatrix; } - diff --git a/src/gpu/GrStencilAndCoverTextContext.h b/src/gpu/GrStencilAndCoverTextContext.h index 295e958036..4c57d3cb81 100644 --- a/src/gpu/GrStencilAndCoverTextContext.h +++ b/src/gpu/GrStencilAndCoverTextContext.h @@ -15,6 +15,7 @@ class GrTextStrike; class GrPath; class GrPathRange; +class GrPathRangeDraw; class SkSurfaceProps; /* @@ -29,8 +30,6 @@ public: virtual ~GrStencilAndCoverTextContext(); private: - static const int kGlyphBufferSize = 1024; - enum RenderMode { /** * This is the render mode used by drawText(), which is mainly used by @@ -55,12 +54,13 @@ private: SkScalar fTextRatio; float fTextInverseRatio; SkGlyphCache* fGlyphCache; + GrPathRange* fGlyphs; + GrPathRangeDraw* fDraw; GrStrokeInfo fStroke; - uint16_t fGlyphIndices[kGlyphBufferSize]; - SkPoint fGlyphPositions[kGlyphBufferSize]; - int fQueuedGlyphCount; - int fFallbackGlyphsIdx; + SkSTArray<32, uint16_t, true> fFallbackIndices; + SkSTArray<32, SkPoint, true> fFallbackPositions; + SkMatrix fContextInitialMatrix; SkMatrix fViewMatrix; SkMatrix fLocalMatrix; @@ -92,10 +92,11 @@ private: size_t textByteLength, RenderMode, const SkMatrix& viewMatrix, const SkIRect& regionClipBounds); bool mapToFallbackContext(SkMatrix* inverse); - void appendGlyph(GrDrawContext* dc, const SkGlyph&, const SkPoint&); + void appendGlyph(const SkGlyph&, const SkPoint&); void flush(GrDrawContext* dc); void finish(GrDrawContext* dc); + typedef GrTextContext INHERITED; }; #endif diff --git a/src/gpu/GrTargetCommands.cpp b/src/gpu/GrTargetCommands.cpp index f2e696426f..2194e08f0a 100644 --- a/src/gpu/GrTargetCommands.cpp +++ b/src/gpu/GrTargetCommands.cpp @@ -43,29 +43,6 @@ void GrTargetCommands::flush(GrGpu* gpu, GrResourceProvider* resourceProvider) { fLastFlushToken = flushState.lastFlushedToken(); } -void GrTargetCommands::DrawPath::execute(GrBatchFlushState* state) { - if (!fState->fCompiled) { - state->gpu()->buildProgramDesc(&fState->fDesc, *fState->fPrimitiveProcessor, - *fState->getPipeline(), fState->fBatchTracker); - fState->fCompiled = true; - } - GrPathRendering::DrawPathArgs args(fState->fPrimitiveProcessor.get(), fState->getPipeline(), - &fState->fDesc, &fState->fBatchTracker, &fStencilSettings); - state->gpu()->pathRendering()->drawPath(args, this->path()); -} - -void GrTargetCommands::DrawPaths::execute(GrBatchFlushState* state) { - if (!fState->fCompiled) { - state->gpu()->buildProgramDesc(&fState->fDesc, *fState->fPrimitiveProcessor, - *fState->getPipeline(), fState->fBatchTracker); - fState->fCompiled = true; - } - GrPathRendering::DrawPathArgs args(fState->fPrimitiveProcessor.get(), fState->getPipeline(), - &fState->fDesc, &fState->fBatchTracker, &fStencilSettings); - state->gpu()->pathRendering()->drawPaths(args, this->pathRange(), fIndices, fIndexType, - fTransforms, fTransformType, fCount); -} - void GrTargetCommands::DrawBatch::execute(GrBatchFlushState* state) { fBatch->draw(state); } diff --git a/src/gpu/GrTargetCommands.h b/src/gpu/GrTargetCommands.h index 4f804c31b9..5d9cdfc5be 100644 --- a/src/gpu/GrTargetCommands.h +++ b/src/gpu/GrTargetCommands.h @@ -30,8 +30,6 @@ public: class Cmd : ::SkNoncopyable { public: enum CmdType { - kDrawPath_CmdType = 2, - kDrawPaths_CmdType = 3, kDrawBatch_CmdType = 4, }; @@ -73,88 +71,6 @@ private: typedef GrGpu::DrawArgs DrawArgs; - // TODO: This can be just a pipeline once paths are in batch, and it should live elsewhere - struct StateForPathDraw : public SkNVRefCnt<StateForPathDraw> { - // TODO get rid of the prim proc parameter when we use batch everywhere - StateForPathDraw(const GrPrimitiveProcessor* primProc = nullptr) - : fPrimitiveProcessor(primProc) - , fCompiled(false) {} - - ~StateForPathDraw() { reinterpret_cast<GrPipeline*>(fPipeline.get())->~GrPipeline(); } - - // This function is only for getting the location in memory where we will create our - // pipeline object. - void* pipelineLocation() { return fPipeline.get(); } - - 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 operator delete(void* p) {} - void* operator new(size_t) { - SkFAIL("All States are created by placement new."); - return sk_malloc_throw(0); - } - - void* operator new(size_t, void* p) { return p; } - void operator delete(void* target, void* placement) { - ::operator delete(target, placement); - } - - typedef GrPendingProgramElement<const GrPrimitiveProcessor> ProgramPrimitiveProcessor; - ProgramPrimitiveProcessor fPrimitiveProcessor; - SkAlignedSStorage<sizeof(GrPipeline)> fPipeline; - GrProgramDesc fDesc; - GrBatchTracker fBatchTracker; - bool fCompiled; - }; - // TODO remove this when State is just a pipeline - friend SkNVRefCnt<StateForPathDraw>; - - struct DrawPath : public Cmd { - DrawPath(StateForPathDraw* state, const GrPath* path) - : Cmd(kDrawPath_CmdType) - , fState(SkRef(state)) - , fPath(path) {} - - const GrPath* path() const { return fPath.get(); } - - void execute(GrBatchFlushState*) override; - - SkAutoTUnref<StateForPathDraw> fState; - GrStencilSettings fStencilSettings; - private: - GrPendingIOResource<const GrPath, kRead_GrIOType> fPath; - }; - - struct DrawPaths : public Cmd { - DrawPaths(StateForPathDraw* state, const GrPathRange* pathRange) - : Cmd(kDrawPaths_CmdType) - , fState(SkRef(state)) - , fPathRange(pathRange) {} - - const GrPathRange* pathRange() const { return fPathRange.get(); } - - void execute(GrBatchFlushState*) override; - - SkAutoTUnref<StateForPathDraw> fState; - char* fIndices; - GrDrawTarget::PathIndexType fIndexType; - float* fTransforms; - GrDrawTarget::PathTransformType fTransformType; - int fCount; - GrStencilSettings fStencilSettings; - - private: - GrPendingIOResource<const GrPathRange, kRead_GrIOType> fPathRange; - }; - struct DrawBatch : public Cmd { DrawBatch(GrBatch* batch) : Cmd(kDrawBatch_CmdType) diff --git a/src/gpu/batches/GrDrawPathBatch.cpp b/src/gpu/batches/GrDrawPathBatch.cpp new file mode 100644 index 0000000000..300024ee2f --- /dev/null +++ b/src/gpu/batches/GrDrawPathBatch.cpp @@ -0,0 +1,138 @@ +/* + * Copyright 2015 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "GrDrawPathBatch.h" + +SkString GrDrawPathBatch::dumpInfo() const { + SkString string; + string.printf("PATH: 0x%p", fPath.get()); + return string; +} + +void GrDrawPathBatch::onDraw(GrBatchFlushState* state) { + GrProgramDesc desc; + state->gpu()->buildProgramDesc(&desc, *this->pathProcessor(), + *this->pipeline(), *this->tracker()); + GrPathRendering::DrawPathArgs args(this->pathProcessor(), this->pipeline(), + &desc, this->tracker(), &this->stencilSettings()); + state->gpu()->pathRendering()->drawPath(args, fPath.get()); +} + +GrDrawPathRangeBatch::~GrDrawPathRangeBatch() { + for (DrawList::Iter iter(fDraws); iter.get(); iter.next()) { + (*iter.get())->unref(); + } +} + +SkString GrDrawPathRangeBatch::dumpInfo() const { + SkString string; + string.printf("RANGE: 0x%p COUNTS: [", *fDraws.head()); + for (DrawList::Iter iter(fDraws); iter.get(); iter.next()) { + string.appendf("%d ,", (*iter.get())->count()); + } + string.remove(string.size() - 2, 2); + string.append("]"); + return string; +} + +bool GrDrawPathRangeBatch::isWinding() const { + static const GrStencilSettings::Face pathFace = GrStencilSettings::kFront_Face; + bool isWinding = kInvert_StencilOp != this->stencilSettings().passOp(pathFace); + if (isWinding) { + // Double check that it is in fact winding. + SkASSERT(kIncClamp_StencilOp == this->stencilSettings().passOp(pathFace)); + SkASSERT(kIncClamp_StencilOp == this->stencilSettings().failOp(pathFace)); + SkASSERT(0x1 != this->stencilSettings().writeMask(pathFace)); + SkASSERT(!this->stencilSettings().isTwoSided()); + } + return isWinding; +} + +GrDrawPathRangeBatch::GrDrawPathRangeBatch(const GrPathProcessor* pathProc, + GrPathRangeDraw* pathRangeDraw) + : INHERITED(pathProc) + , fDraws(4) { + SkDEBUGCODE(pathRangeDraw->fUsedInBatch = true;) + this->initClassID<GrDrawPathRangeBatch>(); + fDraws.addToHead(SkRef(pathRangeDraw)); + fTotalPathCount = pathRangeDraw->count(); + // Don't compute a bounding box. For dst copy texture, we'll opt instead for it to just copy + // the entire dst. Realistically this is a moot point, because any context that supports + // NV_path_rendering will also support NV_blend_equation_advanced. + // For clipping we'll just skip any optimizations based on the bounds. + fBounds.setLargest(); +} + +bool GrDrawPathRangeBatch::onCombineIfPossible(GrBatch* t, const GrCaps& caps) { + GrDrawPathRangeBatch* that = t->cast<GrDrawPathRangeBatch>(); + if (!GrPathRangeDraw::CanMerge(**this->fDraws.head(), **that->fDraws.head())) { + return false; + } + if (!GrPipeline::AreEqual(*this->pipeline(), *that->pipeline(), false)) { + return false; + } + if (!this->pathProcessor()->isEqual(*this->tracker(), *that->pathProcessor(), + *that->tracker())) { + return false; + } + // TODO: Check some other things here. (winding, opaque, pathProc color, vm, ...) + // Try to combine this call with the previous DrawPaths. We do this by stenciling all the + // paths together and then covering them in a single pass. This is not equivalent to two + // separate draw calls, so we can only do it if there is no blending (no overlap would also + // work). Note that it's also possible for overlapping paths to cancel each other's winding + // numbers, and we only partially account for this by not allowing even/odd paths to be + // combined. (Glyphs in the same font tend to wind the same direction so it works out OK.) + if (!this->isWinding() || + this->stencilSettings() != that->stencilSettings() || + this->opts().willColorBlendWithDst()) { + return false; + } + SkASSERT(!that->opts().willColorBlendWithDst()); + fTotalPathCount += that->fTotalPathCount; + while (GrPathRangeDraw** head = that->fDraws.head()) { + fDraws.addToTail(*head); + // We're stealing that's refs, so pop without unreffing. + that->fDraws.popHead(); + } + return true; +} + +void GrDrawPathRangeBatch::onDraw(GrBatchFlushState* state) { + GrProgramDesc desc; + state->gpu()->buildProgramDesc(&desc, *this->pathProcessor(), *this->pipeline(), + *this->tracker()); + GrPathRendering::DrawPathArgs args(this->pathProcessor(), this->pipeline(), + &desc, this->tracker(), &this->stencilSettings()); + if (fDraws.count() == 1) { + const GrPathRangeDraw& draw = **fDraws.head(); + state->gpu()->pathRendering()->drawPaths(args, draw.range(), draw.indices(), + GrPathRange::kU16_PathIndexType, draw.transforms(), draw.transformType(), + draw.count()); + return; + } + + const GrPathRange* range = (*fDraws.head())->range(); + GrPathRendering::PathTransformType transformType = (*fDraws.head())->transformType(); + int floatsPerTransform = GrPathRendering::PathTransformSize(transformType); + SkAutoSTMalloc<512, float> transformStorage(floatsPerTransform * fTotalPathCount); + SkAutoSTMalloc<256, uint16_t> indexStorage(fTotalPathCount); + uint16_t* indices = indexStorage.get(); + float* transforms = transformStorage.get(); + for (DrawList::Iter iter(fDraws); iter.get(); iter.next()) { + SkASSERT((*iter.get())->transformType() == transformType); + SkASSERT((*iter.get())->range() == range); + int cnt = (*iter.get())->count(); + memcpy(indices, (*iter.get())->indices(), cnt * sizeof(uint16_t)); + indices += cnt; + memcpy(transforms, (*iter.get())->transforms(), cnt * floatsPerTransform * sizeof(float)); + transforms += cnt * floatsPerTransform; + } + SkASSERT(indices - indexStorage.get() == fTotalPathCount); + state->gpu()->pathRendering()->drawPaths(args, range, indexStorage.get(), + GrPathRange::kU16_PathIndexType, transformStorage.get(), transformType, + fTotalPathCount); +} diff --git a/src/gpu/batches/GrDrawPathBatch.h b/src/gpu/batches/GrDrawPathBatch.h index cf67cd9bba..e605b3e292 100644 --- a/src/gpu/batches/GrDrawPathBatch.h +++ b/src/gpu/batches/GrDrawPathBatch.h @@ -8,68 +8,170 @@ #ifndef GrDrawPathBatch_DEFINED #define GrDrawPathBatch_DEFINED +#include "GrBatchFlushState.h" #include "GrDrawBatch.h" #include "GrGpu.h" #include "GrPath.h" #include "GrPathRendering.h" #include "GrPathProcessor.h" -class GrDrawPathBatch final : public GrDrawBatch { +#include "SkTLList.h" + +class GrDrawPathBatchBase : public GrDrawBatch { +public: + void getInvariantOutputColor(GrInitInvariantOutput* out) const override { + this->pathProcessor()->getInvariantOutputColor(out); + } + + void getInvariantOutputCoverage(GrInitInvariantOutput* out) const override { + this->pathProcessor()->getInvariantOutputCoverage(out); + } + + void setStencilSettings(const GrStencilSettings& stencil) { fStencilSettings = stencil; } + +protected: + GrDrawPathBatchBase(const GrPathProcessor* pathProc) : fPrimitiveProcessor(pathProc) {} + + GrBatchTracker* tracker() { return reinterpret_cast<GrBatchTracker*>(&fWhatchamacallit); } + const GrPathProcessor* pathProcessor() const { return fPrimitiveProcessor.get(); } + const GrStencilSettings& stencilSettings() const { return fStencilSettings; } + const GrPipelineOptimizations& opts() const { return fOpts; } + +private: + void initBatchTracker(const GrPipelineOptimizations& opts) override { + this->pathProcessor()->initBatchTracker(this->tracker(), opts); + fOpts = opts; + } + + GrPendingProgramElement<const GrPathProcessor> fPrimitiveProcessor; + PathBatchTracker fWhatchamacallit; // TODO: delete this + GrStencilSettings fStencilSettings; + GrPipelineOptimizations fOpts; + + typedef GrDrawBatch INHERITED; +}; + +class GrDrawPathBatch final : public GrDrawPathBatchBase { public: - // This must return the concrete type because we install the stencil settings late :( - static GrDrawPathBatch* Create(const GrPathProcessor* primProc, const GrPath* path) { + // This can't return a more abstract type because we install the stencil settings late :( + static GrDrawPathBatchBase* Create(const GrPathProcessor* primProc, const GrPath* path) { return new GrDrawPathBatch(primProc, path); } const char* name() const override { return "DrawPath"; } - SkString dumpInfo() const override { - SkString string; - string.printf("PATH: 0x%p", fPath.get()); - return string; + SkString dumpInfo() const override; + +private: + GrDrawPathBatch(const GrPathProcessor* pathProc, const GrPath* path) + : INHERITED(pathProc) + , fPath(path) { + fBounds = path->getBounds(); + this->pathProcessor()->viewMatrix().mapRect(&fBounds); + this->initClassID<GrDrawPathBatch>(); } - void getInvariantOutputColor(GrInitInvariantOutput* out) const override { - fPrimitiveProcessor->getInvariantOutputColor(out); + bool onCombineIfPossible(GrBatch* t, const GrCaps& caps) override { return false; } + + void onPrepare(GrBatchFlushState*) override {} + + void onDraw(GrBatchFlushState* state) override; + + GrPendingIOResource<const GrPath, kRead_GrIOType> fPath; + + typedef GrDrawPathBatchBase INHERITED; +}; + +/** + * This could be nested inside the batch class, but for now it must be declarable in a public + * header (GrDrawContext) + */ +class GrPathRangeDraw : public GrNonAtomicRef { +public: + typedef GrPathRendering::PathTransformType TransformType; + + static GrPathRangeDraw* Create(GrPathRange* range, TransformType transformType, + int reserveCnt) { + return SkNEW_ARGS(GrPathRangeDraw, (range, transformType, reserveCnt)); } - void getInvariantOutputCoverage(GrInitInvariantOutput* out) const override { - fPrimitiveProcessor->getInvariantOutputCoverage(out); + void append(uint16_t index, float transform[]) { + fTransforms.push_back_n(GrPathRendering::PathTransformSize(fTransformType), transform); + fIndices.push_back(index); } - void setStencilSettings(const GrStencilSettings& stencil) { fStencilSettings = stencil; } + int count() const { return fIndices.count(); } + + TransformType transformType() const { return fTransformType; } + + const float* transforms() const { return fTransforms.begin(); } + + const uint16_t* indices() const { return fIndices.begin(); } + + const GrPathRange* range() const { return fPathRange.get(); } + + static bool CanMerge(const GrPathRangeDraw& a, const GrPathRangeDraw& b) { + return a.transformType() == b.transformType() && a.range() == b.range(); + } private: - GrBatchTracker* tracker() { return reinterpret_cast<GrBatchTracker*>(&fWhatchamacallit); } - GrDrawPathBatch(const GrPathProcessor* primProc, const GrPath* path) - : fPrimitiveProcessor(primProc) - , fPath(path) { - fBounds = path->getBounds(); - primProc->viewMatrix().mapRect(&fBounds); - this->initClassID<GrDrawPathBatch>(); + GrPathRangeDraw(GrPathRange* range, TransformType transformType, int reserveCnt) + : fPathRange(SkRef(range)) + , fTransformType(transformType) + , fIndices(reserveCnt) + , fTransforms(reserveCnt * GrPathRendering::PathTransformSize(transformType)) { + SkDEBUGCODE(fUsedInBatch = false;) } - void initBatchTracker(const GrPipelineOptimizations& opts) override { - fPrimitiveProcessor->initBatchTracker(this->tracker(), opts); + // Reserve space for 64 paths where indices are 16 bit and transforms are translations. + static const int kIndexReserveCnt = 64; + static const int kTransformBufferReserveCnt = 2 * 64; + + GrPendingIOResource<const GrPathRange, kRead_GrIOType> fPathRange; + GrPathRendering::PathTransformType fTransformType; + SkSTArray<kIndexReserveCnt, uint16_t, true> fIndices; + SkSTArray<kTransformBufferReserveCnt, float, true> fTransforms; + + // To ensure we don't reuse these across batches. +#ifdef SK_DEBUG + bool fUsedInBatch; + friend class GrDrawPathRangeBatch; +#endif + + typedef GrNonAtomicRef INHERITED; +}; + +// Template this if we decide to support index types other than 16bit +class GrDrawPathRangeBatch final : public GrDrawPathBatchBase { +public: + // This can't return a more abstracet type because we install the stencil settings late :( + static GrDrawPathBatchBase* Create(const GrPathProcessor* pathProc, + GrPathRangeDraw* pathRangeDraw) { + return SkNEW_ARGS(GrDrawPathRangeBatch, (pathProc, pathRangeDraw)); } - bool onCombineIfPossible(GrBatch* t, const GrCaps& caps) override { return false; } + ~GrDrawPathRangeBatch() override; + + const char* name() const override { return "DrawPathRange"; } + + SkString dumpInfo() const override; + +private: + inline bool isWinding() const; + + GrDrawPathRangeBatch(const GrPathProcessor* pathProc, GrPathRangeDraw* pathRangeDraw); + + bool onCombineIfPossible(GrBatch* t, const GrCaps& caps) override; void onPrepare(GrBatchFlushState*) override {} - void onDraw(GrBatchFlushState* state) override { - GrProgramDesc desc; - state->gpu()->buildProgramDesc(&desc, *fPrimitiveProcessor.get(), - *this->pipeline(), *this->tracker()); - GrPathRendering::DrawPathArgs args(fPrimitiveProcessor.get(), this->pipeline(), - &desc, this->tracker(), &fStencilSettings); - state->gpu()->pathRendering()->drawPath(args, fPath.get()); - } + void onDraw(GrBatchFlushState* state) override; + + typedef SkTLList<GrPathRangeDraw*> DrawList; + DrawList fDraws; + int fTotalPathCount; - GrPendingProgramElement<const GrPathProcessor> fPrimitiveProcessor; - PathBatchTracker fWhatchamacallit; // TODO: delete this - GrStencilSettings fStencilSettings; - GrPendingIOResource<const GrPath, kRead_GrIOType> fPath; + typedef GrDrawPathBatchBase INHERITED; }; #endif |