BUG=skia:

Review URL: https://codereview.chromium.org/1315563003
This commit is contained in:
bsalomon 2015-09-09 09:48:06 -07:00 коммит произвёл Commit bot
Родитель 5ca4fa3846
Коммит 1fcc01c415
22 изменённых файлов: 380 добавлений и 593 удалений

Просмотреть файл

@ -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',

Просмотреть файл

@ -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

Просмотреть файл

@ -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();
}

Просмотреть файл

@ -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;
};

Просмотреть файл

@ -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() {}

Просмотреть файл

@ -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) {

Просмотреть файл

@ -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,
@ -404,22 +372,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,

Просмотреть файл

@ -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.
@ -186,10 +183,6 @@ public:
bool programUnitTest(GrContext* owner, int maxStages);
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*);

Просмотреть файл

@ -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");

Просмотреть файл

@ -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;

Просмотреть файл

@ -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;
}

Просмотреть файл

@ -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;

Просмотреть файл

@ -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;
}

Просмотреть файл

@ -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"; }

Просмотреть файл

@ -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;

Просмотреть файл

@ -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

Просмотреть файл

@ -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;
}

Просмотреть файл

@ -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

Просмотреть файл

@ -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);
}

Просмотреть файл

@ -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)

Просмотреть файл

@ -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);
}

Просмотреть файл

@ -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:
// This must return the concrete type because we install the stencil settings late :(
static GrDrawPathBatch* Create(const GrPathProcessor* primProc, const GrPath* path) {
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 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;
}
void getInvariantOutputColor(GrInitInvariantOutput* out) const override {
fPrimitiveProcessor->getInvariantOutputColor(out);
}
void getInvariantOutputCoverage(GrInitInvariantOutput* out) const override {
fPrimitiveProcessor->getInvariantOutputCoverage(out);
}
void setStencilSettings(const GrStencilSettings& stencil) { fStencilSettings = stencil; }
SkString dumpInfo() const override;
private:
GrBatchTracker* tracker() { return reinterpret_cast<GrBatchTracker*>(&fWhatchamacallit); }
GrDrawPathBatch(const GrPathProcessor* primProc, const GrPath* path)
: fPrimitiveProcessor(primProc)
, fPath(path) {
GrDrawPathBatch(const GrPathProcessor* pathProc, const GrPath* path)
: INHERITED(pathProc)
, fPath(path) {
fBounds = path->getBounds();
primProc->viewMatrix().mapRect(&fBounds);
this->pathProcessor()->viewMatrix().mapRect(&fBounds);
this->initClassID<GrDrawPathBatch>();
}
void initBatchTracker(const GrPipelineOptimizations& opts) override {
fPrimitiveProcessor->initBatchTracker(this->tracker(), opts);
}
bool onCombineIfPossible(GrBatch* t, const GrCaps& caps) override { return false; }
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;
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));
}
GrPendingProgramElement<const GrPathProcessor> fPrimitiveProcessor;
PathBatchTracker fWhatchamacallit; // TODO: delete this
GrStencilSettings fStencilSettings;
GrPendingIOResource<const GrPath, kRead_GrIOType> fPath;
void append(uint16_t index, float transform[]) {
fTransforms.push_back_n(GrPathRendering::PathTransformSize(fTransformType), transform);
fIndices.push_back(index);
}
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:
GrPathRangeDraw(GrPathRange* range, TransformType transformType, int reserveCnt)
: fPathRange(SkRef(range))
, fTransformType(transformType)
, fIndices(reserveCnt)
, fTransforms(reserveCnt * GrPathRendering::PathTransformSize(transformType)) {
SkDEBUGCODE(fUsedInBatch = false;)
}
// 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));
}
~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;
typedef SkTLList<GrPathRangeDraw*> DrawList;
DrawList fDraws;
int fTotalPathCount;
typedef GrDrawPathBatchBase INHERITED;
};
#endif