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

Side by Side Diff: src/gpu/GrAAHairLinePathRenderer.cpp

Issue 18258005: Add implicit hairline conic rendering to GPU (Closed) Base URL: https://skia.googlecode.com/svn/trunk
Patch Set: Created 7 years, 5 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 unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/gpu/GrAAHairLinePathRenderer.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 1
2 /* 2 /*
3 * Copyright 2011 Google Inc. 3 * Copyright 2011 Google Inc.
4 * 4 *
5 * Use of this source code is governed by a BSD-style license that can be 5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file. 6 * found in the LICENSE file.
7 */ 7 */
8 8
9 #include "GrAAHairLinePathRenderer.h" 9 #include "GrAAHairLinePathRenderer.h"
10 10
11 #include "GrContext.h" 11 #include "GrContext.h"
12 #include "GrDrawState.h" 12 #include "GrDrawState.h"
13 #include "GrDrawTargetCaps.h" 13 #include "GrDrawTargetCaps.h"
14 #include "GrEffect.h" 14 #include "GrEffect.h"
15 #include "GrGpu.h" 15 #include "GrGpu.h"
16 #include "GrIndexBuffer.h" 16 #include "GrIndexBuffer.h"
17 #include "GrPathUtils.h" 17 #include "GrPathUtils.h"
18 #include "GrTBackendEffectFactory.h" 18 #include "GrTBackendEffectFactory.h"
19 #include "SkGeometry.h" 19 #include "SkGeometry.h"
20 #include "SkStroke.h" 20 #include "SkStroke.h"
21 #include "SkTemplates.h" 21 #include "SkTemplates.h"
22 22
23 #include "gl/GrGLEffect.h" 23 #include "gl/GrGLEffect.h"
24 #include "gl/GrGLSL.h" 24 #include "gl/GrGLSL.h"
25 25
26 namespace { 26 namespace {
27 // quadratics are rendered as 5-sided polys in order to bound the 27 // quadratics are rendered as 5-sided polys in order to bound the
28 // AA stroke around the center-curve. See comments in push_quad_index_buffer and 28 // AA stroke around the center-curve. See comments in push_quad_index_buffer and
29 // bloat_quad. 29 // bloat_quad. Quadratics and conics share an index buffer
30 static const int kVertsPerQuad = 5; 30 static const int kVertsPerQuad = 5;
31 static const int kIdxsPerQuad = 9; 31 static const int kIdxsPerQuad = 9;
32 32
33 static const int kVertsPerLineSeg = 4; 33 static const int kVertsPerLineSeg = 4;
34 static const int kIdxsPerLineSeg = 6; 34 static const int kIdxsPerLineSeg = 6;
35 35
36 static const int kNumQuadsInIdxBuffer = 256; 36 static const int kNumQuadsInIdxBuffer = 256;
37 static const size_t kQuadIdxSBufize = kIdxsPerQuad * 37 static const size_t kQuadIdxSBufize = kIdxsPerQuad *
38 sizeof(uint16_t) * 38 sizeof(uint16_t) *
39 kNumQuadsInIdxBuffer; 39 kNumQuadsInIdxBuffer;
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after
110 GrAAHairLinePathRenderer::~GrAAHairLinePathRenderer() { 110 GrAAHairLinePathRenderer::~GrAAHairLinePathRenderer() {
111 fLinesIndexBuffer->unref(); 111 fLinesIndexBuffer->unref();
112 fQuadsIndexBuffer->unref(); 112 fQuadsIndexBuffer->unref();
113 } 113 }
114 114
115 namespace { 115 namespace {
116 116
117 typedef SkTArray<SkPoint, true> PtArray; 117 typedef SkTArray<SkPoint, true> PtArray;
118 #define PREALLOC_PTARRAY(N) SkSTArray<(N),SkPoint, true> 118 #define PREALLOC_PTARRAY(N) SkSTArray<(N),SkPoint, true>
119 typedef SkTArray<int, true> IntArray; 119 typedef SkTArray<int, true> IntArray;
120 typedef SkTArray<float, true> FloatArray;
120 121
121 // Takes 178th time of logf on Z600 / VC2010 122 // Takes 178th time of logf on Z600 / VC2010
122 int get_float_exp(float x) { 123 int get_float_exp(float x) {
123 GR_STATIC_ASSERT(sizeof(int) == sizeof(float)); 124 GR_STATIC_ASSERT(sizeof(int) == sizeof(float));
124 #if GR_DEBUG 125 #if GR_DEBUG
125 static bool tested; 126 static bool tested;
126 if (!tested) { 127 if (!tested) {
127 tested = true; 128 tested = true;
128 GrAssert(get_float_exp(0.25f) == -2); 129 GrAssert(get_float_exp(0.25f) == -2);
129 GrAssert(get_float_exp(0.3f) == -2); 130 GrAssert(get_float_exp(0.3f) == -2);
130 GrAssert(get_float_exp(0.5f) == -1); 131 GrAssert(get_float_exp(0.5f) == -1);
131 GrAssert(get_float_exp(1.f) == 0); 132 GrAssert(get_float_exp(1.f) == 0);
132 GrAssert(get_float_exp(2.f) == 1); 133 GrAssert(get_float_exp(2.f) == 1);
133 GrAssert(get_float_exp(2.5f) == 1); 134 GrAssert(get_float_exp(2.5f) == 1);
134 GrAssert(get_float_exp(8.f) == 3); 135 GrAssert(get_float_exp(8.f) == 3);
135 GrAssert(get_float_exp(100.f) == 6); 136 GrAssert(get_float_exp(100.f) == 6);
136 GrAssert(get_float_exp(1000.f) == 9); 137 GrAssert(get_float_exp(1000.f) == 9);
137 GrAssert(get_float_exp(1024.f) == 10); 138 GrAssert(get_float_exp(1024.f) == 10);
138 GrAssert(get_float_exp(3000000.f) == 21); 139 GrAssert(get_float_exp(3000000.f) == 21);
139 } 140 }
140 #endif 141 #endif
141 const int* iptr = (const int*)&x; 142 const int* iptr = (const int*)&x;
142 return (((*iptr) & 0x7f800000) >> 23) - 127; 143 return (((*iptr) & 0x7f800000) >> 23) - 127;
143 } 144 }
144 145
146 // Uses the max curvature function for quads to estimate
147 // where to chop the conic. If the max curvature is not
148 // found along the curve segment it will return 1 and
149 // dst[0] is the orginal conic. If it returns 2 the dst[0]
150 // and dst[1] are the two new conics.
151 int chop_conic(const SkPoint src[3], SkConic dst[2], const SkScalar weight) {
152 SkScalar t = SkFindQuadMaxCurvature(src);
153 if (t == 0) {
154 if (dst) {
155 dst[0].set(src, weight);
156 }
157 return 1;
158 } else {
159 if (dst) {
160 SkConic conic;
161 conic.set(src, weight);
162 conic.chopAt(t, dst);
163 }
164 return 2;
165 }
166 }
167
168 // returns 0 if quad/conic is degen or close to it
169 // in this case approx the path with lines
170 // otherwise returns 1
171 int is_degen_quad_or_conic(const SkPoint p[3]) {
172 static const SkScalar gDegenerateToLineTol = SK_Scalar1;
173 static const SkScalar gDegenerateToLineTolSqd =
174 SkScalarMul(gDegenerateToLineTol, gDegenerateToLineTol);
175
176 if (p[0].distanceToSqd(p[1]) < gDegenerateToLineTolSqd ||
177 p[1].distanceToSqd(p[2]) < gDegenerateToLineTolSqd) {
178 return 1;
179 }
180
181 SkScalar dsqd = p[1].distanceToLineBetweenSqd(p[0], p[2]);
182 if (dsqd < gDegenerateToLineTolSqd) {
183 return 1;
184 }
185
186 if (p[2].distanceToLineBetweenSqd(p[1], p[0]) < gDegenerateToLineTolSqd) {
187 return 1;
188 }
189 return 0;
190 }
191
145 // we subdivide the quads to avoid huge overfill 192 // we subdivide the quads to avoid huge overfill
146 // if it returns -1 then should be drawn as lines 193 // if it returns -1 then should be drawn as lines
147 int num_quad_subdivs(const SkPoint p[3]) { 194 int num_quad_subdivs(const SkPoint p[3]) {
148 static const SkScalar gDegenerateToLineTol = SK_Scalar1; 195 static const SkScalar gDegenerateToLineTol = SK_Scalar1;
149 static const SkScalar gDegenerateToLineTolSqd = 196 static const SkScalar gDegenerateToLineTolSqd =
150 SkScalarMul(gDegenerateToLineTol, gDegenerateToLineTol); 197 SkScalarMul(gDegenerateToLineTol, gDegenerateToLineTol);
151 198
152 if (p[0].distanceToSqd(p[1]) < gDegenerateToLineTolSqd || 199 if (p[0].distanceToSqd(p[1]) < gDegenerateToLineTolSqd ||
153 p[1].distanceToSqd(p[2]) < gDegenerateToLineTolSqd) { 200 p[1].distanceToSqd(p[2]) < gDegenerateToLineTolSqd) {
154 return -1; 201 return -1;
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
200 * Quads are recorded in device space unless m contains 247 * Quads are recorded in device space unless m contains
201 * perspective, then in they are in src space. We do this because we will 248 * perspective, then in they are in src space. We do this because we will
202 * subdivide large quads to reduce over-fill. This subdivision has to be 249 * subdivide large quads to reduce over-fill. This subdivision has to be
203 * performed before applying the perspective matrix. 250 * performed before applying the perspective matrix.
204 */ 251 */
205 int generate_lines_and_quads(const SkPath& path, 252 int generate_lines_and_quads(const SkPath& path,
206 const SkMatrix& m, 253 const SkMatrix& m,
207 const GrIRect& devClipBounds, 254 const GrIRect& devClipBounds,
208 PtArray* lines, 255 PtArray* lines,
209 PtArray* quads, 256 PtArray* quads,
210 IntArray* quadSubdivCnts) { 257 PtArray* conics,
258 IntArray* quadSubdivCnts,
259 FloatArray* conicWeights) {
211 SkPath::Iter iter(path, false); 260 SkPath::Iter iter(path, false);
212 261
213 int totalQuadCount = 0; 262 int totalQuadCount = 0;
214 GrRect bounds; 263 GrRect bounds;
215 GrIRect ibounds; 264 GrIRect ibounds;
216 265
217 bool persp = m.hasPerspective(); 266 bool persp = m.hasPerspective();
218 267
219 for (;;) { 268 for (;;) {
220 GrPoint pathPts[4]; 269 GrPoint pathPts[4];
221 GrPoint devPts[4]; 270 GrPoint devPts[4];
222 SkPath::Verb verb = iter.next(pathPts); 271 SkPath::Verb verb = iter.next(pathPts);
223 switch (verb) { 272 switch (verb) {
224 case SkPath::kConic_Verb: 273 case SkPath::kConic_Verb: {
225 SkASSERT(0); 274 SkConic dst[2];
275 int conicCnt = chop_conic(pathPts, dst, iter.conicWeight());
276 for (int i = 0; i < conicCnt; ++i) {
277 SkPoint* chopPnts = dst[i].fPts;
278 m.mapPoints(devPts, chopPnts, 3);
279 bounds.setBounds(devPts, 3);
280 bounds.outset(SK_Scalar1, SK_Scalar1);
281 bounds.roundOut(&ibounds);
282 if (SkIRect::Intersects(devClipBounds, ibounds)) {
283 if (is_degen_quad_or_conic(devPts)) {
284 SkPoint* pts = lines->push_back_n(4);
285 pts[0] = devPts[0];
286 pts[1] = devPts[1];
287 pts[2] = devPts[1];
288 pts[3] = devPts[2];
289 } else {
290 // when in perspective keep conics in src space
291 SkPoint* cPts = persp ? chopPnts : devPts;
292 SkPoint* pts = conics->push_back_n(3);
293 pts[0] = cPts[0];
294 pts[1] = cPts[1];
295 pts[2] = cPts[2];
296 conicWeights->push_back() = dst[i].fW;
297 }
298 }
299 }
226 break; 300 break;
227 case SkPath::kMove_Verb: 301 }
302 case SkPath::kMove_Verb:
228 break; 303 break;
229 case SkPath::kLine_Verb: 304 case SkPath::kLine_Verb:
230 m.mapPoints(devPts, pathPts, 2); 305 m.mapPoints(devPts, pathPts, 2);
231 bounds.setBounds(devPts, 2); 306 bounds.setBounds(devPts, 2);
232 bounds.outset(SK_Scalar1, SK_Scalar1); 307 bounds.outset(SK_Scalar1, SK_Scalar1);
233 bounds.roundOut(&ibounds); 308 bounds.roundOut(&ibounds);
234 if (SkIRect::Intersects(devClipBounds, ibounds)) { 309 if (SkIRect::Intersects(devClipBounds, ibounds)) {
235 SkPoint* pts = lines->push_back_n(2); 310 SkPoint* pts = lines->push_back_n(2);
236 pts[0] = devPts[0]; 311 pts[0] = devPts[0];
237 pts[1] = devPts[1]; 312 pts[1] = devPts[1];
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after
341 } 416 }
342 417
343 struct Vertex { 418 struct Vertex {
344 GrPoint fPos; 419 GrPoint fPos;
345 union { 420 union {
346 struct { 421 struct {
347 SkScalar fA; 422 SkScalar fA;
348 SkScalar fB; 423 SkScalar fB;
349 SkScalar fC; 424 SkScalar fC;
350 } fLine; 425 } fLine;
426 struct {
427 SkScalar fA;
428 SkScalar fB;
429 SkScalar fC;
430 SkScalar fD;
431 SkScalar fE;
432 SkScalar fF;
433 } fConic;
351 GrVec fQuadCoord; 434 GrVec fQuadCoord;
352 struct { 435 struct {
353 SkScalar fBogus[4]; 436 SkScalar fBogus[6];
354 }; 437 };
355 }; 438 };
356 }; 439 };
357 GR_STATIC_ASSERT(sizeof(Vertex) == 3 * sizeof(GrPoint)); 440
441 GR_STATIC_ASSERT(sizeof(Vertex) == 4 * sizeof(GrPoint));
358 442
359 void intersect_lines(const SkPoint& ptA, const SkVector& normA, 443 void intersect_lines(const SkPoint& ptA, const SkVector& normA,
360 const SkPoint& ptB, const SkVector& normB, 444 const SkPoint& ptB, const SkVector& normB,
361 SkPoint* result) { 445 SkPoint* result) {
362 446
363 SkScalar lineAW = -normA.dot(ptA); 447 SkScalar lineAW = -normA.dot(ptA);
364 SkScalar lineBW = -normB.dot(ptB); 448 SkScalar lineBW = -normB.dot(ptB);
365 449
366 SkScalar wInv = SkScalarMul(normA.fX, normB.fY) - 450 SkScalar wInv = SkScalarMul(normA.fX, normB.fY) -
367 SkScalarMul(normA.fY, normB.fX); 451 SkScalarMul(normA.fY, normB.fX);
368 wInv = SkScalarInvert(wInv); 452 wInv = SkScalarInvert(wInv);
369 453
370 result->fX = SkScalarMul(normA.fY, lineBW) - SkScalarMul(lineAW, normB.fY); 454 result->fX = SkScalarMul(normA.fY, lineBW) - SkScalarMul(lineAW, normB.fY);
371 result->fX = SkScalarMul(result->fX, wInv); 455 result->fX = SkScalarMul(result->fX, wInv);
372 456
373 result->fY = SkScalarMul(lineAW, normB.fX) - SkScalarMul(normA.fX, lineBW); 457 result->fY = SkScalarMul(lineAW, normB.fX) - SkScalarMul(normA.fX, lineBW);
374 result->fY = SkScalarMul(result->fY, wInv); 458 result->fY = SkScalarMul(result->fY, wInv);
375 } 459 }
376 460
377 void bloat_quad(const SkPoint qpts[3], const SkMatrix* toDevice, 461 void bloat_quad(const SkPoint qpts[3], const SkMatrix* toDevice,
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
447 // include it. 531 // include it.
448 intersect_lines(a0.fPos, abN, c0.fPos, cbN, &b0.fPos); 532 intersect_lines(a0.fPos, abN, c0.fPos, cbN, &b0.fPos);
449 devBounds->growToInclude(b0.fPos.fX, b0.fPos.fY); 533 devBounds->growToInclude(b0.fPos.fX, b0.fPos.fY);
450 534
451 if (toSrc) { 535 if (toSrc) {
452 toSrc->mapPointsWithStride(&verts[0].fPos, sizeof(Vertex), kVertsPerQuad ); 536 toSrc->mapPointsWithStride(&verts[0].fPos, sizeof(Vertex), kVertsPerQuad );
453 } 537 }
454 DevToUV.apply<kVertsPerQuad, sizeof(Vertex), sizeof(GrPoint)>(verts); 538 DevToUV.apply<kVertsPerQuad, sizeof(Vertex), sizeof(GrPoint)>(verts);
455 } 539 }
456 540
541
542 // Input Parametric:
543 // P(t) = (P0*(1-t)^2 + 2*w*P1*t*(1-t) + P2*t^2) / (1-t)^2 + 2*w*t*(1-t) + t^2)
544 // Output Implicit:
545 // Ax^2 + Bxy + Cy^2 + Dx + Ey + F = 0
546 // A = 4w^2*(y0-y1)(y1-y2)-(y0-y2)^2
547 // B = 4w^2*((x0-x1)(y2-y1)+(x1-x2)(y1-y0)) + 2(x0-x2)(y0-y2)
548 // C = 4w^2(x0-x1)(x1-x2) - (x0-x2)^2
549 // D = 4w^2((x0y1-x1y0)(y1-y2)+(x1y2-x2y1)(y0-y1)) + 2(y2-y0)(x0y2-x2y0)
550 // E = 4w^2((y0x1-y1x0)(x1-x2)+(y1x2-y2x1)(x0-x1)) + 2(x2-x0)(y0x2-y2x0)
551 // F = 4w^2(x1y2-x2y1)(x0y1-x1y0) - (x2y0-x0y2)^2
552
553 void set_conic_coeffs(const SkPoint p[3], Vertex verts[kVertsPerQuad], const flo at weight) {
554 const float ww4 = 4 * weight * weight;
555 const float x0Mx1 = p[0].fX - p[1].fX;
556 const float x1Mx2 = p[1].fX - p[2].fX;
557 const float x0Mx2 = p[0].fX - p[2].fX;
558 const float y0My1 = p[0].fY - p[1].fY;
559 const float y1My2 = p[1].fY - p[2].fY;
560 const float y0My2 = p[0].fY - p[2].fY;
561 const float x0y1Mx1y0 = p[0].fX*p[1].fY - p[1].fX*p[0].fY;
562 const float x1y2Mx2y1 = p[1].fX*p[2].fY - p[2].fX*p[1].fY;
563 const float x0y2Mx2y0 = p[0].fX*p[2].fY - p[2].fX*p[0].fY;
564 const float a = ww4 * y0My1 * y1My2 - y0My2 * y0My2;
565 const float b = -ww4 * (x0Mx1 * y1My2 + x1Mx2 * y0My1) + 2 * x0Mx2 * y0My2;
566 const float c = ww4 * x0Mx1 * x1Mx2 - x0Mx2 * x0Mx2;
567 const float d = ww4 * (x0y1Mx1y0 * y1My2 + x1y2Mx2y1 * y0My1) - 2 * y0My2 * x0y2Mx2y0;
568 const float e = -ww4 * (x0y1Mx1y0 * x1Mx2 + x1y2Mx2y1 * x0Mx1) + 2 * x0Mx2 * x0y2Mx2y0;
569 const float f = ww4 * x1y2Mx2y1 * x0y1Mx1y0 - x0y2Mx2y0 * x0y2Mx2y0;
570
571 for (int i = 0; i < kVertsPerQuad; ++i) {
572 verts[i].fConic.fA = a/f;
573 verts[i].fConic.fB = b/f;
574 verts[i].fConic.fC = c/f;
575 verts[i].fConic.fD = d/f;
576 verts[i].fConic.fE = e/f;
577 verts[i].fConic.fF = f/f;
578 }
579 }
580
581 void add_conics(const SkPoint p[3],
582 float weight,
583 const SkMatrix* toDevice,
584 const SkMatrix* toSrc,
585 Vertex** vert,
586 SkRect* devBounds) {
587 bloat_quad(p, toDevice, toSrc, *vert, devBounds);
588 set_conic_coeffs(p, *vert, weight);
589 *vert += kVertsPerQuad;
590 }
591
457 void add_quads(const SkPoint p[3], 592 void add_quads(const SkPoint p[3],
458 int subdiv, 593 int subdiv,
459 const SkMatrix* toDevice, 594 const SkMatrix* toDevice,
460 const SkMatrix* toSrc, 595 const SkMatrix* toSrc,
461 Vertex** vert, 596 Vertex** vert,
462 SkRect* devBounds) { 597 SkRect* devBounds) {
463 GrAssert(subdiv >= 0); 598 GrAssert(subdiv >= 0);
464 if (subdiv) { 599 if (subdiv) {
465 SkPoint newP[5]; 600 SkPoint newP[5];
466 SkChopQuadAtHalf(p, newP); 601 SkChopQuadAtHalf(p, newP);
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
508 (*vert)[1].fPos.set(SK_ScalarMax, SK_ScalarMax); 643 (*vert)[1].fPos.set(SK_ScalarMax, SK_ScalarMax);
509 (*vert)[2].fPos.set(SK_ScalarMax, SK_ScalarMax); 644 (*vert)[2].fPos.set(SK_ScalarMax, SK_ScalarMax);
510 (*vert)[3].fPos.set(SK_ScalarMax, SK_ScalarMax); 645 (*vert)[3].fPos.set(SK_ScalarMax, SK_ScalarMax);
511 } 646 }
512 647
513 *vert += kVertsPerLineSeg; 648 *vert += kVertsPerLineSeg;
514 } 649 }
515 650
516 } 651 }
517 652
653 /**
654 * The output of this effect is a hairline edge for conics.
655 * Conics specified by implicit equation Ax^2 + Bxy + Cy^2 + Dx + Ey + F = 0.
656 * A, B, C, D are the first vec4 of vertex attributes and
657 * E and F are the vec2 attached to 2nd vertex attrribute.
658 * Coverage is max(0, 1-distance).
659 */
660 class HairConicEdgeEffect : public GrEffect {
661 public:
662 static GrEffectRef* Create() {
663 GR_CREATE_STATIC_EFFECT(gHairConicEdgeEffect, HairConicEdgeEffect, ());
664 gHairConicEdgeEffect->ref();
665 return gHairConicEdgeEffect;
666 }
667
668 virtual ~HairConicEdgeEffect() {}
669
670 static const char* Name() { return "HairConicEdge"; }
671
672 virtual void getConstantColorComponents(GrColor* color,
673 uint32_t* validFlags) const SK_OVERR IDE {
674 *validFlags = 0;
675 }
676
677 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE {
678 return GrTBackendEffectFactory<HairConicEdgeEffect>::getInstance();
679 }
680
681 class GLEffect : public GrGLEffect {
682 public:
683 GLEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&)
684 : INHERITED (factory) {}
685
686 virtual void emitCode(GrGLShaderBuilder* builder,
687 const GrDrawEffect& drawEffect,
688 EffectKey key,
689 const char* outputColor,
690 const char* inputColor,
691 const TextureSamplerArray& samplers) SK_OVERRIDE {
692 const char *vsCoeffABCDName, *fsCoeffABCDName;
693 const char *vsCoeffEFName, *fsCoeffEFName;
694
695 SkAssertResult(builder->enableFeature(
696 GrGLShaderBuilder::kStandardDerivatives_GLSLFeature));
697 builder->addVarying(kVec4f_GrSLType, "ConicCoeffsABCD",
698 &vsCoeffABCDName, &fsCoeffABCDName);
699 const SkString* attr0Name =
700 builder->getEffectAttributeName(drawEffect.getVertexAttribIndice s()[0]);
701 builder->vsCodeAppendf("\t%s = %s;\n", vsCoeffABCDName, attr0Name->c _str());
702
703 builder->addVarying(kVec2f_GrSLType, "ConicCoeffsEF",
704 &vsCoeffEFName, &fsCoeffEFName);
705 const SkString* attr1Name =
706 builder->getEffectAttributeName(drawEffect.getVertexAttribIndice s()[1]);
707 builder->vsCodeAppendf("\t%s = %s;\n", vsCoeffEFName, attr1Name->c_s tr());
708
709 // Based on Gustavson 2006: "Beyond the Pixel: towards infinite reso lution textures"
710 builder->fsCodeAppendf("\t\tfloat edgeAlpha;\n");
711
712 builder->fsCodeAppendf("\t\tvec3 uv1 = vec3(%s.xy, 1);\n", builder-> fragmentPosition());
713 builder->fsCodeAppend("\t\tvec3 u2uvv2 = uv1.xxy * uv1.xyy;\n");
714 builder->fsCodeAppendf("\t\tvec3 ABC = %s.xyz;\n", fsCoeffABCDName);
715 builder->fsCodeAppendf("\t\tvec3 DEF = vec3(%s.w, %s.xy);\n",
716 fsCoeffABCDName, fsCoeffEFName);
717
718 builder->fsCodeAppend("\t\tfloat dfdx = dot(uv1,vec3(2.0*ABC.x,ABC.y ,DEF.x));\n");
719 builder->fsCodeAppend("\t\tfloat dfdy = dot(uv1,vec3(ABC.y, 2.0*ABC. z,DEF.y));\n");
720 builder->fsCodeAppend("\t\tfloat gF = dfdx*dfdx + dfdy*dfdy;\n");
721 builder->fsCodeAppend("\t\tedgeAlpha = dot(ABC,u2uvv2) + dot(DEF,uv1 );\n");
722 builder->fsCodeAppend("\t\tedgeAlpha = sqrt(edgeAlpha*edgeAlpha / gF );\n");
723 builder->fsCodeAppend("\t\tedgeAlpha = max((1.0 - edgeAlpha), 0.0);\ n");
724 // Add line below for smooth cubic ramp
725 // builder->fsCodeAppend("\t\tedgeAlpha = edgeAlpha*edgeAlpha*(3.0-2 .0*edgeAlpha);\n");
726
727 SkString modulate;
728 GrGLSLModulatef<4>(&modulate, inputColor, "edgeAlpha");
729 builder->fsCodeAppendf("\t%s = %s;\n", outputColor, modulate.c_str() );
730 }
731
732 static inline EffectKey GenKey(const GrDrawEffect& drawEffect, const GrG LCaps&) {
733 return 0x0;
734 }
735
736 virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_ OVERRIDE {}
737
738 private:
739 typedef GrGLEffect INHERITED;
740 };
741
742 private:
743 HairConicEdgeEffect() {
744 this->addVertexAttrib(kVec4f_GrSLType);
745 this->addVertexAttrib(kVec2f_GrSLType);
746 this->setWillReadFragmentPosition();
747 }
748
749 virtual bool onIsEqual(const GrEffect& other) const SK_OVERRIDE {
750 return true;
751 }
752
753 GR_DECLARE_EFFECT_TEST;
754
755 typedef GrEffect INHERITED;
756 };
757
758 GR_DEFINE_EFFECT_TEST(HairConicEdgeEffect);
759
760 GrEffectRef* HairConicEdgeEffect::TestCreate(SkMWCRandom* random,
761 GrContext*,
762 const GrDrawTargetCaps& caps,
763 GrTexture*[]) {
764 return HairConicEdgeEffect::Create();
765 }
518 /////////////////////////////////////////////////////////////////////////////// 766 ///////////////////////////////////////////////////////////////////////////////
519 767
520 /** 768 /**
521 * The output of this effect is a hairline edge for quadratics. 769 * The output of this effect is a hairline edge for quadratics.
522 * Quadratic specified by 0=u^2-v canonical coords. u and v are the first 770 * Quadratic specified by 0=u^2-v canonical coords. u and v are the first
523 * two components of the vertex attribute. Uses unsigned distance. 771 * two components of the vertex attribute. Uses unsigned distance.
524 * Coverage is min(0, 1-distance). 3rd & 4th component unused. 772 * Coverage is min(0, 1-distance). 3rd & 4th component unused.
525 * Requires shader derivative instruction support. 773 * Requires shader derivative instruction support.
526 */ 774 */
527 class HairQuadEdgeEffect : public GrEffect { 775 class HairQuadEdgeEffect : public GrEffect {
(...skipping 28 matching lines...) Expand all
556 EffectKey key, 804 EffectKey key,
557 const char* outputColor, 805 const char* outputColor,
558 const char* inputColor, 806 const char* inputColor,
559 const TextureSamplerArray& samplers) SK_OVERRIDE { 807 const TextureSamplerArray& samplers) SK_OVERRIDE {
560 const char *vsName, *fsName; 808 const char *vsName, *fsName;
561 const SkString* attrName = 809 const SkString* attrName =
562 builder->getEffectAttributeName(drawEffect.getVertexAttribIndice s()[0]); 810 builder->getEffectAttributeName(drawEffect.getVertexAttribIndice s()[0]);
563 builder->fsCodeAppendf("\t\tfloat edgeAlpha;\n"); 811 builder->fsCodeAppendf("\t\tfloat edgeAlpha;\n");
564 812
565 SkAssertResult(builder->enableFeature( 813 SkAssertResult(builder->enableFeature(
566 GrGLShaderBuilder::kStandardDeriva tives_GLSLFeature)); 814 GrGLShaderBuilder::kStandardDerivatives_GLSLFeature));
567 builder->addVarying(kVec4f_GrSLType, "HairQuadEdge", &vsName, &fsNam e); 815 builder->addVarying(kVec4f_GrSLType, "HairQuadEdge", &vsName, &fsNam e);
568 816
569 builder->fsCodeAppendf("\t\tvec2 duvdx = dFdx(%s.xy);\n", fsName); 817 builder->fsCodeAppendf("\t\tvec2 duvdx = dFdx(%s.xy);\n", fsName);
570 builder->fsCodeAppendf("\t\tvec2 duvdy = dFdy(%s.xy);\n", fsName); 818 builder->fsCodeAppendf("\t\tvec2 duvdy = dFdy(%s.xy);\n", fsName);
571 builder->fsCodeAppendf("\t\tvec2 gF = vec2(2.0*%s.x*duvdx.x - duvdx. y,\n" 819 builder->fsCodeAppendf("\t\tvec2 gF = vec2(2.0*%s.x*duvdx.x - duvdx. y,\n"
572 "\t\t 2.0*%s.x*duvdy.x - duvdy. y);\n", 820 "\t\t 2.0*%s.x*duvdy.x - duvdy. y);\n",
573 fsName, fsName); 821 fsName, fsName);
574 builder->fsCodeAppendf("\t\tedgeAlpha = (%s.x*%s.x - %s.y);\n", fsNa me, fsName, 822 builder->fsCodeAppendf("\t\tedgeAlpha = (%s.x*%s.x - %s.y);\n", fsNa me, fsName,
575 fsName); 823 fsName);
576 builder->fsCodeAppend("\t\tedgeAlpha = sqrt(edgeAlpha*edgeAlpha / do t(gF, gF));\n"); 824 builder->fsCodeAppend("\t\tedgeAlpha = sqrt(edgeAlpha*edgeAlpha / do t(gF, gF));\n");
(...skipping 30 matching lines...) Expand all
607 typedef GrEffect INHERITED; 855 typedef GrEffect INHERITED;
608 }; 856 };
609 857
610 GR_DEFINE_EFFECT_TEST(HairQuadEdgeEffect); 858 GR_DEFINE_EFFECT_TEST(HairQuadEdgeEffect);
611 859
612 GrEffectRef* HairQuadEdgeEffect::TestCreate(SkMWCRandom* random, 860 GrEffectRef* HairQuadEdgeEffect::TestCreate(SkMWCRandom* random,
613 GrContext*, 861 GrContext*,
614 const GrDrawTargetCaps& caps, 862 const GrDrawTargetCaps& caps,
615 GrTexture*[]) { 863 GrTexture*[]) {
616 // Doesn't work without derivative instructions. 864 // Doesn't work without derivative instructions.
617 return caps.shaderDerivativeSupport() ? HairQuadEdgeEffect::Create() : NULL; } 865 return caps.shaderDerivativeSupport() ? HairQuadEdgeEffect::Create() : NULL;
866 }
618 867
619 /////////////////////////////////////////////////////////////////////////////// 868 ///////////////////////////////////////////////////////////////////////////////
620 869
621 /** 870 /**
622 * The output of this effect is a 1-pixel wide line. 871 * The output of this effect is a 1-pixel wide line.
623 * Input is 2D implicit device coord line eq (a*x + b*y +c = 0). 4th component u nused. 872 * Input is 2D implicit device coord line eq (a*x + b*y +c = 0). 4th component u nused.
624 */ 873 */
625 class HairLineEdgeEffect : public GrEffect { 874 class HairLineEdgeEffect : public GrEffect {
626 public: 875 public:
627 876
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after
710 /////////////////////////////////////////////////////////////////////////////// 959 ///////////////////////////////////////////////////////////////////////////////
711 960
712 namespace { 961 namespace {
713 962
714 // position + edge 963 // position + edge
715 extern const GrVertexAttrib gHairlineAttribs[] = { 964 extern const GrVertexAttrib gHairlineAttribs[] = {
716 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBind ing}, 965 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBind ing},
717 {kVec4f_GrVertexAttribType, sizeof(GrPoint), kEffect_GrVertexAttribBindin g} 966 {kVec4f_GrVertexAttribType, sizeof(GrPoint), kEffect_GrVertexAttribBindin g}
718 }; 967 };
719 968
969 // Conic
970 // position + ABCD + EF
971 extern const GrVertexAttrib gConicVertexAttribs[] = {
972 { kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBind ing },
973 { kVec4f_GrVertexAttribType, sizeof(GrPoint), kEffect_GrVertexAttribBindin g },
974 { kVec2f_GrVertexAttribType, 3*sizeof(GrPoint), kEffect_GrVertexAttribBindin g }
975 };
720 }; 976 };
721 977
722 bool GrAAHairLinePathRenderer::createGeom( 978 bool GrAAHairLinePathRenderer::createGeom(
723 const SkPath& path, 979 const SkPath& path,
724 GrDrawTarget* target, 980 GrDrawTarget* target,
725 int* lineCnt, 981 int* lineCnt,
726 int* quadCnt, 982 int* quadCnt,
983 int* conicCnt,
727 GrDrawTarget::AutoReleaseGeometry* arg, 984 GrDrawTarget::AutoReleaseGeometry* arg,
728 SkRect* devBounds) { 985 SkRect* devBounds) {
729 GrDrawState* drawState = target->drawState(); 986 GrDrawState* drawState = target->drawState();
730 int rtHeight = drawState->getRenderTarget()->height(); 987 int rtHeight = drawState->getRenderTarget()->height();
731 988
732 GrIRect devClipBounds; 989 GrIRect devClipBounds;
733 target->getClip()->getConservativeBounds(drawState->getRenderTarget(), &devC lipBounds); 990 target->getClip()->getConservativeBounds(drawState->getRenderTarget(), &devC lipBounds);
734 991
735 SkMatrix viewM = drawState->getViewMatrix(); 992 SkMatrix viewM = drawState->getViewMatrix();
736 993
737 // All the vertices that we compute are within 1 of path control points with the exception of 994 // All the vertices that we compute are within 1 of path control points with the exception of
738 // one of the bounding vertices for each quad. The add_quads() function will update the bounds 995 // one of the bounding vertices for each quad. The add_quads() function will update the bounds
739 // for each quad added. 996 // for each quad added.
740 *devBounds = path.getBounds(); 997 *devBounds = path.getBounds();
741 viewM.mapRect(devBounds); 998 viewM.mapRect(devBounds);
742 devBounds->outset(SK_Scalar1, SK_Scalar1); 999 devBounds->outset(SK_Scalar1, SK_Scalar1);
743 1000
744 PREALLOC_PTARRAY(128) lines; 1001 PREALLOC_PTARRAY(128) lines;
745 PREALLOC_PTARRAY(128) quads; 1002 PREALLOC_PTARRAY(128) quads;
1003 PREALLOC_PTARRAY(128) conics;
746 IntArray qSubdivs; 1004 IntArray qSubdivs;
1005 FloatArray cWeights;
747 *quadCnt = generate_lines_and_quads(path, viewM, devClipBounds, 1006 *quadCnt = generate_lines_and_quads(path, viewM, devClipBounds,
748 &lines, &quads, &qSubdivs); 1007 &lines, &quads, &conics, &qSubdivs, &cWe ights);
749 1008
750 *lineCnt = lines.count() / 2; 1009 *lineCnt = lines.count() / 2;
751 int vertCnt = kVertsPerLineSeg * *lineCnt + kVertsPerQuad * *quadCnt; 1010 *conicCnt = conics.count() / 3;
1011 int vertCnt = kVertsPerLineSeg * *lineCnt + kVertsPerQuad * *quadCnt +
1012 kVertsPerQuad * *conicCnt;
752 1013
753 target->drawState()->setVertexAttribs<gHairlineAttribs>(SK_ARRAY_COUNT(gHair lineAttribs)); 1014 target->drawState()->setVertexAttribs<gConicVertexAttribs>(SK_ARRAY_COUNT(gC onicVertexAttribs));
754 GrAssert(sizeof(Vertex) == target->getDrawState().getVertexSize()); 1015 GrAssert(sizeof(Vertex) == target->getDrawState().getVertexSize());
755 1016
756 if (!arg->set(target, vertCnt, 0)) { 1017 if (!arg->set(target, vertCnt, 0)) {
757 return false; 1018 return false;
758 } 1019 }
759 1020
760 Vertex* verts = reinterpret_cast<Vertex*>(arg->vertices()); 1021 Vertex* verts = reinterpret_cast<Vertex*>(arg->vertices());
761 1022
762 const SkMatrix* toDevice = NULL; 1023 const SkMatrix* toDevice = NULL;
763 const SkMatrix* toSrc = NULL; 1024 const SkMatrix* toSrc = NULL;
764 SkMatrix ivm; 1025 SkMatrix ivm;
765 1026
766 if (viewM.hasPerspective()) { 1027 if (viewM.hasPerspective()) {
767 if (viewM.invert(&ivm)) { 1028 if (viewM.invert(&ivm)) {
768 toDevice = &viewM; 1029 toDevice = &viewM;
769 toSrc = &ivm; 1030 toSrc = &ivm;
770 } 1031 }
771 } 1032 }
772 1033
773 for (int i = 0; i < *lineCnt; ++i) { 1034 for (int i = 0; i < *lineCnt; ++i) {
774 add_line(&lines[2*i], rtHeight, toSrc, &verts); 1035 add_line(&lines[2*i], rtHeight, toSrc, &verts);
775 } 1036 }
776 1037
777 int unsubdivQuadCnt = quads.count() / 3; 1038 int unsubdivQuadCnt = quads.count() / 3;
778 for (int i = 0; i < unsubdivQuadCnt; ++i) { 1039 for (int i = 0; i < unsubdivQuadCnt; ++i) {
779 GrAssert(qSubdivs[i] >= 0); 1040 GrAssert(qSubdivs[i] >= 0);
780 add_quads(&quads[3*i], qSubdivs[i], toDevice, toSrc, &verts, devBounds); 1041 add_quads(&quads[3*i], qSubdivs[i], toDevice, toSrc, &verts, devBounds);
781 } 1042 }
782 1043
1044 // Start Conics
1045 for (int i = 0; i < *conicCnt; ++i) {
1046 add_conics(&conics[3*i], cWeights[i], toDevice, toSrc, &verts, devBounds );
1047 }
783 return true; 1048 return true;
784 } 1049 }
785 1050
786 bool GrAAHairLinePathRenderer::canDrawPath(const SkPath& path, 1051 bool GrAAHairLinePathRenderer::canDrawPath(const SkPath& path,
787 const SkStrokeRec& stroke, 1052 const SkStrokeRec& stroke,
788 const GrDrawTarget* target, 1053 const GrDrawTarget* target,
789 bool antiAlias) const { 1054 bool antiAlias) const {
790 if (!stroke.isHairlineStyle() || !antiAlias) { 1055 if (!stroke.isHairlineStyle() || !antiAlias) {
791 return false; 1056 return false;
792 } 1057 }
793 1058
794 static const uint32_t gReqDerivMask = SkPath::kCubic_SegmentMask | 1059 static const uint32_t gReqDerivMask = SkPath::kCubic_SegmentMask |
795 SkPath::kQuad_SegmentMask; 1060 SkPath::kQuad_SegmentMask;
796 if (!target->caps()->shaderDerivativeSupport() && 1061 if (!target->caps()->shaderDerivativeSupport() &&
797 (gReqDerivMask & path.getSegmentMasks())) { 1062 (gReqDerivMask & path.getSegmentMasks())) {
798 return false; 1063 return false;
799 } 1064 }
800 return true; 1065 return true;
801 } 1066 }
802 1067
803 bool GrAAHairLinePathRenderer::onDrawPath(const SkPath& path, 1068 bool GrAAHairLinePathRenderer::onDrawPath(const SkPath& path,
804 const SkStrokeRec&, 1069 const SkStrokeRec&,
805 GrDrawTarget* target, 1070 GrDrawTarget* target,
806 bool antiAlias) { 1071 bool antiAlias) {
807 1072
808 int lineCnt; 1073 int lineCnt;
809 int quadCnt; 1074 int quadCnt;
1075 int conicCnt;
810 GrDrawTarget::AutoReleaseGeometry arg; 1076 GrDrawTarget::AutoReleaseGeometry arg;
811 SkRect devBounds; 1077 SkRect devBounds;
812 1078
813 if (!this->createGeom(path, 1079 if (!this->createGeom(path,
814 target, 1080 target,
815 &lineCnt, 1081 &lineCnt,
816 &quadCnt, 1082 &quadCnt,
1083 &conicCnt,
817 &arg, 1084 &arg,
818 &devBounds)) { 1085 &devBounds)) {
819 return false; 1086 return false;
820 } 1087 }
821 1088
822 GrDrawTarget::AutoStateRestore asr; 1089 GrDrawTarget::AutoStateRestore asr;
823 1090
824 // createGeom transforms the geometry to device space when the matrix does n ot have 1091 // createGeom transforms the geometry to device space when the matrix does n ot have
825 // perspective. 1092 // perspective.
826 if (target->getDrawState().getViewMatrix().hasPerspective()) { 1093 if (target->getDrawState().getViewMatrix().hasPerspective()) {
827 asr.set(target, GrDrawTarget::kPreserve_ASRInit); 1094 asr.set(target, GrDrawTarget::kPreserve_ASRInit);
828 } else if (!asr.setIdentity(target, GrDrawTarget::kPreserve_ASRInit)) { 1095 } else if (!asr.setIdentity(target, GrDrawTarget::kPreserve_ASRInit)) {
829 return false; 1096 return false;
830 } 1097 }
831 GrDrawState* drawState = target->drawState(); 1098 GrDrawState* drawState = target->drawState();
832 1099
833 // TODO: See whether rendering lines as degenerate quads improves perf 1100 // TODO: See whether rendering lines as degenerate quads improves perf
834 // when we have a mix 1101 // when we have a mix
835 1102
836 enum { 1103 enum {
837 // the edge effects share this stage with glyph rendering 1104 // the edge effects share this stage with glyph rendering
838 // (kGlyphMaskStage in GrTextContext) && SW path rendering 1105 // (kGlyphMaskStage in GrTextContext) && SW path rendering
839 // (kPathMaskStage in GrSWMaskHelper) 1106 // (kPathMaskStage in GrSWMaskHelper)
840 kEdgeEffectStage = GrPaint::kTotalStages, 1107 kEdgeEffectStage = GrPaint::kTotalStages,
841 }; 1108 };
842 static const int kEdgeAttrIndex = 1; 1109 static const int kEdgeAttrIndex = 1;
843 1110
844 GrEffectRef* hairLineEffect = HairLineEdgeEffect::Create(); 1111 GrEffectRef* hairLineEffect = HairLineEdgeEffect::Create();
845 GrEffectRef* hairQuadEffect = HairQuadEdgeEffect::Create(); 1112 GrEffectRef* hairQuadEffect = HairQuadEdgeEffect::Create();
1113 GrEffectRef* hairConicEffect = HairConicEdgeEffect::Create();
846 1114
847 // Check devBounds 1115 // Check devBounds
848 #if GR_DEBUG 1116 #if GR_DEBUG
849 SkRect tolDevBounds = devBounds; 1117 SkRect tolDevBounds = devBounds;
850 tolDevBounds.outset(SK_Scalar1 / 10000, SK_Scalar1 / 10000); 1118 tolDevBounds.outset(SK_Scalar1 / 10000, SK_Scalar1 / 10000);
851 SkRect actualBounds; 1119 SkRect actualBounds;
852 Vertex* verts = reinterpret_cast<Vertex*>(arg.vertices()); 1120 Vertex* verts = reinterpret_cast<Vertex*>(arg.vertices());
853 int vCount = kVertsPerLineSeg * lineCnt + kVertsPerQuad * quadCnt; 1121 int vCount = kVertsPerLineSeg * lineCnt + kVertsPerQuad * quadCnt + kVertsPe rQuad * conicCnt;
854 bool first = true; 1122 bool first = true;
855 for (int i = 0; i < vCount; ++i) { 1123 for (int i = 0; i < vCount; ++i) {
856 SkPoint pos = verts[i].fPos; 1124 SkPoint pos = verts[i].fPos;
857 // This is a hack to workaround the fact that we move some degenerate se gments offscreen. 1125 // This is a hack to workaround the fact that we move some degenerate se gments offscreen.
858 if (SK_ScalarMax == pos.fX) { 1126 if (SK_ScalarMax == pos.fX) {
859 continue; 1127 continue;
860 } 1128 }
861 drawState->getViewMatrix().mapPoints(&pos, 1); 1129 drawState->getViewMatrix().mapPoints(&pos, 1);
862 if (first) { 1130 if (first) {
863 actualBounds.set(pos.fX, pos.fY, pos.fX, pos.fY); 1131 actualBounds.set(pos.fX, pos.fY, pos.fX, pos.fY);
(...skipping 18 matching lines...) Expand all
882 target->drawIndexed(kTriangles_GrPrimitiveType, 1150 target->drawIndexed(kTriangles_GrPrimitiveType,
883 kVertsPerLineSeg*lines, // startV 1151 kVertsPerLineSeg*lines, // startV
884 0, // startI 1152 0, // startI
885 kVertsPerLineSeg*n, // vCount 1153 kVertsPerLineSeg*n, // vCount
886 kIdxsPerLineSeg*n, 1154 kIdxsPerLineSeg*n,
887 &devBounds); // iCount 1155 &devBounds); // iCount
888 lines += n; 1156 lines += n;
889 } 1157 }
890 } 1158 }
891 1159
892 target->setIndexSourceToBuffer(fQuadsIndexBuffer); 1160 {
893 int quads = 0; 1161 GrDrawState::AutoRestoreEffects are(drawState);
894 drawState->addCoverageEffect(hairQuadEffect, kEdgeAttrIndex)->unref(); 1162 target->setIndexSourceToBuffer(fQuadsIndexBuffer);
895 while (quads < quadCnt) { 1163 int quads = 0;
896 int n = GrMin(quadCnt - quads, kNumQuadsInIdxBuffer); 1164 drawState->addCoverageEffect(hairQuadEffect, kEdgeAttrIndex)->unref();
897 target->drawIndexed(kTriangles_GrPrimitiveType, 1165 while (quads < quadCnt) {
898 4 * lineCnt + kVertsPerQuad*quads, // startV 1166 int n = GrMin(quadCnt - quads, kNumQuadsInIdxBuffer);
899 0, // startI 1167 target->drawIndexed(kTriangles_GrPrimitiveType,
900 kVertsPerQuad*n, // vCount 1168 kVertsPerLineSeg * lineCnt + kVertsPerQuad*quads , // startV
901 kIdxsPerQuad*n, // iCount 1169 0, // startI
902 &devBounds); 1170 kVertsPerQuad*n, // vCount
903 quads += n; 1171 kIdxsPerQuad*n, // iCount
1172 &devBounds);
1173 quads += n;
1174 }
1175 }
1176
1177 {
1178 GrDrawState::AutoRestoreEffects are(drawState);
1179 int conics = 0;
1180 drawState->addCoverageEffect(hairConicEffect, 1, 2)->unref();
1181 while (conics < conicCnt) {
1182 int n = GrMin(conicCnt - conics, kNumQuadsInIdxBuffer);
1183 target->drawIndexed(kTriangles_GrPrimitiveType,
1184 kVertsPerLineSeg*lineCnt +
1185 kVertsPerQuad*(quadCnt + conics), // startV
1186 0, // startI
1187 kVertsPerQuad*n, // vCount
1188 kIdxsPerQuad*n, // iCount
1189 &devBounds);
1190 conics += n;
1191 }
904 } 1192 }
905 target->resetIndexSource(); 1193 target->resetIndexSource();
906 1194
907 return true; 1195 return true;
908 } 1196 }
1197
OLDNEW
« no previous file with comments | « src/gpu/GrAAHairLinePathRenderer.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698