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:
parent
f4905ccb6c
commit
3fc6a2fdb2
@ -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
|
||||||
|
@ -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;
|
||||||
};
|
};
|
||||||
|
@ -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,
|
||||||
|
@ -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;
|
||||||
|
Loading…
Reference in New Issue
Block a user