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