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