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