Revert of Create a single command buffer for GrInOrderDrawBuffer (patchset #14 id:1050001 of https://codereview.chromium.org/628453002/)
Reason for revert: New test failing on Android: http://build.chromium.org/p/client.skia.android/builders/Test-Android-Nexus7-Tegra3-Arm7-Release/builds/89/steps/dm/logs/stdio Original issue's description: > Adds a GrTBaseList class that GrInOrderDrawBuffer uses to allocate > all its commands interleaved in contiguous memory. GrTBaseList also > supports extra data associated with objects, so we can store arrays > inline without having to call malloc(). > > Committed: https://skia.googlesource.com/skia/+/47c844aaba81e5a29c773b660e1d6062c766d253 TBR=bsalomon@google.com,reed@google.com,cdalton@nvidia.com NOTREECHECKS=true NOTRY=true Review URL: https://codereview.chromium.org/652843002
This commit is contained in:
parent
be23418776
commit
07894c4d7d
@ -162,7 +162,6 @@
|
||||
'<(skia_src_path)/gpu/GrTexture.cpp',
|
||||
'<(skia_src_path)/gpu/GrTexturePriv.h',
|
||||
'<(skia_src_path)/gpu/GrTextureAccess.cpp',
|
||||
'<(skia_src_path)/gpu/GrTRecorder.h',
|
||||
'<(skia_src_path)/gpu/GrVertexBuffer.h',
|
||||
|
||||
'<(skia_src_path)/gpu/effects/Gr1DKernelEffect.h',
|
||||
|
@ -115,7 +115,6 @@
|
||||
'../tests/GrRedBlackTreeTest.cpp',
|
||||
'../tests/GrSurfaceTest.cpp',
|
||||
'../tests/GrTBSearchTest.cpp',
|
||||
'../tests/GrTRecorderTest.cpp',
|
||||
'../tests/GradientTest.cpp',
|
||||
'../tests/ImageCacheTest.cpp',
|
||||
'../tests/ImageDecodingTest.cpp',
|
||||
|
@ -18,9 +18,6 @@ GrInOrderDrawBuffer::GrInOrderDrawBuffer(GrGpu* gpu,
|
||||
GrVertexBufferAllocPool* vertexPool,
|
||||
GrIndexBufferAllocPool* indexPool)
|
||||
: GrDrawTarget(gpu->getContext())
|
||||
, fCmdBuffer(kCmdBufferInitialSizeInBytes)
|
||||
, fLastState(NULL)
|
||||
, fLastClip(NULL)
|
||||
, fDstGpu(gpu)
|
||||
, fClipSet(true)
|
||||
, fClipProxyState(kUnknown_ClipProxyState)
|
||||
@ -219,7 +216,6 @@ bool GrInOrderDrawBuffer::quickInsideClip(const SkRect& devBounds) {
|
||||
}
|
||||
|
||||
int GrInOrderDrawBuffer::concatInstancedDraw(const DrawInfo& info) {
|
||||
SkASSERT(!fCmdBuffer.empty());
|
||||
SkASSERT(info.isInstanced());
|
||||
|
||||
const GeometrySrcState& geomSrc = this->getGeomSrc();
|
||||
@ -234,17 +230,17 @@ int GrInOrderDrawBuffer::concatInstancedDraw(const DrawInfo& info) {
|
||||
}
|
||||
// Check if there is a draw info that is compatible that uses the same VB from the pool and
|
||||
// the same IB
|
||||
if (kDraw_Cmd != strip_trace_bit(fCmdBuffer.back().fType)) {
|
||||
if (kDraw_Cmd != strip_trace_bit(fCmds.back())) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
Draw* draw = static_cast<Draw*>(&fCmdBuffer.back());
|
||||
Draw* draw = &fDraws.back();
|
||||
GeometryPoolState& poolState = fGeoPoolStateStack.back();
|
||||
const GrVertexBuffer* vertexBuffer = poolState.fPoolVertexBuffer;
|
||||
|
||||
if (!draw->fInfo.isInstanced() ||
|
||||
draw->fInfo.verticesPerInstance() != info.verticesPerInstance() ||
|
||||
draw->fInfo.indicesPerInstance() != info.indicesPerInstance() ||
|
||||
if (!draw->isInstanced() ||
|
||||
draw->verticesPerInstance() != info.verticesPerInstance() ||
|
||||
draw->indicesPerInstance() != info.indicesPerInstance() ||
|
||||
draw->vertexBuffer() != vertexBuffer ||
|
||||
draw->indexBuffer() != geomSrc.fIndexBuffer) {
|
||||
return 0;
|
||||
@ -252,15 +248,15 @@ int GrInOrderDrawBuffer::concatInstancedDraw(const DrawInfo& info) {
|
||||
// info does not yet account for the offset from the start of the pool's VB while the previous
|
||||
// draw record does.
|
||||
int adjustedStartVertex = poolState.fPoolStartVertex + info.startVertex();
|
||||
if (draw->fInfo.startVertex() + draw->fInfo.vertexCount() != adjustedStartVertex) {
|
||||
if (draw->startVertex() + draw->vertexCount() != adjustedStartVertex) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
SkASSERT(poolState.fPoolStartVertex == draw->fInfo.startVertex() + draw->fInfo.vertexCount());
|
||||
SkASSERT(poolState.fPoolStartVertex == draw->startVertex() + draw->vertexCount());
|
||||
|
||||
// how many instances can be concat'ed onto draw given the size of the index buffer
|
||||
int instancesToConcat = this->indexCountInCurrentSource() / info.indicesPerInstance();
|
||||
instancesToConcat -= draw->fInfo.instanceCount();
|
||||
instancesToConcat -= draw->instanceCount();
|
||||
instancesToConcat = SkTMin(instancesToConcat, info.instanceCount());
|
||||
|
||||
// update the amount of reserved vertex data actually referenced in draws
|
||||
@ -268,15 +264,15 @@ int GrInOrderDrawBuffer::concatInstancedDraw(const DrawInfo& info) {
|
||||
drawState.getVertexStride();
|
||||
poolState.fUsedPoolVertexBytes = SkTMax(poolState.fUsedPoolVertexBytes, vertexBytes);
|
||||
|
||||
draw->fInfo.adjustInstanceCount(instancesToConcat);
|
||||
draw->adjustInstanceCount(instancesToConcat);
|
||||
|
||||
// update last fGpuCmdMarkers to include any additional trace markers that have been added
|
||||
if (this->getActiveTraceMarkers().count() > 0) {
|
||||
if (cmd_has_trace_marker(draw->fType)) {
|
||||
if (cmd_has_trace_marker(fCmds.back())) {
|
||||
fGpuCmdMarkers.back().addSet(this->getActiveTraceMarkers());
|
||||
} else {
|
||||
fGpuCmdMarkers.push_back(this->getActiveTraceMarkers());
|
||||
draw->fType = add_trace_bit(draw->fType);
|
||||
fCmds.back() = add_trace_bit(fCmds.back());
|
||||
}
|
||||
}
|
||||
|
||||
@ -313,7 +309,9 @@ void GrInOrderDrawBuffer::onDraw(const DrawInfo& info) {
|
||||
acr.set(this->drawState());
|
||||
}
|
||||
|
||||
this->recordClipIfNecessary();
|
||||
if (this->needsNewClip()) {
|
||||
this->recordClip();
|
||||
}
|
||||
this->recordStateIfNecessary();
|
||||
|
||||
const GrVertexBuffer* vb;
|
||||
@ -336,51 +334,52 @@ void GrInOrderDrawBuffer::onDraw(const DrawInfo& info) {
|
||||
if (info.isInstanced()) {
|
||||
int instancesConcated = this->concatInstancedDraw(info);
|
||||
if (info.instanceCount() > instancesConcated) {
|
||||
draw = GrNEW_APPEND_TO_RECORDER(fCmdBuffer, Draw, (info, vb, ib));
|
||||
draw->fInfo.adjustInstanceCount(-instancesConcated);
|
||||
draw = this->recordDraw(info, vb, ib);
|
||||
draw->adjustInstanceCount(-instancesConcated);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
draw = GrNEW_APPEND_TO_RECORDER(fCmdBuffer, Draw, (info, vb, ib));
|
||||
draw = this->recordDraw(info, vb, ib);
|
||||
}
|
||||
this->recordTraceMarkersIfNecessary();
|
||||
|
||||
// Adjust the starting vertex and index when we are using reserved or array sources to
|
||||
// compensate for the fact that the data was inserted into a larger vb/ib owned by the pool.
|
||||
if (kBuffer_GeometrySrcType != this->getGeomSrc().fVertexSrc) {
|
||||
size_t bytes = (info.vertexCount() + info.startVertex()) * drawState.getVertexStride();
|
||||
poolState.fUsedPoolVertexBytes = SkTMax(poolState.fUsedPoolVertexBytes, bytes);
|
||||
draw->fInfo.adjustStartVertex(poolState.fPoolStartVertex);
|
||||
draw->adjustStartVertex(poolState.fPoolStartVertex);
|
||||
}
|
||||
|
||||
if (info.isIndexed() && kBuffer_GeometrySrcType != this->getGeomSrc().fIndexSrc) {
|
||||
size_t bytes = (info.indexCount() + info.startIndex()) * sizeof(uint16_t);
|
||||
poolState.fUsedPoolIndexBytes = SkTMax(poolState.fUsedPoolIndexBytes, bytes);
|
||||
draw->fInfo.adjustStartIndex(poolState.fPoolStartIndex);
|
||||
draw->adjustStartIndex(poolState.fPoolStartIndex);
|
||||
}
|
||||
}
|
||||
|
||||
void GrInOrderDrawBuffer::onStencilPath(const GrPath* path, SkPath::FillType fill) {
|
||||
this->recordClipIfNecessary();
|
||||
if (this->needsNewClip()) {
|
||||
this->recordClip();
|
||||
}
|
||||
// Only compare the subset of GrDrawState relevant to path stenciling?
|
||||
this->recordStateIfNecessary();
|
||||
StencilPath* sp = GrNEW_APPEND_TO_RECORDER(fCmdBuffer, StencilPath, (path));
|
||||
StencilPath* sp = this->recordStencilPath(path);
|
||||
sp->fFill = fill;
|
||||
this->recordTraceMarkersIfNecessary();
|
||||
}
|
||||
|
||||
void GrInOrderDrawBuffer::onDrawPath(const GrPath* path,
|
||||
SkPath::FillType fill, const GrDeviceCoordTexture* dstCopy) {
|
||||
this->recordClipIfNecessary();
|
||||
if (this->needsNewClip()) {
|
||||
this->recordClip();
|
||||
}
|
||||
// TODO: Only compare the subset of GrDrawState relevant to path covering?
|
||||
this->recordStateIfNecessary();
|
||||
DrawPath* dp = GrNEW_APPEND_TO_RECORDER(fCmdBuffer, DrawPath, (path));
|
||||
dp->fFill = fill;
|
||||
DrawPath* cp = this->recordDrawPath(path);
|
||||
cp->fFill = fill;
|
||||
if (dstCopy) {
|
||||
dp->fDstCopy = *dstCopy;
|
||||
cp->fDstCopy = *dstCopy;
|
||||
}
|
||||
this->recordTraceMarkersIfNecessary();
|
||||
}
|
||||
|
||||
void GrInOrderDrawBuffer::onDrawPaths(const GrPathRange* pathRange,
|
||||
@ -391,25 +390,25 @@ void GrInOrderDrawBuffer::onDrawPaths(const GrPathRange* pathRange,
|
||||
SkASSERT(indices);
|
||||
SkASSERT(transforms);
|
||||
|
||||
this->recordClipIfNecessary();
|
||||
if (this->needsNewClip()) {
|
||||
this->recordClip();
|
||||
}
|
||||
this->recordStateIfNecessary();
|
||||
|
||||
int sizeOfIndices = sizeof(uint32_t) * count;
|
||||
int sizeOfTransforms = sizeof(float) * count *
|
||||
GrPathRendering::PathTransformSize(transformsType);
|
||||
|
||||
DrawPaths* dp = GrNEW_APPEND_WITH_DATA_TO_RECORDER(fCmdBuffer, DrawPaths, (pathRange),
|
||||
sizeOfIndices + sizeOfTransforms);
|
||||
memcpy(dp->indices(), indices, sizeOfIndices);
|
||||
DrawPaths* dp = this->recordDrawPaths(pathRange);
|
||||
dp->fIndices = SkNEW_ARRAY(uint32_t, count); // TODO: Accomplish this without a malloc
|
||||
memcpy(dp->fIndices, indices, sizeof(uint32_t) * count);
|
||||
dp->fCount = count;
|
||||
memcpy(dp->transforms(), transforms, sizeOfTransforms);
|
||||
|
||||
const int transformsLength = GrPathRendering::PathTransformSize(transformsType) * count;
|
||||
dp->fTransforms = SkNEW_ARRAY(float, transformsLength);
|
||||
memcpy(dp->fTransforms, transforms, sizeof(float) * transformsLength);
|
||||
dp->fTransformsType = transformsType;
|
||||
|
||||
dp->fFill = fill;
|
||||
|
||||
if (dstCopy) {
|
||||
dp->fDstCopy = *dstCopy;
|
||||
}
|
||||
|
||||
this->recordTraceMarkersIfNecessary();
|
||||
}
|
||||
|
||||
void GrInOrderDrawBuffer::clear(const SkIRect* rect, GrColor color,
|
||||
@ -426,12 +425,11 @@ void GrInOrderDrawBuffer::clear(const SkIRect* rect, GrColor color,
|
||||
r.setLTRB(0, 0, renderTarget->width(), renderTarget->height());
|
||||
rect = &r;
|
||||
}
|
||||
Clear* clr = GrNEW_APPEND_TO_RECORDER(fCmdBuffer, Clear, (renderTarget));
|
||||
Clear* clr = this->recordClear(renderTarget);
|
||||
GrColorIsPMAssert(color);
|
||||
clr->fColor = color;
|
||||
clr->fRect = *rect;
|
||||
clr->fCanIgnoreRect = canIgnoreRect;
|
||||
this->recordTraceMarkersIfNecessary();
|
||||
}
|
||||
|
||||
void GrInOrderDrawBuffer::discard(GrRenderTarget* renderTarget) {
|
||||
@ -442,21 +440,26 @@ void GrInOrderDrawBuffer::discard(GrRenderTarget* renderTarget) {
|
||||
renderTarget = this->drawState()->getRenderTarget();
|
||||
SkASSERT(renderTarget);
|
||||
}
|
||||
Clear* clr = GrNEW_APPEND_TO_RECORDER(fCmdBuffer, Clear, (renderTarget));
|
||||
Clear* clr = this->recordClear(renderTarget);
|
||||
clr->fColor = GrColor_ILLEGAL;
|
||||
this->recordTraceMarkersIfNecessary();
|
||||
}
|
||||
|
||||
void GrInOrderDrawBuffer::reset() {
|
||||
SkASSERT(1 == fGeoPoolStateStack.count());
|
||||
this->resetVertexSource();
|
||||
this->resetIndexSource();
|
||||
|
||||
fCmdBuffer.reset();
|
||||
fLastState = NULL;
|
||||
fLastClip = NULL;
|
||||
|
||||
fCmds.reset();
|
||||
fDraws.reset();
|
||||
fStencilPaths.reset();
|
||||
fDrawPath.reset();
|
||||
fDrawPaths.reset();
|
||||
fStates.reset();
|
||||
fClears.reset();
|
||||
fVertexPool.reset();
|
||||
fIndexPool.reset();
|
||||
fClips.reset();
|
||||
fCopySurfaces.reset();
|
||||
fGpuCmdMarkers.reset();
|
||||
fClipSet = true;
|
||||
}
|
||||
@ -471,7 +474,8 @@ void GrInOrderDrawBuffer::flush() {
|
||||
SkASSERT(kReserved_GeometrySrcType != this->getGeomSrc().fVertexSrc);
|
||||
SkASSERT(kReserved_GeometrySrcType != this->getGeomSrc().fIndexSrc);
|
||||
|
||||
if (fCmdBuffer.empty()) {
|
||||
int numCmds = fCmds.count();
|
||||
if (0 == numCmds) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -486,35 +490,113 @@ void GrInOrderDrawBuffer::flush() {
|
||||
|
||||
GrDrawState* prevDrawState = SkRef(fDstGpu->drawState());
|
||||
|
||||
CmdBuffer::Iter iter(fCmdBuffer);
|
||||
GrClipData clipData;
|
||||
|
||||
StateAllocator::Iter stateIter(&fStates);
|
||||
ClipAllocator::Iter clipIter(&fClips);
|
||||
ClearAllocator::Iter clearIter(&fClears);
|
||||
DrawAllocator::Iter drawIter(&fDraws);
|
||||
StencilPathAllocator::Iter stencilPathIter(&fStencilPaths);
|
||||
DrawPathAllocator::Iter drawPathIter(&fDrawPath);
|
||||
DrawPathsAllocator::Iter drawPathsIter(&fDrawPaths);
|
||||
CopySurfaceAllocator::Iter copySurfaceIter(&fCopySurfaces);
|
||||
|
||||
int currCmdMarker = 0;
|
||||
|
||||
int currCmdMarker = 0;
|
||||
fDstGpu->saveActiveTraceMarkers();
|
||||
|
||||
while (iter.next()) {
|
||||
for (int c = 0; c < numCmds; ++c) {
|
||||
GrGpuTraceMarker newMarker("", -1);
|
||||
SkString traceString;
|
||||
if (cmd_has_trace_marker(iter->fType)) {
|
||||
if (cmd_has_trace_marker(fCmds[c])) {
|
||||
traceString = fGpuCmdMarkers[currCmdMarker].toString();
|
||||
newMarker.fMarker = traceString.c_str();
|
||||
fDstGpu->addGpuTraceMarker(&newMarker);
|
||||
++currCmdMarker;
|
||||
}
|
||||
|
||||
SkDEBUGCODE(bool isDraw = kDraw_Cmd == strip_trace_bit(iter->fType) ||
|
||||
kStencilPath_Cmd == strip_trace_bit(iter->fType) ||
|
||||
kDrawPath_Cmd == strip_trace_bit(iter->fType) ||
|
||||
kDrawPaths_Cmd == strip_trace_bit(iter->fType));
|
||||
SkASSERT(!isDraw || fDstGpu->drawState() != prevDrawState);
|
||||
|
||||
iter->execute(fDstGpu);
|
||||
|
||||
if (cmd_has_trace_marker(iter->fType)) {
|
||||
switch (strip_trace_bit(fCmds[c])) {
|
||||
case kDraw_Cmd: {
|
||||
SkASSERT(fDstGpu->drawState() != prevDrawState);
|
||||
SkAssertResult(drawIter.next());
|
||||
fDstGpu->setVertexSourceToBuffer(drawIter->vertexBuffer());
|
||||
if (drawIter->isIndexed()) {
|
||||
fDstGpu->setIndexSourceToBuffer(drawIter->indexBuffer());
|
||||
}
|
||||
fDstGpu->executeDraw(*drawIter);
|
||||
break;
|
||||
}
|
||||
case kStencilPath_Cmd: {
|
||||
SkASSERT(fDstGpu->drawState() != prevDrawState);
|
||||
SkAssertResult(stencilPathIter.next());
|
||||
fDstGpu->stencilPath(stencilPathIter->path(), stencilPathIter->fFill);
|
||||
break;
|
||||
}
|
||||
case kDrawPath_Cmd: {
|
||||
SkASSERT(fDstGpu->drawState() != prevDrawState);
|
||||
SkAssertResult(drawPathIter.next());
|
||||
fDstGpu->executeDrawPath(drawPathIter->path(), drawPathIter->fFill,
|
||||
drawPathIter->fDstCopy.texture() ?
|
||||
&drawPathIter->fDstCopy :
|
||||
NULL);
|
||||
break;
|
||||
}
|
||||
case kDrawPaths_Cmd: {
|
||||
SkASSERT(fDstGpu->drawState() != prevDrawState);
|
||||
SkAssertResult(drawPathsIter.next());
|
||||
const GrDeviceCoordTexture* dstCopy =
|
||||
drawPathsIter->fDstCopy.texture() ? &drawPathsIter->fDstCopy : NULL;
|
||||
fDstGpu->executeDrawPaths(drawPathsIter->pathRange(),
|
||||
drawPathsIter->fIndices,
|
||||
drawPathsIter->fCount,
|
||||
drawPathsIter->fTransforms,
|
||||
drawPathsIter->fTransformsType,
|
||||
drawPathsIter->fFill,
|
||||
dstCopy);
|
||||
break;
|
||||
}
|
||||
case kSetState_Cmd:
|
||||
SkAssertResult(stateIter.next());
|
||||
fDstGpu->setDrawState(stateIter.get());
|
||||
break;
|
||||
case kSetClip_Cmd:
|
||||
SkAssertResult(clipIter.next());
|
||||
clipData.fClipStack = &clipIter->fStack;
|
||||
clipData.fOrigin = clipIter->fOrigin;
|
||||
fDstGpu->setClip(&clipData);
|
||||
break;
|
||||
case kClear_Cmd:
|
||||
SkAssertResult(clearIter.next());
|
||||
if (GrColor_ILLEGAL == clearIter->fColor) {
|
||||
fDstGpu->discard(clearIter->renderTarget());
|
||||
} else {
|
||||
fDstGpu->clear(&clearIter->fRect,
|
||||
clearIter->fColor,
|
||||
clearIter->fCanIgnoreRect,
|
||||
clearIter->renderTarget());
|
||||
}
|
||||
break;
|
||||
case kCopySurface_Cmd:
|
||||
SkAssertResult(copySurfaceIter.next());
|
||||
fDstGpu->copySurface(copySurfaceIter->dst(),
|
||||
copySurfaceIter->src(),
|
||||
copySurfaceIter->fSrcRect,
|
||||
copySurfaceIter->fDstPoint);
|
||||
break;
|
||||
}
|
||||
if (cmd_has_trace_marker(fCmds[c])) {
|
||||
fDstGpu->removeGpuTraceMarker(&newMarker);
|
||||
}
|
||||
}
|
||||
|
||||
fDstGpu->restoreActiveTraceMarkers();
|
||||
// we should have consumed all the states, clips, etc.
|
||||
SkASSERT(!stateIter.next());
|
||||
SkASSERT(!clipIter.next());
|
||||
SkASSERT(!clearIter.next());
|
||||
SkASSERT(!drawIter.next());
|
||||
SkASSERT(!copySurfaceIter.next());
|
||||
SkASSERT(!stencilPathIter.next());
|
||||
SkASSERT(!drawPathIter.next());
|
||||
SkASSERT(!drawPathsIter.next());
|
||||
|
||||
SkASSERT(fGpuCmdMarkers.count() == currCmdMarker);
|
||||
|
||||
fDstGpu->setDrawState(prevDrawState);
|
||||
@ -523,58 +605,14 @@ void GrInOrderDrawBuffer::flush() {
|
||||
++fDrawID;
|
||||
}
|
||||
|
||||
void GrInOrderDrawBuffer::Draw::execute(GrDrawTarget* gpu) {
|
||||
gpu->setVertexSourceToBuffer(this->vertexBuffer());
|
||||
if (fInfo.isIndexed()) {
|
||||
gpu->setIndexSourceToBuffer(this->indexBuffer());
|
||||
}
|
||||
gpu->executeDraw(fInfo);
|
||||
}
|
||||
|
||||
void GrInOrderDrawBuffer::StencilPath::execute(GrDrawTarget* gpu) {
|
||||
gpu->stencilPath(this->path(), fFill);
|
||||
}
|
||||
|
||||
void GrInOrderDrawBuffer::DrawPath::execute(GrDrawTarget* gpu) {
|
||||
gpu->executeDrawPath(this->path(), fFill, fDstCopy.texture() ? &fDstCopy : NULL);
|
||||
}
|
||||
|
||||
void GrInOrderDrawBuffer::DrawPaths::execute(GrDrawTarget* gpu) {
|
||||
gpu->executeDrawPaths(this->pathRange(), this->indices(), fCount, this->transforms(),
|
||||
fTransformsType, fFill, fDstCopy.texture() ? &fDstCopy : NULL);
|
||||
}
|
||||
|
||||
void GrInOrderDrawBuffer::SetState::execute(GrDrawTarget* gpu) {
|
||||
gpu->setDrawState(&fState);
|
||||
}
|
||||
|
||||
void GrInOrderDrawBuffer::SetClip::execute(GrDrawTarget* gpu) {
|
||||
// Our fClipData is referenced directly, so we must remain alive for the entire
|
||||
// duration of the flush (after which the gpu's previous clip is restored).
|
||||
gpu->setClip(&fClipData);
|
||||
}
|
||||
|
||||
void GrInOrderDrawBuffer::Clear::execute(GrDrawTarget* gpu) {
|
||||
if (GrColor_ILLEGAL == fColor) {
|
||||
gpu->discard(this->renderTarget());
|
||||
} else {
|
||||
gpu->clear(&fRect, fColor, fCanIgnoreRect, this->renderTarget());
|
||||
}
|
||||
}
|
||||
|
||||
void GrInOrderDrawBuffer::CopySurface::execute(GrDrawTarget* gpu) {
|
||||
gpu->copySurface(this->dst(), this->src(), fSrcRect, fDstPoint);
|
||||
}
|
||||
|
||||
bool GrInOrderDrawBuffer::onCopySurface(GrSurface* dst,
|
||||
GrSurface* src,
|
||||
const SkIRect& srcRect,
|
||||
const SkIPoint& dstPoint) {
|
||||
if (fDstGpu->canCopySurface(dst, src, srcRect, dstPoint)) {
|
||||
CopySurface* cs = GrNEW_APPEND_TO_RECORDER(fCmdBuffer, CopySurface, (dst, src));
|
||||
CopySurface* cs = this->recordCopySurface(dst, src);
|
||||
cs->fSrcRect = srcRect;
|
||||
cs->fDstPoint = dstPoint;
|
||||
this->recordTraceMarkersIfNecessary();
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
@ -794,53 +832,92 @@ void GrInOrderDrawBuffer::geometrySourceWillPop(const GeometrySrcState& restored
|
||||
}
|
||||
|
||||
void GrInOrderDrawBuffer::recordStateIfNecessary() {
|
||||
if (!fLastState) {
|
||||
SetState* ss = GrNEW_APPEND_TO_RECORDER(fCmdBuffer, SetState, (this->getDrawState()));
|
||||
fLastState = &ss->fState;
|
||||
this->convertDrawStateToPendingExec(fLastState);
|
||||
this->recordTraceMarkersIfNecessary();
|
||||
if (fStates.empty()) {
|
||||
this->convertDrawStateToPendingExec(&fStates.push_back(this->getDrawState()));
|
||||
this->addToCmdBuffer(kSetState_Cmd);
|
||||
return;
|
||||
}
|
||||
const GrDrawState& curr = this->getDrawState();
|
||||
switch (GrDrawState::CombineIfPossible(*fLastState, curr, *this->caps())) {
|
||||
GrDrawState& prev = fStates.back();
|
||||
switch (GrDrawState::CombineIfPossible(prev, curr, *this->caps())) {
|
||||
case GrDrawState::kIncompatible_CombinedState:
|
||||
fLastState = &GrNEW_APPEND_TO_RECORDER(fCmdBuffer, SetState, (curr))->fState;
|
||||
this->convertDrawStateToPendingExec(fLastState);
|
||||
this->recordTraceMarkersIfNecessary();
|
||||
this->convertDrawStateToPendingExec(&fStates.push_back(curr));
|
||||
this->addToCmdBuffer(kSetState_Cmd);
|
||||
break;
|
||||
case GrDrawState::kA_CombinedState:
|
||||
case GrDrawState::kAOrB_CombinedState: // Treat the same as kA.
|
||||
break;
|
||||
case GrDrawState::kB_CombinedState:
|
||||
// prev has already been converted to pending execution. That is a one-way ticket.
|
||||
// So here we just destruct the previous state and reinit with a new copy of curr.
|
||||
// Note that this goes away when we move GrIODB over to taking optimized snapshots
|
||||
// of draw states.
|
||||
fLastState->~GrDrawState();
|
||||
SkNEW_PLACEMENT_ARGS(fLastState, GrDrawState, (curr));
|
||||
this->convertDrawStateToPendingExec(fLastState);
|
||||
// So here we just delete prev and push back a new copy of curr. Note that this
|
||||
// goes away when we move GrIODB over to taking optimized snapshots of draw states.
|
||||
fStates.pop_back();
|
||||
this->convertDrawStateToPendingExec(&fStates.push_back(curr));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void GrInOrderDrawBuffer::recordClipIfNecessary() {
|
||||
if (this->getDrawState().isClipState() &&
|
||||
fClipSet &&
|
||||
(!fLastClip || *fLastClip != *this->getClip())) {
|
||||
fLastClip = &GrNEW_APPEND_TO_RECORDER(fCmdBuffer, SetClip, (this->getClip()))->fClipData;
|
||||
this->recordTraceMarkersIfNecessary();
|
||||
fClipSet = false;
|
||||
bool GrInOrderDrawBuffer::needsNewClip() const {
|
||||
if (this->getDrawState().isClipState()) {
|
||||
if (fClipSet &&
|
||||
(fClips.empty() ||
|
||||
fClips.back().fStack != *this->getClip()->fClipStack ||
|
||||
fClips.back().fOrigin != this->getClip()->fOrigin)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void GrInOrderDrawBuffer::addToCmdBuffer(uint8_t cmd) {
|
||||
SkASSERT(!cmd_has_trace_marker(cmd));
|
||||
const GrTraceMarkerSet& activeTraceMarkers = this->getActiveTraceMarkers();
|
||||
if (activeTraceMarkers.count() > 0) {
|
||||
fCmds.push_back(add_trace_bit(cmd));
|
||||
fGpuCmdMarkers.push_back(activeTraceMarkers);
|
||||
} else {
|
||||
fCmds.push_back(cmd);
|
||||
}
|
||||
}
|
||||
|
||||
void GrInOrderDrawBuffer::recordTraceMarkersIfNecessary() {
|
||||
SkASSERT(!fCmdBuffer.empty());
|
||||
SkASSERT(!cmd_has_trace_marker(fCmdBuffer.back().fType));
|
||||
const GrTraceMarkerSet& activeTraceMarkers = this->getActiveTraceMarkers();
|
||||
if (activeTraceMarkers.count() > 0) {
|
||||
fCmdBuffer.back().fType = add_trace_bit(fCmdBuffer.back().fType);
|
||||
fGpuCmdMarkers.push_back(activeTraceMarkers);
|
||||
}
|
||||
void GrInOrderDrawBuffer::recordClip() {
|
||||
fClips.push_back().fStack = *this->getClip()->fClipStack;
|
||||
fClips.back().fOrigin = this->getClip()->fOrigin;
|
||||
fClipSet = false;
|
||||
this->addToCmdBuffer(kSetClip_Cmd);
|
||||
}
|
||||
|
||||
GrInOrderDrawBuffer::Draw* GrInOrderDrawBuffer::recordDraw(const DrawInfo& info,
|
||||
const GrVertexBuffer* vb,
|
||||
const GrIndexBuffer* ib) {
|
||||
this->addToCmdBuffer(kDraw_Cmd);
|
||||
return GrNEW_APPEND_TO_ALLOCATOR(&fDraws, Draw, (info, vb, ib));
|
||||
}
|
||||
|
||||
GrInOrderDrawBuffer::StencilPath* GrInOrderDrawBuffer::recordStencilPath(const GrPath* path) {
|
||||
this->addToCmdBuffer(kStencilPath_Cmd);
|
||||
return GrNEW_APPEND_TO_ALLOCATOR(&fStencilPaths, StencilPath, (path));
|
||||
}
|
||||
|
||||
GrInOrderDrawBuffer::DrawPath* GrInOrderDrawBuffer::recordDrawPath(const GrPath* path) {
|
||||
this->addToCmdBuffer(kDrawPath_Cmd);
|
||||
return GrNEW_APPEND_TO_ALLOCATOR(&fDrawPath, DrawPath, (path));
|
||||
}
|
||||
|
||||
GrInOrderDrawBuffer::DrawPaths* GrInOrderDrawBuffer::recordDrawPaths(const GrPathRange* pathRange) {
|
||||
this->addToCmdBuffer(kDrawPaths_Cmd);
|
||||
return GrNEW_APPEND_TO_ALLOCATOR(&fDrawPaths, DrawPaths, (pathRange));
|
||||
}
|
||||
|
||||
GrInOrderDrawBuffer::Clear* GrInOrderDrawBuffer::recordClear(GrRenderTarget* rt) {
|
||||
this->addToCmdBuffer(kClear_Cmd);
|
||||
return GrNEW_APPEND_TO_ALLOCATOR(&fClears, Clear, (rt));
|
||||
}
|
||||
|
||||
GrInOrderDrawBuffer::CopySurface* GrInOrderDrawBuffer::recordCopySurface(GrSurface* dst,
|
||||
GrSurface* src) {
|
||||
this->addToCmdBuffer(kCopySurface_Cmd);
|
||||
return GrNEW_APPEND_TO_ALLOCATOR(&fCopySurfaces, CopySurface, (dst, src));
|
||||
}
|
||||
|
||||
void GrInOrderDrawBuffer::clipWillBeSet(const GrClipData* newClipData) {
|
||||
|
@ -16,7 +16,6 @@
|
||||
#include "GrPath.h"
|
||||
#include "GrPathRange.h"
|
||||
#include "GrSurface.h"
|
||||
#include "GrTRecorder.h"
|
||||
#include "GrVertexBuffer.h"
|
||||
|
||||
#include "SkClipStack.h"
|
||||
@ -88,7 +87,7 @@ protected:
|
||||
virtual void clipWillBeSet(const GrClipData* newClip) SK_OVERRIDE;
|
||||
|
||||
private:
|
||||
enum {
|
||||
enum Cmd {
|
||||
kDraw_Cmd = 1,
|
||||
kStencilPath_Cmd = 2,
|
||||
kSetState_Cmd = 3,
|
||||
@ -99,54 +98,37 @@ private:
|
||||
kDrawPaths_Cmd = 8,
|
||||
};
|
||||
|
||||
struct Cmd : ::SkNoncopyable {
|
||||
Cmd(uint8_t type) : fType(type) {}
|
||||
virtual ~Cmd() {}
|
||||
|
||||
virtual void execute(GrDrawTarget*) = 0;
|
||||
|
||||
uint8_t fType;
|
||||
};
|
||||
|
||||
struct Draw : public Cmd {
|
||||
class Draw : public DrawInfo {
|
||||
public:
|
||||
Draw(const DrawInfo& info, const GrVertexBuffer* vb, const GrIndexBuffer* ib)
|
||||
: Cmd(kDraw_Cmd)
|
||||
, fInfo(info)
|
||||
: DrawInfo(info)
|
||||
, fVertexBuffer(vb)
|
||||
, fIndexBuffer(ib) {}
|
||||
|
||||
const GrVertexBuffer* vertexBuffer() const { return fVertexBuffer.get(); }
|
||||
const GrIndexBuffer* indexBuffer() const { return fIndexBuffer.get(); }
|
||||
|
||||
virtual void execute(GrDrawTarget*);
|
||||
|
||||
DrawInfo fInfo;
|
||||
|
||||
private:
|
||||
GrPendingIOResource<const GrVertexBuffer, kRead_GrIOType> fVertexBuffer;
|
||||
GrPendingIOResource<const GrIndexBuffer, kRead_GrIOType> fIndexBuffer;
|
||||
};
|
||||
|
||||
struct StencilPath : public Cmd {
|
||||
StencilPath(const GrPath* path) : Cmd(kStencilPath_Cmd), fPath(path) {}
|
||||
struct StencilPath : public ::SkNoncopyable {
|
||||
StencilPath(const GrPath* path) : fPath(path) {}
|
||||
|
||||
const GrPath* path() const { return fPath.get(); }
|
||||
|
||||
virtual void execute(GrDrawTarget*);
|
||||
|
||||
SkPath::FillType fFill;
|
||||
|
||||
private:
|
||||
GrPendingIOResource<const GrPath, kRead_GrIOType> fPath;
|
||||
};
|
||||
|
||||
struct DrawPath : public Cmd {
|
||||
DrawPath(const GrPath* path) : Cmd(kDrawPath_Cmd), fPath(path) {}
|
||||
struct DrawPath : public ::SkNoncopyable {
|
||||
DrawPath(const GrPath* path) : fPath(path) {}
|
||||
|
||||
const GrPath* path() const { return fPath.get(); }
|
||||
|
||||
virtual void execute(GrDrawTarget*);
|
||||
|
||||
SkPath::FillType fFill;
|
||||
GrDeviceCoordTexture fDstCopy;
|
||||
|
||||
@ -154,16 +136,24 @@ private:
|
||||
GrPendingIOResource<const GrPath, kRead_GrIOType> fPath;
|
||||
};
|
||||
|
||||
struct DrawPaths : public Cmd {
|
||||
DrawPaths(const GrPathRange* pathRange) : Cmd(kDrawPaths_Cmd), fPathRange(pathRange) {}
|
||||
struct DrawPaths : public ::SkNoncopyable {
|
||||
DrawPaths(const GrPathRange* pathRange)
|
||||
: fPathRange(pathRange) {}
|
||||
|
||||
~DrawPaths() {
|
||||
if (fTransforms) {
|
||||
SkDELETE_ARRAY(fTransforms);
|
||||
}
|
||||
if (fIndices) {
|
||||
SkDELETE_ARRAY(fIndices);
|
||||
}
|
||||
}
|
||||
|
||||
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(GrDrawTarget*);
|
||||
|
||||
uint32_t* fIndices;
|
||||
size_t fCount;
|
||||
float* fTransforms;
|
||||
PathTransformType fTransformsType;
|
||||
SkPath::FillType fFill;
|
||||
GrDeviceCoordTexture fDstCopy;
|
||||
@ -173,13 +163,11 @@ private:
|
||||
};
|
||||
|
||||
// This is also used to record a discard by setting the color to GrColor_ILLEGAL
|
||||
struct Clear : public Cmd {
|
||||
Clear(GrRenderTarget* rt) : Cmd(kClear_Cmd), fRenderTarget(rt) {}
|
||||
|
||||
struct Clear : public ::SkNoncopyable {
|
||||
Clear(GrRenderTarget* rt) : fRenderTarget(rt) {}
|
||||
~Clear() { }
|
||||
GrRenderTarget* renderTarget() const { return fRenderTarget.get(); }
|
||||
|
||||
virtual void execute(GrDrawTarget*);
|
||||
|
||||
SkIRect fRect;
|
||||
GrColor fColor;
|
||||
bool fCanIgnoreRect;
|
||||
@ -188,14 +176,12 @@ private:
|
||||
GrPendingIOResource<GrRenderTarget, kWrite_GrIOType> fRenderTarget;
|
||||
};
|
||||
|
||||
struct CopySurface : public Cmd {
|
||||
CopySurface(GrSurface* dst, GrSurface* src) : Cmd(kCopySurface_Cmd), fDst(dst), fSrc(src) {}
|
||||
struct CopySurface : public ::SkNoncopyable {
|
||||
CopySurface(GrSurface* dst, GrSurface* src) : fDst(dst), fSrc(src) {}
|
||||
|
||||
GrSurface* dst() const { return fDst.get(); }
|
||||
GrSurface* src() const { return fSrc.get(); }
|
||||
|
||||
virtual void execute(GrDrawTarget*);
|
||||
|
||||
SkIPoint fDstPoint;
|
||||
SkIRect fSrcRect;
|
||||
|
||||
@ -204,33 +190,11 @@ private:
|
||||
GrPendingIOResource<GrSurface, kRead_GrIOType> fSrc;
|
||||
};
|
||||
|
||||
struct SetState : public Cmd {
|
||||
SetState(const GrDrawState& state) : Cmd(kSetState_Cmd), fState(state) {}
|
||||
|
||||
virtual void execute(GrDrawTarget*);
|
||||
|
||||
GrDrawState fState;
|
||||
struct Clip : public ::SkNoncopyable {
|
||||
SkClipStack fStack;
|
||||
SkIPoint fOrigin;
|
||||
};
|
||||
|
||||
struct SetClip : public Cmd {
|
||||
SetClip(const GrClipData* clipData)
|
||||
: Cmd(kSetClip_Cmd),
|
||||
fStackStorage(*clipData->fClipStack) {
|
||||
fClipData.fClipStack = &fStackStorage;
|
||||
fClipData.fOrigin = clipData->fOrigin;
|
||||
}
|
||||
|
||||
virtual void execute(GrDrawTarget*);
|
||||
|
||||
GrClipData fClipData;
|
||||
|
||||
private:
|
||||
SkClipStack fStackStorage;
|
||||
};
|
||||
|
||||
typedef void* TCmdAlign; // This wouldn't be enough align if a command used long double.
|
||||
typedef GrTRecorder<Cmd, TCmdAlign> CmdBuffer;
|
||||
|
||||
// overrides from GrDrawTarget
|
||||
virtual void onDraw(const DrawInfo&) SK_OVERRIDE;
|
||||
virtual void onDrawRect(const SkRect& rect,
|
||||
@ -283,25 +247,57 @@ private:
|
||||
// Determines whether the current draw operation requieres a new drawstate and if so records it.
|
||||
void recordStateIfNecessary();
|
||||
// We lazily record clip changes in order to skip clips that have no effect.
|
||||
void recordClipIfNecessary();
|
||||
// Records any trace markers for a command after adding it to the buffer.
|
||||
void recordTraceMarkersIfNecessary();
|
||||
bool needsNewClip() const;
|
||||
|
||||
// these functions record a command
|
||||
void recordState();
|
||||
void recordClip();
|
||||
Draw* recordDraw(const DrawInfo&, const GrVertexBuffer*, const GrIndexBuffer*);
|
||||
StencilPath* recordStencilPath(const GrPath*);
|
||||
DrawPath* recordDrawPath(const GrPath*);
|
||||
DrawPaths* recordDrawPaths(const GrPathRange*);
|
||||
Clear* recordClear(GrRenderTarget*);
|
||||
CopySurface* recordCopySurface(GrSurface* dst, GrSurface* src);
|
||||
|
||||
virtual bool isIssued(uint32_t drawID) { return drawID != fDrawID; }
|
||||
void addToCmdBuffer(uint8_t cmd);
|
||||
|
||||
// TODO: Use a single allocator for commands and records
|
||||
enum {
|
||||
kCmdBufferInitialSizeInBytes = 64 * 1024,
|
||||
kGeoPoolStatePreAllocCnt = 4,
|
||||
kCmdPreallocCnt = 32,
|
||||
kDrawPreallocCnt = 16,
|
||||
kStencilPathPreallocCnt = 8,
|
||||
kDrawPathPreallocCnt = 8,
|
||||
kDrawPathsPreallocCnt = 8,
|
||||
kStatePreallocCnt = 8,
|
||||
kClipPreallocCnt = 8,
|
||||
kClearPreallocCnt = 8,
|
||||
kGeoPoolStatePreAllocCnt = 4,
|
||||
kCopySurfacePreallocCnt = 4,
|
||||
};
|
||||
|
||||
CmdBuffer fCmdBuffer;
|
||||
GrDrawState* fLastState;
|
||||
GrClipData* fLastClip;
|
||||
typedef GrTAllocator<Draw> DrawAllocator;
|
||||
typedef GrTAllocator<StencilPath> StencilPathAllocator;
|
||||
typedef GrTAllocator<DrawPath> DrawPathAllocator;
|
||||
typedef GrTAllocator<DrawPaths> DrawPathsAllocator;
|
||||
typedef GrTAllocator<GrDrawState> StateAllocator;
|
||||
typedef GrTAllocator<Clear> ClearAllocator;
|
||||
typedef GrTAllocator<CopySurface> CopySurfaceAllocator;
|
||||
typedef GrTAllocator<Clip> ClipAllocator;
|
||||
|
||||
SkTArray<GrTraceMarkerSet, false> fGpuCmdMarkers;
|
||||
GrDrawTarget* fDstGpu;
|
||||
bool fClipSet;
|
||||
GrSTAllocator<kDrawPreallocCnt, Draw> fDraws;
|
||||
GrSTAllocator<kStencilPathPreallocCnt, StencilPath> fStencilPaths;
|
||||
GrSTAllocator<kDrawPathPreallocCnt, DrawPath> fDrawPath;
|
||||
GrSTAllocator<kDrawPathsPreallocCnt, DrawPaths> fDrawPaths;
|
||||
GrSTAllocator<kStatePreallocCnt, GrDrawState> fStates;
|
||||
GrSTAllocator<kClearPreallocCnt, Clear> fClears;
|
||||
GrSTAllocator<kCopySurfacePreallocCnt, CopySurface> fCopySurfaces;
|
||||
GrSTAllocator<kClipPreallocCnt, Clip> fClips;
|
||||
|
||||
SkTArray<GrTraceMarkerSet, false> fGpuCmdMarkers;
|
||||
SkSTArray<kCmdPreallocCnt, uint8_t, true> fCmds;
|
||||
GrDrawTarget* fDstGpu;
|
||||
bool fClipSet;
|
||||
|
||||
enum ClipProxyState {
|
||||
kUnknown_ClipProxyState,
|
||||
|
@ -1,251 +0,0 @@
|
||||
/*
|
||||
* Copyright 2014 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef GrTRecorder_DEFINED
|
||||
#define GrTRecorder_DEFINED
|
||||
|
||||
#include "SkTemplates.h"
|
||||
#include "SkTypes.h"
|
||||
|
||||
template<typename TBase, typename TAlign> class GrTRecorder;
|
||||
template<typename TItem> struct GrTRecorderAllocWrapper;
|
||||
|
||||
/**
|
||||
* Records a list of items with a common base type, optional associated data, and
|
||||
* permanent memory addresses.
|
||||
*
|
||||
* This class preallocates its own chunks of memory for hosting objects, so new items can
|
||||
* be created without excessive calls to malloc().
|
||||
*
|
||||
* To create a new item and append it to the back of the list, use the following macros:
|
||||
*
|
||||
* GrNEW_APPEND_TO_RECORDER(recorder, SubclassName, (args))
|
||||
* GrNEW_APPEND_WITH_DATA_TO_RECORDER(recorder, SubclassName, (args), sizeOfData)
|
||||
*
|
||||
* Upon reset or delete, the items are destructed in the same order they were received,
|
||||
* not reverse (stack) order.
|
||||
*
|
||||
* @param TBase Common base type of items in the list. If TBase is not a class with a
|
||||
* virtual destructor, the client is responsible for invoking any necessary
|
||||
* destructors.
|
||||
*
|
||||
* For now, any subclass used in the list must have the same start address
|
||||
* as TBase (or in other words, the types must be convertible via
|
||||
* reinterpret_cast<>). Classes with multiple inheritance (or any subclass
|
||||
* on an obscure compiler) may not be compatible. This is runtime asserted
|
||||
* in debug builds.
|
||||
*
|
||||
* @param TAlign A type whose size is the desired memory alignment for object allocations.
|
||||
* This should be the largest known alignment requirement for all objects
|
||||
* that may be stored in the list.
|
||||
*/
|
||||
template<typename TBase, typename TAlign> class GrTRecorder : SkNoncopyable {
|
||||
public:
|
||||
class Iter;
|
||||
|
||||
/**
|
||||
* Create a recorder.
|
||||
*
|
||||
* @param initialSizeInBytes The amount of memory reserved by the recorder initially,
|
||||
and after calls to reset().
|
||||
*/
|
||||
GrTRecorder(int initialSizeInBytes)
|
||||
: fHeadBlock(MemBlock::Alloc(LengthOf(initialSizeInBytes))),
|
||||
fTailBlock(fHeadBlock),
|
||||
fLastItem(NULL) {}
|
||||
|
||||
~GrTRecorder() {
|
||||
this->reset();
|
||||
sk_free(fHeadBlock);
|
||||
}
|
||||
|
||||
bool empty() { return !fLastItem; }
|
||||
|
||||
TBase& back() {
|
||||
SkASSERT(!this->empty());
|
||||
return *fLastItem;
|
||||
}
|
||||
|
||||
/**
|
||||
* Destruct all items in the list and reset to empty.
|
||||
*/
|
||||
void reset();
|
||||
|
||||
/**
|
||||
* Retrieve the extra data associated with an item that was allocated using
|
||||
* GrNEW_APPEND_WITH_DATA_TO_RECORDER().
|
||||
*
|
||||
* @param item The item whose data to retrieve. The pointer must be of the same type
|
||||
* that was allocated initally; it can't be a pointer to a base class.
|
||||
*
|
||||
* @return The item's associated data.
|
||||
*/
|
||||
template<typename TItem> static const void* GetDataForItem(const TItem* item) {
|
||||
const TAlign* ptr = reinterpret_cast<const TAlign*>(item);
|
||||
return &ptr[length_of<TItem>::kValue];
|
||||
}
|
||||
template<typename TItem> static void* GetDataForItem(TItem* item) {
|
||||
TAlign* ptr = reinterpret_cast<TAlign*>(item);
|
||||
return &ptr[length_of<TItem>::kValue];
|
||||
}
|
||||
|
||||
private:
|
||||
template<typename TItem> struct length_of {
|
||||
enum { kValue = (sizeof(TItem) + sizeof(TAlign) - 1) / sizeof(TAlign) };
|
||||
};
|
||||
static int LengthOf(int bytes) { return (bytes + sizeof(TAlign) - 1) / sizeof(TAlign); }
|
||||
|
||||
struct Header {
|
||||
int fTotalLength;
|
||||
};
|
||||
template<typename TItem> TItem* alloc_back(int dataLength);
|
||||
|
||||
struct MemBlock {
|
||||
static MemBlock* Alloc(int length) {
|
||||
void* ptr = sk_malloc_throw(sizeof(TAlign) * (length_of<MemBlock>::kValue + length));
|
||||
return SkNEW_PLACEMENT_ARGS(ptr, MemBlock, (length));
|
||||
}
|
||||
TAlign& operator [](int i) {
|
||||
return reinterpret_cast<TAlign*>(this)[length_of<MemBlock>::kValue + i];
|
||||
}
|
||||
~MemBlock() { sk_free(fNext); }
|
||||
|
||||
const int fLength;
|
||||
int fBack;
|
||||
MemBlock* fNext;
|
||||
|
||||
private:
|
||||
MemBlock(int length) : fLength(length), fBack(0), fNext(NULL) {}
|
||||
};
|
||||
MemBlock* const fHeadBlock;
|
||||
MemBlock* fTailBlock;
|
||||
|
||||
TBase* fLastItem;
|
||||
|
||||
template<typename TItem> friend struct GrTRecorderAllocWrapper;
|
||||
|
||||
template <typename UBase, typename UAlign, typename UAlloc>
|
||||
friend void* operator new(size_t, GrTRecorder<UBase, UAlign>&,
|
||||
const GrTRecorderAllocWrapper<UAlloc>&);
|
||||
|
||||
friend class Iter;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template<typename TBase, typename TAlign>
|
||||
template<typename TItem>
|
||||
TItem* GrTRecorder<TBase, TAlign>::alloc_back(int dataLength) {
|
||||
const int totalLength = length_of<Header>::kValue + length_of<TItem>::kValue + dataLength;
|
||||
|
||||
if (fTailBlock->fBack + totalLength > fTailBlock->fLength) {
|
||||
SkASSERT(!fTailBlock->fNext);
|
||||
fTailBlock->fNext = MemBlock::Alloc(SkTMax(2 * fTailBlock->fLength, totalLength));
|
||||
fTailBlock = fTailBlock->fNext;
|
||||
}
|
||||
|
||||
Header* header = reinterpret_cast<Header*>(&(*fTailBlock)[fTailBlock->fBack]);
|
||||
TItem* rawPtr = reinterpret_cast<TItem*>(
|
||||
&(*fTailBlock)[fTailBlock->fBack + length_of<Header>::kValue]);
|
||||
|
||||
header->fTotalLength = totalLength;
|
||||
fLastItem = rawPtr;
|
||||
fTailBlock->fBack += totalLength;
|
||||
|
||||
// FIXME: We currently require that the base and subclass share the same start address.
|
||||
// This is not required by the C++ spec, and is likely to not be true in the case of
|
||||
// multiple inheritance or a base class that doesn't have virtual methods (when the
|
||||
// subclass does). It would be ideal to find a more robust solution that comes at no
|
||||
// extra cost to performance or code generality.
|
||||
SkDEBUGCODE(void* baseAddr = fLastItem;
|
||||
void* subclassAddr = rawPtr);
|
||||
SkASSERT(baseAddr == subclassAddr);
|
||||
|
||||
return rawPtr;
|
||||
}
|
||||
|
||||
template<typename TBase, typename TAlign>
|
||||
class GrTRecorder<TBase, TAlign>::Iter {
|
||||
public:
|
||||
Iter(GrTRecorder& recorder) : fBlock(recorder.fHeadBlock), fPosition(0), fItem(NULL) {}
|
||||
|
||||
bool next() {
|
||||
if (fPosition >= fBlock->fBack) {
|
||||
SkASSERT(fPosition == fBlock->fBack);
|
||||
if (!fBlock->fNext) {
|
||||
return false;
|
||||
}
|
||||
SkASSERT(0 != fBlock->fNext->fBack);
|
||||
fBlock = fBlock->fNext;
|
||||
fPosition = 0;
|
||||
}
|
||||
|
||||
Header* header = reinterpret_cast<Header*>(&(*fBlock)[fPosition]);
|
||||
fItem = reinterpret_cast<TBase*>(&(*fBlock)[fPosition + length_of<Header>::kValue]);
|
||||
fPosition += header->fTotalLength;
|
||||
return true;
|
||||
}
|
||||
|
||||
TBase* get() const {
|
||||
SkASSERT(fItem);
|
||||
return fItem;
|
||||
}
|
||||
|
||||
TBase* operator->() const { return this->get(); }
|
||||
|
||||
private:
|
||||
MemBlock* fBlock;
|
||||
int fPosition;
|
||||
TBase* fItem;
|
||||
};
|
||||
|
||||
template<typename TBase, typename TAlign>
|
||||
void GrTRecorder<TBase, TAlign>::reset() {
|
||||
Iter iter(*this);
|
||||
while (iter.next()) {
|
||||
iter->~TBase();
|
||||
}
|
||||
fHeadBlock->fBack = 0;
|
||||
sk_free(fHeadBlock->fNext);
|
||||
fHeadBlock->fNext = NULL;
|
||||
fTailBlock = fHeadBlock;
|
||||
fLastItem = NULL;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template<typename TItem> struct GrTRecorderAllocWrapper {
|
||||
GrTRecorderAllocWrapper() : fDataLength(0) {}
|
||||
|
||||
template <typename TBase, typename TAlign>
|
||||
GrTRecorderAllocWrapper(const GrTRecorder<TBase, TAlign>&, int sizeOfData)
|
||||
: fDataLength(GrTRecorder<TBase, TAlign>::LengthOf(sizeOfData)) {}
|
||||
|
||||
const int fDataLength;
|
||||
};
|
||||
|
||||
template <typename TBase, typename TAlign, typename TItem>
|
||||
void* operator new(size_t size, GrTRecorder<TBase, TAlign>& recorder,
|
||||
const GrTRecorderAllocWrapper<TItem>& wrapper) {
|
||||
SkASSERT(size == sizeof(TItem));
|
||||
return recorder.template alloc_back<TItem>(wrapper.fDataLength);
|
||||
}
|
||||
|
||||
template <typename TBase, typename TAlign, typename TItem>
|
||||
void operator delete(void*, GrTRecorder<TBase, TAlign>&, const GrTRecorderAllocWrapper<TItem>&) {
|
||||
// We only provide an operator delete to work around compiler warnings that can come
|
||||
// up for an unmatched operator new when compiling with exceptions.
|
||||
SK_CRASH();
|
||||
}
|
||||
|
||||
#define GrNEW_APPEND_TO_RECORDER(recorder, type_name, args) \
|
||||
(new (recorder, GrTRecorderAllocWrapper<type_name>()) type_name args)
|
||||
|
||||
#define GrNEW_APPEND_WITH_DATA_TO_RECORDER(recorder, type_name, args, size_of_data) \
|
||||
(new (recorder, GrTRecorderAllocWrapper<type_name>(recorder, size_of_data)) type_name args)
|
||||
|
||||
#endif
|
@ -1,244 +0,0 @@
|
||||
/*
|
||||
* Copyright 2014 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#if SK_SUPPORT_GPU
|
||||
|
||||
#include "SkMatrix.h"
|
||||
#include "SkString.h"
|
||||
#include "GrTRecorder.h"
|
||||
#include "Test.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static int activeRecorderItems = 0;
|
||||
|
||||
class IntWrapper {
|
||||
public:
|
||||
IntWrapper() {}
|
||||
IntWrapper(int value) : fValue(value) {}
|
||||
operator int() { return fValue; }
|
||||
private:
|
||||
int fValue;
|
||||
};
|
||||
|
||||
static void test_empty_back(skiatest::Reporter* reporter) {
|
||||
GrTRecorder<IntWrapper, int> recorder(0);
|
||||
|
||||
REPORTER_ASSERT(reporter, recorder.empty());
|
||||
|
||||
for (int i = 0; i < 100; ++i) {
|
||||
REPORTER_ASSERT(reporter, i == *GrNEW_APPEND_TO_RECORDER(recorder, IntWrapper, (i)));
|
||||
REPORTER_ASSERT(reporter, !recorder.empty());
|
||||
REPORTER_ASSERT(reporter, i == recorder.back());
|
||||
}
|
||||
|
||||
REPORTER_ASSERT(reporter, !recorder.empty());
|
||||
|
||||
recorder.reset();
|
||||
|
||||
REPORTER_ASSERT(reporter, recorder.empty());
|
||||
}
|
||||
|
||||
struct ExtraData {
|
||||
typedef GrTRecorder<ExtraData, int> Recorder;
|
||||
|
||||
ExtraData(int i) : fData(i) {
|
||||
int* extraData = this->extraData();
|
||||
for (int j = 0; j < i; j++) {
|
||||
extraData[j] = i;
|
||||
}
|
||||
++activeRecorderItems;
|
||||
}
|
||||
~ExtraData() {
|
||||
--activeRecorderItems;
|
||||
}
|
||||
int* extraData() {
|
||||
return reinterpret_cast<int*>(Recorder::GetDataForItem(this));
|
||||
}
|
||||
int fData;
|
||||
};
|
||||
|
||||
static void test_extra_data(skiatest::Reporter* reporter) {
|
||||
ExtraData::Recorder recorder(0);
|
||||
for (int i = 0; i < 100; ++i) {
|
||||
GrNEW_APPEND_WITH_DATA_TO_RECORDER(recorder, ExtraData, (i), i * sizeof(int));
|
||||
}
|
||||
REPORTER_ASSERT(reporter, 100 == activeRecorderItems);
|
||||
|
||||
ExtraData::Recorder::Iter iter(recorder);
|
||||
for (int i = 0; i < 100; ++i) {
|
||||
REPORTER_ASSERT(reporter, iter.next());
|
||||
REPORTER_ASSERT(reporter, i == iter->fData);
|
||||
for (int j = 0; j < i; j++) {
|
||||
REPORTER_ASSERT(reporter, i == iter->extraData()[j]);
|
||||
}
|
||||
}
|
||||
REPORTER_ASSERT(reporter, !iter.next());
|
||||
|
||||
recorder.reset();
|
||||
REPORTER_ASSERT(reporter, 0 == activeRecorderItems);
|
||||
}
|
||||
|
||||
enum ClassType {
|
||||
kBase_ClassType,
|
||||
kSubclass_ClassType,
|
||||
kSubSubclass_ClassType,
|
||||
kSubclassExtraData_ClassType,
|
||||
kSubclassEmpty_ClassType,
|
||||
|
||||
kNumClassTypes
|
||||
};
|
||||
|
||||
class Base {
|
||||
public:
|
||||
typedef GrTRecorder<Base, void*> Recorder;
|
||||
|
||||
Base() {
|
||||
fMatrix.reset();
|
||||
++activeRecorderItems;
|
||||
}
|
||||
|
||||
virtual ~Base() { --activeRecorderItems; }
|
||||
|
||||
virtual ClassType getType() { return kBase_ClassType; }
|
||||
|
||||
virtual void validate(skiatest::Reporter* reporter) const {
|
||||
REPORTER_ASSERT(reporter, fMatrix.isIdentity());
|
||||
}
|
||||
|
||||
private:
|
||||
SkMatrix fMatrix;
|
||||
};
|
||||
|
||||
class Subclass : public Base {
|
||||
public:
|
||||
Subclass() : fString("Lorem ipsum dolor sit amet") {}
|
||||
|
||||
virtual ClassType getType() { return kSubclass_ClassType; }
|
||||
|
||||
virtual void validate(skiatest::Reporter* reporter) const {
|
||||
Base::validate(reporter);
|
||||
REPORTER_ASSERT(reporter, !strcmp("Lorem ipsum dolor sit amet", fString.c_str()));
|
||||
}
|
||||
|
||||
private:
|
||||
SkString fString;
|
||||
};
|
||||
|
||||
class SubSubclass : public Subclass {
|
||||
public:
|
||||
SubSubclass() : fInt(1234), fFloat(1.234f) {}
|
||||
|
||||
virtual ClassType getType() { return kSubSubclass_ClassType; }
|
||||
|
||||
virtual void validate(skiatest::Reporter* reporter) const {
|
||||
Subclass::validate(reporter);
|
||||
REPORTER_ASSERT(reporter, 1234 == fInt);
|
||||
REPORTER_ASSERT(reporter, 1.234f == fFloat);
|
||||
}
|
||||
|
||||
private:
|
||||
int fInt;
|
||||
float fFloat;
|
||||
};
|
||||
|
||||
class SubclassExtraData : public Base {
|
||||
public:
|
||||
SubclassExtraData(int length) : fLength(length) {
|
||||
int* data = reinterpret_cast<int*>(Recorder::GetDataForItem(this));
|
||||
for (int i = 0; i < fLength; ++i) {
|
||||
data[i] = 123456789 + 987654321 * i;
|
||||
}
|
||||
}
|
||||
|
||||
virtual ClassType getType() { return kSubclassExtraData_ClassType; }
|
||||
|
||||
virtual void validate(skiatest::Reporter* reporter) const {
|
||||
Base::validate(reporter);
|
||||
const int* data = reinterpret_cast<const int*>(Recorder::GetDataForItem(this));
|
||||
for (int i = 0; i < fLength; ++i) {
|
||||
REPORTER_ASSERT(reporter, 123456789 + 987654321 * i == data[i]);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
int fLength;
|
||||
};
|
||||
|
||||
class SubclassEmpty : public Base {
|
||||
public:
|
||||
virtual ClassType getType() { return kSubclassEmpty_ClassType; }
|
||||
};
|
||||
|
||||
static void test_subclasses(skiatest::Reporter* reporter) {
|
||||
class Order {
|
||||
public:
|
||||
Order() { this->reset(); }
|
||||
void reset() { fCurrent = 0; }
|
||||
ClassType next() {
|
||||
fCurrent = 1664525 * fCurrent + 1013904223;
|
||||
return static_cast<ClassType>(fCurrent % kNumClassTypes);
|
||||
}
|
||||
private:
|
||||
uint32_t fCurrent;
|
||||
};
|
||||
|
||||
Base::Recorder recorder(1024);
|
||||
|
||||
Order order;
|
||||
for (int i = 0; i < 1000; i++) {
|
||||
switch (order.next()) {
|
||||
case kBase_ClassType:
|
||||
GrNEW_APPEND_TO_RECORDER(recorder, Base, ());
|
||||
break;
|
||||
|
||||
case kSubclass_ClassType:
|
||||
GrNEW_APPEND_TO_RECORDER(recorder, Subclass, ());
|
||||
break;
|
||||
|
||||
case kSubSubclass_ClassType:
|
||||
GrNEW_APPEND_TO_RECORDER(recorder, SubSubclass, ());
|
||||
break;
|
||||
|
||||
case kSubclassExtraData_ClassType:
|
||||
GrNEW_APPEND_WITH_DATA_TO_RECORDER(recorder, SubclassExtraData, (i), sizeof(int) * i);
|
||||
break;
|
||||
|
||||
case kSubclassEmpty_ClassType:
|
||||
GrNEW_APPEND_TO_RECORDER(recorder, SubclassEmpty, ());
|
||||
break;
|
||||
|
||||
default:
|
||||
reporter->reportFailed(SkString("Invalid class type"));
|
||||
break;
|
||||
}
|
||||
}
|
||||
REPORTER_ASSERT(reporter, 1000 == activeRecorderItems);
|
||||
|
||||
order.reset();
|
||||
Base::Recorder::Iter iter(recorder);
|
||||
for (int i = 0; i < 1000; ++i) {
|
||||
REPORTER_ASSERT(reporter, iter.next());
|
||||
REPORTER_ASSERT(reporter, order.next() == iter->getType());
|
||||
iter->validate(reporter);
|
||||
}
|
||||
REPORTER_ASSERT(reporter, !iter.next());
|
||||
|
||||
// Don't reset the recorder. It should automatically destruct all its items.
|
||||
}
|
||||
|
||||
DEF_GPUTEST(GrTRecorder, reporter, factory) {
|
||||
test_empty_back(reporter);
|
||||
|
||||
test_extra_data(reporter);
|
||||
REPORTER_ASSERT(reporter, 0 == activeRecorderItems); // test_extra_data should call reset().
|
||||
|
||||
test_subclasses(reporter);
|
||||
REPORTER_ASSERT(reporter, 0 == activeRecorderItems); // Ensure ~GrTRecorder invokes dtors.
|
||||
}
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user