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