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 21static const size_t VERTEX_POOL_VB_SIZE = 1 << 18; 22static const int VERTEX_POOL_VB_COUNT = 4; 23static const size_t INDEX_POOL_IB_SIZE = 1 << 16; 24static const int INDEX_POOL_IB_COUNT = 4; 25 26//////////////////////////////////////////////////////////////////////////////// 27 28extern void gr_run_unittests(); 29 30#define DEBUG_INVAL_BUFFER 0xdeadcafe 31#define DEBUG_INVAL_START_IDX -1 32 33GrGpu::GrGpu() 34 : fContext(NULL) 35 , fResetTimestamp(kExpiredTimestamp+1) 36 , fVertexPool(NULL) 37 , fIndexPool(NULL) 38 , fVertexPoolUseCnt(0) 39 , fIndexPoolUseCnt(0) 40 , fQuadIndexBuffer(NULL) 41 , fUnitSquareVertexBuffer(NULL) 42 , fPathRendererChain(NULL) 43 , fContextIsDirty(true) 44 , fResourceHead(NULL) { 45 46#if GR_DEBUG 47 //gr_run_unittests(); 48#endif 49 50 fGeomPoolStateStack.push_back(); 51#if GR_DEBUG 52 GeometryPoolState& poolState = fGeomPoolStateStack.back(); 53 poolState.fPoolVertexBuffer = (GrVertexBuffer*)DEBUG_INVAL_BUFFER; 54 poolState.fPoolStartVertex = DEBUG_INVAL_START_IDX; 55 poolState.fPoolIndexBuffer = (GrIndexBuffer*)DEBUG_INVAL_BUFFER; 56 poolState.fPoolStartIndex = DEBUG_INVAL_START_IDX; 57#endif 58 resetStats(); 59} 60 61GrGpu::~GrGpu() { 62 this->releaseResources(); 63} 64 65void GrGpu::abandonResources() { 66 67 while (NULL != fResourceHead) { 68 fResourceHead->abandon(); 69 } 70 71 GrAssert(NULL == fQuadIndexBuffer || !fQuadIndexBuffer->isValid()); 72 GrAssert(NULL == fUnitSquareVertexBuffer || 73 !fUnitSquareVertexBuffer->isValid()); 74 GrSafeSetNull(fQuadIndexBuffer); 75 GrSafeSetNull(fUnitSquareVertexBuffer); 76 delete fVertexPool; 77 fVertexPool = NULL; 78 delete fIndexPool; 79 fIndexPool = NULL; 80 // in case path renderer has any GrResources, start from scratch 81 GrSafeSetNull(fPathRendererChain); 82} 83 84void GrGpu::releaseResources() { 85 86 while (NULL != fResourceHead) { 87 fResourceHead->release(); 88 } 89 90 GrAssert(NULL == fQuadIndexBuffer || !fQuadIndexBuffer->isValid()); 91 GrAssert(NULL == fUnitSquareVertexBuffer || 92 !fUnitSquareVertexBuffer->isValid()); 93 GrSafeSetNull(fQuadIndexBuffer); 94 GrSafeSetNull(fUnitSquareVertexBuffer); 95 delete fVertexPool; 96 fVertexPool = NULL; 97 delete fIndexPool; 98 fIndexPool = NULL; 99 // in case path renderer has any GrResources, start from scratch 100 GrSafeSetNull(fPathRendererChain); 101} 102 103void GrGpu::insertResource(GrResource* resource) { 104 GrAssert(NULL != resource); 105 GrAssert(this == resource->getGpu()); 106 GrAssert(NULL == resource->fNext); 107 GrAssert(NULL == resource->fPrevious); 108 109 resource->fNext = fResourceHead; 110 if (NULL != fResourceHead) { 111 GrAssert(NULL == fResourceHead->fPrevious); 112 fResourceHead->fPrevious = resource; 113 } 114 fResourceHead = resource; 115} 116 117void GrGpu::removeResource(GrResource* resource) { 118 GrAssert(NULL != resource); 119 GrAssert(NULL != fResourceHead); 120 121 if (fResourceHead == resource) { 122 GrAssert(NULL == resource->fPrevious); 123 fResourceHead = resource->fNext; 124 } else { 125 GrAssert(NULL != fResourceHead); 126 resource->fPrevious->fNext = resource->fNext; 127 } 128 if (NULL != resource->fNext) { 129 resource->fNext->fPrevious = resource->fPrevious; 130 } 131 resource->fNext = NULL; 132 resource->fPrevious = NULL; 133} 134 135 136void GrGpu::unimpl(const char msg[]) { 137#if GR_DEBUG 138 GrPrintf("--- GrGpu unimplemented(\"%s\")\n", msg); 139#endif 140} 141 142//////////////////////////////////////////////////////////////////////////////// 143 144GrTexture* GrGpu::createTexture(const GrTextureDesc& desc, 145 const void* srcData, size_t rowBytes) { 146 this->handleDirtyContext(); 147 GrTexture* tex = this->onCreateTexture(desc, srcData, rowBytes); 148 if (NULL != tex && 149 (kRenderTarget_GrTextureFlagBit & desc.fFlags) && 150 !(kNoStencil_GrTextureFlagBit & desc.fFlags)) { 151 GrAssert(NULL != tex->asRenderTarget()); 152 // TODO: defer this and attach dynamically 153 if (!this->attachStencilBufferToRenderTarget(tex->asRenderTarget())) { 154 tex->unref(); 155 return NULL; 156 } 157 } 158 return tex; 159} 160 161bool GrGpu::attachStencilBufferToRenderTarget(GrRenderTarget* rt) { 162 GrAssert(NULL == rt->getStencilBuffer()); 163 GrStencilBuffer* sb = 164 this->getContext()->findStencilBuffer(rt->width(), 165 rt->height(), 166 rt->numSamples()); 167 if (NULL != sb) { 168 rt->setStencilBuffer(sb); 169 bool attached = this->attachStencilBufferToRenderTarget(sb, rt); 170 if (!attached) { 171 rt->setStencilBuffer(NULL); 172 } 173 return attached; 174 } 175 if (this->createStencilBufferForRenderTarget(rt, 176 rt->width(), rt->height())) { 177 rt->getStencilBuffer()->ref(); 178 rt->getStencilBuffer()->transferToCacheAndLock(); 179 180 // Right now we're clearing the stencil buffer here after it is 181 // attached to an RT for the first time. When we start matching 182 // stencil buffers with smaller color targets this will no longer 183 // be correct because it won't be guaranteed to clear the entire 184 // sb. 185 // We used to clear down in the GL subclass using a special purpose 186 // FBO. But iOS doesn't allow a stencil-only FBO. It reports unsupported 187 // FBO status. 188 GrDrawState::AutoRenderTargetRestore artr(this->drawState(), rt); 189 this->clearStencil(); 190 return true; 191 } else { 192 return false; 193 } 194} 195 196GrTexture* GrGpu::createPlatformTexture(const GrPlatformTextureDesc& desc) { 197 this->handleDirtyContext(); 198 GrTexture* tex = this->onCreatePlatformTexture(desc); 199 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 213GrRenderTarget* GrGpu::createPlatformRenderTarget(const GrPlatformRenderTargetDesc& desc) { 214 this->handleDirtyContext(); 215 return this->onCreatePlatformRenderTarget(desc); 216} 217 218GrVertexBuffer* GrGpu::createVertexBuffer(uint32_t size, bool dynamic) { 219 this->handleDirtyContext(); 220 return this->onCreateVertexBuffer(size, dynamic); 221} 222 223GrIndexBuffer* GrGpu::createIndexBuffer(uint32_t size, bool dynamic) { 224 this->handleDirtyContext(); 225 return this->onCreateIndexBuffer(size, dynamic); 226} 227 228void 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 236void GrGpu::forceRenderTargetFlush() { 237 this->handleDirtyContext(); 238 this->onForceRenderTargetFlush(); 239} 240 241bool 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 252void 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 263void GrGpu::resolveRenderTarget(GrRenderTarget* target) { 264 GrAssert(target); 265 this->handleDirtyContext(); 266 this->onResolveRenderTarget(target); 267} 268 269 270//////////////////////////////////////////////////////////////////////////////// 271 272static const int MAX_QUADS = 1 << 12; // max possible: (1 << 14) - 1; 273 274GR_STATIC_ASSERT(4 * MAX_QUADS <= 65535); 275 276static 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 287const 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 313const 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 346const 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. 360static 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 393GrStencilFunc 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 403void 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 451namespace { 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. 455int 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 541bool 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 733GrPathRenderer* 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 746void 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 765void 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 771void 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 797void 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 816void GrGpu::finalizeReservedVertices() { 817 GrAssert(NULL != fVertexPool); 818 fVertexPool->unlock(); 819} 820 821void GrGpu::finalizeReservedIndices() { 822 GrAssert(NULL != fIndexPool); 823 fIndexPool->unlock(); 824} 825 826void 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 839void 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 852bool 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 873bool 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 891void 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 899void 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 907void 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 922void 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 936void 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 945void 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 956const GrGpuStats& GrGpu::getStats() const { 957 return fStats; 958} 959 960void GrGpu::resetStats() { 961 memset(&fStats, 0, sizeof(fStats)); 962} 963 964void 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