Home | History | Annotate | Download | only in gpu
      1 /*
      2  * Copyright 2011 Google Inc.
      3  *
      4  * Use of this source code is governed by a BSD-style license that can be
      5  * found in the LICENSE file.
      6  */
      7 
      8 #include "GrInOrderDrawBuffer.h"
      9 
     10 #include "GrBufferAllocPool.h"
     11 #include "GrDrawTargetCaps.h"
     12 #include "GrTextStrike.h"
     13 #include "GrGpu.h"
     14 #include "GrTemplates.h"
     15 #include "GrTexture.h"
     16 
     17 GrInOrderDrawBuffer::GrInOrderDrawBuffer(GrGpu* gpu,
     18                                          GrVertexBufferAllocPool* vertexPool,
     19                                          GrIndexBufferAllocPool* indexPool)
     20     : GrDrawTarget(gpu->getContext())
     21     , fDstGpu(gpu)
     22     , fClipSet(true)
     23     , fClipProxyState(kUnknown_ClipProxyState)
     24     , fVertexPool(*vertexPool)
     25     , fIndexPool(*indexPool)
     26     , fFlushing(false)
     27     , fDrawID(0) {
     28 
     29     fDstGpu->ref();
     30     fCaps.reset(SkRef(fDstGpu->caps()));
     31 
     32     SkASSERT(vertexPool);
     33     SkASSERT(indexPool);
     34 
     35     GeometryPoolState& poolState = fGeoPoolStateStack.push_back();
     36     poolState.fUsedPoolVertexBytes = 0;
     37     poolState.fUsedPoolIndexBytes = 0;
     38 #ifdef SK_DEBUG
     39     poolState.fPoolVertexBuffer = (GrVertexBuffer*)~0;
     40     poolState.fPoolStartVertex = ~0;
     41     poolState.fPoolIndexBuffer = (GrIndexBuffer*)~0;
     42     poolState.fPoolStartIndex = ~0;
     43 #endif
     44     this->reset();
     45 }
     46 
     47 GrInOrderDrawBuffer::~GrInOrderDrawBuffer() {
     48     this->reset();
     49     // This must be called by before the GrDrawTarget destructor
     50     this->releaseGeometry();
     51     fDstGpu->unref();
     52 }
     53 
     54 ////////////////////////////////////////////////////////////////////////////////
     55 
     56 namespace {
     57 void get_vertex_bounds(const void* vertices,
     58                        size_t vertexSize,
     59                        int vertexCount,
     60                        SkRect* bounds) {
     61     SkASSERT(vertexSize >= sizeof(SkPoint));
     62     SkASSERT(vertexCount > 0);
     63     const SkPoint* point = static_cast<const SkPoint*>(vertices);
     64     bounds->fLeft = bounds->fRight = point->fX;
     65     bounds->fTop = bounds->fBottom = point->fY;
     66     for (int i = 1; i < vertexCount; ++i) {
     67         point = reinterpret_cast<SkPoint*>(reinterpret_cast<intptr_t>(point) + vertexSize);
     68         bounds->growToInclude(point->fX, point->fY);
     69     }
     70 }
     71 }
     72 
     73 
     74 namespace {
     75 
     76 extern const GrVertexAttrib kRectAttribs[] = {
     77     {kVec2f_GrVertexAttribType,  0,                               kPosition_GrVertexAttribBinding},
     78     {kVec4ub_GrVertexAttribType, sizeof(SkPoint),                 kColor_GrVertexAttribBinding},
     79     {kVec2f_GrVertexAttribType,  sizeof(SkPoint)+sizeof(GrColor), kLocalCoord_GrVertexAttribBinding},
     80 };
     81 }
     82 
     83 /** We always use per-vertex colors so that rects can be batched across color changes. Sometimes we
     84     have explicit local coords and sometimes not. We *could* always provide explicit local coords
     85     and just duplicate the positions when the caller hasn't provided a local coord rect, but we
     86     haven't seen a use case which frequently switches between local rect and no local rect draws.
     87 
     88     The color param is used to determine whether the opaque hint can be set on the draw state.
     89     The caller must populate the vertex colors itself.
     90 
     91     The vertex attrib order is always pos, color, [local coords].
     92  */
     93 static void set_vertex_attributes(GrDrawState* drawState, bool hasLocalCoords, GrColor color) {
     94     if (hasLocalCoords) {
     95         drawState->setVertexAttribs<kRectAttribs>(3, 2 * sizeof(SkPoint) + sizeof(SkColor));
     96     } else {
     97         drawState->setVertexAttribs<kRectAttribs>(2, sizeof(SkPoint) + sizeof(SkColor));
     98     }
     99     if (0xFF == GrColorUnpackA(color)) {
    100         drawState->setHint(GrDrawState::kVertexColorsAreOpaque_Hint, true);
    101     }
    102 }
    103 
    104 enum {
    105     kTraceCmdBit = 0x80,
    106     kCmdMask = 0x7f,
    107 };
    108 
    109 static inline uint8_t add_trace_bit(uint8_t cmd) { return cmd | kTraceCmdBit; }
    110 
    111 static inline uint8_t strip_trace_bit(uint8_t cmd) { return cmd & kCmdMask; }
    112 
    113 static inline bool cmd_has_trace_marker(uint8_t cmd) { return SkToBool(cmd & kTraceCmdBit); }
    114 
    115 void GrInOrderDrawBuffer::onDrawRect(const SkRect& rect,
    116                                      const SkRect* localRect,
    117                                      const SkMatrix* localMatrix) {
    118     GrDrawState* drawState = this->drawState();
    119 
    120     GrColor color = drawState->getColor();
    121 
    122     set_vertex_attributes(drawState, SkToBool(localRect),  color);
    123 
    124     AutoReleaseGeometry geo(this, 4, 0);
    125     if (!geo.succeeded()) {
    126         GrPrintf("Failed to get space for vertices!\n");
    127         return;
    128     }
    129 
    130     // Go to device coords to allow batching across matrix changes
    131     SkMatrix matrix = drawState->getViewMatrix();
    132 
    133     // When the caller has provided an explicit source rect for a stage then we don't want to
    134     // modify that stage's matrix. Otherwise if the effect is generating its source rect from
    135     // the vertex positions then we have to account for the view matrix change.
    136     GrDrawState::AutoViewMatrixRestore avmr;
    137     if (!avmr.setIdentity(drawState)) {
    138         return;
    139     }
    140 
    141     size_t vstride = drawState->getVertexStride();
    142 
    143     geo.positions()->setRectFan(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, vstride);
    144     matrix.mapPointsWithStride(geo.positions(), vstride, 4);
    145 
    146     SkRect devBounds;
    147     // since we already computed the dev verts, set the bounds hint. This will help us avoid
    148     // unnecessary clipping in our onDraw().
    149     get_vertex_bounds(geo.vertices(), vstride, 4, &devBounds);
    150 
    151     if (localRect) {
    152         static const int kLocalOffset = sizeof(SkPoint) + sizeof(GrColor);
    153         SkPoint* coords = GrTCast<SkPoint*>(GrTCast<intptr_t>(geo.vertices()) + kLocalOffset);
    154         coords->setRectFan(localRect->fLeft, localRect->fTop,
    155                            localRect->fRight, localRect->fBottom,
    156                            vstride);
    157         if (localMatrix) {
    158             localMatrix->mapPointsWithStride(coords, vstride, 4);
    159         }
    160     }
    161 
    162     static const int kColorOffset = sizeof(SkPoint);
    163     GrColor* vertColor = GrTCast<GrColor*>(GrTCast<intptr_t>(geo.vertices()) + kColorOffset);
    164     for (int i = 0; i < 4; ++i) {
    165         *vertColor = color;
    166         vertColor = (GrColor*) ((intptr_t) vertColor + vstride);
    167     }
    168 
    169     this->setIndexSourceToBuffer(this->getContext()->getQuadIndexBuffer());
    170     this->drawIndexedInstances(kTriangles_GrPrimitiveType, 1, 4, 6, &devBounds);
    171 
    172     // to ensure that stashing the drawState ptr is valid
    173     SkASSERT(this->drawState() == drawState);
    174 }
    175 
    176 bool GrInOrderDrawBuffer::quickInsideClip(const SkRect& devBounds) {
    177     if (!this->getDrawState().isClipState()) {
    178         return true;
    179     }
    180     if (kUnknown_ClipProxyState == fClipProxyState) {
    181         SkIRect rect;
    182         bool iior;
    183         this->getClip()->getConservativeBounds(this->getDrawState().getRenderTarget(), &rect, &iior);
    184         if (iior) {
    185             // The clip is a rect. We will remember that in fProxyClip. It is common for an edge (or
    186             // all edges) of the clip to be at the edge of the RT. However, we get that clipping for
    187             // free via the viewport. We don't want to think that clipping must be enabled in this
    188             // case. So we extend the clip outward from the edge to avoid these false negatives.
    189             fClipProxyState = kValid_ClipProxyState;
    190             fClipProxy = SkRect::Make(rect);
    191 
    192             if (fClipProxy.fLeft <= 0) {
    193                 fClipProxy.fLeft = SK_ScalarMin;
    194             }
    195             if (fClipProxy.fTop <= 0) {
    196                 fClipProxy.fTop = SK_ScalarMin;
    197             }
    198             if (fClipProxy.fRight >= this->getDrawState().getRenderTarget()->width()) {
    199                 fClipProxy.fRight = SK_ScalarMax;
    200             }
    201             if (fClipProxy.fBottom >= this->getDrawState().getRenderTarget()->height()) {
    202                 fClipProxy.fBottom = SK_ScalarMax;
    203             }
    204         } else {
    205             fClipProxyState = kInvalid_ClipProxyState;
    206         }
    207     }
    208     if (kValid_ClipProxyState == fClipProxyState) {
    209         return fClipProxy.contains(devBounds);
    210     }
    211     SkPoint originOffset = {SkIntToScalar(this->getClip()->fOrigin.fX),
    212                             SkIntToScalar(this->getClip()->fOrigin.fY)};
    213     SkRect clipSpaceBounds = devBounds;
    214     clipSpaceBounds.offset(originOffset);
    215     return this->getClip()->fClipStack->quickContains(clipSpaceBounds);
    216 }
    217 
    218 int GrInOrderDrawBuffer::concatInstancedDraw(const DrawInfo& info) {
    219     SkASSERT(info.isInstanced());
    220 
    221     const GeometrySrcState& geomSrc = this->getGeomSrc();
    222     const GrDrawState& drawState = this->getDrawState();
    223 
    224     // we only attempt to concat the case when reserved verts are used with a client-specified index
    225     // buffer. To make this work with client-specified VBs we'd need to know if the VB was updated
    226     // between draws.
    227     if (kReserved_GeometrySrcType != geomSrc.fVertexSrc ||
    228         kBuffer_GeometrySrcType != geomSrc.fIndexSrc) {
    229         return 0;
    230     }
    231     // Check if there is a draw info that is compatible that uses the same VB from the pool and
    232     // the same IB
    233     if (kDraw_Cmd != strip_trace_bit(fCmds.back())) {
    234         return 0;
    235     }
    236 
    237     Draw* draw = &fDraws.back();
    238     GeometryPoolState& poolState = fGeoPoolStateStack.back();
    239     const GrVertexBuffer* vertexBuffer = poolState.fPoolVertexBuffer;
    240 
    241     if (!draw->isInstanced() ||
    242         draw->verticesPerInstance() != info.verticesPerInstance() ||
    243         draw->indicesPerInstance() != info.indicesPerInstance() ||
    244         draw->vertexBuffer() != vertexBuffer ||
    245         draw->indexBuffer() != geomSrc.fIndexBuffer) {
    246         return 0;
    247     }
    248     // info does not yet account for the offset from the start of the pool's VB while the previous
    249     // draw record does.
    250     int adjustedStartVertex = poolState.fPoolStartVertex + info.startVertex();
    251     if (draw->startVertex() + draw->vertexCount() != adjustedStartVertex) {
    252         return 0;
    253     }
    254 
    255     SkASSERT(poolState.fPoolStartVertex == draw->startVertex() + draw->vertexCount());
    256 
    257     // how many instances can be concat'ed onto draw given the size of the index buffer
    258     int instancesToConcat = this->indexCountInCurrentSource() / info.indicesPerInstance();
    259     instancesToConcat -= draw->instanceCount();
    260     instancesToConcat = SkTMin(instancesToConcat, info.instanceCount());
    261 
    262     // update the amount of reserved vertex data actually referenced in draws
    263     size_t vertexBytes = instancesToConcat * info.verticesPerInstance() *
    264                          drawState.getVertexStride();
    265     poolState.fUsedPoolVertexBytes = SkTMax(poolState.fUsedPoolVertexBytes, vertexBytes);
    266 
    267     draw->adjustInstanceCount(instancesToConcat);
    268 
    269     // update last fGpuCmdMarkers to include any additional trace markers that have been added
    270     if (this->getActiveTraceMarkers().count() > 0) {
    271         if (cmd_has_trace_marker(fCmds.back())) {
    272             fGpuCmdMarkers.back().addSet(this->getActiveTraceMarkers());
    273         } else {
    274             fGpuCmdMarkers.push_back(this->getActiveTraceMarkers());
    275             fCmds.back() = add_trace_bit(fCmds.back());
    276         }
    277     }
    278 
    279     return instancesToConcat;
    280 }
    281 
    282 class AutoClipReenable {
    283 public:
    284     AutoClipReenable() : fDrawState(NULL) {}
    285     ~AutoClipReenable() {
    286         if (fDrawState) {
    287             fDrawState->enableState(GrDrawState::kClip_StateBit);
    288         }
    289     }
    290     void set(GrDrawState* drawState) {
    291         if (drawState->isClipState()) {
    292             fDrawState = drawState;
    293             drawState->disableState(GrDrawState::kClip_StateBit);
    294         }
    295     }
    296 private:
    297     GrDrawState*    fDrawState;
    298 };
    299 
    300 void GrInOrderDrawBuffer::onDraw(const DrawInfo& info) {
    301 
    302     GeometryPoolState& poolState = fGeoPoolStateStack.back();
    303     const GrDrawState& drawState = this->getDrawState();
    304     AutoClipReenable acr;
    305 
    306     if (drawState.isClipState() &&
    307         info.getDevBounds() &&
    308         this->quickInsideClip(*info.getDevBounds())) {
    309         acr.set(this->drawState());
    310     }
    311 
    312     if (this->needsNewClip()) {
    313        this->recordClip();
    314     }
    315     this->recordStateIfNecessary();
    316 
    317     const GrVertexBuffer* vb;
    318     if (kBuffer_GeometrySrcType == this->getGeomSrc().fVertexSrc) {
    319         vb = this->getGeomSrc().fVertexBuffer;
    320     } else {
    321         vb = poolState.fPoolVertexBuffer;
    322     }
    323 
    324     const GrIndexBuffer* ib = NULL;
    325     if (info.isIndexed()) {
    326         if (kBuffer_GeometrySrcType == this->getGeomSrc().fIndexSrc) {
    327             ib = this->getGeomSrc().fIndexBuffer;
    328         } else {
    329             ib = poolState.fPoolIndexBuffer;
    330         }
    331     }
    332 
    333     Draw* draw;
    334     if (info.isInstanced()) {
    335         int instancesConcated = this->concatInstancedDraw(info);
    336         if (info.instanceCount() > instancesConcated) {
    337             draw = this->recordDraw(info, vb, ib);
    338             draw->adjustInstanceCount(-instancesConcated);
    339         } else {
    340             return;
    341         }
    342     } else {
    343         draw = this->recordDraw(info, vb, ib);
    344     }
    345 
    346     // Adjust the starting vertex and index when we are using reserved or array sources to
    347     // compensate for the fact that the data was inserted into a larger vb/ib owned by the pool.
    348     if (kBuffer_GeometrySrcType != this->getGeomSrc().fVertexSrc) {
    349         size_t bytes = (info.vertexCount() + info.startVertex()) * drawState.getVertexStride();
    350         poolState.fUsedPoolVertexBytes = SkTMax(poolState.fUsedPoolVertexBytes, bytes);
    351         draw->adjustStartVertex(poolState.fPoolStartVertex);
    352     }
    353 
    354     if (info.isIndexed() && kBuffer_GeometrySrcType != this->getGeomSrc().fIndexSrc) {
    355         size_t bytes = (info.indexCount() + info.startIndex()) * sizeof(uint16_t);
    356         poolState.fUsedPoolIndexBytes = SkTMax(poolState.fUsedPoolIndexBytes, bytes);
    357         draw->adjustStartIndex(poolState.fPoolStartIndex);
    358     }
    359 }
    360 
    361 void GrInOrderDrawBuffer::onStencilPath(const GrPath* path, SkPath::FillType fill) {
    362     if (this->needsNewClip()) {
    363         this->recordClip();
    364     }
    365     // Only compare the subset of GrDrawState relevant to path stenciling?
    366     this->recordStateIfNecessary();
    367     StencilPath* sp = this->recordStencilPath(path);
    368     sp->fFill = fill;
    369 }
    370 
    371 void GrInOrderDrawBuffer::onDrawPath(const GrPath* path,
    372                                      SkPath::FillType fill, const GrDeviceCoordTexture* dstCopy) {
    373     if (this->needsNewClip()) {
    374         this->recordClip();
    375     }
    376     // TODO: Only compare the subset of GrDrawState relevant to path covering?
    377     this->recordStateIfNecessary();
    378     DrawPath* cp = this->recordDrawPath(path);
    379     cp->fFill = fill;
    380     if (dstCopy) {
    381         cp->fDstCopy = *dstCopy;
    382     }
    383 }
    384 
    385 void GrInOrderDrawBuffer::onDrawPaths(const GrPathRange* pathRange,
    386                                       const uint32_t indices[], int count,
    387                                       const float transforms[], PathTransformType transformsType,
    388                                       SkPath::FillType fill, const GrDeviceCoordTexture* dstCopy) {
    389     SkASSERT(pathRange);
    390     SkASSERT(indices);
    391     SkASSERT(transforms);
    392 
    393     if (this->needsNewClip()) {
    394         this->recordClip();
    395     }
    396     this->recordStateIfNecessary();
    397     DrawPaths* dp = this->recordDrawPaths(pathRange);
    398     dp->fIndices = SkNEW_ARRAY(uint32_t, count); // TODO: Accomplish this without a malloc
    399     memcpy(dp->fIndices, indices, sizeof(uint32_t) * count);
    400     dp->fCount = count;
    401 
    402     const int transformsLength = GrPathRendering::PathTransformSize(transformsType) * count;
    403     dp->fTransforms = SkNEW_ARRAY(float, transformsLength);
    404     memcpy(dp->fTransforms, transforms, sizeof(float) * transformsLength);
    405     dp->fTransformsType = transformsType;
    406 
    407     dp->fFill = fill;
    408 
    409     if (dstCopy) {
    410         dp->fDstCopy = *dstCopy;
    411     }
    412 }
    413 
    414 void GrInOrderDrawBuffer::clear(const SkIRect* rect, GrColor color,
    415                                 bool canIgnoreRect, GrRenderTarget* renderTarget) {
    416     SkIRect r;
    417     if (NULL == renderTarget) {
    418         renderTarget = this->drawState()->getRenderTarget();
    419         SkASSERT(renderTarget);
    420     }
    421     if (NULL == rect) {
    422         // We could do something smart and remove previous draws and clears to
    423         // the current render target. If we get that smart we have to make sure
    424         // those draws aren't read before this clear (render-to-texture).
    425         r.setLTRB(0, 0, renderTarget->width(), renderTarget->height());
    426         rect = &r;
    427     }
    428     Clear* clr = this->recordClear(renderTarget);
    429     GrColorIsPMAssert(color);
    430     clr->fColor = color;
    431     clr->fRect = *rect;
    432     clr->fCanIgnoreRect = canIgnoreRect;
    433 }
    434 
    435 void GrInOrderDrawBuffer::discard(GrRenderTarget* renderTarget) {
    436     if (!this->caps()->discardRenderTargetSupport()) {
    437         return;
    438     }
    439     if (NULL == renderTarget) {
    440         renderTarget = this->drawState()->getRenderTarget();
    441         SkASSERT(renderTarget);
    442     }
    443     Clear* clr = this->recordClear(renderTarget);
    444     clr->fColor = GrColor_ILLEGAL;
    445 }
    446 
    447 void GrInOrderDrawBuffer::reset() {
    448     SkASSERT(1 == fGeoPoolStateStack.count());
    449     this->resetVertexSource();
    450     this->resetIndexSource();
    451 
    452     fCmds.reset();
    453     fDraws.reset();
    454     fStencilPaths.reset();
    455     fDrawPath.reset();
    456     fDrawPaths.reset();
    457     fStates.reset();
    458     fClears.reset();
    459     fVertexPool.reset();
    460     fIndexPool.reset();
    461     fClips.reset();
    462     fCopySurfaces.reset();
    463     fGpuCmdMarkers.reset();
    464     fClipSet = true;
    465 }
    466 
    467 void GrInOrderDrawBuffer::flush() {
    468     if (fFlushing) {
    469         return;
    470     }
    471 
    472     this->getContext()->getFontCache()->updateTextures();
    473 
    474     SkASSERT(kReserved_GeometrySrcType != this->getGeomSrc().fVertexSrc);
    475     SkASSERT(kReserved_GeometrySrcType != this->getGeomSrc().fIndexSrc);
    476 
    477     int numCmds = fCmds.count();
    478     if (0 == numCmds) {
    479         return;
    480     }
    481 
    482     GrAutoTRestore<bool> flushRestore(&fFlushing);
    483     fFlushing = true;
    484 
    485     fVertexPool.unmap();
    486     fIndexPool.unmap();
    487 
    488     GrDrawTarget::AutoClipRestore acr(fDstGpu);
    489     AutoGeometryAndStatePush agasp(fDstGpu, kPreserve_ASRInit);
    490 
    491     GrDrawState* prevDrawState = SkRef(fDstGpu->drawState());
    492 
    493     GrClipData clipData;
    494 
    495     StateAllocator::Iter stateIter(&fStates);
    496     ClipAllocator::Iter clipIter(&fClips);
    497     ClearAllocator::Iter clearIter(&fClears);
    498     DrawAllocator::Iter drawIter(&fDraws);
    499     StencilPathAllocator::Iter stencilPathIter(&fStencilPaths);
    500     DrawPathAllocator::Iter drawPathIter(&fDrawPath);
    501     DrawPathsAllocator::Iter drawPathsIter(&fDrawPaths);
    502     CopySurfaceAllocator::Iter copySurfaceIter(&fCopySurfaces);
    503 
    504     int currCmdMarker   = 0;
    505 
    506     fDstGpu->saveActiveTraceMarkers();
    507     for (int c = 0; c < numCmds; ++c) {
    508         GrGpuTraceMarker newMarker("", -1);
    509         SkString traceString;
    510         if (cmd_has_trace_marker(fCmds[c])) {
    511             traceString = fGpuCmdMarkers[currCmdMarker].toString();
    512             newMarker.fMarker = traceString.c_str();
    513             fDstGpu->addGpuTraceMarker(&newMarker);
    514             ++currCmdMarker;
    515         }
    516         switch (strip_trace_bit(fCmds[c])) {
    517             case kDraw_Cmd: {
    518                 SkASSERT(fDstGpu->drawState() != prevDrawState);
    519                 SkAssertResult(drawIter.next());
    520                 fDstGpu->setVertexSourceToBuffer(drawIter->vertexBuffer());
    521                 if (drawIter->isIndexed()) {
    522                     fDstGpu->setIndexSourceToBuffer(drawIter->indexBuffer());
    523                 }
    524                 fDstGpu->executeDraw(*drawIter);
    525                 break;
    526             }
    527             case kStencilPath_Cmd: {
    528                 SkASSERT(fDstGpu->drawState() != prevDrawState);
    529                 SkAssertResult(stencilPathIter.next());
    530                 fDstGpu->stencilPath(stencilPathIter->path(), stencilPathIter->fFill);
    531                 break;
    532             }
    533             case kDrawPath_Cmd: {
    534                 SkASSERT(fDstGpu->drawState() != prevDrawState);
    535                 SkAssertResult(drawPathIter.next());
    536                 fDstGpu->executeDrawPath(drawPathIter->path(), drawPathIter->fFill,
    537                                          drawPathIter->fDstCopy.texture() ?
    538                                             &drawPathIter->fDstCopy :
    539                                             NULL);
    540                 break;
    541             }
    542             case kDrawPaths_Cmd: {
    543                 SkASSERT(fDstGpu->drawState() != prevDrawState);
    544                 SkAssertResult(drawPathsIter.next());
    545                 const GrDeviceCoordTexture* dstCopy =
    546                     drawPathsIter->fDstCopy.texture() ? &drawPathsIter->fDstCopy : NULL;
    547                 fDstGpu->executeDrawPaths(drawPathsIter->pathRange(),
    548                                           drawPathsIter->fIndices,
    549                                           drawPathsIter->fCount,
    550                                           drawPathsIter->fTransforms,
    551                                           drawPathsIter->fTransformsType,
    552                                           drawPathsIter->fFill,
    553                                           dstCopy);
    554                 break;
    555             }
    556             case kSetState_Cmd:
    557                 SkAssertResult(stateIter.next());
    558                 fDstGpu->setDrawState(stateIter.get());
    559                 break;
    560             case kSetClip_Cmd:
    561                 SkAssertResult(clipIter.next());
    562                 clipData.fClipStack = &clipIter->fStack;
    563                 clipData.fOrigin = clipIter->fOrigin;
    564                 fDstGpu->setClip(&clipData);
    565                 break;
    566             case kClear_Cmd:
    567                 SkAssertResult(clearIter.next());
    568                 if (GrColor_ILLEGAL == clearIter->fColor) {
    569                     fDstGpu->discard(clearIter->renderTarget());
    570                 } else {
    571                     fDstGpu->clear(&clearIter->fRect,
    572                                    clearIter->fColor,
    573                                    clearIter->fCanIgnoreRect,
    574                                    clearIter->renderTarget());
    575                 }
    576                 break;
    577             case kCopySurface_Cmd:
    578                 SkAssertResult(copySurfaceIter.next());
    579                 fDstGpu->copySurface(copySurfaceIter->dst(),
    580                                      copySurfaceIter->src(),
    581                                      copySurfaceIter->fSrcRect,
    582                                      copySurfaceIter->fDstPoint);
    583                 break;
    584         }
    585         if (cmd_has_trace_marker(fCmds[c])) {
    586             fDstGpu->removeGpuTraceMarker(&newMarker);
    587         }
    588     }
    589     fDstGpu->restoreActiveTraceMarkers();
    590     // we should have consumed all the states, clips, etc.
    591     SkASSERT(!stateIter.next());
    592     SkASSERT(!clipIter.next());
    593     SkASSERT(!clearIter.next());
    594     SkASSERT(!drawIter.next());
    595     SkASSERT(!copySurfaceIter.next());
    596     SkASSERT(!stencilPathIter.next());
    597     SkASSERT(!drawPathIter.next());
    598     SkASSERT(!drawPathsIter.next());
    599 
    600     SkASSERT(fGpuCmdMarkers.count() == currCmdMarker);
    601 
    602     fDstGpu->setDrawState(prevDrawState);
    603     prevDrawState->unref();
    604     this->reset();
    605     ++fDrawID;
    606 }
    607 
    608 bool GrInOrderDrawBuffer::onCopySurface(GrSurface* dst,
    609                                         GrSurface* src,
    610                                         const SkIRect& srcRect,
    611                                         const SkIPoint& dstPoint) {
    612     if (fDstGpu->canCopySurface(dst, src, srcRect, dstPoint)) {
    613         CopySurface* cs = this->recordCopySurface(dst, src);
    614         cs->fSrcRect = srcRect;
    615         cs->fDstPoint = dstPoint;
    616         return true;
    617     } else {
    618         return false;
    619     }
    620 }
    621 
    622 bool GrInOrderDrawBuffer::onCanCopySurface(GrSurface* dst,
    623                                            GrSurface* src,
    624                                            const SkIRect& srcRect,
    625                                            const SkIPoint& dstPoint) {
    626     return fDstGpu->canCopySurface(dst, src, srcRect, dstPoint);
    627 }
    628 
    629 void GrInOrderDrawBuffer::initCopySurfaceDstDesc(const GrSurface* src, GrTextureDesc* desc) {
    630     fDstGpu->initCopySurfaceDstDesc(src, desc);
    631 }
    632 
    633 void GrInOrderDrawBuffer::willReserveVertexAndIndexSpace(int vertexCount,
    634                                                          int indexCount) {
    635     // We use geometryHints() to know whether to flush the draw buffer. We
    636     // can't flush if we are inside an unbalanced pushGeometrySource.
    637     // Moreover, flushing blows away vertex and index data that was
    638     // previously reserved. So if the vertex or index data is pulled from
    639     // reserved space and won't be released by this request then we can't
    640     // flush.
    641     bool insideGeoPush = fGeoPoolStateStack.count() > 1;
    642 
    643     bool unreleasedVertexSpace =
    644         !vertexCount &&
    645         kReserved_GeometrySrcType == this->getGeomSrc().fVertexSrc;
    646 
    647     bool unreleasedIndexSpace =
    648         !indexCount &&
    649         kReserved_GeometrySrcType == this->getGeomSrc().fIndexSrc;
    650 
    651     // we don't want to finalize any reserved geom on the target since
    652     // we don't know that the client has finished writing to it.
    653     bool targetHasReservedGeom = fDstGpu->hasReservedVerticesOrIndices();
    654 
    655     int vcount = vertexCount;
    656     int icount = indexCount;
    657 
    658     if (!insideGeoPush &&
    659         !unreleasedVertexSpace &&
    660         !unreleasedIndexSpace &&
    661         !targetHasReservedGeom &&
    662         this->geometryHints(&vcount, &icount)) {
    663 
    664         this->flush();
    665     }
    666 }
    667 
    668 bool GrInOrderDrawBuffer::geometryHints(int* vertexCount,
    669                                         int* indexCount) const {
    670     // we will recommend a flush if the data could fit in a single
    671     // preallocated buffer but none are left and it can't fit
    672     // in the current buffer (which may not be prealloced).
    673     bool flush = false;
    674     if (indexCount) {
    675         int32_t currIndices = fIndexPool.currentBufferIndices();
    676         if (*indexCount > currIndices &&
    677             (!fIndexPool.preallocatedBuffersRemaining() &&
    678              *indexCount <= fIndexPool.preallocatedBufferIndices())) {
    679 
    680             flush = true;
    681         }
    682         *indexCount = currIndices;
    683     }
    684     if (vertexCount) {
    685         size_t vertexStride = this->getDrawState().getVertexStride();
    686         int32_t currVertices = fVertexPool.currentBufferVertices(vertexStride);
    687         if (*vertexCount > currVertices &&
    688             (!fVertexPool.preallocatedBuffersRemaining() &&
    689              *vertexCount <= fVertexPool.preallocatedBufferVertices(vertexStride))) {
    690 
    691             flush = true;
    692         }
    693         *vertexCount = currVertices;
    694     }
    695     return flush;
    696 }
    697 
    698 bool GrInOrderDrawBuffer::onReserveVertexSpace(size_t vertexSize,
    699                                                int vertexCount,
    700                                                void** vertices) {
    701     GeometryPoolState& poolState = fGeoPoolStateStack.back();
    702     SkASSERT(vertexCount > 0);
    703     SkASSERT(vertices);
    704     SkASSERT(0 == poolState.fUsedPoolVertexBytes);
    705 
    706     *vertices = fVertexPool.makeSpace(vertexSize,
    707                                       vertexCount,
    708                                       &poolState.fPoolVertexBuffer,
    709                                       &poolState.fPoolStartVertex);
    710     return SkToBool(*vertices);
    711 }
    712 
    713 bool GrInOrderDrawBuffer::onReserveIndexSpace(int indexCount, void** indices) {
    714     GeometryPoolState& poolState = fGeoPoolStateStack.back();
    715     SkASSERT(indexCount > 0);
    716     SkASSERT(indices);
    717     SkASSERT(0 == poolState.fUsedPoolIndexBytes);
    718 
    719     *indices = fIndexPool.makeSpace(indexCount,
    720                                     &poolState.fPoolIndexBuffer,
    721                                     &poolState.fPoolStartIndex);
    722     return SkToBool(*indices);
    723 }
    724 
    725 void GrInOrderDrawBuffer::releaseReservedVertexSpace() {
    726     GeometryPoolState& poolState = fGeoPoolStateStack.back();
    727     const GeometrySrcState& geoSrc = this->getGeomSrc();
    728 
    729     // If we get a release vertex space call then our current source should either be reserved
    730     // or array (which we copied into reserved space).
    731     SkASSERT(kReserved_GeometrySrcType == geoSrc.fVertexSrc ||
    732              kArray_GeometrySrcType == geoSrc.fVertexSrc);
    733 
    734     // When the caller reserved vertex buffer space we gave it back a pointer
    735     // provided by the vertex buffer pool. At each draw we tracked the largest
    736     // offset into the pool's pointer that was referenced. Now we return to the
    737     // pool any portion at the tail of the allocation that no draw referenced.
    738     size_t reservedVertexBytes = geoSrc.fVertexSize * geoSrc.fVertexCount;
    739     fVertexPool.putBack(reservedVertexBytes -
    740                         poolState.fUsedPoolVertexBytes);
    741     poolState.fUsedPoolVertexBytes = 0;
    742     poolState.fPoolVertexBuffer = NULL;
    743     poolState.fPoolStartVertex = 0;
    744 }
    745 
    746 void GrInOrderDrawBuffer::releaseReservedIndexSpace() {
    747     GeometryPoolState& poolState = fGeoPoolStateStack.back();
    748     const GeometrySrcState& geoSrc = this->getGeomSrc();
    749 
    750     // If we get a release index space call then our current source should either be reserved
    751     // or array (which we copied into reserved space).
    752     SkASSERT(kReserved_GeometrySrcType == geoSrc.fIndexSrc ||
    753              kArray_GeometrySrcType == geoSrc.fIndexSrc);
    754 
    755     // Similar to releaseReservedVertexSpace we return any unused portion at
    756     // the tail
    757     size_t reservedIndexBytes = sizeof(uint16_t) * geoSrc.fIndexCount;
    758     fIndexPool.putBack(reservedIndexBytes - poolState.fUsedPoolIndexBytes);
    759     poolState.fUsedPoolIndexBytes = 0;
    760     poolState.fPoolIndexBuffer = NULL;
    761     poolState.fPoolStartIndex = 0;
    762 }
    763 
    764 void GrInOrderDrawBuffer::onSetVertexSourceToArray(const void* vertexArray, int vertexCount) {
    765     GeometryPoolState& poolState = fGeoPoolStateStack.back();
    766     SkASSERT(0 == poolState.fUsedPoolVertexBytes);
    767 #ifdef SK_DEBUG
    768     bool success =
    769 #endif
    770     fVertexPool.appendVertices(this->getVertexSize(),
    771                                vertexCount,
    772                                vertexArray,
    773                                &poolState.fPoolVertexBuffer,
    774                                &poolState.fPoolStartVertex);
    775     GR_DEBUGASSERT(success);
    776 }
    777 
    778 void GrInOrderDrawBuffer::onSetIndexSourceToArray(const void* indexArray,
    779                                                   int indexCount) {
    780     GeometryPoolState& poolState = fGeoPoolStateStack.back();
    781     SkASSERT(0 == poolState.fUsedPoolIndexBytes);
    782 #ifdef SK_DEBUG
    783     bool success =
    784 #endif
    785     fIndexPool.appendIndices(indexCount,
    786                              indexArray,
    787                              &poolState.fPoolIndexBuffer,
    788                              &poolState.fPoolStartIndex);
    789     GR_DEBUGASSERT(success);
    790 }
    791 
    792 void GrInOrderDrawBuffer::releaseVertexArray() {
    793     // When the client provides an array as the vertex source we handled it
    794     // by copying their array into reserved space.
    795     this->GrInOrderDrawBuffer::releaseReservedVertexSpace();
    796 }
    797 
    798 void GrInOrderDrawBuffer::releaseIndexArray() {
    799     // When the client provides an array as the index source we handled it
    800     // by copying their array into reserved space.
    801     this->GrInOrderDrawBuffer::releaseReservedIndexSpace();
    802 }
    803 
    804 void GrInOrderDrawBuffer::geometrySourceWillPush() {
    805     GeometryPoolState& poolState = fGeoPoolStateStack.push_back();
    806     poolState.fUsedPoolVertexBytes = 0;
    807     poolState.fUsedPoolIndexBytes = 0;
    808 #ifdef SK_DEBUG
    809     poolState.fPoolVertexBuffer = (GrVertexBuffer*)~0;
    810     poolState.fPoolStartVertex = ~0;
    811     poolState.fPoolIndexBuffer = (GrIndexBuffer*)~0;
    812     poolState.fPoolStartIndex = ~0;
    813 #endif
    814 }
    815 
    816 void GrInOrderDrawBuffer::geometrySourceWillPop(const GeometrySrcState& restoredState) {
    817     SkASSERT(fGeoPoolStateStack.count() > 1);
    818     fGeoPoolStateStack.pop_back();
    819     GeometryPoolState& poolState = fGeoPoolStateStack.back();
    820     // we have to assume that any slack we had in our vertex/index data
    821     // is now unreleasable because data may have been appended later in the
    822     // pool.
    823     if (kReserved_GeometrySrcType == restoredState.fVertexSrc ||
    824         kArray_GeometrySrcType == restoredState.fVertexSrc) {
    825         poolState.fUsedPoolVertexBytes = restoredState.fVertexSize * restoredState.fVertexCount;
    826     }
    827     if (kReserved_GeometrySrcType == restoredState.fIndexSrc ||
    828         kArray_GeometrySrcType == restoredState.fIndexSrc) {
    829         poolState.fUsedPoolIndexBytes = sizeof(uint16_t) *
    830                                          restoredState.fIndexCount;
    831     }
    832 }
    833 
    834 void GrInOrderDrawBuffer::recordStateIfNecessary() {
    835     if (fStates.empty()) {
    836         this->convertDrawStateToPendingExec(&fStates.push_back(this->getDrawState()));
    837         this->addToCmdBuffer(kSetState_Cmd);
    838         return;
    839     }
    840     const GrDrawState& curr = this->getDrawState();
    841     GrDrawState& prev = fStates.back();
    842     switch (GrDrawState::CombineIfPossible(prev, curr, *this->caps())) {
    843         case GrDrawState::kIncompatible_CombinedState:
    844             this->convertDrawStateToPendingExec(&fStates.push_back(curr));
    845             this->addToCmdBuffer(kSetState_Cmd);
    846             break;
    847         case GrDrawState::kA_CombinedState:
    848         case GrDrawState::kAOrB_CombinedState: // Treat the same as kA.
    849             break;
    850         case GrDrawState::kB_CombinedState:
    851             // prev has already been converted to pending execution. That is a one-way ticket.
    852             // So here we just delete prev and push back a new copy of curr. Note that this
    853             // goes away when we move GrIODB over to taking optimized snapshots of draw states.
    854             fStates.pop_back();
    855             this->convertDrawStateToPendingExec(&fStates.push_back(curr));
    856             break;
    857     }
    858 }
    859 
    860 bool GrInOrderDrawBuffer::needsNewClip() const {
    861     if (this->getDrawState().isClipState()) {
    862        if (fClipSet &&
    863            (fClips.empty() ||
    864             fClips.back().fStack != *this->getClip()->fClipStack ||
    865             fClips.back().fOrigin != this->getClip()->fOrigin)) {
    866            return true;
    867        }
    868     }
    869     return false;
    870 }
    871 
    872 void GrInOrderDrawBuffer::addToCmdBuffer(uint8_t cmd) {
    873     SkASSERT(!cmd_has_trace_marker(cmd));
    874     const GrTraceMarkerSet& activeTraceMarkers = this->getActiveTraceMarkers();
    875     if (activeTraceMarkers.count() > 0) {
    876         fCmds.push_back(add_trace_bit(cmd));
    877         fGpuCmdMarkers.push_back(activeTraceMarkers);
    878     } else {
    879         fCmds.push_back(cmd);
    880     }
    881 }
    882 
    883 void GrInOrderDrawBuffer::recordClip() {
    884     fClips.push_back().fStack = *this->getClip()->fClipStack;
    885     fClips.back().fOrigin = this->getClip()->fOrigin;
    886     fClipSet = false;
    887     this->addToCmdBuffer(kSetClip_Cmd);
    888 }
    889 
    890 GrInOrderDrawBuffer::Draw* GrInOrderDrawBuffer::recordDraw(const DrawInfo& info,
    891                                                            const GrVertexBuffer* vb,
    892                                                            const GrIndexBuffer* ib) {
    893     this->addToCmdBuffer(kDraw_Cmd);
    894     return GrNEW_APPEND_TO_ALLOCATOR(&fDraws, Draw, (info, vb, ib));
    895 }
    896 
    897 GrInOrderDrawBuffer::StencilPath* GrInOrderDrawBuffer::recordStencilPath(const GrPath* path) {
    898     this->addToCmdBuffer(kStencilPath_Cmd);
    899     return GrNEW_APPEND_TO_ALLOCATOR(&fStencilPaths, StencilPath, (path));
    900 }
    901 
    902 GrInOrderDrawBuffer::DrawPath* GrInOrderDrawBuffer::recordDrawPath(const GrPath* path) {
    903     this->addToCmdBuffer(kDrawPath_Cmd);
    904     return GrNEW_APPEND_TO_ALLOCATOR(&fDrawPath, DrawPath, (path));
    905 }
    906 
    907 GrInOrderDrawBuffer::DrawPaths* GrInOrderDrawBuffer::recordDrawPaths(const GrPathRange* pathRange) {
    908     this->addToCmdBuffer(kDrawPaths_Cmd);
    909     return GrNEW_APPEND_TO_ALLOCATOR(&fDrawPaths, DrawPaths, (pathRange));
    910 }
    911 
    912 GrInOrderDrawBuffer::Clear* GrInOrderDrawBuffer::recordClear(GrRenderTarget* rt) {
    913     this->addToCmdBuffer(kClear_Cmd);
    914     return GrNEW_APPEND_TO_ALLOCATOR(&fClears, Clear, (rt));
    915 }
    916 
    917 GrInOrderDrawBuffer::CopySurface* GrInOrderDrawBuffer::recordCopySurface(GrSurface* dst,
    918                                                                          GrSurface* src) {
    919     this->addToCmdBuffer(kCopySurface_Cmd);
    920     return GrNEW_APPEND_TO_ALLOCATOR(&fCopySurfaces, CopySurface, (dst, src));
    921 }
    922 
    923 void GrInOrderDrawBuffer::clipWillBeSet(const GrClipData* newClipData) {
    924     INHERITED::clipWillBeSet(newClipData);
    925     fClipSet = true;
    926     fClipProxyState = kUnknown_ClipProxyState;
    927 }
    928