Index: src/gpu/GrAAHairLinePathRenderer.cpp |
diff --git a/src/gpu/GrAAHairLinePathRenderer.cpp b/src/gpu/GrAAHairLinePathRenderer.cpp |
index f046af871f5ef1dab82218130e02defc63480e67..ad6550072d796609526880b4829f986509f658f5 100644 |
--- a/src/gpu/GrAAHairLinePathRenderer.cpp |
+++ b/src/gpu/GrAAHairLinePathRenderer.cpp |
@@ -14,19 +14,17 @@ |
#include "GrContext.h" |
#include "GrDefaultGeoProcFactory.h" |
#include "GrDrawTargetCaps.h" |
+#include "GrGpu.h" |
#include "GrIndexBuffer.h" |
#include "GrPathUtils.h" |
#include "GrPipelineBuilder.h" |
#include "GrProcessor.h" |
-#include "GrResourceProvider.h" |
#include "GrVertexBuffer.h" |
#include "SkGeometry.h" |
#include "SkStroke.h" |
#include "SkTemplates.h" |
#include "effects/GrBezierEffect.h" |
- |
-#define PREALLOC_PTARRAY(N) SkSTArray<(N),SkPoint, true> |
// quadratics are rendered as 5-sided polys in order to bound the |
// AA stroke around the center-curve. See comments in push_quad_index_buffer and |
@@ -63,14 +61,6 @@ |
static const int kIdxsPerQuad = SK_ARRAY_COUNT(kQuadIdxBufPattern); |
static const int kQuadNumVertices = 5; |
static const int kQuadsNumInIdxBuffer = 256; |
-GR_DECLARE_STATIC_UNIQUE_KEY(gQuadsIndexBufferKey); |
- |
-static const GrIndexBuffer* ref_quads_index_buffer(GrResourceProvider* resourceProvider) { |
- GR_DEFINE_STATIC_UNIQUE_KEY(gQuadsIndexBufferKey); |
- return resourceProvider->refOrCreateInstancedIndexBuffer( |
- kQuadIdxBufPattern, kIdxsPerQuad, kQuadsNumInIdxBuffer, kQuadNumVertices, |
- gQuadsIndexBufferKey); |
-} |
// Each line segment is rendered as two quads and two triangles. |
@@ -97,17 +87,43 @@ |
static const int kLineSegNumVertices = 6; |
static const int kLineSegsNumInIdxBuffer = 256; |
-GR_DECLARE_STATIC_UNIQUE_KEY(gLinesIndexBufferKey); |
- |
-static const GrIndexBuffer* ref_lines_index_buffer(GrResourceProvider* resourceProvider) { |
- GR_DEFINE_STATIC_UNIQUE_KEY(gLinesIndexBufferKey); |
- return resourceProvider->refOrCreateInstancedIndexBuffer( |
- kLineSegIdxBufPattern, kIdxsPerLineSeg, kLineSegsNumInIdxBuffer, kLineSegNumVertices, |
- gLinesIndexBufferKey); |
-} |
+GrPathRenderer* GrAAHairLinePathRenderer::Create(GrContext* context) { |
+ GrGpu* gpu = context->getGpu(); |
+ GrIndexBuffer* qIdxBuf = gpu->createInstancedIndexBuffer(kQuadIdxBufPattern, |
+ kIdxsPerQuad, |
+ kQuadsNumInIdxBuffer, |
+ kQuadNumVertices); |
+ SkAutoTUnref<GrIndexBuffer> qIdxBuffer(qIdxBuf); |
+ GrIndexBuffer* lIdxBuf = gpu->createInstancedIndexBuffer(kLineSegIdxBufPattern, |
+ kIdxsPerLineSeg, |
+ kLineSegsNumInIdxBuffer, |
+ kLineSegNumVertices); |
+ SkAutoTUnref<GrIndexBuffer> lIdxBuffer(lIdxBuf); |
+ return SkNEW_ARGS(GrAAHairLinePathRenderer, |
+ (context, lIdxBuf, qIdxBuf)); |
+} |
+ |
+GrAAHairLinePathRenderer::GrAAHairLinePathRenderer( |
+ const GrContext* context, |
+ const GrIndexBuffer* linesIndexBuffer, |
+ const GrIndexBuffer* quadsIndexBuffer) { |
+ fLinesIndexBuffer = linesIndexBuffer; |
+ linesIndexBuffer->ref(); |
+ fQuadsIndexBuffer = quadsIndexBuffer; |
+ quadsIndexBuffer->ref(); |
+} |
+ |
+GrAAHairLinePathRenderer::~GrAAHairLinePathRenderer() { |
+ fLinesIndexBuffer->unref(); |
+ fQuadsIndexBuffer->unref(); |
+} |
+ |
+namespace { |
+ |
+#define PREALLOC_PTARRAY(N) SkSTArray<(N),SkPoint, true> |
// Takes 178th time of logf on Z600 / VC2010 |
-static int get_float_exp(float x) { |
+int get_float_exp(float x) { |
GR_STATIC_ASSERT(sizeof(int) == sizeof(float)); |
#ifdef SK_DEBUG |
static bool tested; |
@@ -135,7 +151,7 @@ |
// found along the curve segment it will return 1 and |
// dst[0] is the original conic. If it returns 2 the dst[0] |
// and dst[1] are the two new conics. |
-static int split_conic(const SkPoint src[3], SkConic dst[2], const SkScalar weight) { |
+int split_conic(const SkPoint src[3], SkConic dst[2], const SkScalar weight) { |
SkScalar t = SkFindQuadMaxCurvature(src); |
if (t == 0) { |
if (dst) { |
@@ -155,7 +171,7 @@ |
// Calls split_conic on the entire conic and then once more on each subsection. |
// Most cases will result in either 1 conic (chop point is not within t range) |
// or 3 points (split once and then one subsection is split again). |
-static int chop_conic(const SkPoint src[3], SkConic dst[4], const SkScalar weight) { |
+int chop_conic(const SkPoint src[3], SkConic dst[4], const SkScalar weight) { |
SkConic dstTemp[2]; |
int conicCnt = split_conic(src, dstTemp, weight); |
if (2 == conicCnt) { |
@@ -170,7 +186,7 @@ |
// returns 0 if quad/conic is degen or close to it |
// in this case approx the path with lines |
// otherwise returns 1 |
-static int is_degen_quad_or_conic(const SkPoint p[3], SkScalar* dsqd) { |
+int is_degen_quad_or_conic(const SkPoint p[3], SkScalar* dsqd) { |
static const SkScalar gDegenerateToLineTol = SK_Scalar1; |
static const SkScalar gDegenerateToLineTolSqd = |
SkScalarMul(gDegenerateToLineTol, gDegenerateToLineTol); |
@@ -191,14 +207,14 @@ |
return 0; |
} |
-static int is_degen_quad_or_conic(const SkPoint p[3]) { |
+int is_degen_quad_or_conic(const SkPoint p[3]) { |
SkScalar dsqd; |
return is_degen_quad_or_conic(p, &dsqd); |
} |
// we subdivide the quads to avoid huge overfill |
// if it returns -1 then should be drawn as lines |
-static int num_quad_subdivs(const SkPoint p[3]) { |
+int num_quad_subdivs(const SkPoint p[3]) { |
SkScalar dsqd; |
if (is_degen_quad_or_conic(p, &dsqd)) { |
return -1; |
@@ -234,14 +250,14 @@ |
* subdivide large quads to reduce over-fill. This subdivision has to be |
* performed before applying the perspective matrix. |
*/ |
-static int gather_lines_and_quads(const SkPath& path, |
- const SkMatrix& m, |
- const SkIRect& devClipBounds, |
- GrAAHairLinePathRenderer::PtArray* lines, |
- GrAAHairLinePathRenderer::PtArray* quads, |
- GrAAHairLinePathRenderer::PtArray* conics, |
- GrAAHairLinePathRenderer::IntArray* quadSubdivCnts, |
- GrAAHairLinePathRenderer::FloatArray* conicWeights) { |
+int gather_lines_and_quads(const SkPath& path, |
+ const SkMatrix& m, |
+ const SkIRect& devClipBounds, |
+ GrAAHairLinePathRenderer::PtArray* lines, |
+ GrAAHairLinePathRenderer::PtArray* quads, |
+ GrAAHairLinePathRenderer::PtArray* conics, |
+ GrAAHairLinePathRenderer::IntArray* quadSubdivCnts, |
+ GrAAHairLinePathRenderer::FloatArray* conicWeights) { |
SkPath::Iter iter(path, false); |
int totalQuadCount = 0; |
@@ -425,9 +441,9 @@ |
GR_STATIC_ASSERT(sizeof(BezierVertex) == 3 * sizeof(SkPoint)); |
-static void intersect_lines(const SkPoint& ptA, const SkVector& normA, |
- const SkPoint& ptB, const SkVector& normB, |
- SkPoint* result) { |
+void intersect_lines(const SkPoint& ptA, const SkVector& normA, |
+ const SkPoint& ptB, const SkVector& normB, |
+ SkPoint* result) { |
SkScalar lineAW = -normA.dot(ptA); |
SkScalar lineBW = -normB.dot(ptB); |
@@ -443,14 +459,14 @@ |
result->fY = SkScalarMul(result->fY, wInv); |
} |
-static void set_uv_quad(const SkPoint qpts[3], BezierVertex verts[kQuadNumVertices]) { |
+void set_uv_quad(const SkPoint qpts[3], BezierVertex verts[kQuadNumVertices]) { |
// this should be in the src space, not dev coords, when we have perspective |
GrPathUtils::QuadUVMatrix DevToUV(qpts); |
DevToUV.apply<kQuadNumVertices, sizeof(BezierVertex), sizeof(SkPoint)>(verts); |
} |
-static void bloat_quad(const SkPoint qpts[3], const SkMatrix* toDevice, |
- const SkMatrix* toSrc, BezierVertex verts[kQuadNumVertices]) { |
+void bloat_quad(const SkPoint qpts[3], const SkMatrix* toDevice, |
+ const SkMatrix* toSrc, BezierVertex verts[kQuadNumVertices]) { |
SkASSERT(!toDevice == !toSrc); |
// original quad is specified by tri a,b,c |
SkPoint a = qpts[0]; |
@@ -528,8 +544,8 @@ |
// f(x, y, w) = f(P) = K^2 - LM |
// K = dot(k, P), L = dot(l, P), M = dot(m, P) |
// k, l, m are calculated in function GrPathUtils::getConicKLM |
-static void set_conic_coeffs(const SkPoint p[3], BezierVertex verts[kQuadNumVertices], |
- const SkScalar weight) { |
+void set_conic_coeffs(const SkPoint p[3], BezierVertex verts[kQuadNumVertices], |
+ const SkScalar weight) { |
SkScalar klm[9]; |
GrPathUtils::getConicKLM(p, weight, klm); |
@@ -542,21 +558,21 @@ |
} |
} |
-static void add_conics(const SkPoint p[3], |
- const SkScalar weight, |
- const SkMatrix* toDevice, |
- const SkMatrix* toSrc, |
- BezierVertex** vert) { |
+void add_conics(const SkPoint p[3], |
+ const SkScalar weight, |
+ const SkMatrix* toDevice, |
+ const SkMatrix* toSrc, |
+ BezierVertex** vert) { |
bloat_quad(p, toDevice, toSrc, *vert); |
set_conic_coeffs(p, *vert, weight); |
*vert += kQuadNumVertices; |
} |
-static void add_quads(const SkPoint p[3], |
- int subdiv, |
- const SkMatrix* toDevice, |
- const SkMatrix* toSrc, |
- BezierVertex** vert) { |
+void add_quads(const SkPoint p[3], |
+ int subdiv, |
+ const SkMatrix* toDevice, |
+ const SkMatrix* toSrc, |
+ BezierVertex** vert) { |
SkASSERT(subdiv >= 0); |
if (subdiv) { |
SkPoint newP[5]; |
@@ -570,10 +586,10 @@ |
} |
} |
-static void add_line(const SkPoint p[2], |
- const SkMatrix* toSrc, |
- uint8_t coverage, |
- LineVertex** vert) { |
+void add_line(const SkPoint p[2], |
+ const SkMatrix* toSrc, |
+ uint8_t coverage, |
+ LineVertex** vert) { |
const SkPoint& a = p[0]; |
const SkPoint& b = p[1]; |
@@ -615,6 +631,8 @@ |
*vert += kLineSegNumVertices; |
} |
+} |
+ |
/////////////////////////////////////////////////////////////////////////////// |
bool GrAAHairLinePathRenderer::canDrawPath(const GrDrawTarget* target, |
@@ -685,8 +703,11 @@ |
SkIRect fDevClipBounds; |
}; |
- static GrBatch* Create(const Geometry& geometry) { |
- return SkNEW_ARGS(AAHairlineBatch, (geometry)); |
+ // TODO Batch itself should not hold on to index buffers. Instead, these should live in the |
+ // cache. |
+ static GrBatch* Create(const Geometry& geometry, const GrIndexBuffer* linesIndexBuffer, |
+ const GrIndexBuffer* quadsIndexBuffer) { |
+ return SkNEW_ARGS(AAHairlineBatch, (geometry, linesIndexBuffer, quadsIndexBuffer)); |
} |
const char* name() const override { return "AAHairlineBatch"; } |
@@ -724,7 +745,11 @@ |
typedef SkTArray<int, true> IntArray; |
typedef SkTArray<float, true> FloatArray; |
- AAHairlineBatch(const Geometry& geometry) { |
+ AAHairlineBatch(const Geometry& geometry, const GrIndexBuffer* linesIndexBuffer, |
+ const GrIndexBuffer* quadsIndexBuffer) |
+ : fLinesIndexBuffer(linesIndexBuffer) |
+ , fQuadsIndexBuffer(quadsIndexBuffer) { |
+ SkASSERT(linesIndexBuffer && quadsIndexBuffer); |
this->initClassID<AAHairlineBatch>(); |
fGeoData.push_back(geometry); |
@@ -783,6 +808,8 @@ |
BatchTracker fBatch; |
SkSTArray<1, Geometry, true> fGeoData; |
+ const GrIndexBuffer* fLinesIndexBuffer; |
+ const GrIndexBuffer* fQuadsIndexBuffer; |
}; |
void AAHairlineBatch::generateGeometry(GrBatchTarget* batchTarget, const GrPipeline* pipeline) { |
@@ -853,8 +880,6 @@ |
// do lines first |
if (lineCount) { |
- SkAutoTUnref<const GrIndexBuffer> linesIndexBuffer( |
- ref_lines_index_buffer(batchTarget->resourceProvider())); |
batchTarget->initDraw(lineGP, pipeline); |
// TODO remove this when batch is everywhere |
@@ -875,7 +900,7 @@ |
&vertexBuffer, |
&firstVertex); |
- if (!vertices || !linesIndexBuffer) { |
+ if (!vertices) { |
SkDebugf("Could not allocate vertices\n"); |
return; |
} |
@@ -890,7 +915,7 @@ |
{ |
GrDrawTarget::DrawInfo info; |
info.setVertexBuffer(vertexBuffer); |
- info.setIndexBuffer(linesIndexBuffer); |
+ info.setIndexBuffer(fLinesIndexBuffer); |
info.setPrimitiveType(kTriangles_GrPrimitiveType); |
info.setStartIndex(0); |
@@ -911,9 +936,6 @@ |
if (quadCount || conicCount) { |
const GrVertexBuffer* vertexBuffer; |
int firstVertex; |
- |
- SkAutoTUnref<const GrIndexBuffer> quadsIndexBuffer( |
- ref_quads_index_buffer(batchTarget->resourceProvider())); |
size_t vertexStride = sizeof(BezierVertex); |
int vertexCount = kQuadNumVertices * quadCount + kQuadNumVertices * conicCount; |
@@ -922,7 +944,7 @@ |
&vertexBuffer, |
&firstVertex); |
- if (!vertices || !quadsIndexBuffer) { |
+ if (!vertices) { |
SkDebugf("Could not allocate vertices\n"); |
return; |
} |
@@ -955,7 +977,7 @@ |
{ |
GrDrawTarget::DrawInfo info; |
info.setVertexBuffer(vertexBuffer); |
- info.setIndexBuffer(quadsIndexBuffer); |
+ info.setIndexBuffer(fQuadsIndexBuffer); |
info.setPrimitiveType(kTriangles_GrPrimitiveType); |
info.setStartIndex(0); |
@@ -987,7 +1009,7 @@ |
{ |
GrDrawTarget::DrawInfo info; |
info.setVertexBuffer(vertexBuffer); |
- info.setIndexBuffer(quadsIndexBuffer); |
+ info.setIndexBuffer(fQuadsIndexBuffer); |
info.setPrimitiveType(kTriangles_GrPrimitiveType); |
info.setStartIndex(0); |
@@ -1011,7 +1033,9 @@ |
const SkMatrix& viewMatrix, |
const SkPath& path, |
const GrStrokeInfo& stroke, |
- const SkIRect& devClipBounds) { |
+ const SkIRect& devClipBounds, |
+ const GrIndexBuffer* linesIndexBuffer, |
+ const GrIndexBuffer* quadsIndexBuffer) { |
SkScalar hairlineCoverage; |
uint8_t newCoverage = 0xff; |
if (GrPathRenderer::IsStrokeHairlineOrEquivalent(stroke, viewMatrix, &hairlineCoverage)) { |
@@ -1025,7 +1049,7 @@ |
geometry.fPath = path; |
geometry.fDevClipBounds = devClipBounds; |
- return AAHairlineBatch::Create(geometry); |
+ return AAHairlineBatch::Create(geometry, linesIndexBuffer, quadsIndexBuffer); |
} |
bool GrAAHairLinePathRenderer::onDrawPath(GrDrawTarget* target, |
@@ -1035,12 +1059,18 @@ |
const SkPath& path, |
const GrStrokeInfo& stroke, |
bool) { |
+ if (!fLinesIndexBuffer || !fQuadsIndexBuffer) { |
+ SkDebugf("unable to allocate indices\n"); |
+ return false; |
+ } |
+ |
SkIRect devClipBounds; |
pipelineBuilder->clip().getConservativeBounds(pipelineBuilder->getRenderTarget(), |
&devClipBounds); |
SkAutoTUnref<GrBatch> batch(create_hairline_batch(color, viewMatrix, path, stroke, |
- devClipBounds)); |
+ devClipBounds, fLinesIndexBuffer, |
+ fQuadsIndexBuffer)); |
target->drawBatch(pipelineBuilder, batch); |
return true; |
@@ -1051,13 +1081,28 @@ |
#ifdef GR_TEST_UTILS |
BATCH_TEST_DEFINE(AAHairlineBatch) { |
+ // TODO put these in the cache |
+ static GrIndexBuffer* gQuadIndexBuffer; |
+ static GrIndexBuffer* gLineIndexBuffer; |
+ if (!gQuadIndexBuffer) { |
+ gQuadIndexBuffer = context->getGpu()->createInstancedIndexBuffer(kQuadIdxBufPattern, |
+ kIdxsPerQuad, |
+ kQuadsNumInIdxBuffer, |
+ kQuadNumVertices); |
+ gLineIndexBuffer = context->getGpu()->createInstancedIndexBuffer(kLineSegIdxBufPattern, |
+ kIdxsPerLineSeg, |
+ kLineSegsNumInIdxBuffer, |
+ kLineSegNumVertices); |
+ } |
+ |
GrColor color = GrRandomColor(random); |
SkMatrix viewMatrix = GrTest::TestMatrix(random); |
GrStrokeInfo stroke(SkStrokeRec::kHairline_InitStyle); |
SkPath path = GrTest::TestPath(random); |
SkIRect devClipBounds; |
devClipBounds.setEmpty(); |
- return create_hairline_batch(color, viewMatrix, path, stroke, devClipBounds); |
+ return create_hairline_batch(color, viewMatrix, path, stroke, devClipBounds, gLineIndexBuffer, |
+ gQuadIndexBuffer); |
} |
#endif |