Index: src/gpu/GrFlushToGpuDrawTarget.cpp |
diff --git a/src/gpu/GrFlushToGpuDrawTarget.cpp b/src/gpu/GrFlushToGpuDrawTarget.cpp |
new file mode 100644 |
index 0000000000000000000000000000000000000000..b8604684b110f2af1a8c27c11cee7509d346fc62 |
--- /dev/null |
+++ b/src/gpu/GrFlushToGpuDrawTarget.cpp |
@@ -0,0 +1,251 @@ |
+/* |
+ * 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 "GrGpu.h" |
+#include "GrTextStrike.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(); |
+ fVertexPool->unmap(); |
+ fIndexPool->unmap(); |
+ |
+ 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; |
+ } |
+} |