| /* |
| * Copyright 2014 Google Inc. |
| * |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. |
| */ |
| |
| #include "GrFlushToGpuDrawTarget.h" |
| #include "GrContext.h" |
| #include "GrFontCache.h" |
| #include "GrGpu.h" |
| #include "GrBufferAllocPool.h" |
| |
| GrFlushToGpuDrawTarget::GrFlushToGpuDrawTarget(GrGpu* gpu, |
| GrVertexBufferAllocPool* vertexPool, |
| GrIndexBufferAllocPool* indexPool) |
| : INHERITED(gpu->getContext()) |
| , fGpu(SkRef(gpu)) |
| , fVertexPool(vertexPool) |
| , fIndexPool(indexPool) |
| , fFlushing(false) { |
| |
| fCaps.reset(SkRef(fGpu->caps())); |
| |
| SkASSERT(vertexPool); |
| SkASSERT(indexPool); |
| |
| GeometryPoolState& poolState = fGeoPoolStateStack.push_back(); |
| poolState.fUsedPoolVertexBytes = 0; |
| poolState.fUsedPoolIndexBytes = 0; |
| #ifdef SK_DEBUG |
| poolState.fPoolVertexBuffer = (GrVertexBuffer*)~0; |
| poolState.fPoolStartVertex = ~0; |
| poolState.fPoolIndexBuffer = (GrIndexBuffer*)~0; |
| poolState.fPoolStartIndex = ~0; |
| #endif |
| } |
| |
| GrFlushToGpuDrawTarget::~GrFlushToGpuDrawTarget() { |
| // This must be called by before the GrDrawTarget destructor |
| this->releaseGeometry(); |
| } |
| |
| void GrFlushToGpuDrawTarget::setDrawBuffers(DrawInfo* info, size_t vertexStride) { |
| GeometryPoolState& poolState = fGeoPoolStateStack.back(); |
| if (kBuffer_GeometrySrcType == this->getGeomSrc().fVertexSrc) { |
| info->setVertexBuffer(this->getGeomSrc().fVertexBuffer); |
| } else { |
| // Update the bytes used since the last reserve-geom request. |
| size_t bytes = (info->vertexCount() + info->startVertex()) * vertexStride; |
| poolState.fUsedPoolVertexBytes = SkTMax(poolState.fUsedPoolVertexBytes, bytes); |
| info->setVertexBuffer(poolState.fPoolVertexBuffer); |
| info->adjustStartVertex(poolState.fPoolStartVertex); |
| } |
| |
| if (info->isIndexed()) { |
| if (kBuffer_GeometrySrcType == this->getGeomSrc().fIndexSrc) { |
| info->setIndexBuffer(this->getGeomSrc().fIndexBuffer); |
| } else { |
| // Update the bytes used since the last reserve-geom request. |
| size_t bytes = (info->indexCount() + info->startIndex()) * sizeof(uint16_t); |
| poolState.fUsedPoolIndexBytes = SkTMax(poolState.fUsedPoolIndexBytes, bytes); |
| info->setIndexBuffer(poolState.fPoolIndexBuffer); |
| info->adjustStartIndex(poolState.fPoolStartIndex); |
| } |
| } |
| } |
| |
| void GrFlushToGpuDrawTarget::reset() { |
| SkASSERT(1 == fGeoPoolStateStack.count()); |
| this->resetVertexSource(); |
| this->resetIndexSource(); |
| |
| fVertexPool->reset(); |
| fIndexPool->reset(); |
| |
| this->onReset(); |
| } |
| |
| void GrFlushToGpuDrawTarget::flush() { |
| SkASSERT(kReserved_GeometrySrcType != this->getGeomSrc().fVertexSrc); |
| SkASSERT(kReserved_GeometrySrcType != this->getGeomSrc().fIndexSrc); |
| |
| if (fFlushing) { |
| return; |
| } |
| fFlushing = true; |
| |
| fGpu->getContext()->getFontCache()->updateTextures(); |
| |
| fGpu->saveActiveTraceMarkers(); |
| |
| this->onFlush(); |
| |
| fGpu->restoreActiveTraceMarkers(); |
| |
| fFlushing = false; |
| this->reset(); |
| } |
| |
| void GrFlushToGpuDrawTarget::willReserveVertexAndIndexSpace(int vertexCount, |
| size_t vertexStride, |
| int indexCount) { |
| // We use geometryHints() to know whether to flush the draw buffer. We |
| // can't flush if we are inside an unbalanced pushGeometrySource. |
| // Moreover, flushing blows away vertex and index data that was |
| // previously reserved. So if the vertex or index data is pulled from |
| // reserved space and won't be released by this request then we can't |
| // flush. |
| bool insideGeoPush = fGeoPoolStateStack.count() > 1; |
| |
| bool unreleasedVertexSpace = |
| !vertexCount && |
| kReserved_GeometrySrcType == this->getGeomSrc().fVertexSrc; |
| |
| bool unreleasedIndexSpace = |
| !indexCount && |
| kReserved_GeometrySrcType == this->getGeomSrc().fIndexSrc; |
| |
| int vcount = vertexCount; |
| int icount = indexCount; |
| |
| if (!insideGeoPush && |
| !unreleasedVertexSpace && |
| !unreleasedIndexSpace && |
| this->geometryHints(vertexStride, &vcount, &icount)) { |
| this->flush(); |
| } |
| } |
| |
| bool GrFlushToGpuDrawTarget::geometryHints(size_t vertexStride, |
| int* vertexCount, |
| int* indexCount) const { |
| // we will recommend a flush if the data could fit in a single |
| // preallocated buffer but none are left and it can't fit |
| // in the current buffer (which may not be prealloced). |
| bool flush = false; |
| if (indexCount) { |
| int32_t currIndices = fIndexPool->currentBufferIndices(); |
| if (*indexCount > currIndices && |
| (!fIndexPool->preallocatedBuffersRemaining() && |
| *indexCount <= fIndexPool->preallocatedBufferIndices())) { |
| |
| flush = true; |
| } |
| *indexCount = currIndices; |
| } |
| if (vertexCount) { |
| int32_t currVertices = fVertexPool->currentBufferVertices(vertexStride); |
| if (*vertexCount > currVertices && |
| (!fVertexPool->preallocatedBuffersRemaining() && |
| *vertexCount <= fVertexPool->preallocatedBufferVertices(vertexStride))) { |
| |
| flush = true; |
| } |
| *vertexCount = currVertices; |
| } |
| return flush; |
| } |
| |
| bool GrFlushToGpuDrawTarget::onReserveVertexSpace(size_t vertexSize, |
| int vertexCount, |
| void** vertices) { |
| GeometryPoolState& poolState = fGeoPoolStateStack.back(); |
| SkASSERT(vertexCount > 0); |
| SkASSERT(vertices); |
| SkASSERT(0 == poolState.fUsedPoolVertexBytes); |
| |
| *vertices = fVertexPool->makeSpace(vertexSize, |
| vertexCount, |
| &poolState.fPoolVertexBuffer, |
| &poolState.fPoolStartVertex); |
| return SkToBool(*vertices); |
| } |
| |
| bool GrFlushToGpuDrawTarget::onReserveIndexSpace(int indexCount, void** indices) { |
| GeometryPoolState& poolState = fGeoPoolStateStack.back(); |
| SkASSERT(indexCount > 0); |
| SkASSERT(indices); |
| SkASSERT(0 == poolState.fUsedPoolIndexBytes); |
| |
| *indices = fIndexPool->makeSpace(indexCount, |
| &poolState.fPoolIndexBuffer, |
| &poolState.fPoolStartIndex); |
| return SkToBool(*indices); |
| } |
| |
| void GrFlushToGpuDrawTarget::releaseReservedVertexSpace() { |
| GeometryPoolState& poolState = fGeoPoolStateStack.back(); |
| const GeometrySrcState& geoSrc = this->getGeomSrc(); |
| |
| // If we get a release vertex space call then our current source should either be reserved |
| // or array (which we copied into reserved space). |
| SkASSERT(kReserved_GeometrySrcType == geoSrc.fVertexSrc); |
| |
| // When the caller reserved vertex buffer space we gave it back a pointer |
| // provided by the vertex buffer pool. At each draw we tracked the largest |
| // offset into the pool's pointer that was referenced. Now we return to the |
| // pool any portion at the tail of the allocation that no draw referenced. |
| size_t reservedVertexBytes = geoSrc.fVertexSize * geoSrc.fVertexCount; |
| fVertexPool->putBack(reservedVertexBytes - poolState.fUsedPoolVertexBytes); |
| poolState.fUsedPoolVertexBytes = 0; |
| poolState.fPoolVertexBuffer = NULL; |
| poolState.fPoolStartVertex = 0; |
| } |
| |
| void GrFlushToGpuDrawTarget::releaseReservedIndexSpace() { |
| GeometryPoolState& poolState = fGeoPoolStateStack.back(); |
| const GeometrySrcState& geoSrc = this->getGeomSrc(); |
| |
| // If we get a release index space call then our current source should either be reserved |
| // or array (which we copied into reserved space). |
| SkASSERT(kReserved_GeometrySrcType == geoSrc.fIndexSrc); |
| |
| // Similar to releaseReservedVertexSpace we return any unused portion at |
| // the tail |
| size_t reservedIndexBytes = sizeof(uint16_t) * geoSrc.fIndexCount; |
| fIndexPool->putBack(reservedIndexBytes - poolState.fUsedPoolIndexBytes); |
| poolState.fUsedPoolIndexBytes = 0; |
| poolState.fPoolIndexBuffer = NULL; |
| poolState.fPoolStartIndex = 0; |
| } |
| |
| void GrFlushToGpuDrawTarget::geometrySourceWillPush() { |
| GeometryPoolState& poolState = fGeoPoolStateStack.push_back(); |
| poolState.fUsedPoolVertexBytes = 0; |
| poolState.fUsedPoolIndexBytes = 0; |
| #ifdef SK_DEBUG |
| poolState.fPoolVertexBuffer = (GrVertexBuffer*)~0; |
| poolState.fPoolStartVertex = ~0; |
| poolState.fPoolIndexBuffer = (GrIndexBuffer*)~0; |
| poolState.fPoolStartIndex = ~0; |
| #endif |
| } |
| |
| void GrFlushToGpuDrawTarget::geometrySourceWillPop(const GeometrySrcState& restoredState) { |
| SkASSERT(fGeoPoolStateStack.count() > 1); |
| fGeoPoolStateStack.pop_back(); |
| GeometryPoolState& poolState = fGeoPoolStateStack.back(); |
| // we have to assume that any slack we had in our vertex/index data |
| // is now unreleasable because data may have been appended later in the |
| // pool. |
| if (kReserved_GeometrySrcType == restoredState.fVertexSrc) { |
| poolState.fUsedPoolVertexBytes = restoredState.fVertexSize * restoredState.fVertexCount; |
| } |
| if (kReserved_GeometrySrcType == restoredState.fIndexSrc) { |
| poolState.fUsedPoolIndexBytes = sizeof(uint16_t) * restoredState.fIndexCount; |
| } |
| } |
| |
| bool GrFlushToGpuDrawTarget::onCanCopySurface(const GrSurface* dst, |
| const GrSurface* src, |
| const SkIRect& srcRect, |
| const SkIPoint& dstPoint) { |
| return getGpu()->canCopySurface(dst, src, srcRect, dstPoint); |
| } |
| |
| bool GrFlushToGpuDrawTarget::onInitCopySurfaceDstDesc(const GrSurface* src, GrSurfaceDesc* desc) { |
| return getGpu()->initCopySurfaceDstDesc(src, desc); |
| } |