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