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