aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--gyp/gpu.gypi1
-rw-r--r--include/gpu/GrDrawContext.h19
-rw-r--r--src/gpu/GrBufferedDrawTarget.cpp62
-rw-r--r--src/gpu/GrBufferedDrawTarget.h69
-rw-r--r--src/gpu/GrCommandBuilder.h14
-rw-r--r--src/gpu/GrDrawContext.cpp20
-rw-r--r--src/gpu/GrDrawTarget.cpp84
-rw-r--r--src/gpu/GrDrawTarget.h46
-rw-r--r--src/gpu/GrGeometryProcessor.h8
-rw-r--r--src/gpu/GrImmediateDrawTarget.h14
-rw-r--r--src/gpu/GrInOrderCommandBuilder.cpp75
-rw-r--r--src/gpu/GrInOrderCommandBuilder.h12
-rw-r--r--src/gpu/GrPathProcessor.cpp6
-rw-r--r--src/gpu/GrPathProcessor.h6
-rw-r--r--src/gpu/GrPrimitiveProcessor.h4
-rw-r--r--src/gpu/GrReorderCommandBuilder.h17
-rw-r--r--src/gpu/GrStencilAndCoverTextContext.cpp78
-rw-r--r--src/gpu/GrStencilAndCoverTextContext.h15
-rw-r--r--src/gpu/GrTargetCommands.cpp23
-rw-r--r--src/gpu/GrTargetCommands.h84
-rw-r--r--src/gpu/batches/GrDrawPathBatch.cpp138
-rw-r--r--src/gpu/batches/GrDrawPathBatch.h170
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