зеркало из https://github.com/mozilla/moz-skia.git
GrPathRangeBatch
BUG=skia: Review URL: https://codereview.chromium.org/1315563003
This commit is contained in:
Родитель
5ca4fa3846
Коммит
1fcc01c415
|
@ -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
|
||||
|
|
Загрузка…
Ссылка в новой задаче