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