GrGpu.cpp revision a2d71482db8b6d752a51c96da74768d7dfc27932
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 "GrContext.h" 14#include "GrIndexBuffer.h" 15#include "GrStencilBuffer.h" 16#include "GrVertexBuffer.h" 17 18// probably makes no sense for this to be less than a page 19static const size_t VERTEX_POOL_VB_SIZE = 1 << 18; 20static const int VERTEX_POOL_VB_COUNT = 4; 21static const size_t INDEX_POOL_IB_SIZE = 1 << 16; 22static const int INDEX_POOL_IB_COUNT = 4; 23 24//////////////////////////////////////////////////////////////////////////////// 25 26extern void gr_run_unittests(); 27 28#define DEBUG_INVAL_BUFFER 0xdeadcafe 29#define DEBUG_INVAL_START_IDX -1 30 31GrGpu::GrGpu() 32 : fClipMaskManager(this) 33 , fContext(NULL) 34 , fResetTimestamp(kExpiredTimestamp+1) 35 , fVertexPool(NULL) 36 , fIndexPool(NULL) 37 , fVertexPoolUseCnt(0) 38 , fIndexPoolUseCnt(0) 39 , fQuadIndexBuffer(NULL) 40 , fUnitSquareVertexBuffer(NULL) 41 , fContextIsDirty(true) 42 , fResourceHead(NULL) { 43 44#if GR_DEBUG 45 //gr_run_unittests(); 46#endif 47 48 fGeomPoolStateStack.push_back(); 49#if GR_DEBUG 50 GeometryPoolState& poolState = fGeomPoolStateStack.back(); 51 poolState.fPoolVertexBuffer = (GrVertexBuffer*)DEBUG_INVAL_BUFFER; 52 poolState.fPoolStartVertex = DEBUG_INVAL_START_IDX; 53 poolState.fPoolIndexBuffer = (GrIndexBuffer*)DEBUG_INVAL_BUFFER; 54 poolState.fPoolStartIndex = DEBUG_INVAL_START_IDX; 55#endif 56 57 for (int i = 0; i < kGrPixelConfigCount; ++i) { 58 fConfigRenderSupport[i] = false; 59 }; 60} 61 62GrGpu::~GrGpu() { 63 this->releaseResources(); 64} 65 66void GrGpu::abandonResources() { 67 68 fClipMaskManager.releaseResources(); 69 70 while (NULL != fResourceHead) { 71 fResourceHead->abandon(); 72 } 73 74 GrAssert(NULL == fQuadIndexBuffer || !fQuadIndexBuffer->isValid()); 75 GrAssert(NULL == fUnitSquareVertexBuffer || 76 !fUnitSquareVertexBuffer->isValid()); 77 GrSafeSetNull(fQuadIndexBuffer); 78 GrSafeSetNull(fUnitSquareVertexBuffer); 79 delete fVertexPool; 80 fVertexPool = NULL; 81 delete fIndexPool; 82 fIndexPool = NULL; 83} 84 85void GrGpu::releaseResources() { 86 87 fClipMaskManager.releaseResources(); 88 89 while (NULL != fResourceHead) { 90 fResourceHead->release(); 91 } 92 93 GrAssert(NULL == fQuadIndexBuffer || !fQuadIndexBuffer->isValid()); 94 GrAssert(NULL == fUnitSquareVertexBuffer || 95 !fUnitSquareVertexBuffer->isValid()); 96 GrSafeSetNull(fQuadIndexBuffer); 97 GrSafeSetNull(fUnitSquareVertexBuffer); 98 delete fVertexPool; 99 fVertexPool = NULL; 100 delete fIndexPool; 101 fIndexPool = NULL; 102} 103 104void GrGpu::insertResource(GrResource* resource) { 105 GrAssert(NULL != resource); 106 GrAssert(this == resource->getGpu()); 107 GrAssert(NULL == resource->fNext); 108 GrAssert(NULL == resource->fPrevious); 109 110 resource->fNext = fResourceHead; 111 if (NULL != fResourceHead) { 112 GrAssert(NULL == fResourceHead->fPrevious); 113 fResourceHead->fPrevious = resource; 114 } 115 fResourceHead = resource; 116} 117 118void GrGpu::removeResource(GrResource* resource) { 119 GrAssert(NULL != resource); 120 GrAssert(NULL != fResourceHead); 121 122 if (fResourceHead == resource) { 123 GrAssert(NULL == resource->fPrevious); 124 fResourceHead = resource->fNext; 125 } else { 126 GrAssert(NULL != fResourceHead); 127 resource->fPrevious->fNext = resource->fNext; 128 } 129 if (NULL != resource->fNext) { 130 resource->fNext->fPrevious = resource->fPrevious; 131 } 132 resource->fNext = NULL; 133 resource->fPrevious = NULL; 134} 135 136 137void GrGpu::unimpl(const char msg[]) { 138#if GR_DEBUG 139 GrPrintf("--- GrGpu unimplemented(\"%s\")\n", msg); 140#endif 141} 142 143//////////////////////////////////////////////////////////////////////////////// 144 145GrTexture* GrGpu::createTexture(const GrTextureDesc& desc, 146 const void* srcData, size_t rowBytes) { 147 this->handleDirtyContext(); 148 GrTexture* tex = this->onCreateTexture(desc, srcData, rowBytes); 149 if (NULL != tex && 150 (kRenderTarget_GrTextureFlagBit & desc.fFlags) && 151 !(kNoStencil_GrTextureFlagBit & desc.fFlags)) { 152 GrAssert(NULL != tex->asRenderTarget()); 153 // TODO: defer this and attach dynamically 154 if (!this->attachStencilBufferToRenderTarget(tex->asRenderTarget())) { 155 tex->unref(); 156 return NULL; 157 } 158 } 159 return tex; 160} 161 162bool GrGpu::attachStencilBufferToRenderTarget(GrRenderTarget* rt) { 163 GrAssert(NULL == rt->getStencilBuffer()); 164 GrStencilBuffer* sb = 165 this->getContext()->findStencilBuffer(rt->width(), 166 rt->height(), 167 rt->numSamples()); 168 if (NULL != sb) { 169 rt->setStencilBuffer(sb); 170 bool attached = this->attachStencilBufferToRenderTarget(sb, rt); 171 if (!attached) { 172 rt->setStencilBuffer(NULL); 173 } 174 return attached; 175 } 176 if (this->createStencilBufferForRenderTarget(rt, 177 rt->width(), rt->height())) { 178 rt->getStencilBuffer()->ref(); 179 rt->getStencilBuffer()->transferToCacheAndLock(); 180 181 // Right now we're clearing the stencil buffer here after it is 182 // attached to an RT for the first time. When we start matching 183 // stencil buffers with smaller color targets this will no longer 184 // be correct because it won't be guaranteed to clear the entire 185 // sb. 186 // We used to clear down in the GL subclass using a special purpose 187 // FBO. But iOS doesn't allow a stencil-only FBO. It reports unsupported 188 // FBO status. 189 GrDrawState::AutoRenderTargetRestore artr(this->drawState(), rt); 190 this->clearStencil(); 191 return true; 192 } else { 193 return false; 194 } 195} 196 197GrTexture* GrGpu::createPlatformTexture(const GrPlatformTextureDesc& desc) { 198 this->handleDirtyContext(); 199 GrTexture* tex = this->onCreatePlatformTexture(desc); 200 if (NULL == tex) { 201 return NULL; 202 } 203 // TODO: defer this and attach dynamically 204 GrRenderTarget* tgt = tex->asRenderTarget(); 205 if (NULL != tgt && 206 !this->attachStencilBufferToRenderTarget(tgt)) { 207 tex->unref(); 208 return NULL; 209 } else { 210 return tex; 211 } 212} 213 214GrRenderTarget* GrGpu::createPlatformRenderTarget(const GrPlatformRenderTargetDesc& desc) { 215 this->handleDirtyContext(); 216 return this->onCreatePlatformRenderTarget(desc); 217} 218 219GrVertexBuffer* GrGpu::createVertexBuffer(uint32_t size, bool dynamic) { 220 this->handleDirtyContext(); 221 return this->onCreateVertexBuffer(size, dynamic); 222} 223 224GrIndexBuffer* GrGpu::createIndexBuffer(uint32_t size, bool dynamic) { 225 this->handleDirtyContext(); 226 return this->onCreateIndexBuffer(size, dynamic); 227} 228 229GrPath* GrGpu::createPath(const SkPath& path) { 230 GrAssert(fCaps.fPathStencilingSupport); 231 this->handleDirtyContext(); 232 return this->onCreatePath(path); 233} 234 235void GrGpu::clear(const GrIRect* rect, 236 GrColor color, 237 GrRenderTarget* renderTarget) { 238 GrRenderTarget* oldRT = NULL; 239 if (NULL != renderTarget && 240 renderTarget != this->drawState()->getRenderTarget()) { 241 oldRT = this->drawState()->getRenderTarget(); 242 this->drawState()->setRenderTarget(renderTarget); 243 } 244 245 if (NULL == this->getDrawState().getRenderTarget()) { 246 return; 247 } 248 this->handleDirtyContext(); 249 this->onClear(rect, color); 250 251 if (NULL != oldRT) { 252 this->drawState()->setRenderTarget(oldRT); 253 } 254} 255 256void GrGpu::forceRenderTargetFlush() { 257 this->handleDirtyContext(); 258 this->onForceRenderTargetFlush(); 259} 260 261bool GrGpu::readPixels(GrRenderTarget* target, 262 int left, int top, int width, int height, 263 GrPixelConfig config, void* buffer, 264 size_t rowBytes, bool invertY) { 265 GrAssert(GrPixelConfigIsUnpremultiplied(config) == 266 GrPixelConfigIsUnpremultiplied(target->config())); 267 this->handleDirtyContext(); 268 return this->onReadPixels(target, left, top, width, height, 269 config, buffer, rowBytes, invertY); 270} 271 272void GrGpu::writeTexturePixels(GrTexture* texture, 273 int left, int top, int width, int height, 274 GrPixelConfig config, const void* buffer, 275 size_t rowBytes) { 276 GrAssert(GrPixelConfigIsUnpremultiplied(config) == 277 GrPixelConfigIsUnpremultiplied(texture->config())); 278 this->handleDirtyContext(); 279 this->onWriteTexturePixels(texture, left, top, width, height, 280 config, buffer, rowBytes); 281} 282 283void GrGpu::resolveRenderTarget(GrRenderTarget* target) { 284 GrAssert(target); 285 this->handleDirtyContext(); 286 this->onResolveRenderTarget(target); 287} 288 289 290//////////////////////////////////////////////////////////////////////////////// 291 292static const int MAX_QUADS = 1 << 12; // max possible: (1 << 14) - 1; 293 294GR_STATIC_ASSERT(4 * MAX_QUADS <= 65535); 295 296static inline void fill_indices(uint16_t* indices, int quadCount) { 297 for (int i = 0; i < quadCount; ++i) { 298 indices[6 * i + 0] = 4 * i + 0; 299 indices[6 * i + 1] = 4 * i + 1; 300 indices[6 * i + 2] = 4 * i + 2; 301 indices[6 * i + 3] = 4 * i + 0; 302 indices[6 * i + 4] = 4 * i + 2; 303 indices[6 * i + 5] = 4 * i + 3; 304 } 305} 306 307const GrIndexBuffer* GrGpu::getQuadIndexBuffer() const { 308 if (NULL == fQuadIndexBuffer) { 309 static const int SIZE = sizeof(uint16_t) * 6 * MAX_QUADS; 310 GrGpu* me = const_cast<GrGpu*>(this); 311 fQuadIndexBuffer = me->createIndexBuffer(SIZE, false); 312 if (NULL != fQuadIndexBuffer) { 313 uint16_t* indices = (uint16_t*)fQuadIndexBuffer->lock(); 314 if (NULL != indices) { 315 fill_indices(indices, MAX_QUADS); 316 fQuadIndexBuffer->unlock(); 317 } else { 318 indices = (uint16_t*)GrMalloc(SIZE); 319 fill_indices(indices, MAX_QUADS); 320 if (!fQuadIndexBuffer->updateData(indices, SIZE)) { 321 fQuadIndexBuffer->unref(); 322 fQuadIndexBuffer = NULL; 323 GrCrash("Can't get indices into buffer!"); 324 } 325 GrFree(indices); 326 } 327 } 328 } 329 330 return fQuadIndexBuffer; 331} 332 333const GrVertexBuffer* GrGpu::getUnitSquareVertexBuffer() const { 334 if (NULL == fUnitSquareVertexBuffer) { 335 336 static const GrPoint DATA[] = { 337 { 0, 0 }, 338 { GR_Scalar1, 0 }, 339 { GR_Scalar1, GR_Scalar1 }, 340 { 0, GR_Scalar1 } 341#if 0 342 GrPoint(0, 0), 343 GrPoint(GR_Scalar1,0), 344 GrPoint(GR_Scalar1,GR_Scalar1), 345 GrPoint(0, GR_Scalar1) 346#endif 347 }; 348 static const size_t SIZE = sizeof(DATA); 349 350 GrGpu* me = const_cast<GrGpu*>(this); 351 fUnitSquareVertexBuffer = me->createVertexBuffer(SIZE, false); 352 if (NULL != fUnitSquareVertexBuffer) { 353 if (!fUnitSquareVertexBuffer->updateData(DATA, SIZE)) { 354 fUnitSquareVertexBuffer->unref(); 355 fUnitSquareVertexBuffer = NULL; 356 GrCrash("Can't get vertices into buffer!"); 357 } 358 } 359 } 360 361 return fUnitSquareVertexBuffer; 362} 363 364//////////////////////////////////////////////////////////////////////////////// 365 366bool GrGpu::setupClipAndFlushState(DrawType type) { 367 368 if (!fClipMaskManager.setupClipping(fClip)) { 369 return false; 370 } 371 372 if (!this->flushGraphicsState(type)) { 373 return false; 374 } 375 376 return true; 377} 378 379//////////////////////////////////////////////////////////////////////////////// 380 381void GrGpu::geometrySourceWillPush() { 382 const GeometrySrcState& geoSrc = this->getGeomSrc(); 383 if (kArray_GeometrySrcType == geoSrc.fVertexSrc || 384 kReserved_GeometrySrcType == geoSrc.fVertexSrc) { 385 this->finalizeReservedVertices(); 386 } 387 if (kArray_GeometrySrcType == geoSrc.fIndexSrc || 388 kReserved_GeometrySrcType == geoSrc.fIndexSrc) { 389 this->finalizeReservedIndices(); 390 } 391 GeometryPoolState& newState = fGeomPoolStateStack.push_back(); 392#if GR_DEBUG 393 newState.fPoolVertexBuffer = (GrVertexBuffer*)DEBUG_INVAL_BUFFER; 394 newState.fPoolStartVertex = DEBUG_INVAL_START_IDX; 395 newState.fPoolIndexBuffer = (GrIndexBuffer*)DEBUG_INVAL_BUFFER; 396 newState.fPoolStartIndex = DEBUG_INVAL_START_IDX; 397#endif 398} 399 400void GrGpu::geometrySourceWillPop(const GeometrySrcState& restoredState) { 401 // if popping last entry then pops are unbalanced with pushes 402 GrAssert(fGeomPoolStateStack.count() > 1); 403 fGeomPoolStateStack.pop_back(); 404} 405 406void GrGpu::onDrawIndexed(GrPrimitiveType type, 407 int startVertex, 408 int startIndex, 409 int vertexCount, 410 int indexCount) { 411 412 this->handleDirtyContext(); 413 414 if (!this->setupClipAndFlushState(PrimTypeToDrawType(type))) { 415 return; 416 } 417 418 int sVertex = startVertex; 419 int sIndex = startIndex; 420 setupGeometry(&sVertex, &sIndex, vertexCount, indexCount); 421 422 this->onGpuDrawIndexed(type, sVertex, sIndex, 423 vertexCount, indexCount); 424} 425 426void GrGpu::onDrawNonIndexed(GrPrimitiveType type, 427 int startVertex, 428 int vertexCount) { 429 this->handleDirtyContext(); 430 431 if (!this->setupClipAndFlushState(PrimTypeToDrawType(type))) { 432 return; 433 } 434 435 int sVertex = startVertex; 436 setupGeometry(&sVertex, NULL, vertexCount, 0); 437 438 this->onGpuDrawNonIndexed(type, sVertex, vertexCount); 439} 440 441void GrGpu::onStencilPath(const GrPath* path, GrPathFill fill) { 442 this->handleDirtyContext(); 443 444 // TODO: make this more effecient (don't copy and copy back) 445 GrAutoTRestore<GrStencilSettings> asr(this->drawState()->stencil()); 446 447 this->setStencilPathSettings(*path, fill, this->drawState()->stencil()); 448 if (!this->setupClipAndFlushState(kStencilPath_DrawType)) { 449 return; 450 } 451 452 this->onGpuStencilPath(path, fill); 453} 454 455void GrGpu::finalizeReservedVertices() { 456 GrAssert(NULL != fVertexPool); 457 fVertexPool->unlock(); 458} 459 460void GrGpu::finalizeReservedIndices() { 461 GrAssert(NULL != fIndexPool); 462 fIndexPool->unlock(); 463} 464 465void GrGpu::prepareVertexPool() { 466 if (NULL == fVertexPool) { 467 GrAssert(0 == fVertexPoolUseCnt); 468 fVertexPool = SkNEW_ARGS(GrVertexBufferAllocPool, (this, true, 469 VERTEX_POOL_VB_SIZE, 470 VERTEX_POOL_VB_COUNT)); 471 fVertexPool->releaseGpuRef(); 472 } else if (!fVertexPoolUseCnt) { 473 // the client doesn't have valid data in the pool 474 fVertexPool->reset(); 475 } 476} 477 478void GrGpu::prepareIndexPool() { 479 if (NULL == fIndexPool) { 480 GrAssert(0 == fIndexPoolUseCnt); 481 fIndexPool = SkNEW_ARGS(GrIndexBufferAllocPool, (this, true, 482 INDEX_POOL_IB_SIZE, 483 INDEX_POOL_IB_COUNT)); 484 fIndexPool->releaseGpuRef(); 485 } else if (!fIndexPoolUseCnt) { 486 // the client doesn't have valid data in the pool 487 fIndexPool->reset(); 488 } 489} 490 491bool GrGpu::onReserveVertexSpace(GrVertexLayout vertexLayout, 492 int vertexCount, 493 void** vertices) { 494 GeometryPoolState& geomPoolState = fGeomPoolStateStack.back(); 495 496 GrAssert(vertexCount > 0); 497 GrAssert(NULL != vertices); 498 499 this->prepareVertexPool(); 500 501 *vertices = fVertexPool->makeSpace(vertexLayout, 502 vertexCount, 503 &geomPoolState.fPoolVertexBuffer, 504 &geomPoolState.fPoolStartVertex); 505 if (NULL == *vertices) { 506 return false; 507 } 508 ++fVertexPoolUseCnt; 509 return true; 510} 511 512bool GrGpu::onReserveIndexSpace(int indexCount, void** indices) { 513 GeometryPoolState& geomPoolState = fGeomPoolStateStack.back(); 514 515 GrAssert(indexCount > 0); 516 GrAssert(NULL != indices); 517 518 this->prepareIndexPool(); 519 520 *indices = fIndexPool->makeSpace(indexCount, 521 &geomPoolState.fPoolIndexBuffer, 522 &geomPoolState.fPoolStartIndex); 523 if (NULL == *indices) { 524 return false; 525 } 526 ++fIndexPoolUseCnt; 527 return true; 528} 529 530void GrGpu::releaseReservedVertexSpace() { 531 const GeometrySrcState& geoSrc = this->getGeomSrc(); 532 GrAssert(kReserved_GeometrySrcType == geoSrc.fVertexSrc); 533 size_t bytes = geoSrc.fVertexCount * VertexSize(geoSrc.fVertexLayout); 534 fVertexPool->putBack(bytes); 535 --fVertexPoolUseCnt; 536} 537 538void GrGpu::releaseReservedIndexSpace() { 539 const GeometrySrcState& geoSrc = this->getGeomSrc(); 540 GrAssert(kReserved_GeometrySrcType == geoSrc.fIndexSrc); 541 size_t bytes = geoSrc.fIndexCount * sizeof(uint16_t); 542 fIndexPool->putBack(bytes); 543 --fIndexPoolUseCnt; 544} 545 546void GrGpu::onSetVertexSourceToArray(const void* vertexArray, int vertexCount) { 547 this->prepareVertexPool(); 548 GeometryPoolState& geomPoolState = fGeomPoolStateStack.back(); 549#if GR_DEBUG 550 bool success = 551#endif 552 fVertexPool->appendVertices(this->getVertexLayout(), 553 vertexCount, 554 vertexArray, 555 &geomPoolState.fPoolVertexBuffer, 556 &geomPoolState.fPoolStartVertex); 557 ++fVertexPoolUseCnt; 558 GR_DEBUGASSERT(success); 559} 560 561void GrGpu::onSetIndexSourceToArray(const void* indexArray, int indexCount) { 562 this->prepareIndexPool(); 563 GeometryPoolState& geomPoolState = fGeomPoolStateStack.back(); 564#if GR_DEBUG 565 bool success = 566#endif 567 fIndexPool->appendIndices(indexCount, 568 indexArray, 569 &geomPoolState.fPoolIndexBuffer, 570 &geomPoolState.fPoolStartIndex); 571 ++fIndexPoolUseCnt; 572 GR_DEBUGASSERT(success); 573} 574 575void GrGpu::releaseVertexArray() { 576 // if vertex source was array, we stowed data in the pool 577 const GeometrySrcState& geoSrc = this->getGeomSrc(); 578 GrAssert(kArray_GeometrySrcType == geoSrc.fVertexSrc); 579 size_t bytes = geoSrc.fVertexCount * VertexSize(geoSrc.fVertexLayout); 580 fVertexPool->putBack(bytes); 581 --fVertexPoolUseCnt; 582} 583 584void GrGpu::releaseIndexArray() { 585 // if index source was array, we stowed data in the pool 586 const GeometrySrcState& geoSrc = this->getGeomSrc(); 587 GrAssert(kArray_GeometrySrcType == geoSrc.fIndexSrc); 588 size_t bytes = geoSrc.fIndexCount * sizeof(uint16_t); 589 fIndexPool->putBack(bytes); 590 --fIndexPoolUseCnt; 591} 592 593