Index: src/gpu/GrAAHairLinePathRenderer.cpp |
diff --git a/src/gpu/GrAAHairLinePathRenderer.cpp b/src/gpu/GrAAHairLinePathRenderer.cpp |
index c1f951ab7f91832d95ece209f71b377794c68e48..4a73b53eba53a4338444c2021cabeff6960fe4dc 100644 |
--- a/src/gpu/GrAAHairLinePathRenderer.cpp |
+++ b/src/gpu/GrAAHairLinePathRenderer.cpp |
@@ -29,15 +29,20 @@ namespace { |
static const int kVertsPerQuad = 5; |
static const int kIdxsPerQuad = 9; |
-static const int kVertsPerLineSeg = 4; |
-static const int kIdxsPerLineSeg = 6; |
+static const int kVertsPerLineSeg = 6; |
+static const int kIdxsPerLineSeg = 12; |
static const int kNumQuadsInIdxBuffer = 256; |
static const size_t kQuadIdxSBufize = kIdxsPerQuad * |
sizeof(uint16_t) * |
kNumQuadsInIdxBuffer; |
-bool push_quad_index_data(GrIndexBuffer* qIdxBuffer) { |
+static const int kNumLineSegsInIdxBuffer = 256; |
+static const size_t kLineSegIdxSBufize = kIdxsPerLineSeg * |
+ sizeof(uint16_t) * |
+ kNumLineSegsInIdxBuffer; |
+ |
+static bool push_quad_index_data(GrIndexBuffer* qIdxBuffer) { |
uint16_t* data = (uint16_t*) qIdxBuffer->lock(); |
bool tempData = NULL == data; |
if (tempData) { |
@@ -78,22 +83,66 @@ bool push_quad_index_data(GrIndexBuffer* qIdxBuffer) { |
return true; |
} |
} |
+ |
+static bool push_line_index_data(GrIndexBuffer* lIdxBuffer) { |
+ uint16_t* data = (uint16_t*) lIdxBuffer->lock(); |
+ bool tempData = NULL == data; |
+ if (tempData) { |
+ data = SkNEW_ARRAY(uint16_t, kNumLineSegsInIdxBuffer * kIdxsPerLineSeg); |
+ } |
+ for (int i = 0; i < kNumLineSegsInIdxBuffer; ++i) { |
+ // Each line segment is rendered as two quads, with alpha = 1 along the |
+ // spine of the segment, and alpha = 0 along the outer edges, represented |
+ // horizontally (i.e., the line equation is t*(p1-p0) + p0) |
+ // |
+ // p4 p5 |
+ // p0 p1 |
+ // p2 p3 |
+ // |
+ // Each is drawn as four triangles specified by these 12 indices: |
+ int baseIdx = i * kIdxsPerLineSeg; |
+ uint16_t baseVert = (uint16_t)(i * kVertsPerLineSeg); |
+ data[0 + baseIdx] = baseVert + 0; // p0 |
+ data[1 + baseIdx] = baseVert + 1; // p1 |
+ data[2 + baseIdx] = baseVert + 2; // p2 |
+ |
+ data[3 + baseIdx] = baseVert + 2; // p2 |
+ data[4 + baseIdx] = baseVert + 1; // p1 |
+ data[5 + baseIdx] = baseVert + 3; // p3 |
+ |
+ data[6 + baseIdx] = baseVert + 0; // p0 |
+ data[7 + baseIdx] = baseVert + 5; // p5 |
+ data[8 + baseIdx] = baseVert + 1; // p1 |
+ |
+ data[9 + baseIdx] = baseVert + 0; // p0 |
+ data[10+ baseIdx] = baseVert + 4; // p4 |
+ data[11+ baseIdx] = baseVert + 5; // p5 |
+ } |
+ if (tempData) { |
+ bool ret = lIdxBuffer->updateData(data, kLineSegIdxSBufize); |
+ delete[] data; |
+ return ret; |
+ } else { |
+ lIdxBuffer->unlock(); |
+ return true; |
+ } |
+} |
} |
GrPathRenderer* GrAAHairLinePathRenderer::Create(GrContext* context) { |
- const GrIndexBuffer* lIdxBuffer = context->getQuadIndexBuffer(); |
- if (NULL == lIdxBuffer) { |
- return NULL; |
- } |
GrGpu* gpu = context->getGpu(); |
GrIndexBuffer* qIdxBuf = gpu->createIndexBuffer(kQuadIdxSBufize, false); |
SkAutoTUnref<GrIndexBuffer> qIdxBuffer(qIdxBuf); |
- if (NULL == qIdxBuf || |
- !push_quad_index_data(qIdxBuf)) { |
+ if (NULL == qIdxBuf || !push_quad_index_data(qIdxBuf)) { |
+ return NULL; |
+ } |
+ GrIndexBuffer* lIdxBuf = gpu->createIndexBuffer(kLineSegIdxSBufize, false); |
+ SkAutoTUnref<GrIndexBuffer> lIdxBuffer(lIdxBuf); |
+ if (NULL == lIdxBuf || !push_line_index_data(lIdxBuf)) { |
return NULL; |
} |
return SkNEW_ARGS(GrAAHairLinePathRenderer, |
- (context, lIdxBuffer, qIdxBuf)); |
+ (context, lIdxBuf, qIdxBuf)); |
} |
GrAAHairLinePathRenderer::GrAAHairLinePathRenderer( |
@@ -113,10 +162,7 @@ GrAAHairLinePathRenderer::~GrAAHairLinePathRenderer() { |
namespace { |
-typedef SkTArray<SkPoint, true> PtArray; |
#define PREALLOC_PTARRAY(N) SkSTArray<(N),SkPoint, true> |
-typedef SkTArray<int, true> IntArray; |
-typedef SkTArray<float, true> FloatArray; |
// Takes 178th time of logf on Z600 / VC2010 |
int get_float_exp(float x) { |
@@ -266,11 +312,11 @@ int num_quad_subdivs(const SkPoint p[3]) { |
int generate_lines_and_quads(const SkPath& path, |
const SkMatrix& m, |
const SkIRect& devClipBounds, |
- PtArray* lines, |
- PtArray* quads, |
- PtArray* conics, |
- IntArray* quadSubdivCnts, |
- FloatArray* conicWeights) { |
+ GrAAHairLinePathRenderer::PtArray* lines, |
+ GrAAHairLinePathRenderer::PtArray* quads, |
+ GrAAHairLinePathRenderer::PtArray* conics, |
+ GrAAHairLinePathRenderer::IntArray* quadSubdivCnts, |
+ GrAAHairLinePathRenderer::FloatArray* conicWeights) { |
SkPath::Iter iter(path, false); |
int totalQuadCount = 0; |
@@ -432,15 +478,15 @@ int generate_lines_and_quads(const SkPath& path, |
} |
} |
-struct Vertex { |
+struct LineVertex { |
+ GrPoint fPos; |
+ GrColor fCoverage; |
+}; |
+ |
+struct BezierVertex { |
GrPoint fPos; |
union { |
struct { |
- SkScalar fA; |
- SkScalar fB; |
- SkScalar fC; |
- } fLine; |
- struct { |
SkScalar fK; |
SkScalar fL; |
SkScalar fM; |
@@ -452,7 +498,7 @@ struct Vertex { |
}; |
}; |
-GR_STATIC_ASSERT(sizeof(Vertex) == 3 * sizeof(GrPoint)); |
+GR_STATIC_ASSERT(sizeof(BezierVertex) == 3 * sizeof(GrPoint)); |
void intersect_lines(const SkPoint& ptA, const SkVector& normA, |
const SkPoint& ptB, const SkVector& normB, |
@@ -472,14 +518,14 @@ void intersect_lines(const SkPoint& ptA, const SkVector& normA, |
result->fY = SkScalarMul(result->fY, wInv); |
} |
-void set_uv_quad(const SkPoint qpts[3], Vertex verts[kVertsPerQuad]) { |
+void set_uv_quad(const SkPoint qpts[3], BezierVertex verts[kVertsPerQuad]) { |
// this should be in the src space, not dev coords, when we have perspective |
GrPathUtils::QuadUVMatrix DevToUV(qpts); |
- DevToUV.apply<kVertsPerQuad, sizeof(Vertex), sizeof(GrPoint)>(verts); |
+ DevToUV.apply<kVertsPerQuad, sizeof(BezierVertex), sizeof(GrPoint)>(verts); |
} |
void bloat_quad(const SkPoint qpts[3], const SkMatrix* toDevice, |
- const SkMatrix* toSrc, Vertex verts[kVertsPerQuad], |
+ const SkMatrix* toSrc, BezierVertex verts[kVertsPerQuad], |
SkRect* devBounds) { |
GrAssert(!toDevice == !toSrc); |
// original quad is specified by tri a,b,c |
@@ -504,11 +550,11 @@ void bloat_quad(const SkPoint qpts[3], const SkMatrix* toDevice, |
// |
// edges a0->b0 and b0->c0 are parallel to original edges a->b and b->c, |
// respectively. |
- Vertex& a0 = verts[0]; |
- Vertex& a1 = verts[1]; |
- Vertex& b0 = verts[2]; |
- Vertex& c0 = verts[3]; |
- Vertex& c1 = verts[4]; |
+ BezierVertex& a0 = verts[0]; |
+ BezierVertex& a1 = verts[1]; |
+ BezierVertex& b0 = verts[2]; |
+ BezierVertex& c0 = verts[3]; |
+ BezierVertex& c1 = verts[4]; |
SkVector ab = b; |
ab -= a; |
@@ -550,7 +596,7 @@ void bloat_quad(const SkPoint qpts[3], const SkMatrix* toDevice, |
devBounds->growToInclude(b0.fPos.fX, b0.fPos.fY); |
if (toSrc) { |
- toSrc->mapPointsWithStride(&verts[0].fPos, sizeof(Vertex), kVertsPerQuad); |
+ toSrc->mapPointsWithStride(&verts[0].fPos, sizeof(BezierVertex), kVertsPerQuad); |
} |
} |
@@ -603,7 +649,7 @@ void calc_conic_klm(const SkPoint p[3], const SkScalar weight, |
// 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 calc_conic_klm |
-void set_conic_coeffs(const SkPoint p[3], Vertex verts[kVertsPerQuad], const float weight) { |
+void set_conic_coeffs(const SkPoint p[3], BezierVertex verts[kVertsPerQuad], const float weight) { |
SkScalar k[3]; |
SkScalar l[3]; |
SkScalar m[3]; |
@@ -622,7 +668,7 @@ void add_conics(const SkPoint p[3], |
float weight, |
const SkMatrix* toDevice, |
const SkMatrix* toSrc, |
- Vertex** vert, |
+ BezierVertex** vert, |
SkRect* devBounds) { |
bloat_quad(p, toDevice, toSrc, *vert, devBounds); |
set_conic_coeffs(p, *vert, weight); |
@@ -633,7 +679,7 @@ void add_quads(const SkPoint p[3], |
int subdiv, |
const SkMatrix* toDevice, |
const SkMatrix* toSrc, |
- Vertex** vert, |
+ BezierVertex** vert, |
SkRect* devBounds) { |
GrAssert(subdiv >= 0); |
if (subdiv) { |
@@ -651,7 +697,8 @@ void add_quads(const SkPoint p[3], |
void add_line(const SkPoint p[2], |
int rtHeight, |
const SkMatrix* toSrc, |
- Vertex** vert) { |
+ GrColor coverage, |
+ LineVertex** vert) { |
const SkPoint& a = p[0]; |
const SkPoint& b = p[1]; |
@@ -661,29 +708,28 @@ void add_line(const SkPoint p[2], |
if (orthVec.setLength(SK_Scalar1)) { |
orthVec.setOrthog(orthVec); |
- SkScalar lineC = -(a.dot(orthVec)); |
for (int i = 0; i < kVertsPerLineSeg; ++i) { |
- (*vert)[i].fPos = (i < 2) ? a : b; |
- if (0 == i || 3 == i) { |
+ (*vert)[i].fPos = (i & 0x1) ? b : a; |
+ if (i & 0x2) { |
+ (*vert)[i].fPos += orthVec; |
+ (*vert)[i].fCoverage = 0; |
+ } else if (i & 0x4) { |
(*vert)[i].fPos -= orthVec; |
+ (*vert)[i].fCoverage = 0; |
} else { |
- (*vert)[i].fPos += orthVec; |
+ (*vert)[i].fCoverage = coverage; |
} |
- (*vert)[i].fLine.fA = orthVec.fX; |
- (*vert)[i].fLine.fB = orthVec.fY; |
- (*vert)[i].fLine.fC = lineC; |
} |
if (NULL != toSrc) { |
toSrc->mapPointsWithStride(&(*vert)->fPos, |
- sizeof(Vertex), |
+ sizeof(LineVertex), |
kVertsPerLineSeg); |
} |
} else { |
// just make it degenerate and likely offscreen |
- (*vert)[0].fPos.set(SK_ScalarMax, SK_ScalarMax); |
- (*vert)[1].fPos.set(SK_ScalarMax, SK_ScalarMax); |
- (*vert)[2].fPos.set(SK_ScalarMax, SK_ScalarMax); |
- (*vert)[3].fPos.set(SK_ScalarMax, SK_ScalarMax); |
+ for (int i = 0; i < kVertsPerLineSeg; ++i) { |
+ (*vert)[i].fPos.set(SK_ScalarMax, SK_ScalarMax); |
+ } |
} |
*vert += kVertsPerLineSeg; |
@@ -934,174 +980,117 @@ GrEffectRef* HairQuadEdgeEffect::TestCreate(SkMWCRandom* random, |
/////////////////////////////////////////////////////////////////////////////// |
-/** |
- * The output of this effect is a 1-pixel wide line. |
- * Input is 2D implicit device coord line eq (a*x + b*y +c = 0). 4th component unused. |
- */ |
-class HairLineEdgeEffect : public GrEffect { |
-public: |
- |
- static GrEffectRef* Create() { |
- GR_CREATE_STATIC_EFFECT(gHairLineEdge, HairLineEdgeEffect, ()); |
- gHairLineEdge->ref(); |
- return gHairLineEdge; |
- } |
- |
- virtual ~HairLineEdgeEffect() {} |
- |
- static const char* Name() { return "HairLineEdge"; } |
- |
- virtual void getConstantColorComponents(GrColor* color, |
- uint32_t* validFlags) const SK_OVERRIDE { |
- *validFlags = 0; |
- } |
- |
- virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE { |
- return GrTBackendEffectFactory<HairLineEdgeEffect>::getInstance(); |
- } |
- |
- class GLEffect : public GrGLEffect { |
- public: |
- GLEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&) |
- : INHERITED (factory) {} |
- |
- virtual void emitCode(GrGLShaderBuilder* builder, |
- const GrDrawEffect& drawEffect, |
- EffectKey key, |
- const char* outputColor, |
- const char* inputColor, |
- const TextureSamplerArray& samplers) SK_OVERRIDE { |
- const char *vsName, *fsName; |
- const SkString* attrName = |
- builder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]); |
- builder->fsCodeAppendf("\t\tfloat edgeAlpha;\n"); |
- |
- builder->addVarying(kVec4f_GrSLType, "HairLineEdge", &vsName, &fsName); |
- |
- builder->fsCodeAppendf("\t\tedgeAlpha = abs(dot(vec3(%s.xy,1), %s.xyz));\n", |
- builder->fragmentPosition(), fsName); |
- builder->fsCodeAppendf("\t\tedgeAlpha = max(1.0 - edgeAlpha, 0.0);\n"); |
- |
- SkString modulate; |
- GrGLSLModulatef<4>(&modulate, inputColor, "edgeAlpha"); |
- builder->fsCodeAppendf("\t%s = %s;\n", outputColor, modulate.c_str()); |
- |
- builder->vsCodeAppendf("\t%s = %s;\n", vsName, attrName->c_str()); |
- } |
- |
- static inline EffectKey GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) { |
- return 0x0; |
- } |
- |
- virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE {} |
- |
- private: |
- typedef GrGLEffect INHERITED; |
- }; |
- |
-private: |
- HairLineEdgeEffect() { |
- this->addVertexAttrib(kVec4f_GrSLType); |
- this->setWillReadFragmentPosition(); |
- } |
- |
- virtual bool onIsEqual(const GrEffect& other) const SK_OVERRIDE { |
- return true; |
- } |
- |
- GR_DECLARE_EFFECT_TEST; |
- |
- typedef GrEffect INHERITED; |
-}; |
- |
-GR_DEFINE_EFFECT_TEST(HairLineEdgeEffect); |
- |
-GrEffectRef* HairLineEdgeEffect::TestCreate(SkMWCRandom* random, |
- GrContext*, |
- const GrDrawTargetCaps& caps, |
- GrTexture*[]) { |
- return HairLineEdgeEffect::Create(); |
-} |
- |
-/////////////////////////////////////////////////////////////////////////////// |
- |
namespace { |
// position + edge |
-extern const GrVertexAttrib gHairlineAttribs[] = { |
+extern const GrVertexAttrib gHairlineBezierAttribs[] = { |
{kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding}, |
{kVec4f_GrVertexAttribType, sizeof(GrPoint), kEffect_GrVertexAttribBinding} |
}; |
+ |
+// position + coverage |
+extern const GrVertexAttrib gHairlineLineAttribs[] = { |
+ {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding}, |
+ {kVec4ub_GrVertexAttribType, sizeof(GrPoint), kCoverage_GrVertexAttribBinding}, |
+}; |
+ |
}; |
-bool GrAAHairLinePathRenderer::createGeom( |
+bool GrAAHairLinePathRenderer::createLineGeom( |
const SkPath& path, |
GrDrawTarget* target, |
- int* lineCnt, |
- int* quadCnt, |
- int* conicCnt, |
+ const PtArray& lines, |
+ int lineCnt, |
GrDrawTarget::AutoReleaseGeometry* arg, |
SkRect* devBounds) { |
GrDrawState* drawState = target->drawState(); |
int rtHeight = drawState->getRenderTarget()->height(); |
- SkIRect devClipBounds; |
- target->getClip()->getConservativeBounds(drawState->getRenderTarget(), &devClipBounds); |
- |
- SkMatrix viewM = drawState->getViewMatrix(); |
+ const SkMatrix& viewM = drawState->getViewMatrix(); |
- // All the vertices that we compute are within 1 of path control points with the exception of |
- // one of the bounding vertices for each quad. The add_quads() function will update the bounds |
- // for each quad added. |
*devBounds = path.getBounds(); |
viewM.mapRect(devBounds); |
devBounds->outset(SK_Scalar1, SK_Scalar1); |
- PREALLOC_PTARRAY(128) lines; |
- PREALLOC_PTARRAY(128) quads; |
- PREALLOC_PTARRAY(128) conics; |
- IntArray qSubdivs; |
- FloatArray cWeights; |
- *quadCnt = generate_lines_and_quads(path, viewM, devClipBounds, |
- &lines, &quads, &conics, &qSubdivs, &cWeights); |
- |
- *lineCnt = lines.count() / 2; |
- *conicCnt = conics.count() / 3; |
- int vertCnt = kVertsPerLineSeg * *lineCnt + kVertsPerQuad * *quadCnt + |
- kVertsPerQuad * *conicCnt; |
+ int vertCnt = kVertsPerLineSeg * lineCnt; |
- target->drawState()->setVertexAttribs<gHairlineAttribs>(SK_ARRAY_COUNT(gHairlineAttribs)); |
- GrAssert(sizeof(Vertex) == target->getDrawState().getVertexSize()); |
+ target->drawState()->setVertexAttribs<gHairlineLineAttribs>(SK_ARRAY_COUNT(gHairlineLineAttribs)); |
+ GrAssert(sizeof(LineVertex) == target->getDrawState().getVertexSize()); |
if (!arg->set(target, vertCnt, 0)) { |
return false; |
} |
- Vertex* verts = reinterpret_cast<Vertex*>(arg->vertices()); |
+ LineVertex* verts = reinterpret_cast<LineVertex*>(arg->vertices()); |
- const SkMatrix* toDevice = NULL; |
const SkMatrix* toSrc = NULL; |
SkMatrix ivm; |
if (viewM.hasPerspective()) { |
if (viewM.invert(&ivm)) { |
- toDevice = &viewM; |
toSrc = &ivm; |
} |
} |
- for (int i = 0; i < *lineCnt; ++i) { |
- add_line(&lines[2*i], rtHeight, toSrc, &verts); |
+ for (int i = 0; i < lineCnt; ++i) { |
+ add_line(&lines[2*i], rtHeight, toSrc, drawState->getCoverage(), &verts); |
} |
+ return true; |
+} |
+ |
+bool GrAAHairLinePathRenderer::createBezierGeom( |
+ const SkPath& path, |
+ GrDrawTarget* target, |
+ const PtArray& quads, |
+ int quadCnt, |
+ const PtArray& conics, |
+ int conicCnt, |
+ const IntArray& qSubdivs, |
+ const FloatArray& cWeights, |
+ GrDrawTarget::AutoReleaseGeometry* arg, |
+ SkRect* devBounds) { |
+ GrDrawState* drawState = target->drawState(); |
+ |
+ const SkMatrix& viewM = drawState->getViewMatrix(); |
+ |
+ // All the vertices that we compute are within 1 of path control points with the exception of |
+ // one of the bounding vertices for each quad. The add_quads() function will update the bounds |
+ // for each quad added. |
+ *devBounds = path.getBounds(); |
+ viewM.mapRect(devBounds); |
+ devBounds->outset(SK_Scalar1, SK_Scalar1); |
+ |
+ int vertCnt = kVertsPerQuad * quadCnt + kVertsPerQuad * conicCnt; |
+ |
+ target->drawState()->setVertexAttribs<gHairlineBezierAttribs>(SK_ARRAY_COUNT(gHairlineBezierAttribs)); |
+ GrAssert(sizeof(BezierVertex) == target->getDrawState().getVertexSize()); |
+ |
+ if (!arg->set(target, vertCnt, 0)) { |
+ return false; |
+ } |
+ |
+ BezierVertex* verts = reinterpret_cast<BezierVertex*>(arg->vertices()); |
+ |
+ const SkMatrix* toDevice = NULL; |
+ const SkMatrix* toSrc = NULL; |
+ SkMatrix ivm; |
+ |
+ if (viewM.hasPerspective()) { |
+ if (viewM.invert(&ivm)) { |
+ toDevice = &viewM; |
+ toSrc = &ivm; |
+ } |
+ } |
+ |
int unsubdivQuadCnt = quads.count() / 3; |
for (int i = 0; i < unsubdivQuadCnt; ++i) { |
GrAssert(qSubdivs[i] >= 0); |
add_quads(&quads[3*i], qSubdivs[i], toDevice, toSrc, &verts, devBounds); |
} |
- |
+ |
// Start Conics |
- for (int i = 0; i < *conicCnt; ++i) { |
+ for (int i = 0; i < conicCnt; ++i) { |
add_conics(&conics[3*i], cWeights[i], toDevice, toSrc, &verts, devBounds); |
} |
return true; |
@@ -1122,54 +1111,14 @@ bool GrAAHairLinePathRenderer::canDrawPath(const SkPath& path, |
return false; |
} |
-bool GrAAHairLinePathRenderer::onDrawPath(const SkPath& path, |
- const SkStrokeRec&, |
- GrDrawTarget* target, |
- bool antiAlias) { |
- |
- int lineCnt; |
- int quadCnt; |
- int conicCnt; |
- GrDrawTarget::AutoReleaseGeometry arg; |
- SkRect devBounds; |
- |
- if (!this->createGeom(path, |
- target, |
- &lineCnt, |
- &quadCnt, |
- &conicCnt, |
- &arg, |
- &devBounds)) { |
- return false; |
- } |
- |
- GrDrawTarget::AutoStateRestore asr; |
- |
- // createGeom transforms the geometry to device space when the matrix does not have |
- // perspective. |
- if (target->getDrawState().getViewMatrix().hasPerspective()) { |
- asr.set(target, GrDrawTarget::kPreserve_ASRInit); |
- } else if (!asr.setIdentity(target, GrDrawTarget::kPreserve_ASRInit)) { |
- return false; |
- } |
- GrDrawState* drawState = target->drawState(); |
- |
- // TODO: See whether rendering lines as degenerate quads improves perf |
- // when we have a mix |
- |
- static const int kEdgeAttrIndex = 1; |
- |
- GrEffectRef* hairLineEffect = HairLineEdgeEffect::Create(); |
- GrEffectRef* hairQuadEffect = HairQuadEdgeEffect::Create(); |
- GrEffectRef* hairConicEffect = HairConicEdgeEffect::Create(); |
- |
- // Check devBounds |
-#if GR_DEBUG |
+template <class VertexType> |
+bool check_bounds(GrDrawState* drawState, const SkRect& devBounds, void* vertices, int vCount) |
+{ |
SkRect tolDevBounds = devBounds; |
tolDevBounds.outset(SK_Scalar1 / 10000, SK_Scalar1 / 10000); |
SkRect actualBounds; |
- Vertex* verts = reinterpret_cast<Vertex*>(arg.vertices()); |
- int vCount = kVertsPerLineSeg * lineCnt + kVertsPerQuad * quadCnt + kVertsPerQuad * conicCnt; |
+ |
+ VertexType* verts = reinterpret_cast<VertexType*>(vertices); |
bool first = true; |
for (int i = 0; i < vCount; ++i) { |
SkPoint pos = verts[i].fPos; |
@@ -1186,61 +1135,153 @@ bool GrAAHairLinePathRenderer::onDrawPath(const SkPath& path, |
} |
} |
if (!first) { |
- GrAssert(tolDevBounds.contains(actualBounds)); |
+ return tolDevBounds.contains(actualBounds); |
} |
-#endif |
+ |
+ return true; |
+} |
+bool GrAAHairLinePathRenderer::onDrawPath(const SkPath& path, |
+ const SkStrokeRec&, |
+ GrDrawTarget* target, |
+ bool antiAlias) { |
+ |
+ GrDrawState* drawState = target->drawState(); |
+ |
+ SkIRect devClipBounds; |
+ target->getClip()->getConservativeBounds(drawState->getRenderTarget(), &devClipBounds); |
+ |
+ int lineCnt; |
+ int quadCnt; |
+ int conicCnt; |
+ PREALLOC_PTARRAY(128) lines; |
+ PREALLOC_PTARRAY(128) quads; |
+ PREALLOC_PTARRAY(128) conics; |
+ IntArray qSubdivs; |
+ FloatArray cWeights; |
+ quadCnt = generate_lines_and_quads(path, drawState->getViewMatrix(), devClipBounds, |
+ &lines, &quads, &conics, &qSubdivs, &cWeights); |
+ lineCnt = lines.count() / 2; |
+ conicCnt = conics.count() / 3; |
+ |
+ // do lines first |
{ |
- GrDrawState::AutoRestoreEffects are(drawState); |
- target->setIndexSourceToBuffer(fLinesIndexBuffer); |
- int lines = 0; |
- int nBufLines = fLinesIndexBuffer->maxQuads(); |
- drawState->addCoverageEffect(hairLineEffect, kEdgeAttrIndex)->unref(); |
- while (lines < lineCnt) { |
- int n = GrMin(lineCnt - lines, nBufLines); |
- target->drawIndexed(kTriangles_GrPrimitiveType, |
- kVertsPerLineSeg*lines, // startV |
- 0, // startI |
- kVertsPerLineSeg*n, // vCount |
- kIdxsPerLineSeg*n, |
- &devBounds); // iCount |
- lines += n; |
+ GrDrawTarget::AutoReleaseGeometry arg; |
+ SkRect devBounds; |
+ |
+ if (!this->createLineGeom(path, |
+ target, |
+ lines, |
+ lineCnt, |
+ &arg, |
+ &devBounds)) { |
+ return false; |
} |
- } |
- { |
- GrDrawState::AutoRestoreEffects are(drawState); |
- target->setIndexSourceToBuffer(fQuadsIndexBuffer); |
- int quads = 0; |
- drawState->addCoverageEffect(hairQuadEffect, kEdgeAttrIndex)->unref(); |
- while (quads < quadCnt) { |
- int n = GrMin(quadCnt - quads, kNumQuadsInIdxBuffer); |
- target->drawIndexed(kTriangles_GrPrimitiveType, |
- kVertsPerLineSeg * lineCnt + kVertsPerQuad*quads, // startV |
- 0, // startI |
- kVertsPerQuad*n, // vCount |
- kIdxsPerQuad*n, // iCount |
- &devBounds); |
- quads += n; |
+ GrDrawTarget::AutoStateRestore asr; |
+ |
+ // createGeom transforms the geometry to device space when the matrix does not have |
+ // perspective. |
+ if (target->getDrawState().getViewMatrix().hasPerspective()) { |
+ asr.set(target, GrDrawTarget::kPreserve_ASRInit); |
+ } else if (!asr.setIdentity(target, GrDrawTarget::kPreserve_ASRInit)) { |
+ return false; |
+ } |
+ GrDrawState* drawState = target->drawState(); |
+ |
+ // Check devBounds |
+ SkASSERT(check_bounds<LineVertex>(drawState, devBounds, arg.vertices(), |
+ kVertsPerLineSeg * lineCnt)); |
+ |
+ { |
+ GrDrawState::AutoRestoreEffects are(drawState); |
+ target->setIndexSourceToBuffer(fLinesIndexBuffer); |
+ int lines = 0; |
+ while (lines < lineCnt) { |
+ int n = GrMin(lineCnt - lines, kNumLineSegsInIdxBuffer); |
+ target->drawIndexed(kTriangles_GrPrimitiveType, |
+ kVertsPerLineSeg*lines, // startV |
+ 0, // startI |
+ kVertsPerLineSeg*n, // vCount |
+ kIdxsPerLineSeg*n, |
+ &devBounds); // iCount |
+ lines += n; |
+ } |
} |
} |
- |
+ |
+ // then quadratics/conics |
{ |
- GrDrawState::AutoRestoreEffects are(drawState); |
- int conics = 0; |
- drawState->addCoverageEffect(hairConicEffect, 1, 2)->unref(); |
- while (conics < conicCnt) { |
- int n = GrMin(conicCnt - conics, kNumQuadsInIdxBuffer); |
- target->drawIndexed(kTriangles_GrPrimitiveType, |
- kVertsPerLineSeg*lineCnt + |
- kVertsPerQuad*(quadCnt + conics), // startV |
- 0, // startI |
- kVertsPerQuad*n, // vCount |
- kIdxsPerQuad*n, // iCount |
- &devBounds); |
- conics += n; |
+ GrDrawTarget::AutoReleaseGeometry arg; |
+ SkRect devBounds; |
+ |
+ if (!this->createBezierGeom(path, |
+ target, |
+ quads, |
+ quadCnt, |
+ conics, |
+ conicCnt, |
+ qSubdivs, |
+ cWeights, |
+ &arg, |
+ &devBounds)) { |
+ return false; |
+ } |
+ |
+ GrDrawTarget::AutoStateRestore asr; |
+ |
+ // createGeom transforms the geometry to device space when the matrix does not have |
+ // perspective. |
+ if (target->getDrawState().getViewMatrix().hasPerspective()) { |
+ asr.set(target, GrDrawTarget::kPreserve_ASRInit); |
+ } else if (!asr.setIdentity(target, GrDrawTarget::kPreserve_ASRInit)) { |
+ return false; |
+ } |
+ GrDrawState* drawState = target->drawState(); |
+ |
+ static const int kEdgeAttrIndex = 1; |
+ |
+ GrEffectRef* hairQuadEffect = HairQuadEdgeEffect::Create(); |
+ GrEffectRef* hairConicEffect = HairConicEdgeEffect::Create(); |
+ |
+ // Check devBounds |
+ SkASSERT(check_bounds<BezierVertex>(drawState, devBounds, arg.vertices(), |
+ kVertsPerQuad * quadCnt + kVertsPerQuad * conicCnt)); |
+ |
+ { |
+ GrDrawState::AutoRestoreEffects are(drawState); |
+ target->setIndexSourceToBuffer(fQuadsIndexBuffer); |
+ int quads = 0; |
+ drawState->addCoverageEffect(hairQuadEffect, kEdgeAttrIndex)->unref(); |
+ while (quads < quadCnt) { |
+ int n = GrMin(quadCnt - quads, kNumQuadsInIdxBuffer); |
+ target->drawIndexed(kTriangles_GrPrimitiveType, |
+ kVertsPerQuad*quads, // startV |
+ 0, // startI |
+ kVertsPerQuad*n, // vCount |
+ kIdxsPerQuad*n, // iCount |
+ &devBounds); |
+ quads += n; |
+ } |
+ } |
+ |
+ { |
+ GrDrawState::AutoRestoreEffects are(drawState); |
+ int conics = 0; |
+ drawState->addCoverageEffect(hairConicEffect, 1, 2)->unref(); |
+ while (conics < conicCnt) { |
+ int n = GrMin(conicCnt - conics, kNumQuadsInIdxBuffer); |
+ target->drawIndexed(kTriangles_GrPrimitiveType, |
+ kVertsPerQuad*(quadCnt + conics), // startV |
+ 0, // startI |
+ kVertsPerQuad*n, // vCount |
+ kIdxsPerQuad*n, // iCount |
+ &devBounds); |
+ conics += n; |
+ } |
} |
} |
+ |
target->resetIndexSource(); |
return true; |