Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(113)

Unified Diff: src/gpu/GrAAHairLinePathRenderer.cpp

Issue 22900007: Add direct bezier cubic support for GPU shaders (Closed) Base URL: https://skia.googlecode.com/svn/trunk
Patch Set: Created 7 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: src/gpu/GrAAHairLinePathRenderer.cpp
diff --git a/src/gpu/GrAAHairLinePathRenderer.cpp b/src/gpu/GrAAHairLinePathRenderer.cpp
index c1f951ab7f91832d95ece209f71b377794c68e48..47669b4d9b8b37317f44a7e4cf551444bf9d3015 100644
--- a/src/gpu/GrAAHairLinePathRenderer.cpp
+++ b/src/gpu/GrAAHairLinePathRenderer.cpp
@@ -29,6 +29,9 @@ namespace {
static const int kVertsPerQuad = 5;
static const int kIdxsPerQuad = 9;
+static const int kVertsPerCubic = 4;
+static const int kIdxsPerCubic = 6;
+
static const int kVertsPerLineSeg = 4;
static const int kIdxsPerLineSeg = 6;
@@ -37,6 +40,39 @@ static const size_t kQuadIdxSBufize = kIdxsPerQuad *
sizeof(uint16_t) *
kNumQuadsInIdxBuffer;
+static const int kNumCubicsInIdxBuffer = 256;
+static const size_t kCubicIdxSBufize = kIdxsPerCubic *
+ sizeof(uint16_t) *
+ kNumCubicsInIdxBuffer;
+
+bool push_cubic_index_data(GrIndexBuffer* cIdxBuffer) {
+ uint16_t* data = (uint16_t*) cIdxBuffer->lock();
+ bool tempData = NULL == data;
+ if (tempData) {
+ data = SkNEW_ARRAY(uint16_t, kNumCubicsInIdxBuffer * kIdxsPerCubic);
+ }
+ for (int i = 0; i < kNumCubicsInIdxBuffer; ++i) {
+
+ int baseIdx = i * kIdxsPerCubic;
+ uint16_t baseVert = (uint16_t)(i * kVertsPerCubic);
+
+ data[0 + baseIdx] = baseVert + 0;
+ data[1 + baseIdx] = baseVert + 1;
+ data[2 + baseIdx] = baseVert + 2;
+ data[3 + baseIdx] = baseVert + 2;
+ data[4 + baseIdx] = baseVert + 3;
+ data[5 + baseIdx] = baseVert + 0;
+ }
+ if (tempData) {
+ bool ret = cIdxBuffer->updateData(data, kCubicIdxSBufize);
+ delete[] data;
+ return ret;
+ } else {
+ cIdxBuffer->unlock();
+ return true;
+ }
+}
+
bool push_quad_index_data(GrIndexBuffer* qIdxBuffer) {
uint16_t* data = (uint16_t*) qIdxBuffer->lock();
bool tempData = NULL == data;
@@ -92,23 +128,33 @@ GrPathRenderer* GrAAHairLinePathRenderer::Create(GrContext* context) {
!push_quad_index_data(qIdxBuf)) {
return NULL;
}
+ GrIndexBuffer* cIdxBuf = gpu->createIndexBuffer(kCubicIdxSBufize, false);
+ SkAutoTUnref<GrIndexBuffer> cIdxBuffer(cIdxBuf);
+ if (NULL == cIdxBuf ||
+ !push_cubic_index_data(cIdxBuf)) {
+ return NULL;
+ }
return SkNEW_ARGS(GrAAHairLinePathRenderer,
- (context, lIdxBuffer, qIdxBuf));
+ (context, lIdxBuffer, qIdxBuf, cIdxBuf));
}
GrAAHairLinePathRenderer::GrAAHairLinePathRenderer(
const GrContext* context,
const GrIndexBuffer* linesIndexBuffer,
- const GrIndexBuffer* quadsIndexBuffer) {
+ const GrIndexBuffer* quadsIndexBuffer,
+ const GrIndexBuffer* cubicsIndexBuffer) {
fLinesIndexBuffer = linesIndexBuffer;
linesIndexBuffer->ref();
fQuadsIndexBuffer = quadsIndexBuffer;
quadsIndexBuffer->ref();
+ fCubicsIndexBuffer = cubicsIndexBuffer;
+ cubicsIndexBuffer->ref();
}
GrAAHairLinePathRenderer::~GrAAHairLinePathRenderer() {
fLinesIndexBuffer->unref();
fQuadsIndexBuffer->unref();
+ fCubicsIndexBuffer->unref();
}
namespace {
@@ -142,6 +188,9 @@ int get_float_exp(float x) {
return (((*iptr) & 0x7f800000) >> 23) - 127;
}
+//int chop_cubic_at_loop_intersection(const SkPoint src[4], SkPoint dst[10], SkScalar k[3] = NULL,
+// SkScalar l[3] = NULL, SkScalar m[3] = NULL);
+
// Uses the max curvature function for quads to estimate
// where to chop the conic. If the max curvature is not
// found along the curve segment it will return 1 and
@@ -179,6 +228,27 @@ int chop_conic(const SkPoint src[3], SkConic dst[4], const SkScalar weight) {
return conicCnt;
}
+int is_degen_cubic(const SkPoint p[4]) {
+ static const SkScalar gDegenerateToLineTol = SK_Scalar1;
+ static const SkScalar gDegenerateToLineTolSqd =
+ SkScalarMul(gDegenerateToLineTol, gDegenerateToLineTol);
+
+ if (p[0].distanceToSqd(p[3]) < gDegenerateToLineTolSqd &&
+ p[1].distanceToSqd(p[2]) < gDegenerateToLineTolSqd) {
+ return 1;
+ }
+
+ // if the points are all close to being colinear
+ SkScalar dsqd1= p[1].distanceToLineBetweenSqd(p[0], p[3]);
+ SkScalar dsqd2= p[2].distanceToLineBetweenSqd(p[0], p[3]);
+ if (dsqd1 < gDegenerateToLineTolSqd && dsqd2 < gDegenerateToLineTolSqd) {
+ return 1;
+ }
+
+ return 0;
+
+}
+
// returns 0 if quad/conic is degen or close to it
// in this case approx the path with lines
// otherwise returns 1
@@ -269,8 +339,10 @@ int generate_lines_and_quads(const SkPath& path,
PtArray* lines,
PtArray* quads,
PtArray* conics,
+ PtArray* cubics,
IntArray* quadSubdivCnts,
- FloatArray* conicWeights) {
+ FloatArray* conicWeights,
+ FloatArray* cubicKLM) {
SkPath::Iter iter(path, false);
int totalQuadCount = 0;
@@ -367,63 +439,48 @@ int generate_lines_and_quads(const SkPath& path,
}
break;
}
- case SkPath::kCubic_Verb:
+ case SkPath::kCubic_Verb: {
+ SkPoint dst[10];
+ SkScalar klm[9];
+ SkScalar klm_rev[3];
m.mapPoints(devPts, pathPts, 4);
- bounds.setBounds(devPts, 4);
- bounds.outset(SK_Scalar1, SK_Scalar1);
- bounds.roundOut(&ibounds);
- if (SkIRect::Intersects(devClipBounds, ibounds)) {
- PREALLOC_PTARRAY(32) q;
- // we don't need a direction if we aren't constraining the subdivision
- static const SkPath::Direction kDummyDir = SkPath::kCCW_Direction;
- // We convert cubics to quadratics (for now).
- // In perspective have to do conversion in src space.
- if (persp) {
- SkScalar tolScale =
- GrPathUtils::scaleToleranceToSrc(SK_Scalar1, m,
- path.getBounds());
- GrPathUtils::convertCubicToQuads(pathPts, tolScale, false, kDummyDir, &q);
- } else {
- GrPathUtils::convertCubicToQuads(devPts, SK_Scalar1, false, kDummyDir, &q);
- }
- for (int i = 0; i < q.count(); i += 3) {
- SkPoint* qInDevSpace;
- // bounds has to be calculated in device space, but q is
- // in src space when there is perspective.
- if (persp) {
- m.mapPoints(devPts, &q[i], 3);
- bounds.setBounds(devPts, 3);
- qInDevSpace = devPts;
+ int cubicCnt = GrPathUtils::chopCubicAtLoopIntersection(pathPts, dst, klm,
+ klm_rev, devPts);
+ for (int i = 0; i < cubicCnt; ++i) {
+ SkPoint* chopPnts = &dst[i*3];
+ m.mapPoints(devPts, chopPnts, 4);
+ bounds.setBounds(devPts, 4);
+ bounds.outset(SK_Scalar1, SK_Scalar1);
+ bounds.roundOut(&ibounds);
+ if (SkIRect::Intersects(devClipBounds, ibounds)) {
+ if (is_degen_cubic(devPts)) {
+ SkPoint* pts = lines->push_back_n(6);
+ pts[0] = devPts[0];
+ pts[1] = devPts[1];
+ pts[2] = devPts[1];
+ pts[3] = devPts[2];
+ pts[4] = devPts[2];
+ pts[5] = devPts[3];
} else {
- bounds.setBounds(&q[i], 3);
- qInDevSpace = &q[i];
- }
- bounds.outset(SK_Scalar1, SK_Scalar1);
- bounds.roundOut(&ibounds);
- if (SkIRect::Intersects(devClipBounds, ibounds)) {
- int subdiv = num_quad_subdivs(qInDevSpace);
- GrAssert(subdiv >= -1);
- if (-1 == subdiv) {
- SkPoint* pts = lines->push_back_n(4);
- // lines should always be in device coords
- pts[0] = qInDevSpace[0];
- pts[1] = qInDevSpace[1];
- pts[2] = qInDevSpace[1];
- pts[3] = qInDevSpace[2];
- } else {
- SkPoint* pts = quads->push_back_n(3);
- // q is already in src space when there is no
- // perspective and dev coords otherwise.
- pts[0] = q[0 + i];
- pts[1] = q[1 + i];
- pts[2] = q[2 + i];
- quadSubdivCnts->push_back() = subdiv;
- totalQuadCount += 1 << subdiv;
+ // when in perspective keep conics in src space
+ SkPoint* cPts = persp ? chopPnts : devPts;
+ SkPoint* pts = cubics->push_back_n(4);
+ pts[0] = cPts[0];
+ pts[1] = cPts[1];
+ pts[2] = cPts[2];
+ pts[3] = cPts[3];
+ SkScalar* klms = cubicKLM->push_back_n(9);
+ // set sub sections klm to equal klm of whole curve and
+ // flip the signs of k, l if needed
+ memcpy(klms, klm, 9 * sizeof(SkScalar));
+ for (int j = 0; j < 6; ++j) {
+ klms[j] *= klm_rev[i];
}
}
}
}
break;
+ }
case SkPath::kClose_Verb:
break;
case SkPath::kDone_Verb:
@@ -444,7 +501,7 @@ struct Vertex {
SkScalar fK;
SkScalar fL;
SkScalar fM;
- } fConic;
+ } fBezier;
GrVec fQuadCoord;
struct {
SkScalar fBogus[4];
@@ -478,6 +535,66 @@ void set_uv_quad(const SkPoint qpts[3], Vertex verts[kVertsPerQuad]) {
DevToUV.apply<kVertsPerQuad, sizeof(Vertex), sizeof(GrPoint)>(verts);
}
+// Set verts to be bounding box around the control points cpts bloated
+// out by 1 in each direcition
+void bloat_cubic(const SkPoint cpts[4], const SkMatrix* toDevice,
+ const SkMatrix* toSrc, Vertex verts[kVertsPerCubic],
+ SkRect* devBounds) {
+ GrAssert(!toDevice == !toSrc);
+ // original cubic is specified by quad a,b,c,d
+ SkPoint a = cpts[0];
+ SkPoint b = cpts[1];
+ SkPoint c = cpts[2];
+ SkPoint d = cpts[3];
+
+ if (toDevice) {
+ toDevice->mapPoints(&a, 1);
+ toDevice->mapPoints(&b, 1);
+ toDevice->mapPoints(&c, 1);
+ toDevice->mapPoints(&d, 1);
+ }
+
+ SkScalar minX = cpts[0].fX;
+ SkScalar maxX = cpts[0].fX;
+ SkScalar minY = cpts[0].fY;
+ SkScalar maxY = cpts[0].fY;
+
+ for (int i = 1; i < 4; ++i) {
+ minX = SkMinScalar(minX, cpts[i].fX);
+ maxX = SkMaxScalar(maxX, cpts[i].fX);
+ minY = SkMinScalar(minY, cpts[i].fY);
+ maxY = SkMaxScalar(maxY, cpts[i].fY);
+ }
+
+ minX -= 1.0f;
+ maxX += 1.0f;
+ minY -= 1.0f;
+ maxY += 1.0f;
+
+ Vertex& a1 = verts[0];
+ Vertex& b1 = verts[1];
+ Vertex& c1 = verts[2];
+ Vertex& d1 = verts[3];
+
+ a1.fPos.fX = minX;
+ a1.fPos.fY = minY;
+ b1.fPos.fX = maxX;
+ b1.fPos.fY = minY;
+ c1.fPos.fX = maxX;
+ c1.fPos.fY = maxY;
+ d1.fPos.fX = minX;
+ d1.fPos.fY = maxY;
+
+ devBounds->growToInclude(a1.fPos.fX, a1.fPos.fY);
+ devBounds->growToInclude(b1.fPos.fX, b1.fPos.fY);
+ devBounds->growToInclude(c1.fPos.fX, c1.fPos.fY);
+ devBounds->growToInclude(d1.fPos.fX, d1.fPos.fY);
+
+ if (toSrc) {
+ toSrc->mapPointsWithStride(&verts[0].fPos, sizeof(Vertex), kVertsPerCubic);
+ }
+}
+
void bloat_quad(const SkPoint qpts[3], const SkMatrix* toDevice,
const SkMatrix* toSrc, Vertex verts[kVertsPerQuad],
SkRect* devBounds) {
@@ -584,16 +701,16 @@ void calc_conic_klm(const SkPoint p[3], const SkScalar weight,
scale = SkMaxScalar(scale, SkScalarAbs(m[i]));
}
GrAssert(scale > 0);
- scale /= 10.0f;
- k[0] /= scale;
- k[1] /= scale;
- k[2] /= scale;
- l[0] /= scale;
- l[1] /= scale;
- l[2] /= scale;
- m[0] /= scale;
- m[1] /= scale;
- m[2] /= scale;
+ scale = 10.0f / scale;
+ k[0] *= scale;
+ k[1] *= scale;
+ k[2] *= scale;
+ l[0] *= scale;
+ l[1] *= scale;
+ l[2] *= scale;
+ m[0] *= scale;
+ m[1] *= scale;
+ m[2] *= scale;
}
// Equations based off of Loop-Blinn Quadratic GPU Rendering
@@ -603,7 +720,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_klm(const SkPoint p[3], Vertex verts[kVertsPerQuad], const float weight) {
SkScalar k[3];
SkScalar l[3];
SkScalar m[3];
@@ -612,12 +729,32 @@ void set_conic_coeffs(const SkPoint p[3], Vertex verts[kVertsPerQuad], const flo
for (int i = 0; i < kVertsPerQuad; ++i) {
const SkPoint pnt = verts[i].fPos;
- verts[i].fConic.fK = pnt.fX * k[0] + pnt.fY * k[1] + k[2];
- verts[i].fConic.fL = pnt.fX * l[0] + pnt.fY * l[1] + l[2];
- verts[i].fConic.fM = pnt.fX * m[0] + pnt.fY * m[1] + m[2];
+ verts[i].fBezier.fK = pnt.fX * k[0] + pnt.fY * k[1] + k[2];
+ verts[i].fBezier.fL = pnt.fX * l[0] + pnt.fY * l[1] + l[2];
+ verts[i].fBezier.fM = pnt.fX * m[0] + pnt.fY * m[1] + m[2];
+ }
+}
+
+void set_cubic_klm(const SkPoint p[4], Vertex verts[kVertsPerCubic], const SkScalar klm[9]) {
+ for (int i = 0; i < kVertsPerCubic; ++i) {
+ const SkPoint pnt = verts[i].fPos;
+ verts[i].fBezier.fK = pnt.fX * klm[0] + pnt.fY * klm[1] + klm[2];
+ verts[i].fBezier.fL = pnt.fX * klm[3] + pnt.fY * klm[4] + klm[5];
+ verts[i].fBezier.fM = pnt.fX * klm[6] + pnt.fY * klm[7] + klm[8];
}
}
+void add_cubics(const SkPoint p[3],
+ const SkScalar klm[9],
+ const SkMatrix* toDevice,
+ const SkMatrix* toSrc,
+ Vertex** vert,
+ SkRect* devBounds) {
+ bloat_cubic(p, toDevice, toSrc, *vert, devBounds);
+ set_cubic_klm(p, *vert, klm);
+ *vert += kVertsPerCubic;
+}
+
void add_conics(const SkPoint p[3],
float weight,
const SkMatrix* toDevice,
@@ -625,7 +762,7 @@ void add_conics(const SkPoint p[3],
Vertex** vert,
SkRect* devBounds) {
bloat_quad(p, toDevice, toSrc, *vert, devBounds);
- set_conic_coeffs(p, *vert, weight);
+ set_conic_klm(p, *vert, weight);
*vert += kVertsPerQuad;
}
@@ -692,6 +829,105 @@ void add_line(const SkPoint p[2],
}
/**
+ * Shader is based off of "Resolution Independent Curve Rendering using
+ * Programmable Graphics Hardware" by Loop and Blinn.
+ * The output of this effect is a hairline edge for non rational cubics.
+ * Cubics are specified by implicit equation K^3 - LM.
+ * K, L, and M, are the first three values of the vertex attribute,
+ * the fourth value is not used. Distance is calculated using a
+ * first order approximation from the taylor series.
+ * Coverage is max(0, 1-distance).
+ */
+class HairCubicEdgeEffect : public GrEffect {
+public:
+ static GrEffectRef* Create() {
+ GR_CREATE_STATIC_EFFECT(gHairCubicEdgeEffect, HairCubicEdgeEffect, ());
+ gHairCubicEdgeEffect->ref();
+ return gHairCubicEdgeEffect;
+ }
+
+ virtual ~HairCubicEdgeEffect() {}
+
+ static const char* Name() { return "HairCubicEdge"; }
+
+ virtual void getConstantColorComponents(GrColor* color,
+ uint32_t* validFlags) const SK_OVERRIDE {
+ *validFlags = 0;
+ }
+
+ virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE {
+ return GrTBackendEffectFactory<HairCubicEdgeEffect>::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;
+
+ SkAssertResult(builder->enableFeature(
+ GrGLShaderBuilder::kStandardDerivatives_GLSLFeature));
+ builder->addVarying(kVec4f_GrSLType, "CubicCoeffs",
+ &vsName, &fsName);
+ const SkString* attr0Name =
+ builder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]);
+ builder->vsCodeAppendf("\t%s = %s;\n", vsName, attr0Name->c_str());
+
+ builder->fsCodeAppend("\t\tfloat edgeAlpha;\n");
+
+ builder->fsCodeAppendf("\t\tvec3 dklmdx = dFdx(%s.xyz);\n", fsName);
+ builder->fsCodeAppendf("\t\tvec3 dklmdy = dFdy(%s.xyz);\n", fsName);
+ builder->fsCodeAppendf("\t\tfloat dfdx =\n"
+ "\t\t3.0*%s.x*%s.x*dklmdx.x - %s.y*dklmdx.z - %s.z*dklmdx.y;\n",
+ fsName, fsName, fsName, fsName);
+ builder->fsCodeAppendf("\t\tfloat dfdy =\n"
+ "\t\t3.0*%s.x*%s.x*dklmdy.x - %s.y*dklmdy.z - %s.z*dklmdy.y;\n",
+ fsName, fsName, fsName, fsName);
+ builder->fsCodeAppend("\t\tvec2 gF = vec2(dfdx, dfdy);\n");
+ builder->fsCodeAppend("\t\tfloat gFM = sqrt(dot(gF, gF));\n");
+ builder->fsCodeAppendf("\t\tfloat func = abs(%s.x*%s.x*%s.x - %s.y*%s.z);\n",
+ fsName, fsName, fsName, fsName, fsName);
+ builder->fsCodeAppend("\t\tedgeAlpha = func / gFM;\n");
+ builder->fsCodeAppend("\t\tedgeAlpha = max(1.0 - edgeAlpha, 0.0);\n");
+ // Add line below for smooth cubic ramp
+ // builder->fsCodeAppend("\t\tedgeAlpha = edgeAlpha*edgeAlpha*(3.0-2.0*edgeAlpha);\n");
+
+ SkString modulate;
+ GrGLSLModulatef<4>(&modulate, inputColor, "edgeAlpha");
+ builder->fsCodeAppendf("\t%s = %s;\n", outputColor, modulate.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:
+ HairCubicEdgeEffect() {
+ this->addVertexAttrib(kVec4f_GrSLType);
+ }
+
+ virtual bool onIsEqual(const GrEffect& other) const SK_OVERRIDE {
+ return true;
+ }
+
+ GR_DECLARE_EFFECT_TEST;
+
+ typedef GrEffect INHERITED;
+};
+/**
* Shader is based off of Loop-Blinn Quadratic GPU Rendering
* The output of this effect is a hairline edge for conics.
* Conics specified by implicit equation K^2 - LM.
@@ -1040,6 +1276,7 @@ bool GrAAHairLinePathRenderer::createGeom(
int* lineCnt,
int* quadCnt,
int* conicCnt,
+ int* cubicCnt,
GrDrawTarget::AutoReleaseGeometry* arg,
SkRect* devBounds) {
GrDrawState* drawState = target->drawState();
@@ -1060,15 +1297,19 @@ bool GrAAHairLinePathRenderer::createGeom(
PREALLOC_PTARRAY(128) lines;
PREALLOC_PTARRAY(128) quads;
PREALLOC_PTARRAY(128) conics;
+ PREALLOC_PTARRAY(128) cubics;
IntArray qSubdivs;
FloatArray cWeights;
+ FloatArray cubicKLM;
*quadCnt = generate_lines_and_quads(path, viewM, devClipBounds,
- &lines, &quads, &conics, &qSubdivs, &cWeights);
+ &lines, &quads, &conics, &cubics,
+ &qSubdivs, &cWeights, &cubicKLM);
*lineCnt = lines.count() / 2;
*conicCnt = conics.count() / 3;
+ *cubicCnt = cubics.count() / 4;
int vertCnt = kVertsPerLineSeg * *lineCnt + kVertsPerQuad * *quadCnt +
- kVertsPerQuad * *conicCnt;
+ kVertsPerQuad * *conicCnt + kVertsPerCubic * *cubicCnt;
target->drawState()->setVertexAttribs<gHairlineAttribs>(SK_ARRAY_COUNT(gHairlineAttribs));
GrAssert(sizeof(Vertex) == target->getDrawState().getVertexSize());
@@ -1100,10 +1341,13 @@ bool GrAAHairLinePathRenderer::createGeom(
add_quads(&quads[3*i], qSubdivs[i], toDevice, toSrc, &verts, devBounds);
}
- // Start Conics
for (int i = 0; i < *conicCnt; ++i) {
add_conics(&conics[3*i], cWeights[i], toDevice, toSrc, &verts, devBounds);
}
+
+ for (int i = 0; i < *cubicCnt; ++i) {
+ add_cubics(&cubics[4*i], &cubicKLM[9*i], toDevice, toSrc, &verts, devBounds);
+ }
return true;
}
@@ -1130,6 +1374,7 @@ bool GrAAHairLinePathRenderer::onDrawPath(const SkPath& path,
int lineCnt;
int quadCnt;
int conicCnt;
+ int cubicCnt;
GrDrawTarget::AutoReleaseGeometry arg;
SkRect devBounds;
@@ -1138,6 +1383,7 @@ bool GrAAHairLinePathRenderer::onDrawPath(const SkPath& path,
&lineCnt,
&quadCnt,
&conicCnt,
+ &cubicCnt,
&arg,
&devBounds)) {
return false;
@@ -1162,6 +1408,7 @@ bool GrAAHairLinePathRenderer::onDrawPath(const SkPath& path,
GrEffectRef* hairLineEffect = HairLineEdgeEffect::Create();
GrEffectRef* hairQuadEffect = HairQuadEdgeEffect::Create();
GrEffectRef* hairConicEffect = HairConicEdgeEffect::Create();
+ GrEffectRef* hairCubicEffect = HairCubicEdgeEffect::Create();
// Check devBounds
#if GR_DEBUG
@@ -1228,7 +1475,7 @@ bool GrAAHairLinePathRenderer::onDrawPath(const SkPath& path,
{
GrDrawState::AutoRestoreEffects are(drawState);
int conics = 0;
- drawState->addCoverageEffect(hairConicEffect, 1, 2)->unref();
+ drawState->addCoverageEffect(hairConicEffect, kEdgeAttrIndex)->unref();
while (conics < conicCnt) {
int n = GrMin(conicCnt - conics, kNumQuadsInIdxBuffer);
target->drawIndexed(kTriangles_GrPrimitiveType,
@@ -1241,6 +1488,25 @@ bool GrAAHairLinePathRenderer::onDrawPath(const SkPath& path,
conics += n;
}
}
+
+ {
+ GrDrawState::AutoRestoreEffects are(drawState);
+ target->setIndexSourceToBuffer(fCubicsIndexBuffer);
+ int cubics = 0;
+ drawState->addCoverageEffect(hairCubicEffect, kEdgeAttrIndex)->unref();
+ while (cubics < cubicCnt) {
+ int n = GrMin(cubicCnt - cubics, kNumCubicsInIdxBuffer);
+ target->drawIndexed(kTriangles_GrPrimitiveType,
+ kVertsPerLineSeg * lineCnt +
+ kVertsPerQuad * (quadCnt + conicCnt) +
+ kVertsPerCubic * cubics, // startV
+ 0, // startI
+ kVertsPerCubic*n, // vCount
+ kIdxsPerCubic*n, // iCount
+ &devBounds);
+ cubics += n;
+ }
+ }
target->resetIndexSource();
return true;

Powered by Google App Engine
This is Rietveld 408576698