Add GrDrawTarget::drawIndexedInstance, use in default text context.

Review URL: http://codereview.appspot.com/5848064/



git-svn-id: http://skia.googlecode.com/svn/trunk@3444 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/gpu/GrInOrderDrawBuffer.cpp b/src/gpu/GrInOrderDrawBuffer.cpp
index b6581c0..cab4bdd 100644
--- a/src/gpu/GrInOrderDrawBuffer.cpp
+++ b/src/gpu/GrInOrderDrawBuffer.cpp
@@ -42,6 +42,7 @@
     poolState.fPoolIndexBuffer = (GrIndexBuffer*)~0;
     poolState.fPoolStartIndex = ~0;
 #endif
+    fInstancedDrawTracker.reset();
 }
 
 GrInOrderDrawBuffer::~GrInOrderDrawBuffer() {
@@ -71,6 +72,13 @@
     }
 }
 
+////////////////////////////////////////////////////////////////////////////////
+
+void GrInOrderDrawBuffer::resetDrawTracking() {
+    fCurrQuad = 0;
+    fInstancedDrawTracker.reset();
+}
+
 void GrInOrderDrawBuffer::drawRect(const GrRect& rect,
                                    const GrMatrix* matrix,
                                    StageMask stageMask,
@@ -188,11 +196,135 @@
         if (disabledClip) {
             drawState->enableState(GrDrawState::kClip_StateBit);
         }
+        fInstancedDrawTracker.reset();
     } else {
         INHERITED::drawRect(rect, matrix, stageMask, srcRects, srcMatrices);
     }
 }
 
+void GrInOrderDrawBuffer::drawIndexedInstances(GrPrimitiveType type,
+                                               int instanceCount,
+                                               int verticesPerInstance,
+                                               int indicesPerInstance) {
+    if (!verticesPerInstance || !indicesPerInstance) {
+        return;
+    }
+
+    const GeometrySrcState& geomSrc = this->getGeomSrc();
+
+    // we only attempt to concat the case when reserved verts are used with
+    // an index buffer.
+    if (kReserved_GeometrySrcType == geomSrc.fVertexSrc &&
+        kBuffer_GeometrySrcType == geomSrc.fIndexSrc) {
+
+        Draw* draw = NULL;
+        // if the last draw used the same indices/vertices per shape then we
+        // may be able to append to it.
+        if (verticesPerInstance == fInstancedDrawTracker.fVerticesPerInstance &&
+            indicesPerInstance == fInstancedDrawTracker.fIndicesPerInstance) {
+            GrAssert(fDraws.count());
+            draw = &fDraws.back();
+        }
+
+        bool clipChanged = this->needsNewClip();
+        bool stateChanged = this->needsNewState();
+        if (clipChanged) {
+            this->pushClip();
+        }
+        if (stateChanged) {
+            this->pushState();
+        }
+
+        GeometryPoolState& poolState = fGeoPoolStateStack.back();
+        const GrVertexBuffer* vertexBuffer = poolState.fPoolVertexBuffer;
+
+        // Check whether the draw is compatible with this draw in order to
+        // append
+        if (NULL == draw ||
+            clipChanged ||
+            stateChanged ||
+            draw->fIndexBuffer != geomSrc.fIndexBuffer ||
+            draw->fPrimitiveType != type ||
+            draw->fVertexBuffer != vertexBuffer) {
+
+            draw = &fDraws.push_back();
+            draw->fClipChanged = clipChanged;
+            draw->fStateChanged = stateChanged;
+            draw->fIndexBuffer = geomSrc.fIndexBuffer;
+            geomSrc.fIndexBuffer->ref();
+            draw->fVertexBuffer = vertexBuffer;
+            vertexBuffer->ref();
+            draw->fPrimitiveType = type;
+            draw->fStartIndex = 0;
+            draw->fIndexCount = 0;
+            draw->fStartVertex = poolState.fPoolStartVertex;
+            draw->fVertexCount = 0;
+            draw->fVertexLayout = geomSrc.fVertexLayout;
+        } else {
+            GrAssert(!(draw->fIndexCount % indicesPerInstance));
+            GrAssert(!(draw->fVertexCount % verticesPerInstance));
+            GrAssert(poolState.fPoolStartVertex == draw->fStartVertex +
+                                                   draw->fVertexCount);
+        }
+
+        // how many instances can be in a single draw
+        int maxInstancesPerDraw = this->indexCountInCurrentSource() /
+                                  indicesPerInstance;
+        if (!maxInstancesPerDraw) {
+            return;
+        }
+        // how many instances should be concat'ed onto draw
+        int instancesToConcat = maxInstancesPerDraw - draw->fVertexCount /
+                                                      verticesPerInstance;
+        if (maxInstancesPerDraw > instanceCount) {
+            maxInstancesPerDraw = instanceCount;
+            if (instancesToConcat > instanceCount) {
+                instancesToConcat = instanceCount;
+            }
+        }
+
+        // update the amount of reserved data actually referenced in draws
+        size_t vertexBytes = instanceCount * verticesPerInstance *
+                             VertexSize(draw->fVertexLayout);
+        poolState.fUsedPoolVertexBytes =
+                            GrMax(poolState.fUsedPoolVertexBytes, vertexBytes);
+
+        while (instanceCount) {
+            if (!instancesToConcat) {
+                int startVertex = draw->fStartVertex + draw->fVertexCount;
+                draw = &fDraws.push_back();
+                draw->fClipChanged = false;
+                draw->fStateChanged = false;
+                draw->fIndexBuffer = geomSrc.fIndexBuffer;
+                geomSrc.fIndexBuffer->ref();
+                draw->fVertexBuffer = vertexBuffer;
+                vertexBuffer->ref();
+                draw->fPrimitiveType = type;
+                draw->fStartIndex = 0;
+                draw->fStartVertex = startVertex;
+                draw->fVertexCount = 0;
+                draw->fVertexLayout = geomSrc.fVertexLayout;
+                instancesToConcat = maxInstancesPerDraw;
+            }
+            draw->fVertexCount += instancesToConcat * verticesPerInstance;
+            draw->fIndexCount += instancesToConcat * indicesPerInstance;
+            instanceCount -= instancesToConcat;
+            instancesToConcat = 0;
+        }
+
+        // update draw tracking for next draw
+        fCurrQuad = 0;
+        fInstancedDrawTracker.fVerticesPerInstance = verticesPerInstance;
+        fInstancedDrawTracker.fIndicesPerInstance = indicesPerInstance;
+    } else {
+        this->INHERITED::drawIndexedInstances(type,
+                                              instanceCount,
+                                              verticesPerInstance,
+                                              indicesPerInstance);
+    }
+
+}
+
 void GrInOrderDrawBuffer::onDrawIndexed(GrPrimitiveType primitiveType,
                                         int startVertex,
                                         int startIndex,
@@ -203,7 +335,7 @@
         return;
     }
 
-    fCurrQuad = 0;
+    this->resetDrawTracking();
 
     GeometryPoolState& poolState = fGeoPoolStateStack.back();
 
@@ -270,7 +402,7 @@
         return;
     }
 
-    fCurrQuad = 0;
+    this->resetDrawTracking();
 
     GeometryPoolState& poolState = fGeoPoolStateStack.back();
 
@@ -359,7 +491,7 @@
 
     fClips.reset();
 
-    fCurrQuad = 0;
+    this->resetDrawTracking();
 }
 
 void GrInOrderDrawBuffer::playback(GrDrawTarget* target) {
@@ -608,6 +740,7 @@
     GeometryPoolState& poolState = fGeoPoolStateStack.push_back();
     poolState.fUsedPoolVertexBytes = 0;
     poolState.fUsedPoolIndexBytes = 0;
+    this->resetDrawTracking();
 #if GR_DEBUG
     poolState.fPoolVertexBuffer = (GrVertexBuffer*)~0;
     poolState.fPoolStartVertex = ~0;
@@ -635,6 +768,7 @@
         poolState.fUsedPoolIndexBytes = sizeof(uint16_t) * 
                                          restoredState.fIndexCount;
     }
+    this->resetDrawTracking();
 }
 
 bool GrInOrderDrawBuffer::needsNewState() const {