Index: src/gpu/GrInOrderDrawBuffer.cpp |
diff --git a/src/gpu/GrInOrderDrawBuffer.cpp b/src/gpu/GrInOrderDrawBuffer.cpp |
index 70d61ecfffba21ef67ab4c8bd1a8fdff53034770..a760dcbf6fc4fd147811df36a5dd41ea7918c23e 100644 |
--- a/src/gpu/GrInOrderDrawBuffer.cpp |
+++ b/src/gpu/GrInOrderDrawBuffer.cpp |
@@ -7,6 +7,7 @@ |
#include "GrInOrderDrawBuffer.h" |
+#include "GrBufferAllocPool.h" |
#include "GrDefaultGeoProcFactory.h" |
#include "GrDrawTargetCaps.h" |
#include "GrGpu.h" |
@@ -20,7 +21,9 @@ GrInOrderDrawBuffer::GrInOrderDrawBuffer(GrGpu* gpu, |
: INHERITED(gpu, vertexPool, indexPool) |
, fCmdBuffer(kCmdBufferInitialSizeInBytes) |
, fPrevState(NULL) |
- , fDrawID(0) { |
+ , fDrawID(0) |
+ , fBatchTarget(gpu, vertexPool, indexPool) |
+ , fDrawBatch(NULL) { |
SkASSERT(vertexPool); |
SkASSERT(indexPool); |
@@ -210,6 +213,7 @@ int GrInOrderDrawBuffer::concatInstancedDraw(const GrPipelineBuilder& pipelineBu |
Draw* draw = static_cast<Draw*>(&fCmdBuffer.back()); |
if (!draw->fInfo.isInstanced() || |
+ draw->fInfo.primitiveType() != info.primitiveType() || |
draw->fInfo.verticesPerInstance() != info.verticesPerInstance() || |
draw->fInfo.indicesPerInstance() != info.indicesPerInstance() || |
draw->fInfo.vertexBuffer() != info.vertexBuffer() || |
@@ -247,6 +251,9 @@ void GrInOrderDrawBuffer::onDraw(const GrPipelineBuilder& pipelineBuilder, |
const GrDeviceCoordTexture* dstCopy) { |
SkASSERT(info.vertexBuffer() && (!info.isIndexed() || info.indexBuffer())); |
+ // This closeBatch call is required because we may introduce new draws when we setup clip |
+ this->closeBatch(); |
+ |
if (!this->recordStateAndShouldDraw(pipelineBuilder, gp, scissorState, dstCopy)) { |
return; |
} |
@@ -266,6 +273,30 @@ void GrInOrderDrawBuffer::onDraw(const GrPipelineBuilder& pipelineBuilder, |
this->recordTraceMarkersIfNecessary(); |
} |
+void GrInOrderDrawBuffer::onDrawBatch(GrBatch* batch, |
+ const GrPipelineBuilder& pipelineBuilder, |
+ const GrScissorState& scissorState, |
+ const GrDeviceCoordTexture* dstCopy) { |
+ if (!this->recordStateAndShouldDraw(batch, pipelineBuilder, scissorState, dstCopy)) { |
+ return; |
+ } |
+ |
+ // Check if there is a Batch Draw we can batch with |
+ if (kDrawBatch_Cmd != strip_trace_bit(fCmdBuffer.back().fType)) { |
+ fDrawBatch = GrNEW_APPEND_TO_RECORDER(fCmdBuffer, DrawBatch, (batch)); |
+ return; |
+ } |
+ |
+ DrawBatch* draw = static_cast<DrawBatch*>(&fCmdBuffer.back()); |
+ if (draw->fBatch->combineIfPossible(batch)) { |
+ return; |
+ } else { |
+ this->closeBatch(); |
+ fDrawBatch = GrNEW_APPEND_TO_RECORDER(fCmdBuffer, DrawBatch, (batch)); |
+ } |
+ this->recordTraceMarkersIfNecessary(); |
+} |
+ |
void GrInOrderDrawBuffer::onStencilPath(const GrPipelineBuilder& pipelineBuilder, |
const GrPathProcessor* pathProc, |
const GrPath* path, |
@@ -286,6 +317,8 @@ void GrInOrderDrawBuffer::onDrawPath(const GrPipelineBuilder& pipelineBuilder, |
const GrScissorState& scissorState, |
const GrStencilSettings& stencilSettings, |
const GrDeviceCoordTexture* dstCopy) { |
+ this->closeBatch(); |
+ |
// TODO: Only compare the subset of GrPipelineBuilder relevant to path covering? |
if (!this->recordStateAndShouldDraw(pipelineBuilder, pathProc, scissorState, dstCopy)) { |
return; |
@@ -310,6 +343,8 @@ void GrInOrderDrawBuffer::onDrawPaths(const GrPipelineBuilder& pipelineBuilder, |
SkASSERT(indices); |
SkASSERT(transformValues); |
+ this->closeBatch(); |
+ |
if (!this->recordStateAndShouldDraw(pipelineBuilder, pathProc, scissorState, dstCopy)) { |
return; |
} |
@@ -403,6 +438,7 @@ void GrInOrderDrawBuffer::onReset() { |
reset_data_buffer(&fPathIndexBuffer, kPathIdxBufferMinReserve); |
reset_data_buffer(&fPathTransformBuffer, kPathXformBufferMinReserve); |
fGpuCmdMarkers.reset(); |
+ fDrawBatch = NULL; |
} |
void GrInOrderDrawBuffer::onFlush() { |
@@ -410,15 +446,21 @@ void GrInOrderDrawBuffer::onFlush() { |
return; |
} |
+ // Updated every time we find a set state cmd to reflect the current state in the playback |
+ // stream. |
+ SetState* currentState = NULL; |
+ |
+ // TODO this is temporary while batch is being rolled out |
+ this->closeBatch(); |
+ this->getVertexAllocPool()->unmap(); |
+ this->getIndexAllocPool()->unmap(); |
+ fBatchTarget.preFlush(); |
+ currentState = NULL; |
CmdBuffer::Iter iter(fCmdBuffer); |
int currCmdMarker = 0; |
- // Updated every time we find a set state cmd to reflect the current state in the playback |
- // stream. |
- SetState* currentState = NULL; |
- |
while (iter.next()) { |
GrGpuTraceMarker newMarker("", -1); |
SkString traceString; |
@@ -429,13 +471,25 @@ void GrInOrderDrawBuffer::onFlush() { |
++currCmdMarker; |
} |
- if (kSetState_Cmd == strip_trace_bit(iter->fType)) { |
+ // TODO temporary hack |
+ if (kDrawBatch_Cmd == strip_trace_bit(iter->fType)) { |
+ fBatchTarget.flushNext(); |
+ continue; |
+ } |
+ |
+ bool isSetState = kSetState_Cmd == strip_trace_bit(iter->fType); |
+ if (isSetState) { |
SetState* ss = reinterpret_cast<SetState*>(iter.get()); |
- this->getGpu()->buildProgramDesc(&ss->fDesc, *ss->fPrimitiveProcessor, ss->fPipeline, |
- ss->fPipeline.descInfo(), ss->fBatchTracker); |
+ // TODO sometimes we have a prim proc, othertimes we have a GrBatch. Eventually we will |
+ // only have GrBatch and we can delete this |
+ if (ss->fPrimitiveProcessor) { |
+ this->getGpu()->buildProgramDesc(&ss->fDesc, *ss->fPrimitiveProcessor, |
+ ss->fPipeline, |
+ ss->fPipeline.descInfo(), |
+ ss->fBatchTracker); |
+ } |
currentState = ss; |
- |
} else { |
iter->execute(this, currentState); |
} |
@@ -445,6 +499,9 @@ void GrInOrderDrawBuffer::onFlush() { |
} |
} |
+ // TODO see copious notes about hack |
+ fBatchTarget.postFlush(); |
+ |
SkASSERT(fGpuCmdMarkers.count() == currCmdMarker); |
++fDrawID; |
} |
@@ -484,6 +541,11 @@ void GrInOrderDrawBuffer::DrawPaths::execute(GrInOrderDrawBuffer* buf, const Set |
fCount, fStencilSettings); |
} |
+void GrInOrderDrawBuffer::DrawBatch::execute(GrInOrderDrawBuffer* buf, const SetState* state) { |
+ SkASSERT(state); |
+ fBatch->generateGeometry(buf->getBatchTarget(), &state->fPipeline); |
+} |
+ |
void GrInOrderDrawBuffer::SetState::execute(GrInOrderDrawBuffer*, const SetState*) {} |
void GrInOrderDrawBuffer::Clear::execute(GrInOrderDrawBuffer* buf, const SetState*) { |
@@ -531,7 +593,7 @@ bool GrInOrderDrawBuffer::recordStateAndShouldDraw(const GrPipelineBuilder& pipe |
ss->fPrimitiveProcessor->initBatchTracker(&ss->fBatchTracker, |
ss->fPipeline.getInitBatchTracker()); |
- if (fPrevState && |
+ if (fPrevState && fPrevState->fPrimitiveProcessor.get() && |
fPrevState->fPrimitiveProcessor->canMakeEqual(fPrevState->fBatchTracker, |
*ss->fPrimitiveProcessor, |
ss->fBatchTracker) && |
@@ -544,6 +606,34 @@ bool GrInOrderDrawBuffer::recordStateAndShouldDraw(const GrPipelineBuilder& pipe |
return true; |
} |
+bool GrInOrderDrawBuffer::recordStateAndShouldDraw(GrBatch* batch, |
+ const GrPipelineBuilder& pipelineBuilder, |
+ const GrScissorState& scissor, |
+ const GrDeviceCoordTexture* dstCopy) { |
+ // TODO this gets much simpler when we have batches everywhere. |
+ // If the previous command is also a set state, then we check to see if it has a Batch. If so, |
+ // and we can make the two batches equal, and we can combine the states, then we make them equal |
+ SetState* ss = GrNEW_APPEND_TO_RECORDER(fCmdBuffer, SetState, |
+ (batch, pipelineBuilder, *this->getGpu()->caps(), scissor, |
+ dstCopy)); |
+ if (ss->fPipeline.mustSkip()) { |
+ fCmdBuffer.pop_back(); |
+ return false; |
+ } |
+ |
+ batch->initBatchTracker(ss->fPipeline.getInitBatchTracker()); |
+ |
+ if (fPrevState && !fPrevState->fPrimitiveProcessor.get() && |
+ fPrevState->fPipeline.isEqual(ss->fPipeline)) { |
+ fCmdBuffer.pop_back(); |
+ } else { |
+ this->closeBatch(); |
+ fPrevState = ss; |
+ this->recordTraceMarkersIfNecessary(); |
+ } |
+ return true; |
+} |
+ |
void GrInOrderDrawBuffer::recordTraceMarkersIfNecessary() { |
SkASSERT(!fCmdBuffer.empty()); |
SkASSERT(!cmd_has_trace_marker(fCmdBuffer.back().fType)); |
@@ -553,3 +643,42 @@ void GrInOrderDrawBuffer::recordTraceMarkersIfNecessary() { |
fGpuCmdMarkers.push_back(activeTraceMarkers); |
} |
} |
+ |
+void GrInOrderDrawBuffer::closeBatch() { |
+ if (fDrawBatch) { |
+ fDrawBatch->execute(this, fPrevState); |
+ fDrawBatch = NULL; |
+ } |
+} |
+ |
+void GrInOrderDrawBuffer::willReserveVertexAndIndexSpace(int vertexCount, |
+ size_t vertexStride, |
+ int indexCount) { |
+ this->closeBatch(); |
+ |
+ // 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 = this->getGeoPoolStateStack().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(); |
+ } |
+} |