GrInOrderDrawBuffer.cpp revision 1b3ce47c7b6c14c84d7aaee249b33f9d3b473050
1
2/*
3 * Copyright 2011 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8
9
10#include "GrInOrderDrawBuffer.h"
11#include "GrBufferAllocPool.h"
12#include "GrGpu.h"
13#include "GrIndexBuffer.h"
14#include "GrPath.h"
15#include "GrRenderTarget.h"
16#include "GrTexture.h"
17#include "GrVertexBuffer.h"
18
19GrInOrderDrawBuffer::GrInOrderDrawBuffer(const GrGpu* gpu,
20                                         GrVertexBufferAllocPool* vertexPool,
21                                         GrIndexBufferAllocPool* indexPool)
22    : fAutoFlushTarget(NULL)
23    , fClipSet(true)
24    , fVertexPool(*vertexPool)
25    , fIndexPool(*indexPool)
26    , fLastRectVertexLayout(0)
27    , fQuadIndexBuffer(NULL)
28    , fMaxQuads(0)
29    , fFlushing(false) {
30
31    fCaps = gpu->getCaps();
32
33    GrAssert(NULL != vertexPool);
34    GrAssert(NULL != indexPool);
35
36    GeometryPoolState& poolState = fGeoPoolStateStack.push_back();
37    poolState.fUsedPoolVertexBytes = 0;
38    poolState.fUsedPoolIndexBytes = 0;
39#if GR_DEBUG
40    poolState.fPoolVertexBuffer = (GrVertexBuffer*)~0;
41    poolState.fPoolStartVertex = ~0;
42    poolState.fPoolIndexBuffer = (GrIndexBuffer*)~0;
43    poolState.fPoolStartIndex = ~0;
44#endif
45    this->reset();
46}
47
48GrInOrderDrawBuffer::~GrInOrderDrawBuffer() {
49    this->reset();
50    // This must be called by before the GrDrawTarget destructor
51    this->releaseGeometry();
52    GrSafeUnref(fQuadIndexBuffer);
53    GrSafeUnref(fAutoFlushTarget);
54}
55
56void GrInOrderDrawBuffer::setQuadIndexBuffer(const GrIndexBuffer* indexBuffer) {
57    bool newIdxBuffer = fQuadIndexBuffer != indexBuffer;
58    if (newIdxBuffer) {
59        GrSafeUnref(fQuadIndexBuffer);
60        fQuadIndexBuffer = indexBuffer;
61        GrSafeRef(fQuadIndexBuffer);
62        fCurrQuad = 0;
63        fMaxQuads = (NULL == indexBuffer) ? 0 : indexBuffer->maxQuads();
64    } else {
65        GrAssert((NULL == indexBuffer && 0 == fMaxQuads) ||
66                 (indexBuffer->maxQuads() == fMaxQuads));
67    }
68}
69
70////////////////////////////////////////////////////////////////////////////////
71
72void GrInOrderDrawBuffer::resetDrawTracking() {
73    fCurrQuad = 0;
74    fInstancedDrawTracker.reset();
75}
76
77void GrInOrderDrawBuffer::drawRect(const GrRect& rect,
78                                   const GrMatrix* matrix,
79                                   const GrRect* srcRects[],
80                                   const GrMatrix* srcMatrices[]) {
81
82    GrAssert(!(NULL == fQuadIndexBuffer && fCurrQuad));
83    GrAssert(!(fDraws.empty() && fCurrQuad));
84    GrAssert(!(0 != fMaxQuads && NULL == fQuadIndexBuffer));
85
86    GrDrawState* drawState = this->drawState();
87
88    // if we have a quad IB then either append to the previous run of
89    // rects or start a new run
90    if (fMaxQuads) {
91
92        bool appendToPreviousDraw = false;
93        GrVertexLayout layout = GetRectVertexLayout(srcRects);
94        AutoReleaseGeometry geo(this, layout, 4, 0);
95        if (!geo.succeeded()) {
96            GrPrintf("Failed to get space for vertices!\n");
97            return;
98        }
99        GrMatrix combinedMatrix = drawState->getViewMatrix();
100        // We go to device space so that matrix changes allow us to concat
101        // rect draws. When the caller has provided explicit source rects
102        // then we don't want to modify the sampler matrices. Otherwise we do
103        // we have to account for the view matrix change in the sampler
104        // matrices.
105        uint32_t explicitCoordMask = 0;
106        if (srcRects) {
107            for (int s = 0; s < GrDrawState::kNumStages; ++s) {
108                if (srcRects[s]) {
109                    explicitCoordMask |= (1 << s);
110                }
111            }
112        }
113        GrDrawTarget::AutoDeviceCoordDraw adcd(this, explicitCoordMask);
114        if (!adcd.succeeded()) {
115            return;
116        }
117        if (NULL != matrix) {
118            combinedMatrix.preConcat(*matrix);
119        }
120
121        SetRectVertices(rect, &combinedMatrix, srcRects, srcMatrices, layout, geo.vertices());
122
123        // we don't want to miss an opportunity to batch rects together
124        // simply because the clip has changed if the clip doesn't affect
125        // the rect.
126        bool disabledClip = false;
127
128        if (drawState->isClipState()) {
129
130            GrRect devClipRect;
131            bool isIntersectionOfRects = false;
132
133            fClip->fClipStack->getConservativeBounds(-fClip->fOrigin.fX,
134                                                     -fClip->fOrigin.fY,
135                                                     drawState->getRenderTarget()->width(),
136                                                     drawState->getRenderTarget()->height(),
137                                                     &devClipRect,
138                                                     &isIntersectionOfRects);
139
140            if (isIntersectionOfRects) {
141                // If the clip rect touches the edge of the viewport, extended it
142                // out (close) to infinity to avoid bogus intersections.
143                // We might consider a more exact clip to viewport if this
144                // conservative test fails.
145                const GrRenderTarget* target = drawState->getRenderTarget();
146                if (0 >= devClipRect.fLeft) {
147                    devClipRect.fLeft = GR_ScalarMin;
148                }
149                if (target->width() <= devClipRect.fRight) {
150                    devClipRect.fRight = GR_ScalarMax;
151                }
152                if (0 >= devClipRect.top()) {
153                    devClipRect.fTop = GR_ScalarMin;
154                }
155                if (target->height() <= devClipRect.fBottom) {
156                    devClipRect.fBottom = GR_ScalarMax;
157                }
158                int stride = VertexSize(layout);
159                bool insideClip = true;
160                for (int v = 0; v < 4; ++v) {
161                    const GrPoint& p = *GetVertexPoint(geo.vertices(), v, stride);
162                    if (!devClipRect.contains(p)) {
163                        insideClip = false;
164                        break;
165                    }
166                }
167                if (insideClip) {
168                    drawState->disableState(GrDrawState::kClip_StateBit);
169                    disabledClip = true;
170                }
171            }
172        }
173
174        if (!this->needsNewClip() &&
175            !this->needsNewState() &&
176            fCurrQuad > 0 &&
177            fCurrQuad < fMaxQuads &&
178            layout == fLastRectVertexLayout) {
179
180            int vsize = VertexSize(layout);
181
182            Draw& lastDraw = fDraws.back();
183
184            GrAssert(lastDraw.fIndexBuffer == fQuadIndexBuffer);
185            GrAssert(kTriangles_GrPrimitiveType == lastDraw.fPrimitiveType);
186            GrAssert(0 == lastDraw.fVertexCount % 4);
187            GrAssert(0 == lastDraw.fIndexCount % 6);
188            GrAssert(0 == lastDraw.fStartIndex);
189
190            GeometryPoolState& poolState = fGeoPoolStateStack.back();
191
192            appendToPreviousDraw =
193                kDraw_Cmd != fCmds.back() &&
194                lastDraw.fVertexBuffer == poolState.fPoolVertexBuffer &&
195                (fCurrQuad * 4 + lastDraw.fStartVertex) == poolState.fPoolStartVertex;
196
197            if (appendToPreviousDraw) {
198                lastDraw.fVertexCount += 4;
199                lastDraw.fIndexCount += 6;
200                fCurrQuad += 1;
201                // we reserved above, so we should be the first
202                // use of this vertex reservation.
203                GrAssert(0 == poolState.fUsedPoolVertexBytes);
204                poolState.fUsedPoolVertexBytes = 4 * vsize;
205            }
206        }
207        if (!appendToPreviousDraw) {
208            this->setIndexSourceToBuffer(fQuadIndexBuffer);
209            this->drawIndexed(kTriangles_GrPrimitiveType, 0, 0, 4, 6);
210            fCurrQuad = 1;
211            fLastRectVertexLayout = layout;
212        }
213        if (disabledClip) {
214            drawState->enableState(GrDrawState::kClip_StateBit);
215        }
216        fInstancedDrawTracker.reset();
217    } else {
218        INHERITED::drawRect(rect, matrix, srcRects, srcMatrices);
219    }
220}
221
222void GrInOrderDrawBuffer::drawIndexedInstances(GrPrimitiveType type,
223                                               int instanceCount,
224                                               int verticesPerInstance,
225                                               int indicesPerInstance) {
226    if (!verticesPerInstance || !indicesPerInstance) {
227        return;
228    }
229
230    const GeometrySrcState& geomSrc = this->getGeomSrc();
231
232    // we only attempt to concat the case when reserved verts are used with
233    // an index buffer.
234    if (kReserved_GeometrySrcType == geomSrc.fVertexSrc &&
235        kBuffer_GeometrySrcType == geomSrc.fIndexSrc) {
236
237        if (this->needsNewClip()) {
238            this->recordClip();
239        }
240        if (this->needsNewState()) {
241            this->recordState();
242        }
243
244        Draw* draw = NULL;
245        // if the last draw used the same indices/vertices per shape then we
246        // may be able to append to it.
247        if (kDraw_Cmd == fCmds.back() &&
248            verticesPerInstance == fInstancedDrawTracker.fVerticesPerInstance &&
249            indicesPerInstance == fInstancedDrawTracker.fIndicesPerInstance) {
250            GrAssert(fDraws.count());
251            draw = &fDraws.back();
252        }
253
254        GeometryPoolState& poolState = fGeoPoolStateStack.back();
255        const GrVertexBuffer* vertexBuffer = poolState.fPoolVertexBuffer;
256
257        // Check whether the draw is compatible with this draw in order to
258        // append
259        if (NULL == draw ||
260            draw->fIndexBuffer != geomSrc.fIndexBuffer ||
261            draw->fPrimitiveType != type ||
262            draw->fVertexBuffer != vertexBuffer) {
263
264            draw = this->recordDraw();
265            draw->fIndexBuffer = geomSrc.fIndexBuffer;
266            geomSrc.fIndexBuffer->ref();
267            draw->fVertexBuffer = vertexBuffer;
268            vertexBuffer->ref();
269            draw->fPrimitiveType = type;
270            draw->fStartIndex = 0;
271            draw->fIndexCount = 0;
272            draw->fStartVertex = poolState.fPoolStartVertex;
273            draw->fVertexCount = 0;
274            draw->fVertexLayout = geomSrc.fVertexLayout;
275        } else {
276            GrAssert(!(draw->fIndexCount % indicesPerInstance));
277            GrAssert(!(draw->fVertexCount % verticesPerInstance));
278            GrAssert(poolState.fPoolStartVertex == draw->fStartVertex +
279                                                   draw->fVertexCount);
280        }
281
282        // how many instances can be in a single draw
283        int maxInstancesPerDraw = this->indexCountInCurrentSource() /
284                                  indicesPerInstance;
285        if (!maxInstancesPerDraw) {
286            return;
287        }
288        // how many instances should be concat'ed onto draw
289        int instancesToConcat = maxInstancesPerDraw - draw->fVertexCount /
290                                                      verticesPerInstance;
291        if (maxInstancesPerDraw > instanceCount) {
292            maxInstancesPerDraw = instanceCount;
293            if (instancesToConcat > instanceCount) {
294                instancesToConcat = instanceCount;
295            }
296        }
297
298        // update the amount of reserved data actually referenced in draws
299        size_t vertexBytes = instanceCount * verticesPerInstance *
300                             VertexSize(draw->fVertexLayout);
301        poolState.fUsedPoolVertexBytes =
302                            GrMax(poolState.fUsedPoolVertexBytes, vertexBytes);
303
304        while (instanceCount) {
305            if (!instancesToConcat) {
306                int startVertex = draw->fStartVertex + draw->fVertexCount;
307                draw = this->recordDraw();
308                draw->fIndexBuffer = geomSrc.fIndexBuffer;
309                geomSrc.fIndexBuffer->ref();
310                draw->fVertexBuffer = vertexBuffer;
311                vertexBuffer->ref();
312                draw->fPrimitiveType = type;
313                draw->fStartIndex = 0;
314                draw->fStartVertex = startVertex;
315                draw->fVertexCount = 0;
316                draw->fVertexLayout = geomSrc.fVertexLayout;
317                instancesToConcat = maxInstancesPerDraw;
318            }
319            draw->fVertexCount += instancesToConcat * verticesPerInstance;
320            draw->fIndexCount += instancesToConcat * indicesPerInstance;
321            instanceCount -= instancesToConcat;
322            instancesToConcat = 0;
323        }
324
325        // update draw tracking for next draw
326        fCurrQuad = 0;
327        fInstancedDrawTracker.fVerticesPerInstance = verticesPerInstance;
328        fInstancedDrawTracker.fIndicesPerInstance = indicesPerInstance;
329    } else {
330        this->INHERITED::drawIndexedInstances(type,
331                                              instanceCount,
332                                              verticesPerInstance,
333                                              indicesPerInstance);
334    }
335
336}
337
338void GrInOrderDrawBuffer::onDrawIndexed(GrPrimitiveType primitiveType,
339                                        int startVertex,
340                                        int startIndex,
341                                        int vertexCount,
342                                        int indexCount) {
343
344    if (!vertexCount || !indexCount) {
345        return;
346    }
347
348    this->resetDrawTracking();
349
350    GeometryPoolState& poolState = fGeoPoolStateStack.back();
351
352    if (this->needsNewClip()) {
353       this->recordClip();
354    }
355    if (this->needsNewState()) {
356        this->recordState();
357    }
358
359    Draw* draw = this->recordDraw();
360
361    draw->fPrimitiveType = primitiveType;
362    draw->fStartVertex   = startVertex;
363    draw->fStartIndex    = startIndex;
364    draw->fVertexCount   = vertexCount;
365    draw->fIndexCount    = indexCount;
366
367    draw->fVertexLayout = this->getVertexLayout();
368    switch (this->getGeomSrc().fVertexSrc) {
369    case kBuffer_GeometrySrcType:
370        draw->fVertexBuffer = this->getGeomSrc().fVertexBuffer;
371        break;
372    case kReserved_GeometrySrcType: // fallthrough
373    case kArray_GeometrySrcType: {
374        size_t vertexBytes = (vertexCount + startVertex) *
375                             VertexSize(draw->fVertexLayout);
376        poolState.fUsedPoolVertexBytes =
377                            GrMax(poolState.fUsedPoolVertexBytes, vertexBytes);
378        draw->fVertexBuffer = poolState.fPoolVertexBuffer;
379        draw->fStartVertex += poolState.fPoolStartVertex;
380        break;
381    }
382    default:
383        GrCrash("unknown geom src type");
384    }
385    draw->fVertexBuffer->ref();
386
387    switch (this->getGeomSrc().fIndexSrc) {
388    case kBuffer_GeometrySrcType:
389        draw->fIndexBuffer = this->getGeomSrc().fIndexBuffer;
390        break;
391    case kReserved_GeometrySrcType: // fallthrough
392    case kArray_GeometrySrcType: {
393        size_t indexBytes = (indexCount + startIndex) * sizeof(uint16_t);
394        poolState.fUsedPoolIndexBytes =
395                            GrMax(poolState.fUsedPoolIndexBytes, indexBytes);
396        draw->fIndexBuffer = poolState.fPoolIndexBuffer;
397        draw->fStartIndex += poolState.fPoolStartIndex;
398        break;
399    }
400    default:
401        GrCrash("unknown geom src type");
402    }
403    draw->fIndexBuffer->ref();
404}
405
406void GrInOrderDrawBuffer::onDrawNonIndexed(GrPrimitiveType primitiveType,
407                                           int startVertex,
408                                           int vertexCount) {
409    if (!vertexCount) {
410        return;
411    }
412
413    this->resetDrawTracking();
414
415    GeometryPoolState& poolState = fGeoPoolStateStack.back();
416    if (this->needsNewClip()) {
417        this->recordClip();
418    }
419    if (this->needsNewState()) {
420        this->recordState();
421    }
422
423    Draw* draw = this->recordDraw();
424    draw->fPrimitiveType = primitiveType;
425    draw->fStartVertex   = startVertex;
426    draw->fStartIndex    = 0;
427    draw->fVertexCount   = vertexCount;
428    draw->fIndexCount    = 0;
429
430    draw->fVertexLayout = this->getVertexLayout();
431    switch (this->getGeomSrc().fVertexSrc) {
432    case kBuffer_GeometrySrcType:
433        draw->fVertexBuffer = this->getGeomSrc().fVertexBuffer;
434        break;
435    case kReserved_GeometrySrcType: // fallthrough
436    case kArray_GeometrySrcType: {
437        size_t vertexBytes = (vertexCount + startVertex) *
438                             VertexSize(draw->fVertexLayout);
439        poolState.fUsedPoolVertexBytes =
440                            GrMax(poolState.fUsedPoolVertexBytes, vertexBytes);
441        draw->fVertexBuffer = poolState.fPoolVertexBuffer;
442        draw->fStartVertex += poolState.fPoolStartVertex;
443        break;
444    }
445    default:
446        GrCrash("unknown geom src type");
447    }
448    draw->fVertexBuffer->ref();
449    draw->fIndexBuffer = NULL;
450}
451
452void GrInOrderDrawBuffer::onStencilPath(const GrPath* path, GrPathFill fill) {
453    if (this->needsNewClip()) {
454        this->recordClip();
455    }
456    // Only compare the subset of GrDrawState relevant to path stenciling?
457    if (this->needsNewState()) {
458        this->recordState();
459    }
460    StencilPath* sp = this->recordStencilPath();
461    sp->fPath.reset(path);
462    path->ref();
463    sp->fFill = fill;
464}
465
466void GrInOrderDrawBuffer::clear(const GrIRect* rect,
467                                GrColor color,
468                                GrRenderTarget* renderTarget) {
469    GrIRect r;
470    if (NULL == renderTarget) {
471        renderTarget = this->drawState()->getRenderTarget();
472        GrAssert(NULL != renderTarget);
473    }
474    if (NULL == rect) {
475        // We could do something smart and remove previous draws and clears to
476        // the current render target. If we get that smart we have to make sure
477        // those draws aren't read before this clear (render-to-texture).
478        r.setLTRB(0, 0, renderTarget->width(), renderTarget->height());
479        rect = &r;
480    }
481    Clear* clr = this->recordClear();
482    clr->fColor = color;
483    clr->fRect = *rect;
484    clr->fRenderTarget = renderTarget;
485    renderTarget->ref();
486}
487
488void GrInOrderDrawBuffer::reset() {
489    GrAssert(1 == fGeoPoolStateStack.count());
490    this->resetVertexSource();
491    this->resetIndexSource();
492    int numDraws = fDraws.count();
493    for (int d = 0; d < numDraws; ++d) {
494        // we always have a VB, but not always an IB
495        GrAssert(NULL != fDraws[d].fVertexBuffer);
496        fDraws[d].fVertexBuffer->unref();
497        GrSafeUnref(fDraws[d].fIndexBuffer);
498    }
499    fCmds.reset();
500    fDraws.reset();
501    fStencilPaths.reset();
502    fStates.reset();
503    fClears.reset();
504    fVertexPool.reset();
505    fIndexPool.reset();
506    fClips.reset();
507    fClipOrigins.reset();
508    fClipSet = true;
509
510    this->resetDrawTracking();
511
512    // we start off with a default clip and state so that we don't have
513    // to do count checks on fClips, fStates, or fCmds before checking their
514    // last entry.
515    this->recordDefaultState();
516    this->recordDefaultClip();
517}
518
519bool GrInOrderDrawBuffer::playback(GrDrawTarget* target) {
520    GrAssert(kReserved_GeometrySrcType != this->getGeomSrc().fVertexSrc);
521    GrAssert(kReserved_GeometrySrcType != this->getGeomSrc().fIndexSrc);
522
523    GrAssert(NULL != target);
524    GrAssert(target != this); // not considered and why?
525
526    int numCmds = fCmds.count();
527    GrAssert(numCmds >= 2);
528    if (2 == numCmds) {
529        GrAssert(kSetState_Cmd == fCmds[0]);
530        GrAssert(kSetClip_Cmd  == fCmds[1]);
531        return false;
532    }
533
534    fVertexPool.unlock();
535    fIndexPool.unlock();
536
537    GrDrawTarget::AutoClipRestore acr(target);
538    AutoGeometryPush agp(target);
539    GrDrawState* prevDrawState = target->drawState();
540    prevDrawState->ref();
541
542    GrClipData clipData;
543
544    int currState       = 0;
545    int currClip        = 0;
546    int currClear       = 0;
547    int currDraw        = 0;
548    int currStencilPath = 0;
549
550    for (int c = 0; c < numCmds; ++c) {
551        switch (fCmds[c]) {
552            case kDraw_Cmd: {
553                const Draw& draw = fDraws[currDraw];
554                target->setVertexSourceToBuffer(draw.fVertexLayout, draw.fVertexBuffer);
555                if (draw.fIndexCount) {
556                    target->setIndexSourceToBuffer(draw.fIndexBuffer);
557                }
558
559                if (draw.fIndexCount) {
560                    target->drawIndexed(draw.fPrimitiveType,
561                                        draw.fStartVertex,
562                                        draw.fStartIndex,
563                                        draw.fVertexCount,
564                                        draw.fIndexCount);
565                } else {
566                    target->drawNonIndexed(draw.fPrimitiveType,
567                                           draw.fStartVertex,
568                                           draw.fVertexCount);
569                }
570                ++currDraw;
571                break;
572            }
573            case kStencilPath_Cmd: {
574                const StencilPath& sp = fStencilPaths[currStencilPath];
575                target->stencilPath(sp.fPath.get(), sp.fFill);
576                ++currStencilPath;
577                break;
578            }
579            case kSetState_Cmd:
580                target->setDrawState(&fStates[currState]);
581                ++currState;
582                break;
583            case kSetClip_Cmd:
584                clipData.fClipStack = &fClips[currClip];
585                clipData.fOrigin = fClipOrigins[currClip];
586                target->setClip(&clipData);
587                ++currClip;
588                break;
589            case kClear_Cmd:
590                target->clear(&fClears[currClear].fRect,
591                              fClears[currClear].fColor,
592                              fClears[currClear].fRenderTarget);
593                ++currClear;
594                break;
595        }
596    }
597    // we should have consumed all the states, clips, etc.
598    GrAssert(fStates.count() == currState);
599    GrAssert(fClips.count() == currClip);
600    GrAssert(fClipOrigins.count() == currClip);
601    GrAssert(fClears.count() == currClear);
602    GrAssert(fDraws.count()  == currDraw);
603
604    target->setDrawState(prevDrawState);
605    prevDrawState->unref();
606    return true;
607}
608
609void GrInOrderDrawBuffer::setAutoFlushTarget(GrDrawTarget* target) {
610    GrSafeAssign(fAutoFlushTarget, target);
611}
612
613void GrInOrderDrawBuffer::willReserveVertexAndIndexSpace(
614                                GrVertexLayout vertexLayout,
615                                int vertexCount,
616                                int indexCount) {
617    if (NULL != fAutoFlushTarget) {
618        // We use geometryHints() to know whether to flush the draw buffer. We
619        // can't flush if we are inside an unbalanced pushGeometrySource.
620        // Moreover, flushing blows away vertex and index data that was
621        // previously reserved. So if the vertex or index data is pulled from
622        // reserved space and won't be released by this request then we can't
623        // flush.
624        bool insideGeoPush = fGeoPoolStateStack.count() > 1;
625
626        bool unreleasedVertexSpace =
627            !vertexCount &&
628            kReserved_GeometrySrcType == this->getGeomSrc().fVertexSrc;
629
630        bool unreleasedIndexSpace =
631            !indexCount &&
632            kReserved_GeometrySrcType == this->getGeomSrc().fIndexSrc;
633
634        // we don't want to finalize any reserved geom on the target since
635        // we don't know that the client has finished writing to it.
636        bool targetHasReservedGeom =
637            fAutoFlushTarget->hasReservedVerticesOrIndices();
638
639        int vcount = vertexCount;
640        int icount = indexCount;
641
642        if (!insideGeoPush &&
643            !unreleasedVertexSpace &&
644            !unreleasedIndexSpace &&
645            !targetHasReservedGeom &&
646            this->geometryHints(vertexLayout, &vcount, &icount)) {
647
648            this->flushTo(fAutoFlushTarget);
649        }
650    }
651}
652
653bool GrInOrderDrawBuffer::geometryHints(GrVertexLayout vertexLayout,
654                                        int* vertexCount,
655                                        int* indexCount) const {
656    // we will recommend a flush if the data could fit in a single
657    // preallocated buffer but none are left and it can't fit
658    // in the current buffer (which may not be prealloced).
659    bool flush = false;
660    if (NULL != indexCount) {
661        int32_t currIndices = fIndexPool.currentBufferIndices();
662        if (*indexCount > currIndices &&
663            (!fIndexPool.preallocatedBuffersRemaining() &&
664             *indexCount <= fIndexPool.preallocatedBufferIndices())) {
665
666            flush = true;
667        }
668        *indexCount = currIndices;
669    }
670    if (NULL != vertexCount) {
671        int32_t currVertices = fVertexPool.currentBufferVertices(vertexLayout);
672        if (*vertexCount > currVertices &&
673            (!fVertexPool.preallocatedBuffersRemaining() &&
674             *vertexCount <= fVertexPool.preallocatedBufferVertices(vertexLayout))) {
675
676            flush = true;
677        }
678        *vertexCount = currVertices;
679    }
680    return flush;
681}
682
683bool GrInOrderDrawBuffer::onReserveVertexSpace(GrVertexLayout vertexLayout,
684                                               int vertexCount,
685                                               void** vertices) {
686    GeometryPoolState& poolState = fGeoPoolStateStack.back();
687    GrAssert(vertexCount > 0);
688    GrAssert(NULL != vertices);
689    GrAssert(0 == poolState.fUsedPoolVertexBytes);
690
691    *vertices = fVertexPool.makeSpace(vertexLayout,
692                                      vertexCount,
693                                      &poolState.fPoolVertexBuffer,
694                                      &poolState.fPoolStartVertex);
695    return NULL != *vertices;
696}
697
698bool GrInOrderDrawBuffer::onReserveIndexSpace(int indexCount, void** indices) {
699    GeometryPoolState& poolState = fGeoPoolStateStack.back();
700    GrAssert(indexCount > 0);
701    GrAssert(NULL != indices);
702    GrAssert(0 == poolState.fUsedPoolIndexBytes);
703
704    *indices = fIndexPool.makeSpace(indexCount,
705                                    &poolState.fPoolIndexBuffer,
706                                    &poolState.fPoolStartIndex);
707    return NULL != *indices;
708}
709
710void GrInOrderDrawBuffer::releaseReservedVertexSpace() {
711    GeometryPoolState& poolState = fGeoPoolStateStack.back();
712    const GeometrySrcState& geoSrc = this->getGeomSrc();
713
714    // If we get a release vertex space call then our current source should either be reserved
715    // or array (which we copied into reserved space).
716    GrAssert(kReserved_GeometrySrcType == geoSrc.fVertexSrc ||
717             kArray_GeometrySrcType == geoSrc.fVertexSrc);
718
719    // When the caller reserved vertex buffer space we gave it back a pointer
720    // provided by the vertex buffer pool. At each draw we tracked the largest
721    // offset into the pool's pointer that was referenced. Now we return to the
722    // pool any portion at the tail of the allocation that no draw referenced.
723    size_t reservedVertexBytes = VertexSize(geoSrc.fVertexLayout) *
724                                 geoSrc.fVertexCount;
725    fVertexPool.putBack(reservedVertexBytes -
726                        poolState.fUsedPoolVertexBytes);
727    poolState.fUsedPoolVertexBytes = 0;
728    poolState.fPoolVertexBuffer = NULL;
729    poolState.fPoolStartVertex = 0;
730}
731
732void GrInOrderDrawBuffer::releaseReservedIndexSpace() {
733    GeometryPoolState& poolState = fGeoPoolStateStack.back();
734    const GeometrySrcState& geoSrc = this->getGeomSrc();
735
736    // If we get a release index space call then our current source should either be reserved
737    // or array (which we copied into reserved space).
738    GrAssert(kReserved_GeometrySrcType == geoSrc.fIndexSrc ||
739             kArray_GeometrySrcType == geoSrc.fIndexSrc);
740
741    // Similar to releaseReservedVertexSpace we return any unused portion at
742    // the tail
743    size_t reservedIndexBytes = sizeof(uint16_t) * geoSrc.fIndexCount;
744    fIndexPool.putBack(reservedIndexBytes - poolState.fUsedPoolIndexBytes);
745    poolState.fUsedPoolIndexBytes = 0;
746    poolState.fPoolIndexBuffer = NULL;
747    poolState.fPoolStartIndex = 0;
748}
749
750void GrInOrderDrawBuffer::onSetVertexSourceToArray(const void* vertexArray,
751                                                   int vertexCount) {
752
753    GeometryPoolState& poolState = fGeoPoolStateStack.back();
754    GrAssert(0 == poolState.fUsedPoolVertexBytes);
755#if GR_DEBUG
756    bool success =
757#endif
758    fVertexPool.appendVertices(this->getVertexLayout(),
759                               vertexCount,
760                               vertexArray,
761                               &poolState.fPoolVertexBuffer,
762                               &poolState.fPoolStartVertex);
763    GR_DEBUGASSERT(success);
764}
765
766void GrInOrderDrawBuffer::onSetIndexSourceToArray(const void* indexArray,
767                                                  int indexCount) {
768    GeometryPoolState& poolState = fGeoPoolStateStack.back();
769    GrAssert(0 == poolState.fUsedPoolIndexBytes);
770#if GR_DEBUG
771    bool success =
772#endif
773    fIndexPool.appendIndices(indexCount,
774                             indexArray,
775                             &poolState.fPoolIndexBuffer,
776                             &poolState.fPoolStartIndex);
777    GR_DEBUGASSERT(success);
778}
779
780void GrInOrderDrawBuffer::releaseVertexArray() {
781    // When the client provides an array as the vertex source we handled it
782    // by copying their array into reserved space.
783    this->GrInOrderDrawBuffer::releaseReservedVertexSpace();
784}
785
786void GrInOrderDrawBuffer::releaseIndexArray() {
787    // When the client provides an array as the index source we handled it
788    // by copying their array into reserved space.
789    this->GrInOrderDrawBuffer::releaseReservedIndexSpace();
790}
791
792void GrInOrderDrawBuffer::geometrySourceWillPush() {
793    GeometryPoolState& poolState = fGeoPoolStateStack.push_back();
794    poolState.fUsedPoolVertexBytes = 0;
795    poolState.fUsedPoolIndexBytes = 0;
796    this->resetDrawTracking();
797#if GR_DEBUG
798    poolState.fPoolVertexBuffer = (GrVertexBuffer*)~0;
799    poolState.fPoolStartVertex = ~0;
800    poolState.fPoolIndexBuffer = (GrIndexBuffer*)~0;
801    poolState.fPoolStartIndex = ~0;
802#endif
803}
804
805void GrInOrderDrawBuffer::geometrySourceWillPop(
806                                        const GeometrySrcState& restoredState) {
807    GrAssert(fGeoPoolStateStack.count() > 1);
808    fGeoPoolStateStack.pop_back();
809    GeometryPoolState& poolState = fGeoPoolStateStack.back();
810    // we have to assume that any slack we had in our vertex/index data
811    // is now unreleasable because data may have been appended later in the
812    // pool.
813    if (kReserved_GeometrySrcType == restoredState.fVertexSrc ||
814        kArray_GeometrySrcType == restoredState.fVertexSrc) {
815        poolState.fUsedPoolVertexBytes =
816            VertexSize(restoredState.fVertexLayout) *
817            restoredState.fVertexCount;
818    }
819    if (kReserved_GeometrySrcType == restoredState.fIndexSrc ||
820        kArray_GeometrySrcType == restoredState.fIndexSrc) {
821        poolState.fUsedPoolIndexBytes = sizeof(uint16_t) *
822                                         restoredState.fIndexCount;
823    }
824    this->resetDrawTracking();
825}
826
827bool GrInOrderDrawBuffer::needsNewState() const {
828    // we should have recorded a default state in reset()
829    GrAssert(!fStates.empty());
830    return fStates.back() != this->getDrawState();
831}
832
833bool GrInOrderDrawBuffer::needsNewClip() const {
834   if (this->getDrawState().isClipState()) {
835       if (fClipSet &&
836           (fClips.back() != *fClip->fClipStack ||
837            fClipOrigins.back() != fClip->fOrigin)) {
838           return true;
839       }
840    }
841    return false;
842}
843
844void GrInOrderDrawBuffer::recordClip() {
845    fClips.push_back() = *fClip->fClipStack;
846    fClipOrigins.push_back() = fClip->fOrigin;
847    fClipSet = false;
848    fCmds.push_back(kSetClip_Cmd);
849}
850
851void GrInOrderDrawBuffer::recordDefaultClip() {
852    fClips.push_back() = SkClipStack();
853    fClipOrigins.push_back() = SkIPoint::Make(0, 0);
854    fCmds.push_back(kSetClip_Cmd);
855}
856
857void GrInOrderDrawBuffer::recordState() {
858    fStates.push_back(this->getDrawState());
859    fCmds.push_back(kSetState_Cmd);
860}
861
862void GrInOrderDrawBuffer::recordDefaultState() {
863    fStates.push_back(GrDrawState());
864    fCmds.push_back(kSetState_Cmd);
865}
866
867GrInOrderDrawBuffer::Draw* GrInOrderDrawBuffer::recordDraw() {
868    fCmds.push_back(kDraw_Cmd);
869    return &fDraws.push_back();
870}
871
872GrInOrderDrawBuffer::StencilPath* GrInOrderDrawBuffer::recordStencilPath() {
873    fCmds.push_back(kStencilPath_Cmd);
874    return &fStencilPaths.push_back();
875}
876
877GrInOrderDrawBuffer::Clear* GrInOrderDrawBuffer::recordClear() {
878    fCmds.push_back(kClear_Cmd);
879    return &fClears.push_back();
880}
881
882void GrInOrderDrawBuffer::clipWillBeSet(const GrClipData* newClipData) {
883    INHERITED::clipWillBeSet(newClipData);
884    fClipSet = true;
885}
886