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