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