GrGpu.cpp revision 6b20c2ded4bc546853719c88d1cf13b36fd89bcb
1
2/*
3 * Copyright 2010 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 "GrGpu.h"
11
12#include "GrBufferAllocPool.h"
13#include "GrClipIterator.h"
14#include "GrContext.h"
15#include "GrIndexBuffer.h"
16#include "GrPathRenderer.h"
17#include "GrGLStencilBuffer.h"
18#include "GrVertexBuffer.h"
19
20// probably makes no sense for this to be less than a page
21static const size_t VERTEX_POOL_VB_SIZE = 1 << 18;
22static const int VERTEX_POOL_VB_COUNT = 4;
23static const size_t INDEX_POOL_IB_SIZE = 1 << 16;
24static const int INDEX_POOL_IB_COUNT = 4;
25
26////////////////////////////////////////////////////////////////////////////////
27
28extern void gr_run_unittests();
29
30#define DEBUG_INVAL_BUFFER    0xdeadcafe
31#define DEBUG_INVAL_START_IDX -1
32
33GrGpu::GrGpu()
34    : fContext(NULL)
35    , fResetTimestamp(kExpiredTimestamp+1)
36    , fVertexPool(NULL)
37    , fIndexPool(NULL)
38    , fVertexPoolUseCnt(0)
39    , fIndexPoolUseCnt(0)
40    , fQuadIndexBuffer(NULL)
41    , fUnitSquareVertexBuffer(NULL)
42    , fPathRendererChain(NULL)
43    , fContextIsDirty(true)
44    , fResourceHead(NULL) {
45
46#if GR_DEBUG
47    //gr_run_unittests();
48#endif
49
50    fGeomPoolStateStack.push_back();
51#if GR_DEBUG
52    GeometryPoolState& poolState = fGeomPoolStateStack.back();
53    poolState.fPoolVertexBuffer = (GrVertexBuffer*)DEBUG_INVAL_BUFFER;
54    poolState.fPoolStartVertex = DEBUG_INVAL_START_IDX;
55    poolState.fPoolIndexBuffer = (GrIndexBuffer*)DEBUG_INVAL_BUFFER;
56    poolState.fPoolStartIndex = DEBUG_INVAL_START_IDX;
57#endif
58    resetStats();
59}
60
61GrGpu::~GrGpu() {
62    this->releaseResources();
63}
64
65void GrGpu::abandonResources() {
66
67    while (NULL != fResourceHead) {
68        fResourceHead->abandon();
69    }
70
71    GrAssert(NULL == fQuadIndexBuffer || !fQuadIndexBuffer->isValid());
72    GrAssert(NULL == fUnitSquareVertexBuffer ||
73             !fUnitSquareVertexBuffer->isValid());
74    GrSafeSetNull(fQuadIndexBuffer);
75    GrSafeSetNull(fUnitSquareVertexBuffer);
76    delete fVertexPool;
77    fVertexPool = NULL;
78    delete fIndexPool;
79    fIndexPool = NULL;
80    // in case path renderer has any GrResources, start from scratch
81    GrSafeSetNull(fPathRendererChain);
82}
83
84void GrGpu::releaseResources() {
85
86    while (NULL != fResourceHead) {
87        fResourceHead->release();
88    }
89
90    GrAssert(NULL == fQuadIndexBuffer || !fQuadIndexBuffer->isValid());
91    GrAssert(NULL == fUnitSquareVertexBuffer ||
92             !fUnitSquareVertexBuffer->isValid());
93    GrSafeSetNull(fQuadIndexBuffer);
94    GrSafeSetNull(fUnitSquareVertexBuffer);
95    delete fVertexPool;
96    fVertexPool = NULL;
97    delete fIndexPool;
98    fIndexPool = NULL;
99    // in case path renderer has any GrResources, start from scratch
100    GrSafeSetNull(fPathRendererChain);
101}
102
103void GrGpu::insertResource(GrResource* resource) {
104    GrAssert(NULL != resource);
105    GrAssert(this == resource->getGpu());
106    GrAssert(NULL == resource->fNext);
107    GrAssert(NULL == resource->fPrevious);
108
109    resource->fNext = fResourceHead;
110    if (NULL != fResourceHead) {
111        GrAssert(NULL == fResourceHead->fPrevious);
112        fResourceHead->fPrevious = resource;
113    }
114    fResourceHead = resource;
115}
116
117void GrGpu::removeResource(GrResource* resource) {
118    GrAssert(NULL != resource);
119    GrAssert(NULL != fResourceHead);
120
121    if (fResourceHead == resource) {
122        GrAssert(NULL == resource->fPrevious);
123        fResourceHead = resource->fNext;
124    } else {
125        GrAssert(NULL != fResourceHead);
126        resource->fPrevious->fNext = resource->fNext;
127    }
128    if (NULL != resource->fNext) {
129        resource->fNext->fPrevious = resource->fPrevious;
130    }
131    resource->fNext = NULL;
132    resource->fPrevious = NULL;
133}
134
135
136void GrGpu::unimpl(const char msg[]) {
137#if GR_DEBUG
138    GrPrintf("--- GrGpu unimplemented(\"%s\")\n", msg);
139#endif
140}
141
142////////////////////////////////////////////////////////////////////////////////
143
144GrTexture* GrGpu::createTexture(const GrTextureDesc& desc,
145                                const void* srcData, size_t rowBytes) {
146    this->handleDirtyContext();
147    GrTexture* tex = this->onCreateTexture(desc, srcData, rowBytes);
148    if (NULL != tex &&
149        (kRenderTarget_GrTextureFlagBit & desc.fFlags) &&
150        !(kNoStencil_GrTextureFlagBit & desc.fFlags)) {
151        GrAssert(NULL != tex->asRenderTarget());
152        // TODO: defer this and attach dynamically
153        if (!this->attachStencilBufferToRenderTarget(tex->asRenderTarget())) {
154            tex->unref();
155            return NULL;
156        }
157    }
158    return tex;
159}
160
161bool GrGpu::attachStencilBufferToRenderTarget(GrRenderTarget* rt) {
162    GrAssert(NULL == rt->getStencilBuffer());
163    GrStencilBuffer* sb =
164        this->getContext()->findStencilBuffer(rt->width(),
165                                              rt->height(),
166                                              rt->numSamples());
167    if (NULL != sb) {
168        rt->setStencilBuffer(sb);
169        bool attached = this->attachStencilBufferToRenderTarget(sb, rt);
170        if (!attached) {
171            rt->setStencilBuffer(NULL);
172        }
173        return attached;
174    }
175    if (this->createStencilBufferForRenderTarget(rt,
176                                                 rt->width(), rt->height())) {
177        rt->getStencilBuffer()->ref();
178        rt->getStencilBuffer()->transferToCacheAndLock();
179
180        // Right now we're clearing the stencil buffer here after it is
181        // attached to an RT for the first time. When we start matching
182        // stencil buffers with smaller color targets this will no longer
183        // be correct because it won't be guaranteed to clear the entire
184        // sb.
185        // We used to clear down in the GL subclass using a special purpose
186        // FBO. But iOS doesn't allow a stencil-only FBO. It reports unsupported
187        // FBO status.
188        GrDrawState::AutoRenderTargetRestore artr(this->drawState(), rt);
189        this->clearStencil();
190        return true;
191    } else {
192        return false;
193    }
194}
195
196GrTexture* GrGpu::createPlatformTexture(const GrPlatformTextureDesc& desc) {
197    this->handleDirtyContext();
198    GrTexture* tex = this->onCreatePlatformTexture(desc);
199    // TODO: defer this and attach dynamically
200    GrRenderTarget* tgt = tex->asRenderTarget();
201    if (NULL != tgt &&
202        !this->attachStencilBufferToRenderTarget(tgt)) {
203        tex->unref();
204        return NULL;
205    } else {
206        return tex;
207    }
208}
209
210GrRenderTarget* GrGpu::createPlatformRenderTarget(const GrPlatformRenderTargetDesc& desc) {
211    this->handleDirtyContext();
212    return this->onCreatePlatformRenderTarget(desc);
213}
214
215GrResource* GrGpu::createPlatformSurface(const GrPlatformSurfaceDesc& desc) {
216    this->handleDirtyContext();
217    return this->onCreatePlatformSurface(desc);
218}
219
220GrVertexBuffer* GrGpu::createVertexBuffer(uint32_t size, bool dynamic) {
221    this->handleDirtyContext();
222    return this->onCreateVertexBuffer(size, dynamic);
223}
224
225GrIndexBuffer* GrGpu::createIndexBuffer(uint32_t size, bool dynamic) {
226    this->handleDirtyContext();
227    return this->onCreateIndexBuffer(size, dynamic);
228}
229
230void GrGpu::clear(const GrIRect* rect, GrColor color) {
231    if (NULL == this->getDrawState().getRenderTarget()) {
232        return;
233    }
234    this->handleDirtyContext();
235    this->onClear(rect, color);
236}
237
238void GrGpu::forceRenderTargetFlush() {
239    this->handleDirtyContext();
240    this->onForceRenderTargetFlush();
241}
242
243bool GrGpu::readPixels(GrRenderTarget* target,
244                       int left, int top, int width, int height,
245                       GrPixelConfig config, void* buffer,
246                       size_t rowBytes, bool invertY) {
247    GrAssert(GrPixelConfigIsUnpremultiplied(config) ==
248             GrPixelConfigIsUnpremultiplied(target->config()));
249    this->handleDirtyContext();
250    return this->onReadPixels(target, left, top, width, height,
251                              config, buffer, rowBytes, invertY);
252}
253
254void GrGpu::writeTexturePixels(GrTexture* texture,
255                               int left, int top, int width, int height,
256                               GrPixelConfig config, const void* buffer,
257                               size_t rowBytes) {
258    GrAssert(GrPixelConfigIsUnpremultiplied(config) ==
259             GrPixelConfigIsUnpremultiplied(texture->config()));
260    this->handleDirtyContext();
261    this->onWriteTexturePixels(texture, left, top, width, height,
262                               config, buffer, rowBytes);
263}
264
265////////////////////////////////////////////////////////////////////////////////
266
267static const int MAX_QUADS = 1 << 12; // max possible: (1 << 14) - 1;
268
269GR_STATIC_ASSERT(4 * MAX_QUADS <= 65535);
270
271static inline void fill_indices(uint16_t* indices, int quadCount) {
272    for (int i = 0; i < quadCount; ++i) {
273        indices[6 * i + 0] = 4 * i + 0;
274        indices[6 * i + 1] = 4 * i + 1;
275        indices[6 * i + 2] = 4 * i + 2;
276        indices[6 * i + 3] = 4 * i + 0;
277        indices[6 * i + 4] = 4 * i + 2;
278        indices[6 * i + 5] = 4 * i + 3;
279    }
280}
281
282const GrIndexBuffer* GrGpu::getQuadIndexBuffer() const {
283    if (NULL == fQuadIndexBuffer) {
284        static const int SIZE = sizeof(uint16_t) * 6 * MAX_QUADS;
285        GrGpu* me = const_cast<GrGpu*>(this);
286        fQuadIndexBuffer = me->createIndexBuffer(SIZE, false);
287        if (NULL != fQuadIndexBuffer) {
288            uint16_t* indices = (uint16_t*)fQuadIndexBuffer->lock();
289            if (NULL != indices) {
290                fill_indices(indices, MAX_QUADS);
291                fQuadIndexBuffer->unlock();
292            } else {
293                indices = (uint16_t*)GrMalloc(SIZE);
294                fill_indices(indices, MAX_QUADS);
295                if (!fQuadIndexBuffer->updateData(indices, SIZE)) {
296                    fQuadIndexBuffer->unref();
297                    fQuadIndexBuffer = NULL;
298                    GrCrash("Can't get indices into buffer!");
299                }
300                GrFree(indices);
301            }
302        }
303    }
304
305    return fQuadIndexBuffer;
306}
307
308const GrVertexBuffer* GrGpu::getUnitSquareVertexBuffer() const {
309    if (NULL == fUnitSquareVertexBuffer) {
310
311        static const GrPoint DATA[] = {
312            { 0,            0 },
313            { GR_Scalar1,   0 },
314            { GR_Scalar1,   GR_Scalar1 },
315            { 0,            GR_Scalar1 }
316#if 0
317            GrPoint(0,         0),
318            GrPoint(GR_Scalar1,0),
319            GrPoint(GR_Scalar1,GR_Scalar1),
320            GrPoint(0,         GR_Scalar1)
321#endif
322        };
323        static const size_t SIZE = sizeof(DATA);
324
325        GrGpu* me = const_cast<GrGpu*>(this);
326        fUnitSquareVertexBuffer = me->createVertexBuffer(SIZE, false);
327        if (NULL != fUnitSquareVertexBuffer) {
328            if (!fUnitSquareVertexBuffer->updateData(DATA, SIZE)) {
329                fUnitSquareVertexBuffer->unref();
330                fUnitSquareVertexBuffer = NULL;
331                GrCrash("Can't get vertices into buffer!");
332            }
333        }
334    }
335
336    return fUnitSquareVertexBuffer;
337}
338
339////////////////////////////////////////////////////////////////////////////////
340
341// stencil settings to use when clip is in stencil
342const GrStencilSettings GrGpu::gClipStencilSettings = {
343    kKeep_StencilOp,             kKeep_StencilOp,
344    kKeep_StencilOp,             kKeep_StencilOp,
345    kAlwaysIfInClip_StencilFunc, kAlwaysIfInClip_StencilFunc,
346    0x0000,                      0x0000,
347    0x0000,                      0x0000,
348    0x0000,                      0x0000
349};
350
351// mapping of clip-respecting stencil funcs to normal stencil funcs
352// mapping depends on whether stencil-clipping is in effect.
353static const GrStencilFunc gGrClipToNormalStencilFunc[2][kClipStencilFuncCount] = {
354    {// Stencil-Clipping is DISABLED, effectively always inside the clip
355        // In the Clip Funcs
356        kAlways_StencilFunc,          // kAlwaysIfInClip_StencilFunc
357        kEqual_StencilFunc,           // kEqualIfInClip_StencilFunc
358        kLess_StencilFunc,            // kLessIfInClip_StencilFunc
359        kLEqual_StencilFunc,          // kLEqualIfInClip_StencilFunc
360        // Special in the clip func that forces user's ref to be 0.
361        kNotEqual_StencilFunc,        // kNonZeroIfInClip_StencilFunc
362                                      // make ref 0 and do normal nequal.
363    },
364    {// Stencil-Clipping is ENABLED
365        // In the Clip Funcs
366        kEqual_StencilFunc,           // kAlwaysIfInClip_StencilFunc
367                                      // eq stencil clip bit, mask
368                                      // out user bits.
369
370        kEqual_StencilFunc,           // kEqualIfInClip_StencilFunc
371                                      // add stencil bit to mask and ref
372
373        kLess_StencilFunc,            // kLessIfInClip_StencilFunc
374        kLEqual_StencilFunc,          // kLEqualIfInClip_StencilFunc
375                                      // for both of these we can add
376                                      // the clip bit to the mask and
377                                      // ref and compare as normal
378        // Special in the clip func that forces user's ref to be 0.
379        kLess_StencilFunc,            // kNonZeroIfInClip_StencilFunc
380                                      // make ref have only the clip bit set
381                                      // and make comparison be less
382                                      // 10..0 < 1..user_bits..
383    }
384};
385
386GrStencilFunc GrGpu::ConvertStencilFunc(bool stencilInClip, GrStencilFunc func) {
387    GrAssert(func >= 0);
388    if (func >= kBasicStencilFuncCount) {
389        GrAssert(func < kStencilFuncCount);
390        func = gGrClipToNormalStencilFunc[stencilInClip ? 1 : 0][func - kBasicStencilFuncCount];
391        GrAssert(func >= 0 && func < kBasicStencilFuncCount);
392    }
393    return func;
394}
395
396void GrGpu::ConvertStencilFuncAndMask(GrStencilFunc func,
397                                      bool clipInStencil,
398                                      unsigned int clipBit,
399                                      unsigned int userBits,
400                                      unsigned int* ref,
401                                      unsigned int* mask) {
402    if (func < kBasicStencilFuncCount) {
403        *mask &= userBits;
404        *ref &= userBits;
405    } else {
406        if (clipInStencil) {
407            switch (func) {
408                case kAlwaysIfInClip_StencilFunc:
409                    *mask = clipBit;
410                    *ref = clipBit;
411                    break;
412                case kEqualIfInClip_StencilFunc:
413                case kLessIfInClip_StencilFunc:
414                case kLEqualIfInClip_StencilFunc:
415                    *mask = (*mask & userBits) | clipBit;
416                    *ref = (*ref & userBits) | clipBit;
417                    break;
418                case kNonZeroIfInClip_StencilFunc:
419                    *mask = (*mask & userBits) | clipBit;
420                    *ref = clipBit;
421                    break;
422                default:
423                    GrCrash("Unknown stencil func");
424            }
425        } else {
426            *mask &= userBits;
427            *ref &= userBits;
428        }
429    }
430}
431
432////////////////////////////////////////////////////////////////////////////////
433
434#define VISUALIZE_COMPLEX_CLIP 0
435
436#if VISUALIZE_COMPLEX_CLIP
437    #include "GrRandom.h"
438    GrRandom gRandom;
439    #define SET_RANDOM_COLOR this->setColor(0xff000000 | gRandom.nextU());
440#else
441    #define SET_RANDOM_COLOR
442#endif
443
444namespace {
445// determines how many elements at the head of the clip can be skipped and
446// whether the initial clear should be to the inside- or outside-the-clip value,
447// and what op should be used to draw the first element that isn't skipped.
448int process_initial_clip_elements(const GrClip& clip,
449                                  const GrRect& bounds,
450                                  bool* clearToInside,
451                                  GrSetOp* startOp) {
452
453    // logically before the first element of the clip stack is
454    // processed the clip is entirely open. However, depending on the
455    // first set op we may prefer to clear to 0 for performance. We may
456    // also be able to skip the initial clip paths/rects. We loop until
457    // we cannot skip an element.
458    int curr;
459    bool done = false;
460    *clearToInside = true;
461    int count = clip.getElementCount();
462
463    for (curr = 0; curr < count && !done; ++curr) {
464        switch (clip.getOp(curr)) {
465            case kReplace_SetOp:
466                // replace ignores everything previous
467                *startOp = kReplace_SetOp;
468                *clearToInside = false;
469                done = true;
470                break;
471            case kIntersect_SetOp:
472                // if this element contains the entire bounds then we
473                // can skip it.
474                if (kRect_ClipType == clip.getElementType(curr)
475                    && clip.getRect(curr).contains(bounds)) {
476                    break;
477                }
478                // if everything is initially clearToInside then intersect is
479                // same as clear to 0 and treat as a replace. Otherwise,
480                // set stays empty.
481                if (*clearToInside) {
482                    *startOp = kReplace_SetOp;
483                    *clearToInside = false;
484                    done = true;
485                }
486                break;
487                // we can skip a leading union.
488            case kUnion_SetOp:
489                // if everything is initially outside then union is
490                // same as replace. Otherwise, every pixel is still
491                // clearToInside
492                if (!*clearToInside) {
493                    *startOp = kReplace_SetOp;
494                    done = true;
495                }
496                break;
497            case kXor_SetOp:
498                // xor is same as difference or replace both of which
499                // can be 1-pass instead of 2 for xor.
500                if (*clearToInside) {
501                    *startOp = kDifference_SetOp;
502                } else {
503                    *startOp = kReplace_SetOp;
504                }
505                done = true;
506                break;
507            case kDifference_SetOp:
508                // if all pixels are clearToInside then we have to process the
509                // difference, otherwise it has no effect and all pixels
510                // remain outside.
511                if (*clearToInside) {
512                    *startOp = kDifference_SetOp;
513                    done = true;
514                }
515                break;
516            case kReverseDifference_SetOp:
517                // if all pixels are clearToInside then reverse difference
518                // produces empty set. Otherise it is same as replace
519                if (*clearToInside) {
520                    *clearToInside = false;
521                } else {
522                    *startOp = kReplace_SetOp;
523                    done = true;
524                }
525                break;
526            default:
527                GrCrash("Unknown set op.");
528        }
529    }
530    return done ? curr-1 : count;
531}
532}
533
534bool GrGpu::setupClipAndFlushState(GrPrimitiveType type) {
535    const GrIRect* r = NULL;
536    GrIRect clipRect;
537
538    GrDrawState* drawState = this->drawState();
539    const GrRenderTarget* rt = drawState->getRenderTarget();
540
541    // GrDrawTarget should have filtered this for us
542    GrAssert(NULL != rt);
543
544    if (drawState->isClipState()) {
545
546        GrRect bounds;
547        GrRect rtRect;
548        rtRect.setLTRB(0, 0,
549                       GrIntToScalar(rt->width()), GrIntToScalar(rt->height()));
550        if (fClip.hasConservativeBounds()) {
551            bounds = fClip.getConservativeBounds();
552            if (!bounds.intersect(rtRect)) {
553                bounds.setEmpty();
554            }
555        } else {
556            bounds = rtRect;
557        }
558
559        bounds.roundOut(&clipRect);
560        if  (clipRect.isEmpty()) {
561            clipRect.setLTRB(0,0,0,0);
562        }
563        r = &clipRect;
564
565        // use the stencil clip if we can't represent the clip as a rectangle.
566        fClipInStencil = !fClip.isRect() && !fClip.isEmpty() &&
567                         !bounds.isEmpty();
568
569        // TODO: dynamically attach a SB when needed.
570        GrStencilBuffer* stencilBuffer = rt->getStencilBuffer();
571        if (fClipInStencil && NULL == stencilBuffer) {
572            return false;
573        }
574
575        if (fClipInStencil &&
576            stencilBuffer->mustRenderClip(fClip, rt->width(), rt->height())) {
577
578            stencilBuffer->setLastClip(fClip, rt->width(), rt->height());
579
580            // we set the current clip to the bounds so that our recursive
581            // draws are scissored to them. We use the copy of the complex clip
582            // we just stashed on the SB to render from. We set it back after
583            // we finish drawing it into the stencil.
584            const GrClip& clip = stencilBuffer->getLastClip();
585            fClip.setFromRect(bounds);
586
587            AutoStateRestore asr(this);
588            AutoGeometryPush agp(this);
589
590            drawState->setViewMatrix(GrMatrix::I());
591            this->flushScissor(NULL);
592#if !VISUALIZE_COMPLEX_CLIP
593            drawState->enableState(GrDrawState::kNoColorWrites_StateBit);
594#else
595            drawState->disableState(GrDrawState::kNoColorWrites_StateBit);
596#endif
597            int count = clip.getElementCount();
598            int clipBit = stencilBuffer->bits();
599            SkASSERT((clipBit <= 16) &&
600                     "Ganesh only handles 16b or smaller stencil buffers");
601            clipBit = (1 << (clipBit-1));
602
603            bool clearToInside;
604            GrSetOp startOp = kReplace_SetOp; // suppress warning
605            int start = process_initial_clip_elements(clip,
606                                                      rtRect,
607                                                      &clearToInside,
608                                                      &startOp);
609
610            this->clearStencilClip(clipRect, clearToInside);
611
612            // walk through each clip element and perform its set op
613            // with the existing clip.
614            for (int c = start; c < count; ++c) {
615                GrPathFill fill;
616                bool fillInverted;
617                // enabled at bottom of loop
618                drawState->disableState(kModifyStencilClip_StateBit);
619
620                bool canRenderDirectToStencil; // can the clip element be drawn
621                                               // directly to the stencil buffer
622                                               // with a non-inverted fill rule
623                                               // without extra passes to
624                                               // resolve in/out status.
625
626                GrPathRenderer* pr = NULL;
627                const GrPath* clipPath = NULL;
628                GrPathRenderer::AutoClearPath arp;
629                if (kRect_ClipType == clip.getElementType(c)) {
630                    canRenderDirectToStencil = true;
631                    fill = kEvenOdd_PathFill;
632                    fillInverted = false;
633                    // there is no point in intersecting a screen filling
634                    // rectangle.
635                    if (kIntersect_SetOp == clip.getOp(c) &&
636                        clip.getRect(c).contains(rtRect)) {
637                        continue;
638                    }
639                } else {
640                    fill = clip.getPathFill(c);
641                    fillInverted = GrIsFillInverted(fill);
642                    fill = GrNonInvertedFill(fill);
643                    clipPath = &clip.getPath(c);
644                    pr = this->getClipPathRenderer(*clipPath, fill);
645                    if (NULL == pr) {
646                        fClipInStencil = false;
647                        fClip = clip;
648                        return false;
649                    }
650                    canRenderDirectToStencil =
651                        !pr->requiresStencilPass(this, *clipPath, fill);
652                    arp.set(pr, this, clipPath, fill, false, NULL);
653                }
654
655                GrSetOp op = (c == start) ? startOp : clip.getOp(c);
656                int passes;
657                GrStencilSettings stencilSettings[GrStencilSettings::kMaxStencilClipPasses];
658
659                bool canDrawDirectToClip; // Given the renderer, the element,
660                                          // fill rule, and set operation can
661                                          // we render the element directly to
662                                          // stencil bit used for clipping.
663                canDrawDirectToClip =
664                    GrStencilSettings::GetClipPasses(op,
665                                                     canRenderDirectToStencil,
666                                                     clipBit,
667                                                     fillInverted,
668                                                     &passes, stencilSettings);
669
670                // draw the element to the client stencil bits if necessary
671                if (!canDrawDirectToClip) {
672                    static const GrStencilSettings gDrawToStencil = {
673                        kIncClamp_StencilOp, kIncClamp_StencilOp,
674                        kIncClamp_StencilOp, kIncClamp_StencilOp,
675                        kAlways_StencilFunc, kAlways_StencilFunc,
676                        0xffff,              0xffff,
677                        0x0000,              0x0000,
678                        0xffff,              0xffff,
679                    };
680                    SET_RANDOM_COLOR
681                    if (kRect_ClipType == clip.getElementType(c)) {
682                        *drawState->stencil() = gDrawToStencil;
683                        this->drawSimpleRect(clip.getRect(c), NULL, 0);
684                    } else {
685                        if (canRenderDirectToStencil) {
686                            *drawState->stencil() = gDrawToStencil;
687                            pr->drawPath(0);
688                        } else {
689                            pr->drawPathToStencil();
690                        }
691                    }
692                }
693
694                // now we modify the clip bit by rendering either the clip
695                // element directly or a bounding rect of the entire clip.
696                drawState->enableState(kModifyStencilClip_StateBit);
697                for (int p = 0; p < passes; ++p) {
698                    *drawState->stencil() = stencilSettings[p];
699                    if (canDrawDirectToClip) {
700                        if (kRect_ClipType == clip.getElementType(c)) {
701                            SET_RANDOM_COLOR
702                            this->drawSimpleRect(clip.getRect(c), NULL, 0);
703                        } else {
704                            SET_RANDOM_COLOR
705                            pr->drawPath(0);
706                        }
707                    } else {
708                        SET_RANDOM_COLOR
709                        this->drawSimpleRect(bounds, NULL, 0);
710                    }
711                }
712            }
713            // restore clip
714            fClip = clip;
715            // recusive draws would have disabled this since they drew with
716            // the clip bounds as clip.
717            fClipInStencil = true;
718        }
719    }
720
721    // Must flush the scissor after graphics state
722    if (!this->flushGraphicsState(type)) {
723        return false;
724    }
725    this->flushScissor(r);
726    return true;
727}
728
729GrPathRenderer* GrGpu::getClipPathRenderer(const GrPath& path,
730                                           GrPathFill fill) {
731    if (NULL == fPathRendererChain) {
732        fPathRendererChain =
733            new GrPathRendererChain(this->getContext(),
734                                    GrPathRendererChain::kNonAAOnly_UsageFlag);
735    }
736    return fPathRendererChain->getPathRenderer(this->getCaps(),
737                                               path, fill, false);
738}
739
740
741////////////////////////////////////////////////////////////////////////////////
742
743void GrGpu::geometrySourceWillPush() {
744    const GeometrySrcState& geoSrc = this->getGeomSrc();
745    if (kArray_GeometrySrcType == geoSrc.fVertexSrc ||
746        kReserved_GeometrySrcType == geoSrc.fVertexSrc) {
747        this->finalizeReservedVertices();
748    }
749    if (kArray_GeometrySrcType == geoSrc.fIndexSrc ||
750        kReserved_GeometrySrcType == geoSrc.fIndexSrc) {
751        this->finalizeReservedIndices();
752    }
753    GeometryPoolState& newState = fGeomPoolStateStack.push_back();
754#if GR_DEBUG
755    newState.fPoolVertexBuffer = (GrVertexBuffer*)DEBUG_INVAL_BUFFER;
756    newState.fPoolStartVertex = DEBUG_INVAL_START_IDX;
757    newState.fPoolIndexBuffer = (GrIndexBuffer*)DEBUG_INVAL_BUFFER;
758    newState.fPoolStartIndex = DEBUG_INVAL_START_IDX;
759#endif
760}
761
762void GrGpu::geometrySourceWillPop(const GeometrySrcState& restoredState) {
763    // if popping last entry then pops are unbalanced with pushes
764    GrAssert(fGeomPoolStateStack.count() > 1);
765    fGeomPoolStateStack.pop_back();
766}
767
768void GrGpu::onDrawIndexed(GrPrimitiveType type,
769                          int startVertex,
770                          int startIndex,
771                          int vertexCount,
772                          int indexCount) {
773
774    this->handleDirtyContext();
775
776    if (!this->setupClipAndFlushState(type)) {
777        return;
778    }
779
780#if GR_COLLECT_STATS
781    fStats.fVertexCnt += vertexCount;
782    fStats.fIndexCnt  += indexCount;
783    fStats.fDrawCnt   += 1;
784#endif
785
786    int sVertex = startVertex;
787    int sIndex = startIndex;
788    setupGeometry(&sVertex, &sIndex, vertexCount, indexCount);
789
790    this->onGpuDrawIndexed(type, sVertex, sIndex,
791                           vertexCount, indexCount);
792}
793
794void GrGpu::onDrawNonIndexed(GrPrimitiveType type,
795                           int startVertex,
796                           int vertexCount) {
797    this->handleDirtyContext();
798
799    if (!this->setupClipAndFlushState(type)) {
800        return;
801    }
802#if GR_COLLECT_STATS
803    fStats.fVertexCnt += vertexCount;
804    fStats.fDrawCnt   += 1;
805#endif
806
807    int sVertex = startVertex;
808    setupGeometry(&sVertex, NULL, vertexCount, 0);
809
810    this->onGpuDrawNonIndexed(type, sVertex, vertexCount);
811}
812
813void GrGpu::finalizeReservedVertices() {
814    GrAssert(NULL != fVertexPool);
815    fVertexPool->unlock();
816}
817
818void GrGpu::finalizeReservedIndices() {
819    GrAssert(NULL != fIndexPool);
820    fIndexPool->unlock();
821}
822
823void GrGpu::prepareVertexPool() {
824    if (NULL == fVertexPool) {
825        GrAssert(0 == fVertexPoolUseCnt);
826        fVertexPool = new GrVertexBufferAllocPool(this, true,
827                                                  VERTEX_POOL_VB_SIZE,
828                                                  VERTEX_POOL_VB_COUNT);
829        fVertexPool->releaseGpuRef();
830    } else if (!fVertexPoolUseCnt) {
831        // the client doesn't have valid data in the pool
832        fVertexPool->reset();
833    }
834}
835
836void GrGpu::prepareIndexPool() {
837    if (NULL == fIndexPool) {
838        GrAssert(0 == fIndexPoolUseCnt);
839        fIndexPool = new GrIndexBufferAllocPool(this, true,
840                                                INDEX_POOL_IB_SIZE,
841                                                INDEX_POOL_IB_COUNT);
842        fIndexPool->releaseGpuRef();
843    } else if (!fIndexPoolUseCnt) {
844        // the client doesn't have valid data in the pool
845        fIndexPool->reset();
846    }
847}
848
849bool GrGpu::onReserveVertexSpace(GrVertexLayout vertexLayout,
850                                 int vertexCount,
851                                 void** vertices) {
852    GeometryPoolState& geomPoolState = fGeomPoolStateStack.back();
853
854    GrAssert(vertexCount > 0);
855    GrAssert(NULL != vertices);
856
857    this->prepareVertexPool();
858
859    *vertices = fVertexPool->makeSpace(vertexLayout,
860                                       vertexCount,
861                                       &geomPoolState.fPoolVertexBuffer,
862                                       &geomPoolState.fPoolStartVertex);
863    if (NULL == *vertices) {
864        return false;
865    }
866    ++fVertexPoolUseCnt;
867    return true;
868}
869
870bool GrGpu::onReserveIndexSpace(int indexCount, void** indices) {
871    GeometryPoolState& geomPoolState = fGeomPoolStateStack.back();
872
873    GrAssert(indexCount > 0);
874    GrAssert(NULL != indices);
875
876    this->prepareIndexPool();
877
878    *indices = fIndexPool->makeSpace(indexCount,
879                                     &geomPoolState.fPoolIndexBuffer,
880                                     &geomPoolState.fPoolStartIndex);
881    if (NULL == *indices) {
882        return false;
883    }
884    ++fIndexPoolUseCnt;
885    return true;
886}
887
888void GrGpu::releaseReservedVertexSpace() {
889    const GeometrySrcState& geoSrc = this->getGeomSrc();
890    GrAssert(kReserved_GeometrySrcType == geoSrc.fVertexSrc);
891    size_t bytes = geoSrc.fVertexCount * VertexSize(geoSrc.fVertexLayout);
892    fVertexPool->putBack(bytes);
893    --fVertexPoolUseCnt;
894}
895
896void GrGpu::releaseReservedIndexSpace() {
897    const GeometrySrcState& geoSrc = this->getGeomSrc();
898    GrAssert(kReserved_GeometrySrcType == geoSrc.fIndexSrc);
899    size_t bytes = geoSrc.fIndexCount * sizeof(uint16_t);
900    fIndexPool->putBack(bytes);
901    --fIndexPoolUseCnt;
902}
903
904void GrGpu::onSetVertexSourceToArray(const void* vertexArray, int vertexCount) {
905    this->prepareVertexPool();
906    GeometryPoolState& geomPoolState = fGeomPoolStateStack.back();
907#if GR_DEBUG
908    bool success =
909#endif
910    fVertexPool->appendVertices(this->getGeomSrc().fVertexLayout,
911                                vertexCount,
912                                vertexArray,
913                                &geomPoolState.fPoolVertexBuffer,
914                                &geomPoolState.fPoolStartVertex);
915    ++fVertexPoolUseCnt;
916    GR_DEBUGASSERT(success);
917}
918
919void GrGpu::onSetIndexSourceToArray(const void* indexArray, int indexCount) {
920    this->prepareIndexPool();
921    GeometryPoolState& geomPoolState = fGeomPoolStateStack.back();
922#if GR_DEBUG
923    bool success =
924#endif
925    fIndexPool->appendIndices(indexCount,
926                              indexArray,
927                              &geomPoolState.fPoolIndexBuffer,
928                              &geomPoolState.fPoolStartIndex);
929    ++fIndexPoolUseCnt;
930    GR_DEBUGASSERT(success);
931}
932
933void GrGpu::releaseVertexArray() {
934    // if vertex source was array, we stowed data in the pool
935    const GeometrySrcState& geoSrc = this->getGeomSrc();
936    GrAssert(kArray_GeometrySrcType == geoSrc.fVertexSrc);
937    size_t bytes = geoSrc.fVertexCount * VertexSize(geoSrc.fVertexLayout);
938    fVertexPool->putBack(bytes);
939    --fVertexPoolUseCnt;
940}
941
942void GrGpu::releaseIndexArray() {
943    // if index source was array, we stowed data in the pool
944    const GeometrySrcState& geoSrc = this->getGeomSrc();
945    GrAssert(kArray_GeometrySrcType == geoSrc.fIndexSrc);
946    size_t bytes = geoSrc.fIndexCount * sizeof(uint16_t);
947    fIndexPool->putBack(bytes);
948    --fIndexPoolUseCnt;
949}
950
951////////////////////////////////////////////////////////////////////////////////
952
953const GrGpuStats& GrGpu::getStats() const {
954    return fStats;
955}
956
957void GrGpu::resetStats() {
958    memset(&fStats, 0, sizeof(fStats));
959}
960
961void GrGpu::printStats() const {
962    if (GR_COLLECT_STATS) {
963     GrPrintf(
964     "-v-------------------------GPU STATS----------------------------v-\n"
965     "Stats collection is: %s\n"
966     "Draws: %04d, Verts: %04d, Indices: %04d\n"
967     "ProgChanges: %04d, TexChanges: %04d, RTChanges: %04d\n"
968     "TexCreates: %04d, RTCreates:%04d\n"
969     "-^--------------------------------------------------------------^-\n",
970     (GR_COLLECT_STATS ? "ON" : "OFF"),
971    fStats.fDrawCnt, fStats.fVertexCnt, fStats.fIndexCnt,
972    fStats.fProgChngCnt, fStats.fTextureChngCnt, fStats.fRenderTargetChngCnt,
973    fStats.fTextureCreateCnt, fStats.fRenderTargetCreateCnt);
974    }
975}
976
977////////////////////////////////////////////////////////////////////////////////
978
979const GrSamplerState GrSamplerState::gClampNearest;
980