Home | History | Annotate | Download | only in src
      1 /*
      2     Copyright 2010 Google Inc.
      3 
      4     Licensed under the Apache License, Version 2.0 (the "License");
      5     you may not use this file except in compliance with the License.
      6     You may obtain a copy of the License at
      7 
      8          http://www.apache.org/licenses/LICENSE-2.0
      9 
     10     Unless required by applicable law or agreed to in writing, software
     11     distributed under the License is distributed on an "AS IS" BASIS,
     12     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13     See the License for the specific language governing permissions and
     14     limitations under the License.
     15  */
     16 
     17 #include "GrGpu.h"
     18 #include "GrMemory.h"
     19 #include "GrTextStrike.h"
     20 #include "GrTextureCache.h"
     21 #include "GrClipIterator.h"
     22 #include "GrIndexBuffer.h"
     23 #include "GrVertexBuffer.h"
     24 #include "GrBufferAllocPool.h"
     25 #include "GrPathRenderer.h"
     26 
     27 // probably makes no sense for this to be less than a page
     28 static const size_t VERTEX_POOL_VB_SIZE = 1 << 12;
     29 static const int VERTEX_POOL_VB_COUNT = 1;
     30 
     31 
     32 ////////////////////////////////////////////////////////////////////////////////
     33 
     34 extern void gr_run_unittests();
     35 
     36 GrGpu::GrGpu()
     37     : f8bitPaletteSupport(false)
     38     , fCurrPoolVertexBuffer(NULL)
     39     , fCurrPoolStartVertex(0)
     40     , fCurrPoolIndexBuffer(NULL)
     41     , fCurrPoolStartIndex(0)
     42     , fContext(NULL)
     43     , fVertexPool(NULL)
     44     , fIndexPool(NULL)
     45     , fQuadIndexBuffer(NULL)
     46     , fUnitSquareVertexBuffer(NULL)
     47     , fDefaultPathRenderer(NULL)
     48     , fClientPathRenderer(NULL)
     49     , fContextIsDirty(true)
     50     , fVertexPoolInUse(false)
     51     , fIndexPoolInUse(false)
     52     , fResourceHead(NULL) {
     53 
     54 #if GR_DEBUG
     55     //gr_run_unittests();
     56 #endif
     57     resetStats();
     58 }
     59 
     60 GrGpu::~GrGpu() {
     61     releaseResources();
     62 }
     63 
     64 void GrGpu::abandonResources() {
     65 
     66     while (NULL != fResourceHead) {
     67         fResourceHead->abandon();
     68     }
     69 
     70     GrAssert(NULL == fQuadIndexBuffer || !fQuadIndexBuffer->isValid());
     71     GrAssert(NULL == fUnitSquareVertexBuffer ||
     72              !fUnitSquareVertexBuffer->isValid());
     73     GrSafeSetNull(fQuadIndexBuffer);
     74     GrSafeSetNull(fUnitSquareVertexBuffer);
     75     delete fVertexPool;
     76     fVertexPool = NULL;
     77     delete fIndexPool;
     78     fIndexPool = NULL;
     79 }
     80 
     81 void GrGpu::releaseResources() {
     82 
     83     while (NULL != fResourceHead) {
     84         fResourceHead->release();
     85     }
     86 
     87     GrAssert(NULL == fQuadIndexBuffer || !fQuadIndexBuffer->isValid());
     88     GrAssert(NULL == fUnitSquareVertexBuffer ||
     89              !fUnitSquareVertexBuffer->isValid());
     90     GrSafeSetNull(fQuadIndexBuffer);
     91     GrSafeSetNull(fUnitSquareVertexBuffer);
     92     delete fVertexPool;
     93     fVertexPool = NULL;
     94     delete fIndexPool;
     95     fIndexPool = NULL;
     96 }
     97 
     98 void GrGpu::insertResource(GrResource* resource) {
     99     GrAssert(NULL != resource);
    100     GrAssert(this == resource->getGpu());
    101     GrAssert(NULL == resource->fNext);
    102     GrAssert(NULL == resource->fPrevious);
    103 
    104     resource->fNext = fResourceHead;
    105     if (NULL != fResourceHead) {
    106         GrAssert(NULL == fResourceHead->fPrevious);
    107         fResourceHead->fPrevious = resource;
    108     }
    109     fResourceHead = resource;
    110 }
    111 
    112 void GrGpu::removeResource(GrResource* resource) {
    113     GrAssert(NULL != resource);
    114     GrAssert(NULL != fResourceHead);
    115 
    116     if (fResourceHead == resource) {
    117         GrAssert(NULL == resource->fPrevious);
    118         fResourceHead = resource->fNext;
    119     } else {
    120         GrAssert(NULL != fResourceHead);
    121         resource->fPrevious->fNext = resource->fNext;
    122     }
    123     if (NULL != resource->fNext) {
    124         resource->fNext->fPrevious = resource->fPrevious;
    125     }
    126     resource->fNext = NULL;
    127     resource->fPrevious = NULL;
    128 }
    129 
    130 
    131 void GrGpu::unimpl(const char msg[]) {
    132 #if GR_DEBUG
    133     GrPrintf("--- GrGpu unimplemented(\"%s\")\n", msg);
    134 #endif
    135 }
    136 
    137 ////////////////////////////////////////////////////////////////////////////////
    138 
    139 GrTexture* GrGpu::createTexture(const GrTextureDesc& desc,
    140                                 const void* srcData, size_t rowBytes) {
    141     this->handleDirtyContext();
    142     return this->onCreateTexture(desc, srcData, rowBytes);
    143 }
    144 
    145 GrRenderTarget* GrGpu::createRenderTargetFrom3DApiState() {
    146     this->handleDirtyContext();
    147     return this->onCreateRenderTargetFrom3DApiState();
    148 }
    149 
    150 GrResource* GrGpu::createPlatformSurface(const GrPlatformSurfaceDesc& desc) {
    151     this->handleDirtyContext();
    152     return this->onCreatePlatformSurface(desc);
    153 }
    154 
    155 GrVertexBuffer* GrGpu::createVertexBuffer(uint32_t size, bool dynamic) {
    156     this->handleDirtyContext();
    157     return this->onCreateVertexBuffer(size, dynamic);
    158 }
    159 
    160 GrIndexBuffer* GrGpu::createIndexBuffer(uint32_t size, bool dynamic) {
    161     this->handleDirtyContext();
    162     return this->onCreateIndexBuffer(size, dynamic);
    163 }
    164 
    165 void GrGpu::clear(const GrIRect* rect, GrColor color) {
    166     this->handleDirtyContext();
    167     this->onClear(rect, color);
    168 }
    169 
    170 void GrGpu::forceRenderTargetFlush() {
    171     this->handleDirtyContext();
    172     this->onForceRenderTargetFlush();
    173 }
    174 
    175 bool GrGpu::readPixels(GrRenderTarget* target,
    176                        int left, int top, int width, int height,
    177                        GrPixelConfig config, void* buffer) {
    178 
    179     this->handleDirtyContext();
    180     return this->onReadPixels(target, left, top, width, height, config, buffer);
    181 }
    182 
    183 ////////////////////////////////////////////////////////////////////////////////
    184 
    185 static const int MAX_QUADS = 1 << 12; // max possible: (1 << 14) - 1;
    186 
    187 GR_STATIC_ASSERT(4 * MAX_QUADS <= 65535);
    188 
    189 static inline void fill_indices(uint16_t* indices, int quadCount) {
    190     for (int i = 0; i < quadCount; ++i) {
    191         indices[6 * i + 0] = 4 * i + 0;
    192         indices[6 * i + 1] = 4 * i + 1;
    193         indices[6 * i + 2] = 4 * i + 2;
    194         indices[6 * i + 3] = 4 * i + 0;
    195         indices[6 * i + 4] = 4 * i + 2;
    196         indices[6 * i + 5] = 4 * i + 3;
    197     }
    198 }
    199 
    200 const GrIndexBuffer* GrGpu::getQuadIndexBuffer() const {
    201     if (NULL == fQuadIndexBuffer) {
    202         static const int SIZE = sizeof(uint16_t) * 6 * MAX_QUADS;
    203         GrGpu* me = const_cast<GrGpu*>(this);
    204         fQuadIndexBuffer = me->createIndexBuffer(SIZE, false);
    205         if (NULL != fQuadIndexBuffer) {
    206             uint16_t* indices = (uint16_t*)fQuadIndexBuffer->lock();
    207             if (NULL != indices) {
    208                 fill_indices(indices, MAX_QUADS);
    209                 fQuadIndexBuffer->unlock();
    210             } else {
    211                 indices = (uint16_t*)GrMalloc(SIZE);
    212                 fill_indices(indices, MAX_QUADS);
    213                 if (!fQuadIndexBuffer->updateData(indices, SIZE)) {
    214                     fQuadIndexBuffer->unref();
    215                     fQuadIndexBuffer = NULL;
    216                     GrCrash("Can't get indices into buffer!");
    217                 }
    218                 GrFree(indices);
    219             }
    220         }
    221     }
    222 
    223     return fQuadIndexBuffer;
    224 }
    225 
    226 const GrVertexBuffer* GrGpu::getUnitSquareVertexBuffer() const {
    227     if (NULL == fUnitSquareVertexBuffer) {
    228 
    229         static const GrPoint DATA[] = {
    230             { 0,            0 },
    231             { GR_Scalar1,   0 },
    232             { GR_Scalar1,   GR_Scalar1 },
    233             { 0,            GR_Scalar1 }
    234 #if 0
    235             GrPoint(0,         0),
    236             GrPoint(GR_Scalar1,0),
    237             GrPoint(GR_Scalar1,GR_Scalar1),
    238             GrPoint(0,         GR_Scalar1)
    239 #endif
    240         };
    241         static const size_t SIZE = sizeof(DATA);
    242 
    243         GrGpu* me = const_cast<GrGpu*>(this);
    244         fUnitSquareVertexBuffer = me->createVertexBuffer(SIZE, false);
    245         if (NULL != fUnitSquareVertexBuffer) {
    246             if (!fUnitSquareVertexBuffer->updateData(DATA, SIZE)) {
    247                 fUnitSquareVertexBuffer->unref();
    248                 fUnitSquareVertexBuffer = NULL;
    249                 GrCrash("Can't get vertices into buffer!");
    250             }
    251         }
    252     }
    253 
    254     return fUnitSquareVertexBuffer;
    255 }
    256 
    257 ////////////////////////////////////////////////////////////////////////////////
    258 
    259 void GrGpu::clipWillBeSet(const GrClip& newClip) {
    260     if (newClip != fClip) {
    261         fClipState.fClipIsDirty = true;
    262     }
    263 }
    264 
    265 ////////////////////////////////////////////////////////////////////////////////
    266 
    267 // stencil settings to use when clip is in stencil
    268 const GrStencilSettings GrGpu::gClipStencilSettings = {
    269     kKeep_StencilOp,             kKeep_StencilOp,
    270     kKeep_StencilOp,             kKeep_StencilOp,
    271     kAlwaysIfInClip_StencilFunc, kAlwaysIfInClip_StencilFunc,
    272     0,                           0,
    273     0,                           0,
    274     0,                           0
    275 };
    276 
    277 // mapping of clip-respecting stencil funcs to normal stencil funcs
    278 // mapping depends on whether stencil-clipping is in effect.
    279 static const GrStencilFunc gGrClipToNormalStencilFunc[2][kClipStencilFuncCount] = {
    280     {// Stencil-Clipping is DISABLED, effectively always inside the clip
    281         // In the Clip Funcs
    282         kAlways_StencilFunc,          // kAlwaysIfInClip_StencilFunc
    283         kEqual_StencilFunc,           // kEqualIfInClip_StencilFunc
    284         kLess_StencilFunc,            // kLessIfInClip_StencilFunc
    285         kLEqual_StencilFunc,          // kLEqualIfInClip_StencilFunc
    286         // Special in the clip func that forces user's ref to be 0.
    287         kNotEqual_StencilFunc,        // kNonZeroIfInClip_StencilFunc
    288                                       // make ref 0 and do normal nequal.
    289     },
    290     {// Stencil-Clipping is ENABLED
    291         // In the Clip Funcs
    292         kEqual_StencilFunc,           // kAlwaysIfInClip_StencilFunc
    293                                       // eq stencil clip bit, mask
    294                                       // out user bits.
    295 
    296         kEqual_StencilFunc,           // kEqualIfInClip_StencilFunc
    297                                       // add stencil bit to mask and ref
    298 
    299         kLess_StencilFunc,            // kLessIfInClip_StencilFunc
    300         kLEqual_StencilFunc,          // kLEqualIfInClip_StencilFunc
    301                                       // for both of these we can add
    302                                       // the clip bit to the mask and
    303                                       // ref and compare as normal
    304         // Special in the clip func that forces user's ref to be 0.
    305         kLess_StencilFunc,            // kNonZeroIfInClip_StencilFunc
    306                                       // make ref have only the clip bit set
    307                                       // and make comparison be less
    308                                       // 10..0 < 1..user_bits..
    309     }
    310 };
    311 
    312 GrStencilFunc GrGpu::ConvertStencilFunc(bool stencilInClip, GrStencilFunc func) {
    313     GrAssert(func >= 0);
    314     if (func >= kBasicStencilFuncCount) {
    315         GrAssert(func < kStencilFuncCount);
    316         func = gGrClipToNormalStencilFunc[stencilInClip ? 1 : 0][func - kBasicStencilFuncCount];
    317         GrAssert(func >= 0 && func < kBasicStencilFuncCount);
    318     }
    319     return func;
    320 }
    321 
    322 void GrGpu::ConvertStencilFuncAndMask(GrStencilFunc func,
    323                                       bool clipInStencil,
    324                                       unsigned int clipBit,
    325                                       unsigned int userBits,
    326                                       unsigned int* ref,
    327                                       unsigned int* mask) {
    328     if (func < kBasicStencilFuncCount) {
    329         *mask &= userBits;
    330         *ref &= userBits;
    331     } else {
    332         if (clipInStencil) {
    333             switch (func) {
    334                 case kAlwaysIfInClip_StencilFunc:
    335                     *mask = clipBit;
    336                     *ref = clipBit;
    337                     break;
    338                 case kEqualIfInClip_StencilFunc:
    339                 case kLessIfInClip_StencilFunc:
    340                 case kLEqualIfInClip_StencilFunc:
    341                     *mask = (*mask & userBits) | clipBit;
    342                     *ref = (*ref & userBits) | clipBit;
    343                     break;
    344                 case kNonZeroIfInClip_StencilFunc:
    345                     *mask = (*mask & userBits) | clipBit;
    346                     *ref = clipBit;
    347                     break;
    348                 default:
    349                     GrCrash("Unknown stencil func");
    350             }
    351         } else {
    352             *mask &= userBits;
    353             *ref &= userBits;
    354         }
    355     }
    356 }
    357 
    358 ////////////////////////////////////////////////////////////////////////////////
    359 
    360 #define VISUALIZE_COMPLEX_CLIP 0
    361 
    362 #if VISUALIZE_COMPLEX_CLIP
    363     #include "GrRandom.h"
    364     GrRandom gRandom;
    365     #define SET_RANDOM_COLOR this->setColor(0xff000000 | gRandom.nextU());
    366 #else
    367     #define SET_RANDOM_COLOR
    368 #endif
    369 
    370 bool GrGpu::setupClipAndFlushState(GrPrimitiveType type) {
    371     const GrIRect* r = NULL;
    372     GrIRect clipRect;
    373 
    374     // we check this early because we need a valid
    375     // render target to setup stencil clipping
    376     // before even going into flushGraphicsState
    377     if (NULL == fCurrDrawState.fRenderTarget) {
    378         GrAssert(!"No render target bound.");
    379         return false;
    380     }
    381 
    382     if (fCurrDrawState.fFlagBits & kClip_StateBit) {
    383         GrRenderTarget& rt = *fCurrDrawState.fRenderTarget;
    384 
    385         GrRect bounds;
    386         GrRect rtRect;
    387         rtRect.setLTRB(0, 0,
    388                        GrIntToScalar(rt.width()), GrIntToScalar(rt.height()));
    389         if (fClip.hasConservativeBounds()) {
    390             bounds = fClip.getConservativeBounds();
    391             if (!bounds.intersect(rtRect)) {
    392                 bounds.setEmpty();
    393             }
    394         } else {
    395             bounds = rtRect;
    396         }
    397 
    398         bounds.roundOut(&clipRect);
    399         if  (clipRect.isEmpty()) {
    400             clipRect.setLTRB(0,0,0,0);
    401         }
    402         r = &clipRect;
    403 
    404         fClipState.fClipInStencil = !fClip.isRect() &&
    405                                     !fClip.isEmpty() &&
    406                                     !bounds.isEmpty();
    407 
    408         if (fClipState.fClipInStencil &&
    409             (fClipState.fClipIsDirty ||
    410              fClip != rt.fLastStencilClip)) {
    411 
    412             rt.fLastStencilClip = fClip;
    413             // we set the current clip to the bounds so that our recursive
    414             // draws are scissored to them. We use the copy of the complex clip
    415             // in the rt to render
    416             const GrClip& clip = rt.fLastStencilClip;
    417             fClip.setFromRect(bounds);
    418 
    419             AutoStateRestore asr(this);
    420             AutoInternalDrawGeomRestore aidgr(this);
    421 
    422             this->setViewMatrix(GrMatrix::I());
    423             this->clearStencilClip(clipRect);
    424             this->flushScissor(NULL);
    425 #if !VISUALIZE_COMPLEX_CLIP
    426             this->enableState(kNoColorWrites_StateBit);
    427 #else
    428             this->disableState(kNoColorWrites_StateBit);
    429 #endif
    430             int count = clip.getElementCount();
    431             int clipBit = rt.stencilBits();
    432             clipBit = (1 << (clipBit-1));
    433 
    434             // often we'll see the first two elements of the clip are
    435             // the full rt size and another element intersected with it.
    436             // We can skip the first full-size rect and save a big rect draw.
    437             int firstElement = 0;
    438             if (clip.getElementCount() > 1 &&
    439                 kRect_ClipType == clip.getElementType(0) &&
    440                 kIntersect_SetOp == clip.getOp(1)&&
    441                 clip.getRect(0).contains(bounds)) {
    442                 firstElement = 1;
    443             }
    444 
    445             // walk through each clip element and perform its set op
    446             // with the existing clip.
    447             for (int c = firstElement; c < count; ++c) {
    448                 GrPathFill fill;
    449                 // enabled at bottom of loop
    450                 this->disableState(kModifyStencilClip_StateBit);
    451 
    452                 bool canRenderDirectToStencil; // can the clip element be drawn
    453                                                // directly to the stencil buffer
    454                                                // with a non-inverted fill rule
    455                                                // without extra passes to
    456                                                // resolve in/out status.
    457 
    458                 GrPathRenderer* pr = NULL;
    459                 const GrPath* clipPath = NULL;
    460                 if (kRect_ClipType == clip.getElementType(c)) {
    461                     canRenderDirectToStencil = true;
    462                     fill = kEvenOdd_PathFill;
    463                 } else {
    464                     fill = clip.getPathFill(c);
    465                     clipPath = &clip.getPath(c);
    466                     pr = this->getClipPathRenderer(*clipPath, NonInvertedFill(fill));
    467                     canRenderDirectToStencil =
    468                         !pr->requiresStencilPass(this, *clipPath,
    469                                                  NonInvertedFill(fill));
    470                 }
    471 
    472                 GrSetOp op = firstElement == c ? kReplace_SetOp : clip.getOp(c);
    473                 int passes;
    474                 GrStencilSettings stencilSettings[GrStencilSettings::kMaxStencilClipPasses];
    475 
    476                 bool canDrawDirectToClip; // Given the renderer, the element,
    477                                           // fill rule, and set operation can
    478                                           // we render the element directly to
    479                                           // stencil bit used for clipping.
    480                 canDrawDirectToClip =
    481                     GrStencilSettings::GetClipPasses(op,
    482                                                      canRenderDirectToStencil,
    483                                                      clipBit,
    484                                                      IsFillInverted(fill),
    485                                                      &passes, stencilSettings);
    486 
    487                 // draw the element to the client stencil bits if necessary
    488                 if (!canDrawDirectToClip) {
    489                     static const GrStencilSettings gDrawToStencil = {
    490                         kIncClamp_StencilOp, kIncClamp_StencilOp,
    491                         kIncClamp_StencilOp, kIncClamp_StencilOp,
    492                         kAlways_StencilFunc, kAlways_StencilFunc,
    493                         0xffffffff,          0xffffffff,
    494                         0x00000000,          0x00000000,
    495                         0xffffffff,          0xffffffff,
    496                     };
    497                     SET_RANDOM_COLOR
    498                     if (kRect_ClipType == clip.getElementType(c)) {
    499                         this->setStencil(gDrawToStencil);
    500                         this->drawSimpleRect(clip.getRect(c), NULL, 0);
    501                     } else {
    502                         if (canRenderDirectToStencil) {
    503                             this->setStencil(gDrawToStencil);
    504                             pr->drawPath(this, 0, *clipPath, NonInvertedFill(fill),
    505                                          NULL);
    506                         } else {
    507                             pr->drawPathToStencil(this, *clipPath,
    508                                                   NonInvertedFill(fill),
    509                                                   NULL);
    510                         }
    511                     }
    512                 }
    513 
    514                 // now we modify the clip bit by rendering either the clip
    515                 // element directly or a bounding rect of the entire clip.
    516                 this->enableState(kModifyStencilClip_StateBit);
    517                 for (int p = 0; p < passes; ++p) {
    518                     this->setStencil(stencilSettings[p]);
    519                     if (canDrawDirectToClip) {
    520                         if (kRect_ClipType == clip.getElementType(c)) {
    521                             SET_RANDOM_COLOR
    522                             this->drawSimpleRect(clip.getRect(c), NULL, 0);
    523                         } else {
    524                             SET_RANDOM_COLOR
    525                             GrAssert(!IsFillInverted(fill));
    526                             pr->drawPath(this, 0, *clipPath, fill, NULL);
    527                         }
    528                     } else {
    529                         SET_RANDOM_COLOR
    530                         this->drawSimpleRect(bounds, NULL, 0);
    531                     }
    532                 }
    533             }
    534             fClip = clip;
    535             // recusive draws would have disabled this.
    536             fClipState.fClipInStencil = true;
    537         }
    538 
    539         fClipState.fClipIsDirty = false;
    540     }
    541 
    542     // Must flush the scissor after graphics state
    543     if (!this->flushGraphicsState(type)) {
    544         return false;
    545     }
    546     this->flushScissor(r);
    547     return true;
    548 }
    549 
    550 GrPathRenderer* GrGpu::getClipPathRenderer(const GrPath& path,
    551                                            GrPathFill fill) {
    552     if (NULL != fClientPathRenderer &&
    553         fClientPathRenderer->canDrawPath(this, path, fill)) {
    554             return fClientPathRenderer;
    555     } else {
    556         if (NULL == fDefaultPathRenderer) {
    557             fDefaultPathRenderer =
    558                 new GrDefaultPathRenderer(this->supportsTwoSidedStencil(),
    559                                           this->supportsStencilWrapOps());
    560         }
    561         GrAssert(fDefaultPathRenderer->canDrawPath(this, path, fill));
    562         return fDefaultPathRenderer;
    563     }
    564 }
    565 
    566 
    567 ////////////////////////////////////////////////////////////////////////////////
    568 
    569 void GrGpu::drawIndexed(GrPrimitiveType type,
    570                         int startVertex,
    571                         int startIndex,
    572                         int vertexCount,
    573                         int indexCount) {
    574     GrAssert(kReserved_GeometrySrcType != fGeometrySrc.fVertexSrc ||
    575              fReservedGeometry.fLocked);
    576     GrAssert(kReserved_GeometrySrcType != fGeometrySrc.fIndexSrc ||
    577              fReservedGeometry.fLocked);
    578 
    579     this->handleDirtyContext();
    580 
    581     if (!this->setupClipAndFlushState(type)) {
    582         return;
    583     }
    584 
    585 #if GR_COLLECT_STATS
    586     fStats.fVertexCnt += vertexCount;
    587     fStats.fIndexCnt  += indexCount;
    588     fStats.fDrawCnt   += 1;
    589 #endif
    590 
    591     int sVertex = startVertex;
    592     int sIndex = startIndex;
    593     setupGeometry(&sVertex, &sIndex, vertexCount, indexCount);
    594 
    595     this->onDrawIndexed(type, sVertex, sIndex,
    596                         vertexCount, indexCount);
    597 }
    598 
    599 void GrGpu::drawNonIndexed(GrPrimitiveType type,
    600                            int startVertex,
    601                            int vertexCount) {
    602     GrAssert(kReserved_GeometrySrcType != fGeometrySrc.fVertexSrc ||
    603              fReservedGeometry.fLocked);
    604 
    605     this->handleDirtyContext();
    606 
    607     if (!this->setupClipAndFlushState(type)) {
    608         return;
    609     }
    610 #if GR_COLLECT_STATS
    611     fStats.fVertexCnt += vertexCount;
    612     fStats.fDrawCnt   += 1;
    613 #endif
    614 
    615     int sVertex = startVertex;
    616     setupGeometry(&sVertex, NULL, vertexCount, 0);
    617 
    618     this->onDrawNonIndexed(type, sVertex, vertexCount);
    619 }
    620 
    621 void GrGpu::finalizeReservedVertices() {
    622     GrAssert(NULL != fVertexPool);
    623     fVertexPool->unlock();
    624 }
    625 
    626 void GrGpu::finalizeReservedIndices() {
    627     GrAssert(NULL != fIndexPool);
    628     fIndexPool->unlock();
    629 }
    630 
    631 void GrGpu::prepareVertexPool() {
    632     if (NULL == fVertexPool) {
    633         fVertexPool = new GrVertexBufferAllocPool(this, true,
    634                                                   VERTEX_POOL_VB_SIZE,
    635                                                   VERTEX_POOL_VB_COUNT);
    636         fVertexPool->releaseGpuRef();
    637     } else if (!fVertexPoolInUse) {
    638         // the client doesn't have valid data in the pool
    639         fVertexPool->reset();
    640     }
    641 }
    642 
    643 void GrGpu::prepareIndexPool() {
    644     if (NULL == fIndexPool) {
    645         fIndexPool = new GrIndexBufferAllocPool(this, true, 0, 1);
    646         fIndexPool->releaseGpuRef();
    647     } else if (!fIndexPoolInUse) {
    648         // the client doesn't have valid data in the pool
    649         fIndexPool->reset();
    650     }
    651 }
    652 
    653 bool GrGpu::onAcquireGeometry(GrVertexLayout vertexLayout,
    654                               void**         vertices,
    655                               void**         indices) {
    656     GrAssert(!fReservedGeometry.fLocked);
    657     size_t reservedVertexSpace = 0;
    658 
    659     if (fReservedGeometry.fVertexCount) {
    660         GrAssert(NULL != vertices);
    661 
    662         this->prepareVertexPool();
    663 
    664         *vertices = fVertexPool->makeSpace(vertexLayout,
    665                                            fReservedGeometry.fVertexCount,
    666                                            &fCurrPoolVertexBuffer,
    667                                            &fCurrPoolStartVertex);
    668         if (NULL == *vertices) {
    669             return false;
    670         }
    671         reservedVertexSpace = VertexSize(vertexLayout) *
    672                               fReservedGeometry.fVertexCount;
    673     }
    674     if (fReservedGeometry.fIndexCount) {
    675         GrAssert(NULL != indices);
    676 
    677         this->prepareIndexPool();
    678 
    679         *indices = fIndexPool->makeSpace(fReservedGeometry.fIndexCount,
    680                                          &fCurrPoolIndexBuffer,
    681                                          &fCurrPoolStartIndex);
    682         if (NULL == *indices) {
    683             fVertexPool->putBack(reservedVertexSpace);
    684             fCurrPoolVertexBuffer = NULL;
    685             return false;
    686         }
    687     }
    688     return true;
    689 }
    690 
    691 void GrGpu::onReleaseGeometry() {}
    692 
    693 void GrGpu::onSetVertexSourceToArray(const void* vertexArray, int vertexCount) {
    694     GrAssert(!fReservedGeometry.fLocked || !fReservedGeometry.fVertexCount);
    695     this->prepareVertexPool();
    696 #if GR_DEBUG
    697     bool success =
    698 #endif
    699     fVertexPool->appendVertices(fGeometrySrc.fVertexLayout,
    700                                 vertexCount,
    701                                 vertexArray,
    702                                 &fCurrPoolVertexBuffer,
    703                                 &fCurrPoolStartVertex);
    704     GR_DEBUGASSERT(success);
    705 }
    706 
    707 void GrGpu::onSetIndexSourceToArray(const void* indexArray, int indexCount) {
    708     GrAssert(!fReservedGeometry.fLocked || !fReservedGeometry.fIndexCount);
    709     this->prepareIndexPool();
    710 #if GR_DEBUG
    711     bool success =
    712 #endif
    713     fIndexPool->appendIndices(indexCount,
    714                               indexArray,
    715                               &fCurrPoolIndexBuffer,
    716                               &fCurrPoolStartIndex);
    717     GR_DEBUGASSERT(success);
    718 }
    719 
    720 ////////////////////////////////////////////////////////////////////////////////
    721 
    722 const GrGpuStats& GrGpu::getStats() const {
    723     return fStats;
    724 }
    725 
    726 void GrGpu::resetStats() {
    727     memset(&fStats, 0, sizeof(fStats));
    728 }
    729 
    730 void GrGpu::printStats() const {
    731     if (GR_COLLECT_STATS) {
    732      GrPrintf(
    733      "-v-------------------------GPU STATS----------------------------v-\n"
    734      "Stats collection is: %s\n"
    735      "Draws: %04d, Verts: %04d, Indices: %04d\n"
    736      "ProgChanges: %04d, TexChanges: %04d, RTChanges: %04d\n"
    737      "TexCreates: %04d, RTCreates:%04d\n"
    738      "-^--------------------------------------------------------------^-\n",
    739      (GR_COLLECT_STATS ? "ON" : "OFF"),
    740     fStats.fDrawCnt, fStats.fVertexCnt, fStats.fIndexCnt,
    741     fStats.fProgChngCnt, fStats.fTextureChngCnt, fStats.fRenderTargetChngCnt,
    742     fStats.fTextureCreateCnt, fStats.fRenderTargetCreateCnt);
    743     }
    744 }
    745 
    746 ////////////////////////////////////////////////////////////////////////////////
    747 const GrSamplerState GrSamplerState::gClampNoFilter(
    748     GrSamplerState::kClamp_WrapMode,
    749     GrSamplerState::kClamp_WrapMode,
    750     GrSamplerState::kNormal_SampleMode,
    751     GrMatrix::I(),
    752     GrSamplerState::kNearest_Filter);
    753 
    754 
    755 
    756 
    757