Split GrTargetCommands into its own files

Review URL: https://codereview.chromium.org/979493002
diff --git a/src/gpu/GrTargetCommands.cpp b/src/gpu/GrTargetCommands.cpp
new file mode 100644
index 0000000..d326226
--- /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;
+}
+