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