Combine similar DrawPaths calls in GrInOrderDrawBuffer

Combines adjacent DrawPaths commands into one single call when a
conservative set of conditions are met. The end result is that whole
paragraphs can be drawn with a single call to
gliStencilThenCoverFillPathInstancedNV(), rather than one call for
each line.

BUG=skia:

Review URL: https://codereview.chromium.org/712223002
This commit is contained in:
cdalton 2014-11-13 11:54:20 -08:00 committed by Commit bot
parent f4905ccb6c
commit 3fc6a2fdb2
4 changed files with 107 additions and 42 deletions

View File

@ -50,3 +50,7 @@ imagemagnifier
#reed #reed
modecolorfilters modecolorfilters
# cdalton https://codereview.chromium.org/712223002
# Pixels off by one from covering gradient fills with different bounding boxes
textblobshader

View File

@ -50,11 +50,11 @@ public:
struct ScissorState { struct ScissorState {
ScissorState() : fEnabled(false) {} ScissorState() : fEnabled(false) {}
void set(const SkIRect& rect) { fRect = rect; fEnabled = true; } void set(const SkIRect& rect) { fRect = rect; fEnabled = true; }
bool operator==(const ScissorState& other) { bool operator==(const ScissorState& other) const {
return fEnabled == other.fEnabled && return fEnabled == other.fEnabled &&
(false == fEnabled || fRect == other.fRect); (false == fEnabled || fRect == other.fRect);
} }
bool operator!=(const ScissorState& other) { return !(*this == other); } bool operator!=(const ScissorState& other) const { return !(*this == other); }
bool fEnabled; bool fEnabled;
SkIRect fRect; SkIRect fRect;
}; };

View File

@ -33,6 +33,9 @@ GrInOrderDrawBuffer::GrInOrderDrawBuffer(GrGpu* gpu,
SkASSERT(vertexPool); SkASSERT(vertexPool);
SkASSERT(indexPool); SkASSERT(indexPool);
fPathIndexBuffer.setReserve(kPathIdxBufferMinReserve);
fPathTransformBuffer.setReserve(kPathXformBufferMinReserve);
GeometryPoolState& poolState = fGeoPoolStateStack.push_back(); GeometryPoolState& poolState = fGeoPoolStateStack.push_back();
poolState.fUsedPoolVertexBytes = 0; poolState.fUsedPoolVertexBytes = 0;
poolState.fUsedPoolIndexBytes = 0; poolState.fUsedPoolIndexBytes = 0;
@ -102,6 +105,32 @@ static void set_vertex_attributes(GrDrawState* drawState, bool hasLocalCoords, G
} }
} }
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;
}
template<typename T> static void reset_data_buffer(SkTDArray<T>* buffer, int minReserve) {
// Assume the next time this buffer fills up it will use approximately the same amount
// of space as last time. Only resize if we're using less than a third of the
// allocated space, and leave enough for 50% growth over last time.
if (3 * buffer->count() < buffer->reserved() && buffer->reserved() > minReserve) {
int reserve = SkTMax(minReserve, buffer->count() * 3 / 2);
buffer->reset();
buffer->setReserve(reserve);
} else {
buffer->rewind();
}
}
enum { enum {
kTraceCmdBit = 0x80, kTraceCmdBit = 0x80,
kCmdMask = 0x7f, kCmdMask = 0x7f,
@ -335,15 +364,35 @@ void GrInOrderDrawBuffer::onDrawPaths(const GrPathRange* pathRange,
this->recordStateIfNecessary(GrGpu::kDrawPaths_DrawType, dstCopy); this->recordStateIfNecessary(GrGpu::kDrawPaths_DrawType, dstCopy);
int sizeOfIndices = sizeof(uint32_t) * count; uint32_t* savedIndices = fPathIndexBuffer.append(count, indices);
int sizeOfTransforms = sizeof(float) * count * float* savedTransforms = fPathTransformBuffer.append(count *
GrPathRendering::PathTransformSize(transformsType); GrPathRendering::PathTransformSize(transformsType), transforms);
DrawPaths* dp = GrNEW_APPEND_WITH_DATA_TO_RECORDER(fCmdBuffer, DrawPaths, (pathRange), if (kDrawPaths_Cmd == strip_trace_bit(fCmdBuffer.back().fType)) {
sizeOfIndices + sizeOfTransforms); // The previous command was also DrawPaths. Try to collapse this call into the one
memcpy(dp->indices(), indices, sizeOfIndices); // before. Note that stencilling all the paths at once, then covering, may not be
// equivalent to two separate draw calls if there is overlap. Blending won't work,
// and the combined calls may also cancel each other's winding numbers in some
// places. For now the winding numbers are only an issue if the fill is even/odd,
// because DrawPaths is currently only used for glyphs, and glyphs in the same
// font tend to all wind in the same direction.
DrawPaths* previous = static_cast<DrawPaths*>(&fCmdBuffer.back());
if (pathRange == previous->pathRange() &&
transformsType == previous->fTransformsType &&
scissorState == previous->fScissorState &&
stencilSettings == previous->fStencilSettings &&
path_fill_type_is_winding(stencilSettings) &&
!this->getDrawState().willBlendWithDst()) {
// Fold this DrawPaths call into the one previous.
previous->fCount += count;
return;
}
}
DrawPaths* dp = GrNEW_APPEND_TO_RECORDER(fCmdBuffer, DrawPaths, (pathRange));
dp->fIndicesLocation = savedIndices - fPathIndexBuffer.begin();
dp->fCount = count; dp->fCount = count;
memcpy(dp->transforms(), transforms, sizeOfTransforms); dp->fTransformsLocation = savedTransforms - fPathTransformBuffer.begin();
dp->fTransformsType = transformsType; dp->fTransformsType = transformsType;
dp->fScissorState = scissorState; dp->fScissorState = scissorState;
dp->fStencilSettings = stencilSettings; dp->fStencilSettings = stencilSettings;
@ -408,6 +457,8 @@ void GrInOrderDrawBuffer::reset() {
fLastState = NULL; fLastState = NULL;
fVertexPool.reset(); fVertexPool.reset();
fIndexPool.reset(); fIndexPool.reset();
reset_data_buffer(&fPathIndexBuffer, kPathIdxBufferMinReserve);
reset_data_buffer(&fPathTransformBuffer, kPathXformBufferMinReserve);
fGpuCmdMarkers.reset(); fGpuCmdMarkers.reset();
} }
@ -457,7 +508,7 @@ void GrInOrderDrawBuffer::flush() {
&ss->fDstCopy, &ss->fDstCopy,
ss->fDrawType)); ss->fDrawType));
} else { } else {
iter->execute(fDstGpu, currentOptState.get()); iter->execute(this, currentOptState.get());
} }
if (cmd_has_trace_marker(iter->fType)) { if (cmd_has_trace_marker(iter->fType)) {
@ -472,58 +523,64 @@ void GrInOrderDrawBuffer::flush() {
++fDrawID; ++fDrawID;
} }
void GrInOrderDrawBuffer::Draw::execute(GrGpu* gpu, const GrOptDrawState* optState) { void GrInOrderDrawBuffer::Draw::execute(GrInOrderDrawBuffer* buf, const GrOptDrawState* optState) {
if (!optState) { if (!optState) {
return; return;
} }
gpu->setVertexSourceToBuffer(this->vertexBuffer(), optState->getVertexStride()); GrGpu* dstGpu = buf->fDstGpu;
dstGpu->setVertexSourceToBuffer(this->vertexBuffer(), optState->getVertexStride());
if (fInfo.isIndexed()) { if (fInfo.isIndexed()) {
gpu->setIndexSourceToBuffer(this->indexBuffer()); dstGpu->setIndexSourceToBuffer(this->indexBuffer());
} }
gpu->draw(*optState, fInfo, fScissorState); dstGpu->draw(*optState, fInfo, fScissorState);
} }
void GrInOrderDrawBuffer::StencilPath::execute(GrGpu* gpu, const GrOptDrawState* optState) { void GrInOrderDrawBuffer::StencilPath::execute(GrInOrderDrawBuffer* buf,
const GrOptDrawState* optState) {
if (!optState) { if (!optState) {
return; return;
} }
gpu->stencilPath(*optState, this->path(), fScissorState, fStencilSettings); buf->fDstGpu->stencilPath(*optState, this->path(), fScissorState, fStencilSettings);
} }
void GrInOrderDrawBuffer::DrawPath::execute(GrGpu* gpu, const GrOptDrawState* optState) { void GrInOrderDrawBuffer::DrawPath::execute(GrInOrderDrawBuffer* buf,
const GrOptDrawState* optState) {
if (!optState) { if (!optState) {
return; return;
} }
gpu->drawPath(*optState, this->path(), fScissorState, fStencilSettings, buf->fDstGpu->drawPath(*optState, this->path(), fScissorState, fStencilSettings,
fDstCopy.texture() ? &fDstCopy : NULL); fDstCopy.texture() ? &fDstCopy : NULL);
} }
void GrInOrderDrawBuffer::DrawPaths::execute(GrGpu* gpu, const GrOptDrawState* optState) { void GrInOrderDrawBuffer::DrawPaths::execute(GrInOrderDrawBuffer* buf,
const GrOptDrawState* optState) {
if (!optState) { if (!optState) {
return; return;
} }
gpu->drawPaths(*optState, this->pathRange(), this->indices(), fCount, this->transforms(), buf->fDstGpu->drawPaths(*optState, this->pathRange(),
fTransformsType, fScissorState, fStencilSettings, &buf->fPathIndexBuffer[fIndicesLocation], fCount,
fDstCopy.texture() ? &fDstCopy : NULL); &buf->fPathTransformBuffer[fTransformsLocation], fTransformsType,
fScissorState, fStencilSettings, fDstCopy.texture() ? &fDstCopy : NULL);
} }
void GrInOrderDrawBuffer::SetState::execute(GrGpu* gpu, const GrOptDrawState*) { void GrInOrderDrawBuffer::SetState::execute(GrInOrderDrawBuffer*, const GrOptDrawState*) {
} }
void GrInOrderDrawBuffer::Clear::execute(GrGpu* gpu, const GrOptDrawState*) { void GrInOrderDrawBuffer::Clear::execute(GrInOrderDrawBuffer* buf, const GrOptDrawState*) {
if (GrColor_ILLEGAL == fColor) { if (GrColor_ILLEGAL == fColor) {
gpu->discard(this->renderTarget()); buf->fDstGpu->discard(this->renderTarget());
} else { } else {
gpu->clear(&fRect, fColor, fCanIgnoreRect, this->renderTarget()); buf->fDstGpu->clear(&fRect, fColor, fCanIgnoreRect, this->renderTarget());
} }
} }
void GrInOrderDrawBuffer::ClearStencilClip::execute(GrGpu* gpu, const GrOptDrawState*) { void GrInOrderDrawBuffer::ClearStencilClip::execute(GrInOrderDrawBuffer* buf,
gpu->clearStencilClip(fRect, fInsideClip, this->renderTarget()); const GrOptDrawState*) {
buf->fDstGpu->clearStencilClip(fRect, fInsideClip, this->renderTarget());
} }
void GrInOrderDrawBuffer::CopySurface::execute(GrGpu* gpu, const GrOptDrawState*){ void GrInOrderDrawBuffer::CopySurface::execute(GrInOrderDrawBuffer* buf, const GrOptDrawState*) {
gpu->copySurface(this->dst(), this->src(), fSrcRect, fDstPoint); buf->fDstGpu->copySurface(this->dst(), this->src(), fSrcRect, fDstPoint);
} }
bool GrInOrderDrawBuffer::copySurface(GrSurface* dst, bool GrInOrderDrawBuffer::copySurface(GrSurface* dst,

View File

@ -110,7 +110,7 @@ private:
Cmd(uint8_t type) : fType(type) {} Cmd(uint8_t type) : fType(type) {}
virtual ~Cmd() {} virtual ~Cmd() {}
virtual void execute(GrGpu*, const GrOptDrawState*) = 0; virtual void execute(GrInOrderDrawBuffer*, const GrOptDrawState*) = 0;
uint8_t fType; uint8_t fType;
}; };
@ -129,7 +129,7 @@ private:
const GrVertexBuffer* vertexBuffer() const { return fVertexBuffer.get(); } const GrVertexBuffer* vertexBuffer() const { return fVertexBuffer.get(); }
const GrIndexBuffer* indexBuffer() const { return fIndexBuffer.get(); } const GrIndexBuffer* indexBuffer() const { return fIndexBuffer.get(); }
virtual void execute(GrGpu*, const GrOptDrawState*); virtual void execute(GrInOrderDrawBuffer*, const GrOptDrawState*);
DrawInfo fInfo; DrawInfo fInfo;
ScissorState fScissorState; ScissorState fScissorState;
@ -144,7 +144,7 @@ private:
const GrPath* path() const { return fPath.get(); } const GrPath* path() const { return fPath.get(); }
virtual void execute(GrGpu*, const GrOptDrawState*); virtual void execute(GrInOrderDrawBuffer*, const GrOptDrawState*);
ScissorState fScissorState; ScissorState fScissorState;
GrStencilSettings fStencilSettings; GrStencilSettings fStencilSettings;
@ -158,7 +158,7 @@ private:
const GrPath* path() const { return fPath.get(); } const GrPath* path() const { return fPath.get(); }
virtual void execute(GrGpu*, const GrOptDrawState*); virtual void execute(GrInOrderDrawBuffer*, const GrOptDrawState*);
GrDeviceCoordTexture fDstCopy; GrDeviceCoordTexture fDstCopy;
ScissorState fScissorState; ScissorState fScissorState;
@ -172,12 +172,12 @@ private:
DrawPaths(const GrPathRange* pathRange) : Cmd(kDrawPaths_Cmd), fPathRange(pathRange) {} DrawPaths(const GrPathRange* pathRange) : Cmd(kDrawPaths_Cmd), fPathRange(pathRange) {}
const GrPathRange* pathRange() const { return fPathRange.get(); } const GrPathRange* pathRange() const { return fPathRange.get(); }
uint32_t* indices() { return reinterpret_cast<uint32_t*>(CmdBuffer::GetDataForItem(this)); }
float* transforms() { return reinterpret_cast<float*>(&this->indices()[fCount]); }
virtual void execute(GrGpu*, const GrOptDrawState*); virtual void execute(GrInOrderDrawBuffer*, const GrOptDrawState*);
int fIndicesLocation;
size_t fCount; size_t fCount;
int fTransformsLocation;
PathTransformType fTransformsType; PathTransformType fTransformsType;
GrDeviceCoordTexture fDstCopy; GrDeviceCoordTexture fDstCopy;
ScissorState fScissorState; ScissorState fScissorState;
@ -193,7 +193,7 @@ private:
GrRenderTarget* renderTarget() const { return fRenderTarget.get(); } GrRenderTarget* renderTarget() const { return fRenderTarget.get(); }
virtual void execute(GrGpu*, const GrOptDrawState*); virtual void execute(GrInOrderDrawBuffer*, const GrOptDrawState*);
SkIRect fRect; SkIRect fRect;
GrColor fColor; GrColor fColor;
@ -209,7 +209,7 @@ private:
GrRenderTarget* renderTarget() const { return fRenderTarget.get(); } GrRenderTarget* renderTarget() const { return fRenderTarget.get(); }
virtual void execute(GrGpu*, const GrOptDrawState*); virtual void execute(GrInOrderDrawBuffer*, const GrOptDrawState*);
SkIRect fRect; SkIRect fRect;
bool fInsideClip; bool fInsideClip;
@ -224,7 +224,7 @@ private:
GrSurface* dst() const { return fDst.get(); } GrSurface* dst() const { return fDst.get(); }
GrSurface* src() const { return fSrc.get(); } GrSurface* src() const { return fSrc.get(); }
virtual void execute(GrGpu*, const GrOptDrawState*); virtual void execute(GrInOrderDrawBuffer*, const GrOptDrawState*);
SkIPoint fDstPoint; SkIPoint fDstPoint;
SkIRect fSrcRect; SkIRect fSrcRect;
@ -237,7 +237,7 @@ private:
struct SetState : public Cmd { struct SetState : public Cmd {
SetState(const GrDrawState& state) : Cmd(kSetState_Cmd), fState(state) {} SetState(const GrDrawState& state) : Cmd(kSetState_Cmd), fState(state) {}
virtual void execute(GrGpu*, const GrOptDrawState*); virtual void execute(GrInOrderDrawBuffer*, const GrOptDrawState*);
GrDrawState fState; GrDrawState fState;
GrGpu::DrawType fDrawType; GrGpu::DrawType fDrawType;
@ -301,6 +301,8 @@ private:
// TODO: Use a single allocator for commands and records // TODO: Use a single allocator for commands and records
enum { enum {
kCmdBufferInitialSizeInBytes = 8 * 1024, kCmdBufferInitialSizeInBytes = 8 * 1024,
kPathIdxBufferMinReserve = 64,
kPathXformBufferMinReserve = 2 * kPathIdxBufferMinReserve,
kGeoPoolStatePreAllocCnt = 4, kGeoPoolStatePreAllocCnt = 4,
}; };
@ -310,6 +312,8 @@ private:
GrGpu* fDstGpu; GrGpu* fDstGpu;
GrVertexBufferAllocPool& fVertexPool; GrVertexBufferAllocPool& fVertexPool;
GrIndexBufferAllocPool& fIndexPool; GrIndexBufferAllocPool& fIndexPool;
SkTDArray<uint32_t> fPathIndexBuffer;
SkTDArray<float> fPathTransformBuffer;
struct GeometryPoolState { struct GeometryPoolState {
const GrVertexBuffer* fPoolVertexBuffer; const GrVertexBuffer* fPoolVertexBuffer;