aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/gpu/GrFlushToGpuDrawTarget.cpp
diff options
context:
space:
mode:
authorGravatar bsalomon <bsalomon@google.com>2014-12-01 08:19:34 -0800
committerGravatar Commit bot <commit-bot@chromium.org>2014-12-01 08:19:34 -0800
commit371bcbcb9fa7f9acba265de9de5dd23f62a64a86 (patch)
tree271506165f21eaa6494953ed85a39853e831ab16 /src/gpu/GrFlushToGpuDrawTarget.cpp
parent5c9c9be1f540e1895e65fbd244caae9135972143 (diff)
Add a base class for GrIODB that handles geometry data
Diffstat (limited to 'src/gpu/GrFlushToGpuDrawTarget.cpp')
-rw-r--r--src/gpu/GrFlushToGpuDrawTarget.cpp251
1 files changed, 251 insertions, 0 deletions
diff --git a/src/gpu/GrFlushToGpuDrawTarget.cpp b/src/gpu/GrFlushToGpuDrawTarget.cpp
new file mode 100644
index 0000000000..b8604684b1
--- /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;
+ }
+}