aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/gpu
diff options
context:
space:
mode:
authorGravatar bsalomon@google.com <bsalomon@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2013-02-01 14:19:27 +0000
committerGravatar bsalomon@google.com <bsalomon@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2013-02-01 14:19:27 +0000
commitd62e88e5af39347a8fc2a5abdf5feb67d7ea256d (patch)
treeaae6adc4d6cb208d0eb9758266abd95f08ac0ad0 /src/gpu
parent2bc4c35733fa1adecaab2551cba4df5a7ff6935b (diff)
Make drawIndexedInstances non-virtual and rewrite GrIODB's drawRect on top of drawIndexedInstances.
R=robertphillips@google.com Review URL: https://codereview.appspot.com/7221078 git-svn-id: http://skia.googlecode.com/svn/trunk@7508 2bbb7eff-a529-9590-31e7-b0007b416f81
Diffstat (limited to 'src/gpu')
-rw-r--r--src/gpu/GrContext.cpp1
-rw-r--r--src/gpu/GrDrawState.cpp26
-rw-r--r--src/gpu/GrDrawState.h31
-rw-r--r--src/gpu/GrDrawTarget.cpp228
-rw-r--r--src/gpu/GrDrawTarget.h97
-rw-r--r--src/gpu/GrInOrderDrawBuffer.cpp551
-rw-r--r--src/gpu/GrInOrderDrawBuffer.h72
7 files changed, 505 insertions, 501 deletions
diff --git a/src/gpu/GrContext.cpp b/src/gpu/GrContext.cpp
index 50d4741160..b729d6971e 100644
--- a/src/gpu/GrContext.cpp
+++ b/src/gpu/GrContext.cpp
@@ -1791,7 +1791,6 @@ void GrContext::setupDrawBuffer() {
fDrawBufferVBAllocPool,
fDrawBufferIBAllocPool));
- fDrawBuffer->setQuadIndexBuffer(this->getQuadIndexBuffer());
if (fDrawBuffer) {
fDrawBuffer->setAutoFlushTarget(fGpu);
fDrawBuffer->setDrawState(fDrawState);
diff --git a/src/gpu/GrDrawState.cpp b/src/gpu/GrDrawState.cpp
index 6079272246..b6c521f093 100644
--- a/src/gpu/GrDrawState.cpp
+++ b/src/gpu/GrDrawState.cpp
@@ -530,6 +530,32 @@ bool GrDrawState::srcAlphaWillBeOne(GrVertexLayout layout) const {
return (GrEffect::kA_ValidComponentFlag & validComponentFlags) && 0xff == GrColorUnpackA(color);
}
+bool GrDrawState::hasSolidCoverage(GrVertexLayout layout) const {
+ // If we're drawing coverage directly then coverage is effectively treated as color.
+ if (this->isCoverageDrawing()) {
+ return true;
+ }
+
+ GrColor coverage;
+ uint32_t validComponentFlags;
+ // Initialize to an unknown starting coverage if per-vertex coverage is specified.
+ if (layout & kCoverage_VertexLayoutBit) {
+ validComponentFlags = 0;
+ } else {
+ coverage = fCommon.fCoverage;
+ validComponentFlags = GrEffect::kAll_ValidComponentFlags;
+ }
+
+ // Run through the coverage stages and see if the coverage will be all ones at the end.
+ for (int s = this->getFirstCoverageStage(); s < GrDrawState::kNumStages; ++s) {
+ const GrEffectRef* effect = this->getStage(s).getEffect();
+ if (NULL != effect) {
+ (*effect)->getConstantColorComponents(&coverage, &validComponentFlags);
+ }
+ }
+ return (GrEffect::kAll_ValidComponentFlags == validComponentFlags) && (0xffffffff == coverage);
+}
+
////////////////////////////////////////////////////////////////////////////////
void GrDrawState::AutoViewMatrixRestore::restore() {
diff --git a/src/gpu/GrDrawState.h b/src/gpu/GrDrawState.h
index dc2023901f..0a0b0da33d 100644
--- a/src/gpu/GrDrawState.h
+++ b/src/gpu/GrDrawState.h
@@ -304,8 +304,15 @@ public:
int* coverageOffset,
int* edgeOffset);
- // determine if src alpha is guaranteed to be one for all src pixels
- bool srcAlphaWillBeOne(GrVertexLayout vertexLayout) const;
+ /**
+ * Determines whether src alpha is guaranteed to be one for all src pixels
+ */
+ bool srcAlphaWillBeOne(GrVertexLayout) const;
+
+ /**
+ * Determines whether the output coverage is guaranteed to be one for all pixels hit by a draw.
+ */
+ bool hasSolidCoverage(GrVertexLayout) const;
/**
* Accessing positions, texture coords, or colors, of a vertex within an
@@ -409,14 +416,28 @@ public:
*/
class AutoColorRestore : public ::GrNoncopyable {
public:
+ AutoColorRestore() : fDrawState(NULL) {}
+
AutoColorRestore(GrDrawState* drawState, GrColor color) {
+ fDrawState = NULL;
+ this->set(drawState, color);
+ }
+
+ void reset() {
+ if (NULL != fDrawState) {
+ fDrawState->setColor(fOldColor);
+ fDrawState = NULL;
+ }
+ }
+
+ void set(GrDrawState* drawState, GrColor color) {
+ this->reset();
fDrawState = drawState;
fOldColor = fDrawState->getColor();
fDrawState->setColor(color);
}
- ~AutoColorRestore() {
- fDrawState->setColor(fOldColor);
- }
+
+ ~AutoColorRestore() { this->reset(); }
private:
GrDrawState* fDrawState;
GrColor fOldColor;
diff --git a/src/gpu/GrDrawTarget.cpp b/src/gpu/GrDrawTarget.cpp
index 04ffaa4451..bb8b9ec167 100644
--- a/src/gpu/GrDrawTarget.cpp
+++ b/src/gpu/GrDrawTarget.cpp
@@ -19,6 +19,66 @@ SK_DEFINE_INST_COUNT(GrDrawTarget)
////////////////////////////////////////////////////////////////////////////////
+GrDrawTarget::DrawInfo& GrDrawTarget::DrawInfo::operator =(const DrawInfo& di) {
+ fPrimitiveType = di.fPrimitiveType;
+ fStartVertex = di.fStartVertex;
+ fStartIndex = di.fStartIndex;
+ fVertexCount = di.fVertexCount;
+ fIndexCount = di.fIndexCount;
+
+ fInstanceCount = di.fInstanceCount;
+ fVerticesPerInstance = di.fVerticesPerInstance;
+ fIndicesPerInstance = di.fIndicesPerInstance;
+
+ if (NULL != di.fDevBounds) {
+ GrAssert(di.fDevBounds == &di.fDevBoundsStorage);
+ fDevBoundsStorage = di.fDevBoundsStorage;
+ fDevBounds = &fDevBoundsStorage;
+ } else {
+ fDevBounds = NULL;
+ }
+ return *this;
+}
+
+#if GR_DEBUG
+bool GrDrawTarget::DrawInfo::isInstanced() const {
+ if (fInstanceCount > 0) {
+ GrAssert(0 == fIndexCount % fIndicesPerInstance);
+ GrAssert(0 == fVertexCount % fVerticesPerInstance);
+ GrAssert(fIndexCount / fIndicesPerInstance == fInstanceCount);
+ GrAssert(fVertexCount / fVerticesPerInstance == fInstanceCount);
+ // there is no way to specify a non-zero start index to drawIndexedInstances().
+ GrAssert(0 == fStartIndex);
+ return true;
+ } else {
+ GrAssert(!fVerticesPerInstance);
+ GrAssert(!fIndicesPerInstance);
+ return false;
+ }
+}
+#endif
+
+void GrDrawTarget::DrawInfo::adjustInstanceCount(int instanceOffset) {
+ GrAssert(this->isInstanced());
+ GrAssert(instanceOffset + fInstanceCount >= 0);
+ fInstanceCount += instanceOffset;
+ fVertexCount = fVerticesPerInstance * fInstanceCount;
+ fIndexCount = fIndicesPerInstance * fInstanceCount;
+}
+
+void GrDrawTarget::DrawInfo::adjustStartVertex(int vertexOffset) {
+ fStartVertex += vertexOffset;
+ GrAssert(fStartVertex >= 0);
+}
+
+void GrDrawTarget::DrawInfo::adjustStartIndex(int indexOffset) {
+ GrAssert(this->isIndexed());
+ fStartIndex += indexOffset;
+ GrAssert(fStartIndex >= 0);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
#define DEBUG_INVAL_BUFFER 0xdeadcafe
#define DEBUG_INVAL_START_IDX -1
@@ -338,9 +398,12 @@ bool GrDrawTarget::checkDraw(GrPrimitiveType type, int startVertex,
return true;
}
-void GrDrawTarget::drawIndexed(GrPrimitiveType type, int startVertex,
- int startIndex, int vertexCount,
- int indexCount) {
+void GrDrawTarget::drawIndexed(GrPrimitiveType type,
+ int startVertex,
+ int startIndex,
+ int vertexCount,
+ int indexCount,
+ const SkRect* devBounds) {
if (indexCount > 0 && this->checkDraw(type, startVertex, startIndex, vertexCount, indexCount)) {
DrawInfo info;
info.fPrimitiveType = type;
@@ -348,13 +411,22 @@ void GrDrawTarget::drawIndexed(GrPrimitiveType type, int startVertex,
info.fStartIndex = startIndex;
info.fVertexCount = vertexCount;
info.fIndexCount = indexCount;
+
+ info.fInstanceCount = 0;
+ info.fVerticesPerInstance = 0;
+ info.fIndicesPerInstance = 0;
+
+ if (NULL != devBounds) {
+ info.setDevBounds(*devBounds);
+ }
this->onDraw(info);
}
}
void GrDrawTarget::drawNonIndexed(GrPrimitiveType type,
int startVertex,
- int vertexCount) {
+ int vertexCount,
+ const SkRect* devBounds) {
if (vertexCount > 0 && this->checkDraw(type, startVertex, -1, vertexCount, -1)) {
DrawInfo info;
info.fPrimitiveType = type;
@@ -362,6 +434,14 @@ void GrDrawTarget::drawNonIndexed(GrPrimitiveType type,
info.fStartIndex = 0;
info.fVertexCount = vertexCount;
info.fIndexCount = 0;
+
+ info.fInstanceCount = 0;
+ info.fVerticesPerInstance = 0;
+ info.fIndicesPerInstance = 0;
+
+ if (NULL != devBounds) {
+ info.setDevBounds(*devBounds);
+ }
this->onDraw(info);
}
}
@@ -546,27 +626,43 @@ bool GrDrawTarget::canApplyCoverage() const {
void GrDrawTarget::drawIndexedInstances(GrPrimitiveType type,
int instanceCount,
int verticesPerInstance,
- int indicesPerInstance) {
+ int indicesPerInstance,
+ const SkRect* devBounds) {
if (!verticesPerInstance || !indicesPerInstance) {
return;
}
- int instancesPerDraw = this->indexCountInCurrentSource() /
- indicesPerInstance;
- if (!instancesPerDraw) {
+ int maxInstancesPerDraw = this->indexCountInCurrentSource() / indicesPerInstance;
+ if (!maxInstancesPerDraw) {
return;
}
- instancesPerDraw = GrMin(instanceCount, instancesPerDraw);
- int startVertex = 0;
+ DrawInfo info;
+ info.fPrimitiveType = type;
+ info.fStartIndex = 0;
+ info.fStartVertex = 0;
+ info.fIndicesPerInstance = indicesPerInstance;
+ info.fVerticesPerInstance = verticesPerInstance;
+
+ // Set the same bounds for all the draws.
+ if (NULL != devBounds) {
+ info.setDevBounds(*devBounds);
+ }
+
while (instanceCount) {
- this->drawIndexed(type,
- startVertex,
- 0,
- verticesPerInstance * instancesPerDraw,
- indicesPerInstance * instancesPerDraw);
- startVertex += verticesPerInstance;
- instanceCount -= instancesPerDraw;
+ info.fInstanceCount = GrMin(instanceCount, maxInstancesPerDraw);
+ info.fVertexCount = info.fInstanceCount * verticesPerInstance;
+ info.fIndexCount = info.fInstanceCount * indicesPerInstance;
+
+ if (this->checkDraw(type,
+ info.fStartVertex,
+ info.fStartIndex,
+ info.fVertexCount,
+ info.fIndexCount)) {
+ this->onDraw(info);
+ }
+ info.fStartVertex += info.fVertexCount;
+ instanceCount -= info.fInstanceCount;
}
}
@@ -576,77 +672,39 @@ void GrDrawTarget::drawRect(const GrRect& rect,
const SkMatrix* matrix,
const GrRect* srcRects[],
const SkMatrix* srcMatrices[]) {
- GrVertexLayout layout = GetRectVertexLayout(srcRects);
-
- AutoReleaseGeometry geo(this, layout, 4, 0);
- if (!geo.succeeded()) {
- GrPrintf("Failed to get space for vertices!\n");
- return;
- }
-
- SetRectVertices(rect, matrix, srcRects,
- srcMatrices, SK_ColorBLACK, layout, geo.vertices());
-
- drawNonIndexed(kTriangleFan_GrPrimitiveType, 0, 4);
-}
-
-GrVertexLayout GrDrawTarget::GetRectVertexLayout(const GrRect* srcRects[]) {
- if (NULL == srcRects) {
- return 0;
- }
-
GrVertexLayout layout = 0;
- for (int i = 0; i < GrDrawState::kNumStages; ++i) {
- int numTC = 0;
- if (NULL != srcRects[i]) {
- layout |= GrDrawState::StageTexCoordVertexLayoutBit(i, numTC);
- ++numTC;
+ uint32_t explicitCoordMask = 0;
+
+ if (NULL != srcRects) {
+ for (int s = 0; s < GrDrawState::kNumStages; ++s) {
+ int numTC = 0;
+ if (NULL != srcRects[s]) {
+ layout |= GrDrawState::StageTexCoordVertexLayoutBit(s, numTC);
+ explicitCoordMask |= (1 << s);
+ ++numTC;
+ }
}
}
- return layout;
-}
-// This method fills int the four vertices for drawing 'rect'.
-// matrix - is applied to each vertex
-// srcRects - provide the uvs for each vertex
-// srcMatrices - are applied to the corresponding 'srcRect'
-// color - vertex color (replicated in each vertex)
-// layout - specifies which uvs and/or color are present
-// vertices - storage for the resulting vertices
-// Note: the color parameter will only be used when kColor_VertexLayoutBit
-// is present in 'layout'
-void GrDrawTarget::SetRectVertices(const GrRect& rect,
- const SkMatrix* matrix,
- const GrRect* srcRects[],
- const SkMatrix* srcMatrices[],
- GrColor color,
- GrVertexLayout layout,
- void* vertices) {
-#if GR_DEBUG
- // check that the layout and srcRects agree
- for (int i = 0; i < GrDrawState::kNumStages; ++i) {
- if (GrDrawState::VertexTexCoordsForStage(i, layout) >= 0) {
- GR_DEBUGASSERT(NULL != srcRects && NULL != srcRects[i]);
- } else {
- GR_DEBUGASSERT(NULL == srcRects || NULL == srcRects[i]);
- }
+ GrDrawState::AutoViewMatrixRestore avmr;
+ if (NULL != matrix) {
+ avmr.set(this->drawState(), *matrix, explicitCoordMask);
}
-#endif
-
- int stageOffsets[GrDrawState::kNumStages], colorOffset;
- int vsize = GrDrawState::VertexSizeAndOffsetsByStage(layout, stageOffsets,
- &colorOffset, NULL, NULL);
- GrTCast<GrPoint*>(vertices)->setRectFan(rect.fLeft, rect.fTop,
- rect.fRight, rect.fBottom,
- vsize);
- if (NULL != matrix) {
- matrix->mapPointsWithStride(GrTCast<GrPoint*>(vertices), vsize, 4);
+ AutoReleaseGeometry geo(this, layout, 4, 0);
+ if (!geo.succeeded()) {
+ GrPrintf("Failed to get space for vertices!\n");
+ return;
}
+ int stageOffsets[GrDrawState::kNumStages];
+ int vsize = GrDrawState::VertexSizeAndOffsetsByStage(layout, stageOffsets, NULL, NULL, NULL);
+ geo.positions()->setRectFan(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, vsize);
+
for (int i = 0; i < GrDrawState::kNumStages; ++i) {
- if (stageOffsets[i] > 0) {
- GrPoint* coords = GrTCast<GrPoint*>(GrTCast<intptr_t>(vertices) +
+ if (explicitCoordMask & (1 << i)) {
+ GrAssert(NULL != stageOffsets[i]);
+ GrPoint* coords = GrTCast<GrPoint*>(GrTCast<intptr_t>(geo.vertices()) +
stageOffsets[i]);
coords->setRectFan(srcRects[i]->fLeft, srcRects[i]->fTop,
srcRects[i]->fRight, srcRects[i]->fBottom,
@@ -654,18 +712,12 @@ void GrDrawTarget::SetRectVertices(const GrRect& rect,
if (NULL != srcMatrices && NULL != srcMatrices[i]) {
srcMatrices[i]->mapPointsWithStride(coords, vsize, 4);
}
+ } else {
+ GrAssert(NULL == stageOffsets[i]);
}
}
- if (colorOffset >= 0) {
-
- GrColor* vertCol = GrTCast<GrColor*>(GrTCast<intptr_t>(vertices) + colorOffset);
-
- for (int i = 0; i < 4; ++i) {
- *vertCol = color;
- vertCol = (GrColor*) ((intptr_t) vertCol + vsize);
- }
- }
+ this->drawNonIndexed(kTriangleFan_GrPrimitiveType, 0, 4);
}
void GrDrawTarget::clipWillBeSet(const GrClipData* clipData) {
diff --git a/src/gpu/GrDrawTarget.h b/src/gpu/GrDrawTarget.h
index 1c8ada11f3..c1444b4f6f 100644
--- a/src/gpu/GrDrawTarget.h
+++ b/src/gpu/GrDrawTarget.h
@@ -26,7 +26,6 @@
class GrClipData;
class GrPath;
class GrVertexBuffer;
-
class SkStrokeRec;
class GrDrawTarget : public GrRefCnt {
@@ -50,6 +49,8 @@ protected:
int fMaxTextureSize;
};
+ class DrawInfo;
+
public:
SK_DECLARE_INST_COUNT(GrDrawTarget)
@@ -361,12 +362,15 @@ public:
* @param indexCount the number of index elements to read. The index count
* is effectively trimmed to the last completely
* specified primitive.
+ * @param devBounds optional bounds hint. This is a promise from the caller,
+ * not a request for clipping.
*/
void drawIndexed(GrPrimitiveType type,
int startVertex,
int startIndex,
int vertexCount,
- int indexCount);
+ int indexCount,
+ const SkRect* devBounds = NULL);
/**
* Draws non-indexed geometry using the current state and current vertex
@@ -376,10 +380,13 @@ public:
* @param startVertex the vertex in the vertex array/buffer corresponding
* to index 0
* @param vertexCount one greater than the max index.
+ * @param devBounds optional bounds hint. This is a promise from the caller,
+ * not a request for clipping.
*/
void drawNonIndexed(GrPrimitiveType type,
int startVertex,
- int vertexCount);
+ int vertexCount,
+ const SkRect* devBounds = NULL);
/**
* Draws path into the stencil buffer. The fill must be either even/odd or
@@ -393,9 +400,13 @@ public:
* and vertex sources. After returning, the vertex and index sources may
* have changed. They should be reestablished before the next drawIndexed
* or drawNonIndexed. This cannot be called between reserving and releasing
- * geometry. The GrDrawTarget subclass may be able to perform additional
- * optimizations if drawRect is used rather than drawIndexed or
- * drawNonIndexed.
+ * geometry.
+ *
+ * A subclass may override this to perform more optimal rect rendering. Its
+ * draws should be funneled through one of the public GrDrawTarget draw methods
+ * (e.g. drawNonIndexed, drawIndexedInstances, ...). The base class draws a two
+ * triangle fan using drawNonIndexed from reserved vertex space.
+ *
* @param rect the rect to draw
* @param matrix optional matrix applied to rect (before viewMatrix)
* @param srcRects specifies rects for stages enabled by stageEnableMask.
@@ -425,7 +436,6 @@ public:
this->drawRect(rect, matrix, NULL, NULL);
}
-
/**
* 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
@@ -440,7 +450,7 @@ public:
* 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
+ * draws will be issued. Moreover, when drawIndexedInstances is called
* multiple times it may be possible for GrDrawTarget to group them into a
* single GPU draw.
*
@@ -453,11 +463,14 @@ public:
* in the above description).
* @param indicesPerInstance The number of indices in each instance (I
* in the above description).
+ * @param devBounds optional bounds hint. This is a promise from the caller,
+ * not a request for clipping.
*/
- virtual void drawIndexedInstances(GrPrimitiveType type,
- int instanceCount,
- int verticesPerInstance,
- int indicesPerInstance);
+ void drawIndexedInstances(GrPrimitiveType type,
+ int instanceCount,
+ int verticesPerInstance,
+ int indicesPerInstance,
+ const SkRect* devBounds = NULL);
/**
* Clear the current render target if one isn't passed in. Ignores the
@@ -474,6 +487,11 @@ public:
*/
virtual void purgeResources() {};
+ /**
+ * For subclass internal use to invoke a call to onDraw(). See DrawInfo below.
+ */
+ void executeDraw(const DrawInfo& info) { this->onDraw(info); }
+
////////////////////////////////////////////////////////////////////////////
/**
@@ -714,48 +732,63 @@ protected:
return this->getGeomSrc().fVertexLayout;
}
- // Helpers for drawRect, protected so subclasses that override drawRect can use them.
- static GrVertexLayout GetRectVertexLayout(const GrRect* srcRects[]);
-
- static void SetRectVertices(const GrRect& rect,
- const SkMatrix* matrix,
- const GrRect* srcRects[],
- const SkMatrix* srcMatrices[],
- GrColor color,
- GrVertexLayout layout,
- void* vertices);
-
Caps fCaps;
+ /**
+ * Used to communicate draws to subclass's onDraw function.
+ */
class DrawInfo {
public:
DrawInfo(const DrawInfo& di) { (*this) = di; }
- DrawInfo& operator =(const DrawInfo& di) {
- fPrimitiveType = di.fPrimitiveType;
- fStartVertex = di.fStartVertex;
- fStartIndex = di.fStartIndex;
- fVertexCount = di.fVertexCount;
- fIndexCount = di.fIndexCount;
- return *this;
- }
+ DrawInfo& operator =(const DrawInfo& di);
GrPrimitiveType primitiveType() const { return fPrimitiveType; }
int startVertex() const { return fStartVertex; }
int startIndex() const { return fStartIndex; }
int vertexCount() const { return fVertexCount; }
int indexCount() const { return fIndexCount; }
+ int verticesPerInstance() const { return fVerticesPerInstance; }
+ int indicesPerInstance() const { return fIndicesPerInstance; }
+ int instanceCount() const { return fInstanceCount; }
bool isIndexed() const { return fIndexCount > 0; }
+#if GR_DEBUG
+ bool isInstanced() const; // this version is longer because of asserts
+#else
+ bool isInstanced() const { return fInstanceCount > 0; }
+#endif
+
+ // adds or remove instances
+ void adjustInstanceCount(int instanceOffset);
+ // shifts the start vertex
+ void adjustStartVertex(int vertexOffset);
+ // shifts the start index
+ void adjustStartIndex(int indexOffset);
+
+ void setDevBounds(const SkRect& bounds) {
+ fDevBoundsStorage = bounds;
+ fDevBounds = &fDevBoundsStorage;
+ }
+ const SkRect* getDevBounds() const { return fDevBounds; }
private:
- DrawInfo() {}
+ DrawInfo() { fDevBounds = NULL; }
+
friend class GrDrawTarget;
+
GrPrimitiveType fPrimitiveType;
int fStartVertex;
int fStartIndex;
int fVertexCount;
int fIndexCount;
+
+ int fInstanceCount;
+ int fVerticesPerInstance;
+ int fIndicesPerInstance;
+
+ SkRect fDevBoundsStorage;
+ SkRect* fDevBounds;
};
private:
diff --git a/src/gpu/GrInOrderDrawBuffer.cpp b/src/gpu/GrInOrderDrawBuffer.cpp
index a0e3e99fe7..bc605fd2bb 100644
--- a/src/gpu/GrInOrderDrawBuffer.cpp
+++ b/src/gpu/GrInOrderDrawBuffer.cpp
@@ -21,13 +21,12 @@ GrInOrderDrawBuffer::GrInOrderDrawBuffer(const GrGpu* gpu,
GrIndexBufferAllocPool* indexPool)
: fAutoFlushTarget(NULL)
, fClipSet(true)
+ , fClipProxyState(kUnknown_ClipProxyState)
, fVertexPool(*vertexPool)
, fIndexPool(*indexPool)
- , fLastRectVertexLayout(0)
- , fQuadIndexBuffer(NULL)
- , fMaxQuads(0)
, fFlushing(false) {
+ fGpu.reset(SkRef(gpu));
fCaps = gpu->getCaps();
GrAssert(NULL != vertexPool);
@@ -49,29 +48,26 @@ GrInOrderDrawBuffer::~GrInOrderDrawBuffer() {
this->reset();
// This must be called by before the GrDrawTarget destructor
this->releaseGeometry();
- GrSafeUnref(fQuadIndexBuffer);
GrSafeUnref(fAutoFlushTarget);
}
-void GrInOrderDrawBuffer::setQuadIndexBuffer(const GrIndexBuffer* indexBuffer) {
- bool newIdxBuffer = fQuadIndexBuffer != indexBuffer;
- if (newIdxBuffer) {
- GrSafeUnref(fQuadIndexBuffer);
- fQuadIndexBuffer = indexBuffer;
- GrSafeRef(fQuadIndexBuffer);
- fCurrQuad = 0;
- fMaxQuads = (NULL == indexBuffer) ? 0 : indexBuffer->maxQuads();
- } else {
- GrAssert((NULL == indexBuffer && 0 == fMaxQuads) ||
- (indexBuffer->maxQuads() == fMaxQuads));
- }
-}
-
////////////////////////////////////////////////////////////////////////////////
-void GrInOrderDrawBuffer::resetDrawTracking() {
- fCurrQuad = 0;
- fInstancedDrawTracker.reset();
+namespace {
+void get_vertex_bounds(const void* vertices,
+ size_t vertexSize,
+ int vertexCount,
+ SkRect* bounds) {
+ GrAssert(vertexSize >= sizeof(GrPoint));
+ GrAssert(vertexCount > 0);
+ const GrPoint* point = static_cast<const GrPoint*>(vertices);
+ bounds->fLeft = bounds->fRight = point->fX;
+ bounds->fTop = bounds->fBottom = point->fY;
+ for (int i = 1; i < vertexCount; ++i) {
+ point = reinterpret_cast<GrPoint*>(reinterpret_cast<intptr_t>(point) + vertexSize);
+ bounds->growToInclude(point->fX, point->fY);
+ }
+}
}
void GrInOrderDrawBuffer::drawRect(const GrRect& rect,
@@ -79,305 +75,223 @@ void GrInOrderDrawBuffer::drawRect(const GrRect& rect,
const GrRect* srcRects[],
const SkMatrix* srcMatrices[]) {
- GrAssert(!(NULL == fQuadIndexBuffer && fCurrQuad));
- GrAssert(!(fDraws.empty() && fCurrQuad));
- GrAssert(!(0 != fMaxQuads && NULL == fQuadIndexBuffer));
-
- GrDrawState* drawState = this->drawState();
-
- // if we have a quad IB then either append to the previous run of
- // rects or start a new run
- if (fMaxQuads) {
-
- bool appendToPreviousDraw = false;
- GrVertexLayout layout = GetRectVertexLayout(srcRects);
-
- // Batching across colors means we move the draw color into the
- // rect's vertex colors to allow greater batching (a lot of rects
- // in a row differing only in color is a common occurence in tables).
- bool batchAcrossColors = true;
- if (!this->getCaps().dualSourceBlendingSupport()) {
- for (int s = 0; s < GrDrawState::kNumStages; ++s) {
- if (this->getDrawState().isStageEnabled(s)) {
- // We disable batching across colors when there is a texture
- // present because (by pushing the the color to the vertices)
- // Ganesh loses track of the rect's opacity. This, in turn, can
- // cause some of the blending optimizations to be disabled. This
- // becomes a huge problem on some of the smaller devices where
- // shader derivatives and dual source blending aren't supported.
- // In those cases paths are often drawn to a texture and then
- // drawn as a texture (using this method). Because dual source
- // blending is disabled (and the blend optimizations are short
- // circuited) some of the more esoteric blend modes can no longer
- // be supported.
- // TODO: add tracking of batchAcrossColors's opacity
- batchAcrossColors = false;
- break;
- }
+ GrVertexLayout layout = 0;
+ GrDrawState::AutoColorRestore acr;
+ GrColor color = this->drawState()->getColor();
+
+ // Using per-vertex colors allows batching across colors. (A lot of rects in a row differing
+ // only in color is a common occurrence in tables). However, having per-vertex colors disables
+ // blending optimizations because we don't know if the color will be solid or not. These
+ // optimizations help determine whether coverage and color can be blended correctly when
+ // dual-source blending isn't available. This comes into play when there is coverage. If colors
+ // were a stage it could take a hint that every vertex's color will be opaque.
+ if (this->getCaps().dualSourceBlendingSupport() ||
+ this->getDrawState().hasSolidCoverage(this->getGeomSrc().fVertexLayout)) {
+ layout |= GrDrawState::kColor_VertexLayoutBit;;
+ // We set the draw state's color to white here. This is done so that any batching performed
+ // in our subclass's onDraw() won't get a false from GrDrawState::op== due to a color
+ // mismatch. TODO: Once vertex layout is owned by GrDrawState it should skip comparing the
+ // constant color in its op== when the kColor layout bit is set and then we can remove this.
+ acr.set(this->drawState(), 0xFFFFFFFF);
+ }
+
+ uint32_t explicitCoordMask = 0;
+ if (NULL != srcRects) {
+ for (int s = 0; s < GrDrawState::kNumStages; ++s) {
+ int numTC = 0;
+ if (NULL != srcRects[s]) {
+ layout |= GrDrawState::StageTexCoordVertexLayoutBit(s, numTC);
+ ++numTC;
+ explicitCoordMask |= (1 << s);
}
}
+ }
- if (batchAcrossColors) {
- layout |= GrDrawState::kColor_VertexLayoutBit;
- }
+ AutoReleaseGeometry geo(this, layout, 4, 0);
+ if (!geo.succeeded()) {
+ GrPrintf("Failed to get space for vertices!\n");
+ return;
+ }
- AutoReleaseGeometry geo(this, layout, 4, 0);
- if (!geo.succeeded()) {
- GrPrintf("Failed to get space for vertices!\n");
- return;
- }
- SkMatrix combinedMatrix = drawState->getViewMatrix();
- // We go to device space so that matrix changes allow us to concat
- // rect draws. When the caller has provided explicit source rects
- // then we don't want to modify the stages' matrices. Otherwise
- // we have to account for the view matrix change in the stage
- // matrices.
- uint32_t explicitCoordMask = 0;
- if (srcRects) {
- for (int s = 0; s < GrDrawState::kNumStages; ++s) {
- if (srcRects[s]) {
- explicitCoordMask |= (1 << s);
- }
+ // Go to device coords to allow batching across matrix changes
+ SkMatrix combinedMatrix;
+ if (NULL != matrix) {
+ combinedMatrix = *matrix;
+ } else {
+ combinedMatrix.reset();
+ }
+ combinedMatrix.postConcat(this->drawState()->getViewMatrix());
+ // When the caller has provided an explicit source rects for a stage then we don't want to
+ // modify that stage's matrix. Otherwise if the effect is generating its source rect from
+ // the vertex positions then we have to account for the view matrix change.
+ GrDrawState::AutoDeviceCoordDraw adcd(this->drawState(), explicitCoordMask);
+ if (!adcd.succeeded()) {
+ return;
+ }
+
+ int stageOffsets[GrDrawState::kNumStages], colorOffset;
+ int vsize = GrDrawState::VertexSizeAndOffsetsByStage(layout, stageOffsets,
+ &colorOffset, NULL, NULL);
+
+ geo.positions()->setRectFan(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, vsize);
+ combinedMatrix.mapPointsWithStride(geo.positions(), vsize, 4);
+
+ SkRect devBounds;
+ // since we already computed the dev verts, set the bounds hint. This will help us avoid
+ // unnecessary clipping in our onDraw().
+ get_vertex_bounds(geo.vertices(), vsize, 4, &devBounds);
+
+ for (int i = 0; i < GrDrawState::kNumStages; ++i) {
+ if (explicitCoordMask & (1 << i)) {
+ GrAssert(NULL != stageOffsets[i]);
+ GrPoint* coords = GrTCast<GrPoint*>(GrTCast<intptr_t>(geo.vertices()) +
+ stageOffsets[i]);
+ coords->setRectFan(srcRects[i]->fLeft, srcRects[i]->fTop,
+ srcRects[i]->fRight, srcRects[i]->fBottom,
+ vsize);
+ if (NULL != srcMatrices && NULL != srcMatrices[i]) {
+ srcMatrices[i]->mapPointsWithStride(coords, vsize, 4);
}
+ } else {
+ GrAssert(NULL == stageOffsets[i]);
}
- GrDrawState::AutoDeviceCoordDraw adcd(this->drawState(), explicitCoordMask);
- if (!adcd.succeeded()) {
- return;
- }
- if (NULL != matrix) {
- combinedMatrix.preConcat(*matrix);
- }
-
- SetRectVertices(rect, &combinedMatrix, srcRects, srcMatrices,
- this->getDrawState().getColor(), layout, geo.vertices());
-
- // Now that the paint's color is stored in the vertices set it to
- // white so that the following code can batch all the rects regardless
- // of paint color
- GrDrawState::AutoColorRestore acr(this->drawState(),
- batchAcrossColors ? SK_ColorWHITE
- : this->getDrawState().getColor());
+ }
- // we don't want to miss an opportunity to batch rects together
- // simply because the clip has changed if the clip doesn't affect
- // the rect.
- bool disabledClip = false;
+ if (colorOffset >= 0) {
+ GrColor* vertColor = GrTCast<GrColor*>(GrTCast<intptr_t>(geo.vertices()) + colorOffset);
+ for (int i = 0; i < 4; ++i) {
+ *vertColor = color;
+ vertColor = (GrColor*) ((intptr_t) vertColor + vsize);
+ }
+ }
- if (drawState->isClipState()) {
+ this->setIndexSourceToBuffer(fGpu->getQuadIndexBuffer());
+ this->drawIndexedInstances(kTriangles_GrPrimitiveType, 1, 4, 6, &devBounds);
+}
- GrRect devClipRect;
- bool isIntersectionOfRects = false;
- const GrClipData* clip = this->getClip();
- clip->fClipStack->getConservativeBounds(-clip->fOrigin.fX,
- -clip->fOrigin.fY,
- drawState->getRenderTarget()->width(),
- drawState->getRenderTarget()->height(),
- &devClipRect,
- &isIntersectionOfRects);
-
- if (isIntersectionOfRects) {
- // If the clip rect touches the edge of the viewport, extended it
- // out (close) to infinity to avoid bogus intersections.
- // We might consider a more exact clip to viewport if this
- // conservative test fails.
- const GrRenderTarget* target = drawState->getRenderTarget();
- if (0 >= devClipRect.fLeft) {
- devClipRect.fLeft = SK_ScalarMin;
- }
- if (target->width() <= devClipRect.fRight) {
- devClipRect.fRight = SK_ScalarMax;
- }
- if (0 >= devClipRect.top()) {
- devClipRect.fTop = SK_ScalarMin;
- }
- if (target->height() <= devClipRect.fBottom) {
- devClipRect.fBottom = SK_ScalarMax;
- }
- int stride = GrDrawState::VertexSize(layout);
- bool insideClip = true;
- for (int v = 0; v < 4; ++v) {
- const GrPoint& p = *GrDrawState::GetVertexPoint(geo.vertices(), v, stride);
- if (!devClipRect.contains(p)) {
- insideClip = false;
- break;
- }
- }
- if (insideClip) {
- drawState->disableState(GrDrawState::kClip_StateBit);
- disabledClip = true;
- }
+bool GrInOrderDrawBuffer::quickInsideClip(const SkRect& devBounds) {
+ if (!this->getDrawState().isClipState()) {
+ return true;
+ }
+ if (kUnknown_ClipProxyState == fClipProxyState) {
+ SkIRect rect;
+ bool iior;
+ this->getClip()->getConservativeBounds(this->getDrawState().getRenderTarget(), &rect, &iior);
+ if (iior) {
+ // The clip is a rect. We will remember that in fProxyClip. It is common for an edge (or
+ // all edges) of the clip to be at the edge of the RT. However, we get that clipping for
+ // free via the viewport. We don't want to think that clipping must be enabled in this
+ // case. So we extend the clip outward from the edge to avoid these false negatives.
+ fClipProxyState = kValid_ClipProxyState;
+ fClipProxy = SkRect::MakeFromIRect(rect);
+
+ if (fClipProxy.fLeft <= 0) {
+ fClipProxy.fLeft = SK_ScalarMin;
}
- }
-
- if (!this->needsNewClip() &&
- !this->needsNewState() &&
- fCurrQuad > 0 &&
- fCurrQuad < fMaxQuads &&
- layout == fLastRectVertexLayout) {
-
- int vsize = GrDrawState::VertexSize(layout);
-
- DrawRecord& lastDraw = fDraws.back();
-
- GrAssert(lastDraw.fIndexBuffer == fQuadIndexBuffer);
- GrAssert(kTriangles_GrPrimitiveType == lastDraw.fPrimitiveType);
- GrAssert(0 == lastDraw.fVertexCount % 4);
- GrAssert(0 == lastDraw.fIndexCount % 6);
- GrAssert(0 == lastDraw.fStartIndex);
-
- GeometryPoolState& poolState = fGeoPoolStateStack.back();
-
- appendToPreviousDraw = kDraw_Cmd == fCmds.back() &&
- lastDraw.fVertexBuffer == poolState.fPoolVertexBuffer &&
- (fCurrQuad * 4 + lastDraw.fStartVertex) ==
- poolState.fPoolStartVertex;
-
- if (appendToPreviousDraw) {
- lastDraw.fVertexCount += 4;
- lastDraw.fIndexCount += 6;
- fCurrQuad += 1;
- // we reserved above, so we should be the first
- // use of this vertex reservation.
- GrAssert(0 == poolState.fUsedPoolVertexBytes);
- poolState.fUsedPoolVertexBytes = 4 * vsize;
+ if (fClipProxy.fTop <= 0) {
+ fClipProxy.fTop = SK_ScalarMin;
}
+ if (fClipProxy.fRight >= this->getDrawState().getRenderTarget()->width()) {
+ fClipProxy.fRight = SK_ScalarMax;
+ }
+ if (fClipProxy.fBottom >= this->getDrawState().getRenderTarget()->height()) {
+ fClipProxy.fBottom = SK_ScalarMax;
+ }
+ } else {
+ fClipProxyState = kInvalid_ClipProxyState;
}
- if (!appendToPreviousDraw) {
- this->setIndexSourceToBuffer(fQuadIndexBuffer);
- this->drawIndexed(kTriangles_GrPrimitiveType, 0, 0, 4, 6);
- fCurrQuad = 1;
- fLastRectVertexLayout = layout;
- }
- if (disabledClip) {
- drawState->enableState(GrDrawState::kClip_StateBit);
- }
- fInstancedDrawTracker.reset();
- } else {
- INHERITED::drawRect(rect, matrix, srcRects, srcMatrices);
}
+ if (kValid_ClipProxyState == fClipProxyState) {
+ return fClipProxy.contains(devBounds);
+ }
+ SkPoint originOffset = {SkIntToScalar(this->getClip()->fOrigin.fX),
+ SkIntToScalar(this->getClip()->fOrigin.fY)};
+ SkRect clipSpaceBounds = devBounds;
+ clipSpaceBounds.offset(originOffset);
+ return this->getClip()->fClipStack->quickContains(clipSpaceBounds);
}
-void GrInOrderDrawBuffer::drawIndexedInstances(GrPrimitiveType type,
- int instanceCount,
- int verticesPerInstance,
- int indicesPerInstance) {
- if (!verticesPerInstance || !indicesPerInstance) {
- return;
- }
+int GrInOrderDrawBuffer::concatInstancedDraw(const DrawInfo& info) {
+ GrAssert(info.isInstanced());
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) {
+ // we only attempt to concat the case when reserved verts are used with a client-specified index
+ // buffer. To make this work with client-specified VBs we'd need to know if the VB was updated
+ // between draws.
+ if (kReserved_GeometrySrcType != geomSrc.fVertexSrc ||
+ kBuffer_GeometrySrcType != geomSrc.fIndexSrc) {
+ return 0;
+ }
+ // Check if there is a draw info that is compatible that uses the same VB from the pool and
+ // the same IB
+ if (kDraw_Cmd != fCmds.back()) {
+ return 0;
+ }
- if (this->needsNewClip()) {
- this->recordClip();
- }
- if (this->needsNewState()) {
- this->recordState();
- }
+ DrawRecord* draw = &fDraws.back();
+ GeometryPoolState& poolState = fGeoPoolStateStack.back();
+ const GrVertexBuffer* vertexBuffer = poolState.fPoolVertexBuffer;
+
+ if (!draw->isInstanced() ||
+ draw->verticesPerInstance() != info.verticesPerInstance() ||
+ draw->indicesPerInstance() != info.indicesPerInstance() ||
+ draw->fVertexBuffer != vertexBuffer ||
+ draw->fIndexBuffer != geomSrc.fIndexBuffer ||
+ draw->fVertexLayout != geomSrc.fVertexLayout) {
+ return 0;
+ }
+ // info does not yet account for the offset from the start of the pool's VB while the previous
+ // draw record does.
+ int adjustedStartVertex = poolState.fPoolStartVertex + info.startVertex();
+ if (draw->startVertex() + draw->vertexCount() != adjustedStartVertex) {
+ return 0;
+ }
- DrawRecord* draw = NULL;
- // if the last draw used the same indices/vertices per shape then we
- // may be able to append to it.
- if (kDraw_Cmd == fCmds.back() &&
- verticesPerInstance == fInstancedDrawTracker.fVerticesPerInstance &&
- indicesPerInstance == fInstancedDrawTracker.fIndicesPerInstance) {
- GrAssert(fDraws.count());
- draw = &fDraws.back();
- }
+ GrAssert(poolState.fPoolStartVertex == draw->startVertex() + draw->vertexCount());
- 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 ||
- draw->fIndexBuffer != geomSrc.fIndexBuffer ||
- draw->fPrimitiveType != type ||
- draw->fVertexBuffer != vertexBuffer) {
-
- draw = this->recordDraw();
- draw->fPrimitiveType = type;
- draw->fStartVertex = poolState.fPoolStartVertex;
- draw->fStartIndex = 0;
- draw->fVertexCount = 0;
- draw->fIndexCount = 0;
- draw->fVertexLayout = geomSrc.fVertexLayout;
- draw->fVertexBuffer = vertexBuffer;
- vertexBuffer->ref();
- draw->fIndexBuffer = geomSrc.fIndexBuffer;
- geomSrc.fIndexBuffer->ref();
- } else {
- GrAssert(!(draw->fIndexCount % indicesPerInstance));
- GrAssert(!(draw->fVertexCount % verticesPerInstance));
- GrAssert(poolState.fPoolStartVertex == draw->fStartVertex +
- draw->fVertexCount);
- }
+ // how many instances can be concat'ed onto draw given the size of the index buffer
+ int instancesToConcat = this->indexCountInCurrentSource() / info.indicesPerInstance();
+ instancesToConcat -= draw->instanceCount();
+ instancesToConcat = GrMin(instancesToConcat, info.instanceCount());
- // 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 vertex data actually referenced in draws
+ size_t vertexBytes = instancesToConcat * info.verticesPerInstance() *
+ GrDrawState::VertexSize(draw->fVertexLayout);
+ poolState.fUsedPoolVertexBytes = GrMax(poolState.fUsedPoolVertexBytes, vertexBytes);
- // update the amount of reserved data actually referenced in draws
- size_t vertexBytes = instanceCount * verticesPerInstance *
- GrDrawState::VertexSize(draw->fVertexLayout);
- poolState.fUsedPoolVertexBytes =
- GrMax(poolState.fUsedPoolVertexBytes, vertexBytes);
-
- while (instanceCount) {
- if (!instancesToConcat) {
- int startVertex = draw->fStartVertex + draw->fVertexCount;
- draw = this->recordDraw();
- draw->fPrimitiveType = type;
- draw->fStartVertex = startVertex;
- draw->fStartIndex = 0;
- draw->fVertexCount = 0;
- draw->fIndexCount = 0;
- draw->fVertexLayout = geomSrc.fVertexLayout;
- draw->fVertexBuffer = vertexBuffer;
- vertexBuffer->ref();
- draw->fIndexBuffer = geomSrc.fIndexBuffer;
- geomSrc.fIndexBuffer->ref();
- instancesToConcat = maxInstancesPerDraw;
- }
- draw->fVertexCount += instancesToConcat * verticesPerInstance;
- draw->fIndexCount += instancesToConcat * indicesPerInstance;
- instanceCount -= instancesToConcat;
- instancesToConcat = 0;
- }
+ draw->adjustInstanceCount(instancesToConcat);
+ return instancesToConcat;
+}
- // update draw tracking for next draw
- fCurrQuad = 0;
- fInstancedDrawTracker.fVerticesPerInstance = verticesPerInstance;
- fInstancedDrawTracker.fIndicesPerInstance = indicesPerInstance;
- } else {
- this->INHERITED::drawIndexedInstances(type,
- instanceCount,
- verticesPerInstance,
- indicesPerInstance);
+class AutoClipReenable {
+public:
+ AutoClipReenable() : fDrawState(NULL) {}
+ ~AutoClipReenable() {
+ if (NULL != fDrawState) {
+ fDrawState->enableState(GrDrawState::kClip_StateBit);
+ }
}
-}
+ void set(GrDrawState* drawState) {
+ if (drawState->isClipState()) {
+ fDrawState = drawState;
+ drawState->disableState(GrDrawState::kClip_StateBit);
+ }
+ }
+private:
+ GrDrawState* fDrawState;
+};
void GrInOrderDrawBuffer::onDraw(const DrawInfo& info) {
- this->resetDrawTracking();
-
GeometryPoolState& poolState = fGeoPoolStateStack.back();
+ AutoClipReenable acr;
+
+ if (this->getDrawState().isClipState() &&
+ NULL != info.getDevBounds() &&
+ this->quickInsideClip(*info.getDevBounds())) {
+ acr.set(this->drawState());
+ }
if (this->needsNewClip()) {
this->recordClip();
@@ -386,7 +300,18 @@ void GrInOrderDrawBuffer::onDraw(const DrawInfo& info) {
this->recordState();
}
- DrawRecord* draw = this->recordDraw(info);
+ DrawRecord* draw;
+ if (info.isInstanced()) {
+ int instancesConcated = this->concatInstancedDraw(info);
+ if (info.instanceCount() > instancesConcated) {
+ draw = this->recordDraw(info);
+ draw->adjustInstanceCount(-instancesConcated);
+ } else {
+ return;
+ }
+ } else {
+ draw = this->recordDraw(info);
+ }
draw->fVertexLayout = this->getVertexLayout();
switch (this->getGeomSrc().fVertexSrc) {
@@ -399,7 +324,7 @@ void GrInOrderDrawBuffer::onDraw(const DrawInfo& info) {
GrDrawState::VertexSize(draw->fVertexLayout);
poolState.fUsedPoolVertexBytes = GrMax(poolState.fUsedPoolVertexBytes, vertexBytes);
draw->fVertexBuffer = poolState.fPoolVertexBuffer;
- draw->fStartVertex += poolState.fPoolStartVertex;
+ draw->adjustStartVertex(poolState.fPoolStartVertex);
break;
}
default:
@@ -417,7 +342,7 @@ void GrInOrderDrawBuffer::onDraw(const DrawInfo& info) {
size_t indexBytes = (info.indexCount() + info.startIndex()) * sizeof(uint16_t);
poolState.fUsedPoolIndexBytes = GrMax(poolState.fUsedPoolIndexBytes, indexBytes);
draw->fIndexBuffer = poolState.fPoolIndexBuffer;
- draw->fStartIndex += poolState.fPoolStartIndex;
+ draw->adjustStartIndex(poolState.fPoolStartIndex);
break;
}
default:
@@ -429,7 +354,6 @@ void GrInOrderDrawBuffer::onDraw(const DrawInfo& info) {
}
}
-
GrInOrderDrawBuffer::StencilPath::StencilPath() : fStroke(SkStrokeRec::kFill_InitStyle) {}
void GrInOrderDrawBuffer::onStencilPath(const GrPath* path, const SkStrokeRec& stroke,
@@ -448,9 +372,7 @@ void GrInOrderDrawBuffer::onStencilPath(const GrPath* path, const SkStrokeRec& s
sp->fStroke = stroke;
}
-void GrInOrderDrawBuffer::clear(const GrIRect* rect,
- GrColor color,
- GrRenderTarget* renderTarget) {
+void GrInOrderDrawBuffer::clear(const GrIRect* rect, GrColor color, GrRenderTarget* renderTarget) {
GrIRect r;
if (NULL == renderTarget) {
renderTarget = this->drawState()->getRenderTarget();
@@ -491,8 +413,6 @@ void GrInOrderDrawBuffer::reset() {
fClips.reset();
fClipOrigins.reset();
fClipSet = true;
-
- this->resetDrawTracking();
}
bool GrInOrderDrawBuffer::flushTo(GrDrawTarget* target) {
@@ -532,21 +452,11 @@ bool GrInOrderDrawBuffer::flushTo(GrDrawTarget* target) {
case kDraw_Cmd: {
const DrawRecord& draw = fDraws[currDraw];
target->setVertexSourceToBuffer(draw.fVertexLayout, draw.fVertexBuffer);
- if (draw.fIndexCount) {
+ if (draw.isIndexed()) {
target->setIndexSourceToBuffer(draw.fIndexBuffer);
}
+ target->executeDraw(draw);
- if (draw.fIndexCount) {
- target->drawIndexed(draw.fPrimitiveType,
- draw.fStartVertex,
- draw.fStartIndex,
- draw.fVertexCount,
- draw.fIndexCount);
- } else {
- target->drawNonIndexed(draw.fPrimitiveType,
- draw.fStartVertex,
- draw.fVertexCount);
- }
++currDraw;
break;
}
@@ -774,7 +684,6 @@ 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;
@@ -802,7 +711,6 @@ void GrInOrderDrawBuffer::geometrySourceWillPop(
poolState.fUsedPoolIndexBytes = sizeof(uint16_t) *
restoredState.fIndexCount;
}
- this->resetDrawTracking();
}
bool GrInOrderDrawBuffer::needsNewState() const {
@@ -834,19 +742,9 @@ void GrInOrderDrawBuffer::recordState() {
fCmds.push_back(kSetState_Cmd);
}
-GrInOrderDrawBuffer::DrawRecord* GrInOrderDrawBuffer::recordDraw() {
- fCmds.push_back(kDraw_Cmd);
- return &fDraws.push_back();
-}
-
GrInOrderDrawBuffer::DrawRecord* GrInOrderDrawBuffer::recordDraw(const DrawInfo& info) {
- DrawRecord* record = this->recordDraw();
- record->fPrimitiveType = info.primitiveType();
- record->fStartVertex = info.startVertex();
- record->fVertexCount = info.vertexCount();
- record->fStartIndex = info.startIndex();
- record->fIndexCount = info.indexCount();
- return record;
+ fCmds.push_back(kDraw_Cmd);
+ return &fDraws.push_back(info);
}
GrInOrderDrawBuffer::StencilPath* GrInOrderDrawBuffer::recordStencilPath() {
@@ -862,4 +760,5 @@ GrInOrderDrawBuffer::Clear* GrInOrderDrawBuffer::recordClear() {
void GrInOrderDrawBuffer::clipWillBeSet(const GrClipData* newClipData) {
INHERITED::clipWillBeSet(newClipData);
fClipSet = true;
+ fClipProxyState = kUnknown_ClipProxyState;
}
diff --git a/src/gpu/GrInOrderDrawBuffer.h b/src/gpu/GrInOrderDrawBuffer.h
index 21011c9650..daa5d06886 100644
--- a/src/gpu/GrInOrderDrawBuffer.h
+++ b/src/gpu/GrInOrderDrawBuffer.h
@@ -55,13 +55,6 @@ public:
virtual ~GrInOrderDrawBuffer();
/**
- * Provides the buffer with an index buffer that can be used for quad rendering.
- * The buffer may be able to batch consecutive drawRects if this is provided.
- * @param indexBuffer index buffer with quad indices.
- */
- void setQuadIndexBuffer(const GrIndexBuffer* indexBuffer);
-
- /**
* Empties the draw buffer of any queued up draws. This must not be called while inside an
* unbalanced pushGeometrySource(). The current draw state and clip are preserved.
*/
@@ -89,24 +82,16 @@ public:
void setAutoFlushTarget(GrDrawTarget* target);
// overrides from GrDrawTarget
- virtual void drawRect(const GrRect& rect,
- const SkMatrix* matrix = NULL,
- const GrRect* srcRects[] = NULL,
- const SkMatrix* srcMatrices[] = NULL) SK_OVERRIDE;
-
- virtual void drawIndexedInstances(GrPrimitiveType type,
- int instanceCount,
- int verticesPerInstance,
- int indicesPerInstance)
- SK_OVERRIDE;
-
virtual bool geometryHints(size_t vertexSize,
int* vertexCount,
int* indexCount) const SK_OVERRIDE;
-
virtual void clear(const GrIRect* rect,
GrColor color,
GrRenderTarget* renderTarget = NULL) SK_OVERRIDE;
+ virtual void drawRect(const GrRect& rect,
+ const SkMatrix* matrix,
+ const GrRect* srcRects[],
+ const SkMatrix* srcMatrices[]) SK_OVERRIDE;
protected:
virtual void clipWillBeSet(const GrClipData* newClip) SK_OVERRIDE;
@@ -120,13 +105,9 @@ private:
kClear_Cmd = 5,
};
- // TODO: Make this derive from DrawInfo
- struct DrawRecord {
- GrPrimitiveType fPrimitiveType;
- int fStartVertex;
- int fStartIndex;
- int fVertexCount;
- int fIndexCount;
+ class DrawRecord : public DrawInfo {
+ public:
+ DrawRecord(const DrawInfo& info) : DrawInfo(info) {}
GrVertexLayout fVertexLayout;
const GrVertexBuffer* fVertexBuffer;
const GrIndexBuffer* fIndexBuffer;
@@ -170,25 +151,24 @@ private:
virtual void willReserveVertexAndIndexSpace(size_t vertexSize,
int vertexCount,
int indexCount) SK_OVERRIDE;
+ bool quickInsideClip(const SkRect& devBounds);
+ // Attempts to concat instances from info onto the previous draw. info must represent an
+ // instanced draw. The caller must have already recorded a new draw state and clip if necessary.
+ int concatInstancedDraw(const DrawInfo& info);
- // we lazily record state and clip changes in order to skip clips and states
- // that have no effect.
+ // we lazily record state and clip changes in order to skip clips and states that have no
+ // effect.
bool needsNewState() const;
bool needsNewClip() const;
// these functions record a command
void recordState();
void recordClip();
- DrawRecord* recordDraw();
DrawRecord* recordDraw(const DrawInfo&);
StencilPath* recordStencilPath();
Clear* recordClear();
- // call this to invalidate the tracking data that is used to concatenate
- // multiple draws into a single draw.
- void resetDrawTracking();
-
enum {
kCmdPreallocCnt = 32,
kDrawPreallocCnt = 8,
@@ -199,6 +179,8 @@ private:
kGeoPoolStatePreAllocCnt = 4,
};
+ SkAutoTUnref<const GrGpu> fGpu;
+
SkSTArray<kCmdPreallocCnt, uint8_t, true> fCmds;
GrSTAllocator<kDrawPreallocCnt, DrawRecord> fDraws;
GrSTAllocator<kStatePreallocCnt, StencilPath> fStencilPaths;
@@ -212,26 +194,18 @@ private:
bool fClipSet;
+ enum ClipProxyState {
+ kUnknown_ClipProxyState,
+ kValid_ClipProxyState,
+ kInvalid_ClipProxyState
+ };
+ ClipProxyState fClipProxyState;
+ SkRect fClipProxy;
+
GrVertexBufferAllocPool& fVertexPool;
GrIndexBufferAllocPool& fIndexPool;
- // these are used to attempt to concatenate drawRect calls
- GrVertexLayout fLastRectVertexLayout;
- const GrIndexBuffer* fQuadIndexBuffer;
- int fMaxQuads;
- int fCurrQuad;
-
- // bookkeeping to attempt to concatenate drawIndexedInstances calls
- struct {
- int fVerticesPerInstance;
- int fIndicesPerInstance;
- void reset() {
- fVerticesPerInstance = 0;
- fIndicesPerInstance = 0;
- }
- } fInstancedDrawTracker;
-
struct GeometryPoolState {
const GrVertexBuffer* fPoolVertexBuffer;
int fPoolStartVertex;