diff options
author | 2014-12-01 08:19:34 -0800 | |
---|---|---|
committer | 2014-12-01 08:19:34 -0800 | |
commit | 371bcbcb9fa7f9acba265de9de5dd23f62a64a86 (patch) | |
tree | 271506165f21eaa6494953ed85a39853e831ab16 /src/gpu/GrFlushToGpuDrawTarget.cpp | |
parent | 5c9c9be1f540e1895e65fbd244caae9135972143 (diff) |
Add a base class for GrIODB that handles geometry data
Review URL: https://codereview.chromium.org/773433002
Diffstat (limited to 'src/gpu/GrFlushToGpuDrawTarget.cpp')
-rw-r--r-- | src/gpu/GrFlushToGpuDrawTarget.cpp | 251 |
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; + } +} |