From: mtklein Date: Tue, 14 Oct 2014 21:29:30 +0000 (-0700) Subject: Revert of Create a single command buffer for GrInOrderDrawBuffer (patchset #17 id... X-Git-Tag: accepted/tizen/5.0/unified/20181102.025319~5414 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=f439c77e9cfc13a4c31b8cb580b11d6ff09d4ed4;p=platform%2Fupstream%2FlibSkiaSharp.git Revert of Create a single command buffer for GrInOrderDrawBuffer (patchset #17 id:1240001 of https://codereview.chromium.org/628453002/) Reason for revert: Leaking memory: http://build.chromium.org/p/client.skia/builders/Test-Ubuntu12-ShuttleA-GTX550Ti-x86_64-Release-Valgrind/builds/9/steps/gm/logs/stdio Original issue's description: > Adds a GrTRecorder class that GrInOrderDrawBuffer uses to allocate > all its commands interleaved in contiguous memory. GrTRecorder also > supports extra data associated with objects, so we can store arrays > inline without having to call malloc(). > > Committed: https://skia.googlesource.com/skia/+/360b6801cfd90485891d709e44cf395d527ba69e TBR=bsalomon@google.com,reed@google.com,cdalton@nvidia.com NOTREECHECKS=true NOTRY=true Review URL: https://codereview.chromium.org/654863003 --- diff --git a/gyp/gpu.gypi b/gyp/gpu.gypi index e8d2f63..a853cf5 100644 --- a/gyp/gpu.gypi +++ b/gyp/gpu.gypi @@ -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', diff --git a/gyp/tests.gypi b/gyp/tests.gypi index 6a20326..fc0d69d 100644 --- a/gyp/tests.gypi +++ b/gyp/tests.gypi @@ -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', diff --git a/src/gpu/GrInOrderDrawBuffer.cpp b/src/gpu/GrInOrderDrawBuffer.cpp index 753a379..b9e84c0 100644 --- a/src/gpu/GrInOrderDrawBuffer.cpp +++ b/src/gpu/GrInOrderDrawBuffer.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(&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; - int currCmdMarker = 0; - fDstGpu->saveActiveTraceMarkers(); + 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; - while (iter.next()) { + fDstGpu->saveActiveTraceMarkers(); + 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,55 +832,94 @@ 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::recordTraceMarkersIfNecessary() { - SkASSERT(!fCmdBuffer.empty()); - SkASSERT(!cmd_has_trace_marker(fCmdBuffer.back().fType)); +void GrInOrderDrawBuffer::addToCmdBuffer(uint8_t cmd) { + SkASSERT(!cmd_has_trace_marker(cmd)); const GrTraceMarkerSet& activeTraceMarkers = this->getActiveTraceMarkers(); if (activeTraceMarkers.count() > 0) { - fCmdBuffer.back().fType = add_trace_bit(fCmdBuffer.back().fType); + fCmds.push_back(add_trace_bit(cmd)); fGpuCmdMarkers.push_back(activeTraceMarkers); + } else { + fCmds.push_back(cmd); } } +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) { INHERITED::clipWillBeSet(newClipData); fClipSet = true; diff --git a/src/gpu/GrInOrderDrawBuffer.h b/src/gpu/GrInOrderDrawBuffer.h index 5d0fc04..485de07 100644 --- a/src/gpu/GrInOrderDrawBuffer.h +++ b/src/gpu/GrInOrderDrawBuffer.h @@ -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 fVertexBuffer; GrPendingIOResource 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 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 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(CmdBuffer::GetDataForItem(this)); } - float* transforms() { return reinterpret_cast(&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 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 fSrc; }; - struct SetState : public Cmd { - SetState(const GrDrawState& state) : Cmd(kSetState_Cmd), fState(state) {} - - virtual void execute(GrDrawTarget*); - - GrDrawState fState; - }; - - 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; + struct Clip : public ::SkNoncopyable { + SkClipStack fStack; + SkIPoint fOrigin; }; - typedef void* TCmdAlign; // This wouldn't be enough align if a command used long double. - typedef GrTRecorder 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; - - SkTArray fGpuCmdMarkers; - GrDrawTarget* fDstGpu; - bool fClipSet; + typedef GrTAllocator DrawAllocator; + typedef GrTAllocator StencilPathAllocator; + typedef GrTAllocator DrawPathAllocator; + typedef GrTAllocator DrawPathsAllocator; + typedef GrTAllocator StateAllocator; + typedef GrTAllocator ClearAllocator; + typedef GrTAllocator CopySurfaceAllocator; + typedef GrTAllocator ClipAllocator; + + GrSTAllocator fDraws; + GrSTAllocator fStencilPaths; + GrSTAllocator fDrawPath; + GrSTAllocator fDrawPaths; + GrSTAllocator fStates; + GrSTAllocator fClears; + GrSTAllocator fCopySurfaces; + GrSTAllocator fClips; + + SkTArray fGpuCmdMarkers; + SkSTArray fCmds; + GrDrawTarget* fDstGpu; + bool fClipSet; enum ClipProxyState { kUnknown_ClipProxyState, diff --git a/src/gpu/GrTRecorder.h b/src/gpu/GrTRecorder.h deleted file mode 100644 index c8f7644..0000000 --- a/src/gpu/GrTRecorder.h +++ /dev/null @@ -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 class GrTRecorder; -template 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 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 static const void* GetDataForItem(const TItem* item) { - const TAlign* ptr = reinterpret_cast(item); - return &ptr[length_of::kValue]; - } - template static void* GetDataForItem(TItem* item) { - TAlign* ptr = reinterpret_cast(item); - return &ptr[length_of::kValue]; - } - -private: - template 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 TItem* alloc_back(int dataLength); - - struct MemBlock { - static MemBlock* Alloc(int length) { - void* ptr = sk_malloc_throw(sizeof(TAlign) * (length_of::kValue + length)); - return SkNEW_PLACEMENT_ARGS(ptr, MemBlock, (length)); - } - TAlign& operator [](int i) { - return reinterpret_cast(this)[length_of::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 friend struct GrTRecorderAllocWrapper; - - template - friend void* operator new(size_t, GrTRecorder&, - const GrTRecorderAllocWrapper&); - - friend class Iter; -}; - -//////////////////////////////////////////////////////////////////////////////// - -template -template -TItem* GrTRecorder::alloc_back(int dataLength) { - const int totalLength = length_of
::kValue + length_of::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(&(*fTailBlock)[fTailBlock->fBack]); - TItem* rawPtr = reinterpret_cast( - &(*fTailBlock)[fTailBlock->fBack + length_of
::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 -class GrTRecorder::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(&(*fBlock)[fPosition]); - fItem = reinterpret_cast(&(*fBlock)[fPosition + length_of
::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 -void GrTRecorder::reset() { - Iter iter(*this); - while (iter.next()) { - iter->~TBase(); - } - fHeadBlock->fBack = 0; - sk_free(fHeadBlock->fNext); - fHeadBlock->fNext = NULL; - fTailBlock = fHeadBlock; - fLastItem = NULL; -} - -//////////////////////////////////////////////////////////////////////////////// - -template struct GrTRecorderAllocWrapper { - GrTRecorderAllocWrapper() : fDataLength(0) {} - - template - GrTRecorderAllocWrapper(const GrTRecorder&, int sizeOfData) - : fDataLength(GrTRecorder::LengthOf(sizeOfData)) {} - - const int fDataLength; -}; - -template -void* operator new(size_t size, GrTRecorder& recorder, - const GrTRecorderAllocWrapper& wrapper) { - SkASSERT(size == sizeof(TItem)); - return recorder.template alloc_back(wrapper.fDataLength); -} - -template -void operator delete(void*, GrTRecorder&, const GrTRecorderAllocWrapper&) { - // 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 args) - -#define GrNEW_APPEND_WITH_DATA_TO_RECORDER(recorder, type_name, args, size_of_data) \ - (new (recorder, GrTRecorderAllocWrapper(recorder, size_of_data)) type_name args) - -#endif diff --git a/tests/GrTRecorderTest.cpp b/tests/GrTRecorderTest.cpp deleted file mode 100644 index a5aedf6..0000000 --- a/tests/GrTRecorderTest.cpp +++ /dev/null @@ -1,245 +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 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 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(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 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(Recorder::GetDataForItem(this)); - for (int i = 0; i < fLength; ++i) { - data[i] = ValueAt(i); - } - } - - virtual ClassType getType() { return kSubclassExtraData_ClassType; } - - virtual void validate(skiatest::Reporter* reporter) const { - Base::validate(reporter); - const int* data = reinterpret_cast(Recorder::GetDataForItem(this)); - for (int i = 0; i < fLength; ++i) { - REPORTER_ASSERT(reporter, ValueAt(i) == data[i]); - } - } - -private: - static int ValueAt(uint64_t i) { return static_cast(123456789 + 987654321 * i); } - 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(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