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