3 * Copyright 2010 Google Inc.
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
12 #include "GrBufferAllocPool.h"
13 #include "GrContext.h"
14 #include "GrDrawTargetCaps.h"
15 #include "GrIndexBuffer.h"
16 #include "GrStencilBuffer.h"
17 #include "GrVertexBuffer.h"
19 // probably makes no sense for this to be less than a page
20 static const size_t VERTEX_POOL_VB_SIZE = 1 << 18;
21 static const int VERTEX_POOL_VB_COUNT = 4;
22 static const size_t INDEX_POOL_IB_SIZE = 1 << 16;
23 static const int INDEX_POOL_IB_COUNT = 4;
25 ////////////////////////////////////////////////////////////////////////////////
27 #define DEBUG_INVAL_BUFFER 0xdeadcafe
28 #define DEBUG_INVAL_START_IDX -1
30 GrGpu::GrGpu(GrContext* context)
31 : GrDrawTarget(context)
32 , fResetTimestamp(kExpiredTimestamp+1)
33 , fResetBits(kAll_GrBackendState)
36 , fVertexPoolUseCnt(0)
38 , fQuadIndexBuffer(NULL) {
40 fClipMaskManager.setGpu(this);
42 fGeomPoolStateStack.push_back();
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;
53 this->releaseResources();
56 void GrGpu::abandonResources() {
58 fClipMaskManager.releaseResources();
60 while (NULL != fResourceList.head()) {
61 fResourceList.head()->abandon();
64 SkASSERT(NULL == fQuadIndexBuffer || !fQuadIndexBuffer->isValid());
65 SkSafeSetNull(fQuadIndexBuffer);
72 void GrGpu::releaseResources() {
74 fClipMaskManager.releaseResources();
76 while (NULL != fResourceList.head()) {
77 fResourceList.head()->release();
80 SkASSERT(NULL == fQuadIndexBuffer || !fQuadIndexBuffer->isValid());
81 SkSafeSetNull(fQuadIndexBuffer);
88 void GrGpu::insertResource(GrResource* resource) {
89 SkASSERT(NULL != resource);
90 SkASSERT(this == resource->getGpu());
92 fResourceList.addToHead(resource);
95 void GrGpu::removeResource(GrResource* resource) {
96 SkASSERT(NULL != resource);
97 SkASSERT(this == resource->getGpu());
99 fResourceList.remove(resource);
103 void GrGpu::unimpl(const char msg[]) {
105 GrPrintf("--- GrGpu unimplemented(\"%s\")\n", msg);
109 ////////////////////////////////////////////////////////////////////////////////
111 GrTexture* GrGpu::createTexture(const GrTextureDesc& desc,
112 const void* srcData, size_t rowBytes) {
113 if (kUnknown_GrPixelConfig == desc.fConfig) {
116 if ((desc.fFlags & kRenderTarget_GrTextureFlagBit) &&
117 !this->caps()->isConfigRenderable(desc.fConfig, desc.fSampleCnt > 0)) {
121 this->handleDirtyContext();
122 GrTexture* tex = this->onCreateTexture(desc, srcData, rowBytes);
124 (kRenderTarget_GrTextureFlagBit & desc.fFlags) &&
125 !(kNoStencil_GrTextureFlagBit & desc.fFlags)) {
126 SkASSERT(NULL != tex->asRenderTarget());
127 // TODO: defer this and attach dynamically
128 if (!this->attachStencilBufferToRenderTarget(tex->asRenderTarget())) {
136 bool GrGpu::attachStencilBufferToRenderTarget(GrRenderTarget* rt) {
137 SkASSERT(NULL == rt->getStencilBuffer());
138 GrStencilBuffer* sb =
139 this->getContext()->findStencilBuffer(rt->width(),
143 rt->setStencilBuffer(sb);
144 bool attached = this->attachStencilBufferToRenderTarget(sb, rt);
146 rt->setStencilBuffer(NULL);
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
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
160 GrDrawState::AutoRenderTargetRestore artr(this->drawState(), rt);
161 this->clearStencil();
168 GrTexture* GrGpu::wrapBackendTexture(const GrBackendTextureDesc& desc) {
169 this->handleDirtyContext();
170 GrTexture* tex = this->onWrapBackendTexture(desc);
174 // TODO: defer this and attach dynamically
175 GrRenderTarget* tgt = tex->asRenderTarget();
177 !this->attachStencilBufferToRenderTarget(tgt)) {
185 GrRenderTarget* GrGpu::wrapBackendRenderTarget(const GrBackendRenderTargetDesc& desc) {
186 this->handleDirtyContext();
187 return this->onWrapBackendRenderTarget(desc);
190 GrVertexBuffer* GrGpu::createVertexBuffer(size_t size, bool dynamic) {
191 this->handleDirtyContext();
192 return this->onCreateVertexBuffer(size, dynamic);
195 GrIndexBuffer* GrGpu::createIndexBuffer(size_t size, bool dynamic) {
196 this->handleDirtyContext();
197 return this->onCreateIndexBuffer(size, dynamic);
200 GrPath* GrGpu::createPath(const SkPath& path, const SkStrokeRec& stroke) {
201 SkASSERT(this->caps()->pathRenderingSupport());
202 this->handleDirtyContext();
203 return this->onCreatePath(path, stroke);
206 void GrGpu::clear(const SkIRect* rect,
209 GrRenderTarget* renderTarget) {
210 GrDrawState::AutoRenderTargetRestore art;
211 if (NULL != renderTarget) {
212 art.set(this->drawState(), renderTarget);
214 if (NULL == this->getDrawState().getRenderTarget()) {
218 this->handleDirtyContext();
219 this->onClear(rect, color, canIgnoreRect);
222 void GrGpu::forceRenderTargetFlush() {
223 this->handleDirtyContext();
224 this->onForceRenderTargetFlush();
227 bool GrGpu::readPixels(GrRenderTarget* target,
228 int left, int top, int width, int height,
229 GrPixelConfig config, void* buffer,
231 this->handleDirtyContext();
232 return this->onReadPixels(target, left, top, width, height,
233 config, buffer, rowBytes);
236 bool GrGpu::writeTexturePixels(GrTexture* texture,
237 int left, int top, int width, int height,
238 GrPixelConfig config, const void* buffer,
240 this->handleDirtyContext();
241 return this->onWriteTexturePixels(texture, left, top, width, height,
242 config, buffer, rowBytes);
245 void GrGpu::resolveRenderTarget(GrRenderTarget* target) {
247 this->handleDirtyContext();
248 this->onResolveRenderTarget(target);
251 static const GrStencilSettings& winding_path_stencil_settings() {
252 GR_STATIC_CONST_SAME_STENCIL_STRUCT(gSettings,
255 kAlwaysIfInClip_StencilFunc,
256 0xFFFF, 0xFFFF, 0xFFFF);
257 return *GR_CONST_STENCIL_SETTINGS_PTR_FROM_STRUCT_PTR(&gSettings);
260 static const GrStencilSettings& even_odd_path_stencil_settings() {
261 GR_STATIC_CONST_SAME_STENCIL_STRUCT(gSettings,
264 kAlwaysIfInClip_StencilFunc,
265 0xFFFF, 0xFFFF, 0xFFFF);
266 return *GR_CONST_STENCIL_SETTINGS_PTR_FROM_STRUCT_PTR(&gSettings);
269 void GrGpu::getPathStencilSettingsForFillType(SkPath::FillType fill, GrStencilSettings* outStencilSettings) {
273 GrCrash("Unexpected path fill.");
275 case SkPath::kWinding_FillType:
276 case SkPath::kInverseWinding_FillType:
277 *outStencilSettings = winding_path_stencil_settings();
279 case SkPath::kEvenOdd_FillType:
280 case SkPath::kInverseEvenOdd_FillType:
281 *outStencilSettings = even_odd_path_stencil_settings();
284 fClipMaskManager.adjustPathStencilParams(outStencilSettings);
288 ////////////////////////////////////////////////////////////////////////////////
290 static const int MAX_QUADS = 1 << 12; // max possible: (1 << 14) - 1;
292 GR_STATIC_ASSERT(4 * MAX_QUADS <= 65535);
294 static inline void fill_indices(uint16_t* indices, int quadCount) {
295 for (int i = 0; i < quadCount; ++i) {
296 indices[6 * i + 0] = 4 * i + 0;
297 indices[6 * i + 1] = 4 * i + 1;
298 indices[6 * i + 2] = 4 * i + 2;
299 indices[6 * i + 3] = 4 * i + 0;
300 indices[6 * i + 4] = 4 * i + 2;
301 indices[6 * i + 5] = 4 * i + 3;
305 const GrIndexBuffer* GrGpu::getQuadIndexBuffer() const {
306 if (NULL == fQuadIndexBuffer) {
307 static const int SIZE = sizeof(uint16_t) * 6 * MAX_QUADS;
308 GrGpu* me = const_cast<GrGpu*>(this);
309 fQuadIndexBuffer = me->createIndexBuffer(SIZE, false);
310 if (NULL != fQuadIndexBuffer) {
311 uint16_t* indices = (uint16_t*)fQuadIndexBuffer->lock();
312 if (NULL != indices) {
313 fill_indices(indices, MAX_QUADS);
314 fQuadIndexBuffer->unlock();
316 indices = (uint16_t*)sk_malloc_throw(SIZE);
317 fill_indices(indices, MAX_QUADS);
318 if (!fQuadIndexBuffer->updateData(indices, SIZE)) {
319 fQuadIndexBuffer->unref();
320 fQuadIndexBuffer = NULL;
321 GrCrash("Can't get indices into buffer!");
328 return fQuadIndexBuffer;
331 ////////////////////////////////////////////////////////////////////////////////
333 bool GrGpu::setupClipAndFlushState(DrawType type, const GrDeviceCoordTexture* dstCopy,
334 GrDrawState::AutoRestoreEffects* are,
335 const SkRect* devBounds) {
336 if (!fClipMaskManager.setupClipping(this->getClip(), are, devBounds)) {
340 if (!this->flushGraphicsState(type, dstCopy)) {
347 ////////////////////////////////////////////////////////////////////////////////
349 void GrGpu::geometrySourceWillPush() {
350 const GeometrySrcState& geoSrc = this->getGeomSrc();
351 if (kArray_GeometrySrcType == geoSrc.fVertexSrc ||
352 kReserved_GeometrySrcType == geoSrc.fVertexSrc) {
353 this->finalizeReservedVertices();
355 if (kArray_GeometrySrcType == geoSrc.fIndexSrc ||
356 kReserved_GeometrySrcType == geoSrc.fIndexSrc) {
357 this->finalizeReservedIndices();
359 GeometryPoolState& newState = fGeomPoolStateStack.push_back();
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;
366 (void) newState; // silence compiler warning
370 void GrGpu::geometrySourceWillPop(const GeometrySrcState& restoredState) {
371 // if popping last entry then pops are unbalanced with pushes
372 SkASSERT(fGeomPoolStateStack.count() > 1);
373 fGeomPoolStateStack.pop_back();
376 void GrGpu::onDraw(const DrawInfo& info) {
377 this->handleDirtyContext();
378 GrDrawState::AutoRestoreEffects are;
379 if (!this->setupClipAndFlushState(PrimTypeToDrawType(info.primitiveType()),
380 info.getDstCopy(), &are, info.getDevBounds())) {
383 this->onGpuDraw(info);
386 void GrGpu::onStencilPath(const GrPath* path, SkPath::FillType fill) {
387 this->handleDirtyContext();
389 GrDrawState::AutoRestoreEffects are;
390 if (!this->setupClipAndFlushState(kStencilPath_DrawType, NULL, &are, NULL)) {
394 this->onGpuStencilPath(path, fill);
398 void GrGpu::onDrawPath(const GrPath* path, SkPath::FillType fill,
399 const GrDeviceCoordTexture* dstCopy) {
400 this->handleDirtyContext();
402 drawState()->setDefaultVertexAttribs();
404 GrDrawState::AutoRestoreEffects are;
405 if (!this->setupClipAndFlushState(kDrawPath_DrawType, dstCopy, &are, NULL)) {
409 this->onGpuDrawPath(path, fill);
412 void GrGpu::finalizeReservedVertices() {
413 SkASSERT(NULL != fVertexPool);
414 fVertexPool->unlock();
417 void GrGpu::finalizeReservedIndices() {
418 SkASSERT(NULL != fIndexPool);
419 fIndexPool->unlock();
422 void GrGpu::prepareVertexPool() {
423 if (NULL == fVertexPool) {
424 SkASSERT(0 == fVertexPoolUseCnt);
425 fVertexPool = SkNEW_ARGS(GrVertexBufferAllocPool, (this, true,
427 VERTEX_POOL_VB_COUNT));
428 fVertexPool->releaseGpuRef();
429 } else if (!fVertexPoolUseCnt) {
430 // the client doesn't have valid data in the pool
431 fVertexPool->reset();
435 void GrGpu::prepareIndexPool() {
436 if (NULL == fIndexPool) {
437 SkASSERT(0 == fIndexPoolUseCnt);
438 fIndexPool = SkNEW_ARGS(GrIndexBufferAllocPool, (this, true,
440 INDEX_POOL_IB_COUNT));
441 fIndexPool->releaseGpuRef();
442 } else if (!fIndexPoolUseCnt) {
443 // the client doesn't have valid data in the pool
448 bool GrGpu::onReserveVertexSpace(size_t vertexSize,
451 GeometryPoolState& geomPoolState = fGeomPoolStateStack.back();
453 SkASSERT(vertexCount > 0);
454 SkASSERT(NULL != vertices);
456 this->prepareVertexPool();
458 *vertices = fVertexPool->makeSpace(vertexSize,
460 &geomPoolState.fPoolVertexBuffer,
461 &geomPoolState.fPoolStartVertex);
462 if (NULL == *vertices) {
469 bool GrGpu::onReserveIndexSpace(int indexCount, void** indices) {
470 GeometryPoolState& geomPoolState = fGeomPoolStateStack.back();
472 SkASSERT(indexCount > 0);
473 SkASSERT(NULL != indices);
475 this->prepareIndexPool();
477 *indices = fIndexPool->makeSpace(indexCount,
478 &geomPoolState.fPoolIndexBuffer,
479 &geomPoolState.fPoolStartIndex);
480 if (NULL == *indices) {
487 void GrGpu::releaseReservedVertexSpace() {
488 const GeometrySrcState& geoSrc = this->getGeomSrc();
489 SkASSERT(kReserved_GeometrySrcType == geoSrc.fVertexSrc);
490 size_t bytes = geoSrc.fVertexCount * geoSrc.fVertexSize;
491 fVertexPool->putBack(bytes);
495 void GrGpu::releaseReservedIndexSpace() {
496 const GeometrySrcState& geoSrc = this->getGeomSrc();
497 SkASSERT(kReserved_GeometrySrcType == geoSrc.fIndexSrc);
498 size_t bytes = geoSrc.fIndexCount * sizeof(uint16_t);
499 fIndexPool->putBack(bytes);
503 void GrGpu::onSetVertexSourceToArray(const void* vertexArray, int vertexCount) {
504 this->prepareVertexPool();
505 GeometryPoolState& geomPoolState = fGeomPoolStateStack.back();
509 fVertexPool->appendVertices(this->getVertexSize(),
512 &geomPoolState.fPoolVertexBuffer,
513 &geomPoolState.fPoolStartVertex);
515 GR_DEBUGASSERT(success);
518 void GrGpu::onSetIndexSourceToArray(const void* indexArray, int indexCount) {
519 this->prepareIndexPool();
520 GeometryPoolState& geomPoolState = fGeomPoolStateStack.back();
524 fIndexPool->appendIndices(indexCount,
526 &geomPoolState.fPoolIndexBuffer,
527 &geomPoolState.fPoolStartIndex);
529 GR_DEBUGASSERT(success);
532 void GrGpu::releaseVertexArray() {
533 // if vertex source was array, we stowed data in the pool
534 const GeometrySrcState& geoSrc = this->getGeomSrc();
535 SkASSERT(kArray_GeometrySrcType == geoSrc.fVertexSrc);
536 size_t bytes = geoSrc.fVertexCount * geoSrc.fVertexSize;
537 fVertexPool->putBack(bytes);
541 void GrGpu::releaseIndexArray() {
542 // if index source was array, we stowed data in the pool
543 const GeometrySrcState& geoSrc = this->getGeomSrc();
544 SkASSERT(kArray_GeometrySrcType == geoSrc.fIndexSrc);
545 size_t bytes = geoSrc.fIndexCount * sizeof(uint16_t);
546 fIndexPool->putBack(bytes);