diff options
author | bsalomon@google.com <bsalomon@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2012-03-20 21:17:58 +0000 |
---|---|---|
committer | bsalomon@google.com <bsalomon@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2012-03-20 21:17:58 +0000 |
commit | 934c570297c1b1f99cb4ca8d012d468a7eddf73f (patch) | |
tree | 0649ced17fed6df8671e621ecbc139238790d2ae | |
parent | 2e7f4c810dc717383df42d27bdba862514ab6d51 (diff) |
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
-rw-r--r-- | src/gpu/GrDefaultTextContext.cpp | 8 | ||||
-rw-r--r-- | src/gpu/GrDrawTarget.cpp | 28 | ||||
-rw-r--r-- | src/gpu/GrDrawTarget.h | 70 | ||||
-rw-r--r-- | src/gpu/GrInOrderDrawBuffer.cpp | 140 | ||||
-rw-r--r-- | src/gpu/GrInOrderDrawBuffer.h | 32 |
5 files changed, 253 insertions, 25 deletions
diff --git a/src/gpu/GrDefaultTextContext.cpp b/src/gpu/GrDefaultTextContext.cpp index a0747b7734..d2c5d924a3 100644 --- a/src/gpu/GrDefaultTextContext.cpp +++ b/src/gpu/GrDefaultTextContext.cpp @@ -33,7 +33,6 @@ void GrDefaultTextContext::flushGlyphs() { GrSamplerState::kRepeat_WrapMode,filter); GrAssert(GrIsALIGN4(fCurrVertex)); - int nIndices = fCurrVertex + (fCurrVertex >> 1); GrAssert(fCurrTexture); drawState->setTexture(kGlyphMaskStage, fCurrTexture); @@ -56,9 +55,10 @@ void GrDefaultTextContext::flushGlyphs() { } fDrawTarget->setIndexSourceToBuffer(fContext->getQuadIndexBuffer()); - - fDrawTarget->drawIndexed(kTriangles_PrimitiveType, - 0, 0, fCurrVertex, nIndices); + int nGlyphs = fCurrVertex / 4; + fDrawTarget->drawIndexedInstances(kTriangles_PrimitiveType, + nGlyphs, + 4, 6); fVertices = NULL; this->INHERITED::reset(); } diff --git a/src/gpu/GrDrawTarget.cpp b/src/gpu/GrDrawTarget.cpp index e9b7e49a98..6d52c2a0da 100644 --- a/src/gpu/GrDrawTarget.cpp +++ b/src/gpu/GrDrawTarget.cpp @@ -1011,6 +1011,34 @@ bool GrDrawTarget::drawWillReadDst() const { this->getBlendOpts()); } +//////////////////////////////////////////////////////////////////////////////// + +void GrDrawTarget::drawIndexedInstances(GrPrimitiveType type, + int instanceCount, + int verticesPerInstance, + int indicesPerInstance) { + if (!verticesPerInstance || !indicesPerInstance) { + return; + } + + int instancesPerDraw = this->indexCountInCurrentSource() / + indicesPerInstance; + if (!instancesPerDraw) { + return; + } + + instancesPerDraw = GrMin(instanceCount, instancesPerDraw); + int startVertex = 0; + while (instanceCount) { + this->drawIndexed(type, + startVertex, + 0, + verticesPerInstance * instancesPerDraw, + indicesPerInstance * instancesPerDraw); + startVertex += verticesPerInstance; + instanceCount -= instancesPerDraw; + } +} //////////////////////////////////////////////////////////////////////////////// diff --git a/src/gpu/GrDrawTarget.h b/src/gpu/GrDrawTarget.h index 629963b51e..3a85767038 100644 --- a/src/gpu/GrDrawTarget.h +++ b/src/gpu/GrDrawTarget.h @@ -14,6 +14,7 @@ #include "GrClip.h" #include "GrColor.h" #include "GrDrawState.h" +#include "GrIndexBuffer.h" #include "GrMatrix.h" #include "GrRefCnt.h" #include "GrSamplerState.h" @@ -263,9 +264,8 @@ public: * There are three types of "sources" of geometry (vertices and indices) for * draw calls made on the target. When performing an indexed draw, the * indices and vertices can use different source types. Once a source is - * specified it can be used for multiple drawIndexed and drawNonIndexed - * calls. However, the time at which the geometry data is no longer editable - * depends on the source type. + * specified it can be used for multiple draws. However, the time at which + * the geometry data is no longer editable depends on the source type. * * Sometimes it is necessary to perform a draw while upstack code has * already specified geometry that it isn't finished with. So there are push @@ -291,8 +291,8 @@ public: * data. The target provides ptrs to hold the vertex and/or index data. * * The data is writable up until the next drawIndexed, drawNonIndexed, - * or pushGeometrySource. At this point the data is frozen and the ptrs - * are no longer valid. + * drawIndexedInstances, or pushGeometrySource. At this point the data is + * frozen and the ptrs are no longer valid. * * Where the space is allocated and how it is uploaded to the GPU is * subclass-dependent. @@ -319,9 +319,9 @@ public: * source is reset and likewise for indexCount. * * The pointers to the space allocated for vertices and indices remain valid - * until a drawIndexed, drawNonIndexed, or push/popGeomtrySource is called. - * At that point logically a snapshot of the data is made and the pointers - * are invalid. + * until a drawIndexed, drawNonIndexed, drawIndexedInstances, or push/ + * popGeomtrySource is called. At that point logically a snapshot of the + * data is made and the pointers are invalid. * * @param vertexLayout the format of vertices (ignored if vertexCount == 0). * @param vertexCount the number of vertices to reserve space for. Can be @@ -387,7 +387,7 @@ public: /** * Sets source of vertex data for the next draw. Data does not have to be - * in the buffer until drawIndexed or drawNonIndexed. + * in the buffer until drawIndexed, drawNonIndexed, or drawIndexedInstances. * * @param buffer vertex buffer containing vertex data. Must be * unlocked before draw call. @@ -398,7 +398,7 @@ public: /** * Sets source of index data for the next indexed draw. Data does not have - * to be in the buffer until drawIndexed or drawNonIndexed. + * to be in the buffer until drawIndexed. * * @param buffer index buffer containing indices. Must be unlocked * before indexed draw call. @@ -503,6 +503,39 @@ public: const GrMatrix* srcMatrices[]); /** + * This call is used to draw multiple instances of some geometry with a + * given number of vertices (V) and indices (I) per-instance. The indices in + * the index source must have the form i[k+I] == i[k] + V. Also, all indices + * i[kI] ... i[(k+1)I-1] must be elements of the range kV ... (k+1)V-1. As a + * concrete example, the following index buffer for drawing a series of + * quads each as two triangles each satisfies these conditions with V=4 and + * I=6: + * (0,1,2,0,2,3, 4,5,6,4,6,7, 8,9,10,8,10,11, ...) + * + * The call assumes that the pattern of indices fills the entire index + * source. The size of the index buffer limits the number of instances that + * can be drawn by the GPU in a single draw. However, the caller may specify + * any (positive) number for instanceCount and if necessary multiple GPU + * draws will be issued. Morever, when drawIndexedInstances is called + * multiple times it may be possible for GrDrawTarget to group them into a + * single GPU draw. + * + * @param type the type of primitives to draw + * @param instanceCount the number of instances to draw. Each instance + * consists of verticesPerInstance vertices indexed by + * indicesPerInstance indices drawn as the primitive + * type specified by type. + * @param verticesPerInstance The number of vertices in each instance (V + * in the above description). + * @param indicesPerInstance The number of indices in each instance (I + * in the above description). + */ + virtual void drawIndexedInstances(GrPrimitiveType type, + int instanceCount, + int verticesPerInstance, + int indicesPerInstance); + + /** * Helper for drawRect when the caller doesn't need separate src rects or * matrices. */ @@ -904,7 +937,22 @@ protected: GrVertexLayout fVertexLayout; }; - + + int indexCountInCurrentSource() const { + const GeometrySrcState& src = this->getGeomSrc(); + switch (src.fIndexSrc) { + case kNone_GeometrySrcType: + return 0; + case kReserved_GeometrySrcType: + case kArray_GeometrySrcType: + return src.fIndexCount; + case kBuffer_GeometrySrcType: + return src.fIndexBuffer->sizeInBytes() / sizeof(uint16_t); + default: + GrCrash("Unexpected Index Source."); + return 0; + } + } // given a vertex layout and a draw state, will a stage be used? static bool StageWillBeUsed(int stage, GrVertexLayout layout, const GrDrawState& state) { diff --git a/src/gpu/GrInOrderDrawBuffer.cpp b/src/gpu/GrInOrderDrawBuffer.cpp index b6581c04e3..cab4bdd875 100644 --- a/src/gpu/GrInOrderDrawBuffer.cpp +++ b/src/gpu/GrInOrderDrawBuffer.cpp @@ -42,6 +42,7 @@ GrInOrderDrawBuffer::GrInOrderDrawBuffer(const GrGpu* gpu, poolState.fPoolIndexBuffer = (GrIndexBuffer*)~0; poolState.fPoolStartIndex = ~0; #endif + fInstancedDrawTracker.reset(); } GrInOrderDrawBuffer::~GrInOrderDrawBuffer() { @@ -71,6 +72,13 @@ void GrInOrderDrawBuffer::setQuadIndexBuffer(const GrIndexBuffer* indexBuffer) { } } +//////////////////////////////////////////////////////////////////////////////// + +void GrInOrderDrawBuffer::resetDrawTracking() { + fCurrQuad = 0; + fInstancedDrawTracker.reset(); +} + void GrInOrderDrawBuffer::drawRect(const GrRect& rect, const GrMatrix* matrix, StageMask stageMask, @@ -188,11 +196,135 @@ void GrInOrderDrawBuffer::drawRect(const GrRect& rect, 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 @@ void GrInOrderDrawBuffer::onDrawIndexed(GrPrimitiveType primitiveType, return; } - fCurrQuad = 0; + this->resetDrawTracking(); GeometryPoolState& poolState = fGeoPoolStateStack.back(); @@ -270,7 +402,7 @@ void GrInOrderDrawBuffer::onDrawNonIndexed(GrPrimitiveType primitiveType, return; } - fCurrQuad = 0; + this->resetDrawTracking(); GeometryPoolState& poolState = fGeoPoolStateStack.back(); @@ -359,7 +491,7 @@ void GrInOrderDrawBuffer::reset() { fClips.reset(); - fCurrQuad = 0; + this->resetDrawTracking(); } void GrInOrderDrawBuffer::playback(GrDrawTarget* target) { @@ -608,6 +740,7 @@ void GrInOrderDrawBuffer::geometrySourceWillPush() { 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 @@ void GrInOrderDrawBuffer::geometrySourceWillPop( poolState.fUsedPoolIndexBytes = sizeof(uint16_t) * restoredState.fIndexCount; } + this->resetDrawTracking(); } bool GrInOrderDrawBuffer::needsNewState() const { diff --git a/src/gpu/GrInOrderDrawBuffer.h b/src/gpu/GrInOrderDrawBuffer.h index b802f960b0..a0880d247c 100644 --- a/src/gpu/GrInOrderDrawBuffer.h +++ b/src/gpu/GrInOrderDrawBuffer.h @@ -109,6 +109,12 @@ public: const GrRect* srcRects[] = NULL, const GrMatrix* srcMatrices[] = NULL) SK_OVERRIDE; + virtual void drawIndexedInstances(GrPrimitiveType type, + int instanceCount, + int verticesPerInstance, + int indicesPerInstance) + SK_OVERRIDE; + virtual bool geometryHints(GrVertexLayout vertexLayout, int* vertexCount, int* indexCount) const SK_OVERRIDE; @@ -116,13 +122,10 @@ public: virtual void clear(const GrIRect* rect, GrColor color) SK_OVERRIDE; protected: - virtual void willReserveVertexAndIndexSpace(GrVertexLayout vertexLayout, int vertexCount, int indexCount) SK_OVERRIDE; - private: - struct Draw { GrPrimitiveType fPrimitiveType; int fStartVertex; @@ -172,7 +175,11 @@ private: void pushState(); void pushClip(); - + + // call this to invalidate the tracking data that is used to concatenate + // multiple draws into a single draw. + void resetDrawTracking(); + enum { kDrawPreallocCnt = 8, kStatePreallocCnt = 8, @@ -190,14 +197,25 @@ private: bool fClipSet; + GrVertexBufferAllocPool& fVertexPool; + + GrIndexBufferAllocPool& fIndexPool; + + // these are used to attempt to concatenate drawRect calls GrVertexLayout fLastRectVertexLayout; const GrIndexBuffer* fQuadIndexBuffer; int fMaxQuads; int fCurrQuad; - GrVertexBufferAllocPool& fVertexPool; - - GrIndexBufferAllocPool& fIndexPool; + // bookkeeping to attempt to concantenate drawIndexedInstances calls + struct { + int fVerticesPerInstance; + int fIndicesPerInstance; + void reset() { + fVerticesPerInstance = 0; + fIndicesPerInstance = 0; + } + } fInstancedDrawTracker; struct GeometryPoolState { const GrVertexBuffer* fPoolVertexBuffer; |