diff options
author | 2015-03-03 12:40:49 -0800 | |
---|---|---|
committer | 2015-03-03 12:40:50 -0800 | |
commit | 193ea935b0a6d94abc533cbdf60c2ac77fe71f1c (patch) | |
tree | 8f15a0e38a507cca09ef8ae0e1a5e1af85df2481 /src/gpu/GrTargetCommands.cpp | |
parent | 030854eb92a9745ffbfe874e1f57d6a2423903eb (diff) |
Split GrTargetCommands into its own files
Review URL: https://codereview.chromium.org/979493002
Diffstat (limited to 'src/gpu/GrTargetCommands.cpp')
-rw-r--r-- | src/gpu/GrTargetCommands.cpp | 472 |
1 files changed, 472 insertions, 0 deletions
diff --git a/src/gpu/GrTargetCommands.cpp b/src/gpu/GrTargetCommands.cpp new file mode 100644 index 0000000000..d326226d1f --- /dev/null +++ b/src/gpu/GrTargetCommands.cpp @@ -0,0 +1,472 @@ +/* + * Copyright 2015 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "GrTargetCommands.h" + +#include "GrColor.h" +#include "GrDefaultGeoProcFactory.h" +#include "GrInOrderDrawBuffer.h" +#include "GrTemplates.h" +#include "SkPoint.h" + +void GrTargetCommands::closeBatch() { + if (fDrawBatch) { + fBatchTarget.resetNumberOfDraws(); + fDrawBatch->execute(NULL, fPrevState); + fDrawBatch->fBatch->setNumberOfDraws(fBatchTarget.numberOfDraws()); + fDrawBatch = NULL; + } +} + +static bool path_fill_type_is_winding(const GrStencilSettings& pathStencilSettings) { + static const GrStencilSettings::Face pathFace = GrStencilSettings::kFront_Face; + bool isWinding = kInvert_StencilOp != pathStencilSettings.passOp(pathFace); + if (isWinding) { + // Double check that it is in fact winding. + SkASSERT(kIncClamp_StencilOp == pathStencilSettings.passOp(pathFace)); + SkASSERT(kIncClamp_StencilOp == pathStencilSettings.failOp(pathFace)); + SkASSERT(0x1 != pathStencilSettings.writeMask(pathFace)); + SkASSERT(!pathStencilSettings.isTwoSided()); + } + return isWinding; +} + +int GrTargetCommands::concatInstancedDraw(GrInOrderDrawBuffer* iodb, + const GrDrawTarget::DrawInfo& info) { + SkASSERT(!fCmdBuffer.empty()); + SkASSERT(info.isInstanced()); + + const GrIndexBuffer* ib; + if (!iodb->canConcatToIndexBuffer(&ib)) { + return 0; + } + + // Check if there is a draw info that is compatible that uses the same VB from the pool and + // the same IB + if (Cmd::kDraw_Cmd != fCmdBuffer.back().type()) { + return 0; + } + + Draw* draw = static_cast<Draw*>(&fCmdBuffer.back()); + + if (!draw->fInfo.isInstanced() || + draw->fInfo.primitiveType() != info.primitiveType() || + draw->fInfo.verticesPerInstance() != info.verticesPerInstance() || + draw->fInfo.indicesPerInstance() != info.indicesPerInstance() || + draw->fInfo.vertexBuffer() != info.vertexBuffer() || + draw->fInfo.indexBuffer() != ib) { + return 0; + } + if (draw->fInfo.startVertex() + draw->fInfo.vertexCount() != info.startVertex()) { + return 0; + } + + // how many instances can be concat'ed onto draw given the size of the index buffer + int instancesToConcat = iodb->indexCountInCurrentSource() / info.indicesPerInstance(); + instancesToConcat -= draw->fInfo.instanceCount(); + instancesToConcat = SkTMin(instancesToConcat, info.instanceCount()); + + draw->fInfo.adjustInstanceCount(instancesToConcat); + + // update last fGpuCmdMarkers to include any additional trace markers that have been added + iodb->recordTraceMarkersIfNecessary(draw); + return instancesToConcat; +} + +GrTargetCommands::Cmd* GrTargetCommands::recordDraw( + GrInOrderDrawBuffer* iodb, + const GrGeometryProcessor* gp, + const GrDrawTarget::DrawInfo& info, + const GrDrawTarget::PipelineInfo& pipelineInfo) { + SkASSERT(info.vertexBuffer() && (!info.isIndexed() || info.indexBuffer())); + this->closeBatch(); + + if (!this->setupPipelineAndShouldDraw(iodb, gp, pipelineInfo)) { + return NULL; + } + + Draw* draw; + if (info.isInstanced()) { + int instancesConcated = this->concatInstancedDraw(iodb, info); + if (info.instanceCount() > instancesConcated) { + draw = GrNEW_APPEND_TO_RECORDER(fCmdBuffer, Draw, (info)); + draw->fInfo.adjustInstanceCount(-instancesConcated); + } else { + return NULL; + } + } else { + draw = GrNEW_APPEND_TO_RECORDER(fCmdBuffer, Draw, (info)); + } + + return draw; +} + +GrTargetCommands::Cmd* GrTargetCommands::recordDrawBatch( + GrInOrderDrawBuffer* iodb, + GrBatch* batch, + const GrDrawTarget::PipelineInfo& pipelineInfo) { + if (!this->setupPipelineAndShouldDraw(iodb, batch, pipelineInfo)) { + return NULL; + } + + // Check if there is a Batch Draw we can batch with + if (Cmd::kDrawBatch_Cmd != fCmdBuffer.back().type() || !fDrawBatch) { + fDrawBatch = GrNEW_APPEND_TO_RECORDER(fCmdBuffer, DrawBatch, (batch, &fBatchTarget)); + return fDrawBatch; + } + + SkASSERT(&fCmdBuffer.back() == fDrawBatch); + if (!fDrawBatch->fBatch->combineIfPossible(batch)) { + this->closeBatch(); + fDrawBatch = GrNEW_APPEND_TO_RECORDER(fCmdBuffer, DrawBatch, (batch, &fBatchTarget)); + } + + return fDrawBatch; +} + +GrTargetCommands::Cmd* GrTargetCommands::recordStencilPath( + GrInOrderDrawBuffer* iodb, + const GrPipelineBuilder& pipelineBuilder, + const GrPathProcessor* pathProc, + const GrPath* path, + const GrScissorState& scissorState, + const GrStencilSettings& stencilSettings) { + this->closeBatch(); + + StencilPath* sp = GrNEW_APPEND_TO_RECORDER(fCmdBuffer, StencilPath, + (path, pipelineBuilder.getRenderTarget())); + + sp->fScissor = scissorState; + sp->fUseHWAA = pipelineBuilder.isHWAntialias(); + sp->fViewMatrix = pathProc->viewMatrix(); + sp->fStencil = stencilSettings; + return sp; +} + +GrTargetCommands::Cmd* GrTargetCommands::recordDrawPath( + GrInOrderDrawBuffer* iodb, + const GrPathProcessor* pathProc, + const GrPath* path, + const GrStencilSettings& stencilSettings, + const GrDrawTarget::PipelineInfo& pipelineInfo) { + this->closeBatch(); + + // TODO: Only compare the subset of GrPipelineBuilder relevant to path covering? + if (!this->setupPipelineAndShouldDraw(iodb, pathProc, pipelineInfo)) { + return NULL; + } + DrawPath* dp = GrNEW_APPEND_TO_RECORDER(fCmdBuffer, DrawPath, (path)); + dp->fStencilSettings = stencilSettings; + return dp; +} + +GrTargetCommands::Cmd* GrTargetCommands::recordDrawPaths( + GrInOrderDrawBuffer* iodb, + const GrPathProcessor* pathProc, + const GrPathRange* pathRange, + const void* indexValues, + GrDrawTarget::PathIndexType indexType, + const float transformValues[], + GrDrawTarget::PathTransformType transformType, + int count, + const GrStencilSettings& stencilSettings, + const GrDrawTarget::PipelineInfo& pipelineInfo) { + SkASSERT(pathRange); + SkASSERT(indexValues); + SkASSERT(transformValues); + this->closeBatch(); + + if (!this->setupPipelineAndShouldDraw(iodb, pathProc, pipelineInfo)) { + return NULL; + } + + char* savedIndices; + float* savedTransforms; + + iodb->appendIndicesAndTransforms(indexValues, indexType, + transformValues, transformType, + count, &savedIndices, &savedTransforms); + + if (Cmd::kDrawPaths_Cmd == fCmdBuffer.back().type()) { + // The previous command was also DrawPaths. Try to collapse this call into the one + // before. Note that stenciling all the paths at once, then covering, may not be + // equivalent to two separate draw calls if there is overlap. Blending won't work, + // and the combined calls may also cancel each other's winding numbers in some + // places. For now the winding numbers are only an issue if the fill is even/odd, + // because DrawPaths is currently only used for glyphs, and glyphs in the same + // font tend to all wind in the same direction. + DrawPaths* previous = static_cast<DrawPaths*>(&fCmdBuffer.back()); + if (pathRange == previous->pathRange() && + indexType == previous->fIndexType && + transformType == previous->fTransformType && + stencilSettings == previous->fStencilSettings && + path_fill_type_is_winding(stencilSettings) && + !pipelineInfo.willBlendWithDst(pathProc)) { + const int indexBytes = GrPathRange::PathIndexSizeInBytes(indexType); + const int xformSize = GrPathRendering::PathTransformSize(transformType); + if (&previous->fIndices[previous->fCount*indexBytes] == savedIndices && + (0 == xformSize || + &previous->fTransforms[previous->fCount*xformSize] == savedTransforms)) { + // Fold this DrawPaths call into the one previous. + previous->fCount += count; + return NULL; + } + } + } + + DrawPaths* dp = GrNEW_APPEND_TO_RECORDER(fCmdBuffer, DrawPaths, (pathRange)); + dp->fIndices = savedIndices; + dp->fIndexType = indexType; + dp->fTransforms = savedTransforms; + dp->fTransformType = transformType; + dp->fCount = count; + dp->fStencilSettings = stencilSettings; + return dp; +} + +GrTargetCommands::Cmd* GrTargetCommands::recordClear(GrInOrderDrawBuffer* iodb, + const SkIRect* rect, + GrColor color, + bool canIgnoreRect, + GrRenderTarget* renderTarget) { + SkASSERT(renderTarget); + this->closeBatch(); + + SkIRect r; + if (NULL == rect) { + // We could do something smart and remove previous draws and clears to + // the current render target. If we get that smart we have to make sure + // those draws aren't read before this clear (render-to-texture). + r.setLTRB(0, 0, renderTarget->width(), renderTarget->height()); + rect = &r; + } + Clear* clr = GrNEW_APPEND_TO_RECORDER(fCmdBuffer, Clear, (renderTarget)); + GrColorIsPMAssert(color); + clr->fColor = color; + clr->fRect = *rect; + clr->fCanIgnoreRect = canIgnoreRect; + return clr; +} + +GrTargetCommands::Cmd* GrTargetCommands::recordClearStencilClip(GrInOrderDrawBuffer* iodb, + const SkIRect& rect, + bool insideClip, + GrRenderTarget* renderTarget) { + SkASSERT(renderTarget); + this->closeBatch(); + + ClearStencilClip* clr = GrNEW_APPEND_TO_RECORDER(fCmdBuffer, ClearStencilClip, (renderTarget)); + clr->fRect = rect; + clr->fInsideClip = insideClip; + return clr; +} + +GrTargetCommands::Cmd* GrTargetCommands::recordDiscard(GrInOrderDrawBuffer* iodb, + GrRenderTarget* renderTarget) { + SkASSERT(renderTarget); + this->closeBatch(); + + Clear* clr = GrNEW_APPEND_TO_RECORDER(fCmdBuffer, Clear, (renderTarget)); + clr->fColor = GrColor_ILLEGAL; + return clr; +} + +void GrTargetCommands::reset() { + fCmdBuffer.reset(); + fPrevState = NULL; + fDrawBatch = NULL; +} + +void GrTargetCommands::flush(GrInOrderDrawBuffer* iodb) { + if (fCmdBuffer.empty()) { + return; + } + + // Updated every time we find a set state cmd to reflect the current state in the playback + // stream. + SetState* currentState = NULL; + + // TODO this is temporary while batch is being rolled out + this->closeBatch(); + iodb->getVertexAllocPool()->unmap(); + iodb->getIndexAllocPool()->unmap(); + fBatchTarget.preFlush(); + + currentState = NULL; + CmdBuffer::Iter iter(fCmdBuffer); + + int currCmdMarker = 0; + + GrGpu* gpu = iodb->getGpu(); + + int i = 0; + while (iter.next()) { + i++; + GrGpuTraceMarker newMarker("", -1); + SkString traceString; + if (iter->isTraced()) { + traceString = iodb->getCmdString(currCmdMarker); + newMarker.fMarker = traceString.c_str(); + gpu->addGpuTraceMarker(&newMarker); + ++currCmdMarker; + } + + // TODO temporary hack + if (Cmd::kDrawBatch_Cmd == iter->type()) { + DrawBatch* db = reinterpret_cast<DrawBatch*>(iter.get()); + fBatchTarget.flushNext(db->fBatch->numberOfDraws()); + continue; + } + + if (Cmd::kSetState_Cmd == iter->type()) { + SetState* ss = reinterpret_cast<SetState*>(iter.get()); + + // TODO sometimes we have a prim proc, othertimes we have a GrBatch. Eventually we + // will only have GrBatch and we can delete this + if (ss->fPrimitiveProcessor) { + gpu->buildProgramDesc(&ss->fDesc, *ss->fPrimitiveProcessor, + *ss->getPipeline(), + ss->fBatchTracker); + } + currentState = ss; + } else { + iter->execute(gpu, currentState); + } + + if (iter->isTraced()) { + gpu->removeGpuTraceMarker(&newMarker); + } + } + + // TODO see copious notes about hack + fBatchTarget.postFlush(); +} + +void GrTargetCommands::Draw::execute(GrGpu* gpu, const SetState* state) { + SkASSERT(state); + DrawArgs args(state->fPrimitiveProcessor.get(), state->getPipeline(), &state->fDesc, + &state->fBatchTracker); + gpu->draw(args, fInfo); +} + +void GrTargetCommands::StencilPath::execute(GrGpu* gpu, const SetState*) { + GrGpu::StencilPathState state; + state.fRenderTarget = fRenderTarget.get(); + state.fScissor = &fScissor; + state.fStencil = &fStencil; + state.fUseHWAA = fUseHWAA; + state.fViewMatrix = &fViewMatrix; + + gpu->stencilPath(this->path(), state); +} + +void GrTargetCommands::DrawPath::execute(GrGpu* gpu, const SetState* state) { + SkASSERT(state); + DrawArgs args(state->fPrimitiveProcessor.get(), state->getPipeline(), &state->fDesc, + &state->fBatchTracker); + gpu->drawPath(args, this->path(), fStencilSettings); +} + +void GrTargetCommands::DrawPaths::execute(GrGpu* gpu, const SetState* state) { + SkASSERT(state); + DrawArgs args(state->fPrimitiveProcessor.get(), state->getPipeline(), &state->fDesc, + &state->fBatchTracker); + gpu->drawPaths(args, this->pathRange(), + fIndices, fIndexType, + fTransforms, fTransformType, + fCount, fStencilSettings); +} + +void GrTargetCommands::DrawBatch::execute(GrGpu*, const SetState* state) { + SkASSERT(state); + fBatch->generateGeometry(fBatchTarget, state->getPipeline()); +} + +void GrTargetCommands::SetState::execute(GrGpu*, const SetState*) {} + +void GrTargetCommands::Clear::execute(GrGpu* gpu, const SetState*) { + if (GrColor_ILLEGAL == fColor) { + gpu->discard(this->renderTarget()); + } else { + gpu->clear(&fRect, fColor, fCanIgnoreRect, this->renderTarget()); + } +} + +void GrTargetCommands::ClearStencilClip::execute(GrGpu* gpu, const SetState*) { + gpu->clearStencilClip(fRect, fInsideClip, this->renderTarget()); +} + +void GrTargetCommands::CopySurface::execute(GrGpu* gpu, const SetState*) { + gpu->copySurface(this->dst(), this->src(), fSrcRect, fDstPoint); +} + +GrTargetCommands::Cmd* GrTargetCommands::recordCopySurface(GrInOrderDrawBuffer* iodb, + GrSurface* dst, + GrSurface* src, + const SkIRect& srcRect, + const SkIPoint& dstPoint) { + if (iodb->getGpu()->canCopySurface(dst, src, srcRect, dstPoint)) { + this->closeBatch(); + CopySurface* cs = GrNEW_APPEND_TO_RECORDER(fCmdBuffer, CopySurface, (dst, src)); + cs->fSrcRect = srcRect; + cs->fDstPoint = dstPoint; + return cs; + } + return NULL; +} + +bool GrTargetCommands::setupPipelineAndShouldDraw(GrInOrderDrawBuffer* iodb, + const GrPrimitiveProcessor* primProc, + const GrDrawTarget::PipelineInfo& pipelineInfo) { + SetState* ss = GrNEW_APPEND_TO_RECORDER(fCmdBuffer, SetState, (primProc)); + iodb->setupPipeline(pipelineInfo, ss->pipelineLocation()); + + if (ss->getPipeline()->mustSkip()) { + fCmdBuffer.pop_back(); + return false; + } + + ss->fPrimitiveProcessor->initBatchTracker(&ss->fBatchTracker, + ss->getPipeline()->getInitBatchTracker()); + + if (fPrevState && fPrevState->fPrimitiveProcessor.get() && + fPrevState->fPrimitiveProcessor->canMakeEqual(fPrevState->fBatchTracker, + *ss->fPrimitiveProcessor, + ss->fBatchTracker) && + fPrevState->getPipeline()->isEqual(*ss->getPipeline())) { + fCmdBuffer.pop_back(); + } else { + fPrevState = ss; + iodb->recordTraceMarkersIfNecessary(ss); + } + return true; +} + +bool GrTargetCommands::setupPipelineAndShouldDraw(GrInOrderDrawBuffer* iodb, + GrBatch* batch, + const GrDrawTarget::PipelineInfo& pipelineInfo) { + SetState* ss = GrNEW_APPEND_TO_RECORDER(fCmdBuffer, SetState, ()); + iodb->setupPipeline(pipelineInfo, ss->pipelineLocation()); + + if (ss->getPipeline()->mustSkip()) { + fCmdBuffer.pop_back(); + return false; + } + + batch->initBatchTracker(ss->getPipeline()->getInitBatchTracker()); + + if (fPrevState && !fPrevState->fPrimitiveProcessor.get() && + fPrevState->getPipeline()->isEqual(*ss->getPipeline())) { + fCmdBuffer.pop_back(); + } else { + this->closeBatch(); + fPrevState = ss; + iodb->recordTraceMarkersIfNecessary(ss); + } + return true; +} + |