OLD | NEW |
1 | |
2 /* | 1 /* |
3 * Copyright 2011 Google Inc. | 2 * Copyright 2011 Google Inc. |
4 * | 3 * |
5 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
6 * found in the LICENSE file. | 5 * found in the LICENSE file. |
7 */ | 6 */ |
8 | 7 |
9 #include "GrAAHairLinePathRenderer.h" | 8 #include "GrAAHairLinePathRenderer.h" |
10 | 9 |
11 #include "GrContext.h" | 10 #include "GrContext.h" |
(...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
139 GrAssert(get_float_exp(3000000.f) == 21); | 138 GrAssert(get_float_exp(3000000.f) == 21); |
140 } | 139 } |
141 #endif | 140 #endif |
142 const int* iptr = (const int*)&x; | 141 const int* iptr = (const int*)&x; |
143 return (((*iptr) & 0x7f800000) >> 23) - 127; | 142 return (((*iptr) & 0x7f800000) >> 23) - 127; |
144 } | 143 } |
145 | 144 |
146 // Uses the max curvature function for quads to estimate | 145 // Uses the max curvature function for quads to estimate |
147 // where to chop the conic. If the max curvature is not | 146 // where to chop the conic. If the max curvature is not |
148 // found along the curve segment it will return 1 and | 147 // found along the curve segment it will return 1 and |
149 // dst[0] is the orginal conic. If it returns 2 the dst[0] | 148 // dst[0] is the original conic. If it returns 2 the dst[0] |
150 // and dst[1] are the two new conics. | 149 // and dst[1] are the two new conics. |
151 int chop_conic(const SkPoint src[3], SkConic dst[2], const SkScalar weight) { | 150 int split_conic(const SkPoint src[3], SkConic dst[2], const SkScalar weight) { |
152 SkScalar t = SkFindQuadMaxCurvature(src); | 151 SkScalar t = SkFindQuadMaxCurvature(src); |
153 if (t == 0) { | 152 if (t == 0) { |
154 if (dst) { | 153 if (dst) { |
155 dst[0].set(src, weight); | 154 dst[0].set(src, weight); |
156 } | 155 } |
157 return 1; | 156 return 1; |
158 } else { | 157 } else { |
159 if (dst) { | 158 if (dst) { |
160 SkConic conic; | 159 SkConic conic; |
161 conic.set(src, weight); | 160 conic.set(src, weight); |
162 conic.chopAt(t, dst); | 161 conic.chopAt(t, dst); |
163 } | 162 } |
164 return 2; | 163 return 2; |
165 } | 164 } |
166 } | 165 } |
167 | 166 |
| 167 // Calls split_conic on the entire conic and then once more on each subsection. |
| 168 // Most cases will result in either 1 conic (chop point is not within t range) |
| 169 // or 3 points (split once and then one subsection is split again). |
| 170 int chop_conic(const SkPoint src[3], SkConic dst[4], const SkScalar weight) { |
| 171 SkConic dstTemp[2]; |
| 172 int conicCnt = split_conic(src, dstTemp, weight); |
| 173 if (2 == conicCnt) { |
| 174 int conicCnt2 = split_conic(dstTemp[0].fPts, dst, dstTemp[0].fW); |
| 175 conicCnt = conicCnt2 + split_conic(dstTemp[1].fPts, &dst[conicCnt2], dst
Temp[1].fW); |
| 176 } else { |
| 177 dst[0] = dstTemp[0]; |
| 178 } |
| 179 return conicCnt; |
| 180 } |
| 181 |
168 // returns 0 if quad/conic is degen or close to it | 182 // returns 0 if quad/conic is degen or close to it |
169 // in this case approx the path with lines | 183 // in this case approx the path with lines |
170 // otherwise returns 1 | 184 // otherwise returns 1 |
171 int is_degen_quad_or_conic(const SkPoint p[3]) { | 185 int is_degen_quad_or_conic(const SkPoint p[3]) { |
172 static const SkScalar gDegenerateToLineTol = SK_Scalar1; | 186 static const SkScalar gDegenerateToLineTol = SK_Scalar1; |
173 static const SkScalar gDegenerateToLineTolSqd = | 187 static const SkScalar gDegenerateToLineTolSqd = |
174 SkScalarMul(gDegenerateToLineTol, gDegenerateToLineTol); | 188 SkScalarMul(gDegenerateToLineTol, gDegenerateToLineTol); |
175 | 189 |
176 if (p[0].distanceToSqd(p[1]) < gDegenerateToLineTolSqd || | 190 if (p[0].distanceToSqd(p[1]) < gDegenerateToLineTolSqd || |
177 p[1].distanceToSqd(p[2]) < gDegenerateToLineTolSqd) { | 191 p[1].distanceToSqd(p[2]) < gDegenerateToLineTolSqd) { |
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
264 SkIRect ibounds; | 278 SkIRect ibounds; |
265 | 279 |
266 bool persp = m.hasPerspective(); | 280 bool persp = m.hasPerspective(); |
267 | 281 |
268 for (;;) { | 282 for (;;) { |
269 GrPoint pathPts[4]; | 283 GrPoint pathPts[4]; |
270 GrPoint devPts[4]; | 284 GrPoint devPts[4]; |
271 SkPath::Verb verb = iter.next(pathPts); | 285 SkPath::Verb verb = iter.next(pathPts); |
272 switch (verb) { | 286 switch (verb) { |
273 case SkPath::kConic_Verb: { | 287 case SkPath::kConic_Verb: { |
274 SkConic dst[2]; | 288 SkConic dst[4]; |
| 289 // We chop the conics to create tighter clipping to hide error |
| 290 // that appears near max curvature of very thin conics. Thin |
| 291 // hyperbolas with high weight still show error. |
275 int conicCnt = chop_conic(pathPts, dst, iter.conicWeight()); | 292 int conicCnt = chop_conic(pathPts, dst, iter.conicWeight()); |
276 for (int i = 0; i < conicCnt; ++i) { | 293 for (int i = 0; i < conicCnt; ++i) { |
277 SkPoint* chopPnts = dst[i].fPts; | 294 SkPoint* chopPnts = dst[i].fPts; |
278 m.mapPoints(devPts, chopPnts, 3); | 295 m.mapPoints(devPts, chopPnts, 3); |
279 bounds.setBounds(devPts, 3); | 296 bounds.setBounds(devPts, 3); |
280 bounds.outset(SK_Scalar1, SK_Scalar1); | 297 bounds.outset(SK_Scalar1, SK_Scalar1); |
281 bounds.roundOut(&ibounds); | 298 bounds.roundOut(&ibounds); |
282 if (SkIRect::Intersects(devClipBounds, ibounds)) { | 299 if (SkIRect::Intersects(devClipBounds, ibounds)) { |
283 if (is_degen_quad_or_conic(devPts)) { | 300 if (is_degen_quad_or_conic(devPts)) { |
284 SkPoint* pts = lines->push_back_n(4); | 301 SkPoint* pts = lines->push_back_n(4); |
(...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
417 | 434 |
418 struct Vertex { | 435 struct Vertex { |
419 GrPoint fPos; | 436 GrPoint fPos; |
420 union { | 437 union { |
421 struct { | 438 struct { |
422 SkScalar fA; | 439 SkScalar fA; |
423 SkScalar fB; | 440 SkScalar fB; |
424 SkScalar fC; | 441 SkScalar fC; |
425 } fLine; | 442 } fLine; |
426 struct { | 443 struct { |
427 SkScalar fA; | 444 SkScalar fK; |
428 SkScalar fB; | 445 SkScalar fL; |
429 SkScalar fC; | 446 SkScalar fM; |
430 SkScalar fD; | |
431 SkScalar fE; | |
432 SkScalar fF; | |
433 } fConic; | 447 } fConic; |
434 GrVec fQuadCoord; | 448 GrVec fQuadCoord; |
435 struct { | 449 struct { |
436 SkScalar fBogus[6]; | 450 SkScalar fBogus[4]; |
437 }; | 451 }; |
438 }; | 452 }; |
439 }; | 453 }; |
440 | 454 |
441 GR_STATIC_ASSERT(sizeof(Vertex) == 4 * sizeof(GrPoint)); | 455 GR_STATIC_ASSERT(sizeof(Vertex) == 3 * sizeof(GrPoint)); |
442 | 456 |
443 void intersect_lines(const SkPoint& ptA, const SkVector& normA, | 457 void intersect_lines(const SkPoint& ptA, const SkVector& normA, |
444 const SkPoint& ptB, const SkVector& normB, | 458 const SkPoint& ptB, const SkVector& normB, |
445 SkPoint* result) { | 459 SkPoint* result) { |
446 | 460 |
447 SkScalar lineAW = -normA.dot(ptA); | 461 SkScalar lineAW = -normA.dot(ptA); |
448 SkScalar lineBW = -normB.dot(ptB); | 462 SkScalar lineBW = -normB.dot(ptB); |
449 | 463 |
450 SkScalar wInv = SkScalarMul(normA.fX, normB.fY) - | 464 SkScalar wInv = SkScalarMul(normA.fX, normB.fY) - |
451 SkScalarMul(normA.fY, normB.fX); | 465 SkScalarMul(normA.fY, normB.fX); |
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
531 // include it. | 545 // include it. |
532 intersect_lines(a0.fPos, abN, c0.fPos, cbN, &b0.fPos); | 546 intersect_lines(a0.fPos, abN, c0.fPos, cbN, &b0.fPos); |
533 devBounds->growToInclude(b0.fPos.fX, b0.fPos.fY); | 547 devBounds->growToInclude(b0.fPos.fX, b0.fPos.fY); |
534 | 548 |
535 if (toSrc) { | 549 if (toSrc) { |
536 toSrc->mapPointsWithStride(&verts[0].fPos, sizeof(Vertex), kVertsPerQuad
); | 550 toSrc->mapPointsWithStride(&verts[0].fPos, sizeof(Vertex), kVertsPerQuad
); |
537 } | 551 } |
538 DevToUV.apply<kVertsPerQuad, sizeof(Vertex), sizeof(GrPoint)>(verts); | 552 DevToUV.apply<kVertsPerQuad, sizeof(Vertex), sizeof(GrPoint)>(verts); |
539 } | 553 } |
540 | 554 |
| 555 // Input: |
| 556 // Three control points: p[0], p[1], p[2] and weight: w |
| 557 // Output: |
| 558 // Let: |
| 559 // l = (2*w * (y1 - y0), 2*w * (x0 - x1), 2*w * (x1*y0 - x0*y1)) |
| 560 // m = (2*w * (y2 - y1), 2*w * (x1 - x2), 2*w * (x2*y1 - x1*y2)) |
| 561 // k = (y2 - y0, x0 - x2, (x2 - x0)*y0 - (y2 - y0)*x0 ) |
| 562 void calc_conic_klm(const SkPoint p[3], const SkScalar weight, |
| 563 SkScalar k[3], SkScalar l[3], SkScalar m[3]) { |
| 564 const SkScalar w2 = 2 * weight; |
| 565 l[0] = w2 * (p[1].fY - p[0].fY); |
| 566 l[1] = w2 * (p[0].fX - p[1].fX); |
| 567 l[2] = w2 * (p[1].fX * p[0].fY - p[0].fX * p[1].fY); |
541 | 568 |
| 569 m[0] = w2 * (p[2].fY - p[1].fY); |
| 570 m[1] = w2 * (p[1].fX - p[2].fX); |
| 571 m[2] = w2 * (p[2].fX * p[1].fY - p[1].fX * p[2].fY); |
| 572 |
| 573 k[0] = p[2].fY - p[0].fY; |
| 574 k[1] = p[0].fX - p[2].fX; |
| 575 k[2] = (p[2].fX - p[0].fX) * p[0].fY - (p[2].fY - p[0].fY) * p[0].fX; |
| 576 |
| 577 // scale the max absolute value of coeffs to 10 |
| 578 SkScalar scale = 0.0f; |
| 579 for (int i = 0; i < 3; ++i) { |
| 580 scale = SkMaxScalar(scale, SkScalarAbs(k[i])); |
| 581 scale = SkMaxScalar(scale, SkScalarAbs(l[i])); |
| 582 scale = SkMaxScalar(scale, SkScalarAbs(m[i])); |
| 583 } |
| 584 GrAssert(scale > 0); |
| 585 scale /= 10.0f; |
| 586 k[0] /= scale; |
| 587 k[1] /= scale; |
| 588 k[2] /= scale; |
| 589 l[0] /= scale; |
| 590 l[1] /= scale; |
| 591 l[2] /= scale; |
| 592 m[0] /= scale; |
| 593 m[1] /= scale; |
| 594 m[2] /= scale; |
| 595 } |
| 596 |
| 597 // Equations based off of Loop-Blinn Quadratic GPU Rendering |
542 // Input Parametric: | 598 // 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) | 599 // 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: | 600 // Output Implicit: |
545 // Ax^2 + Bxy + Cy^2 + Dx + Ey + F = 0 | 601 // f(x, y, w) = f(P) = K^2 - LM |
546 // A = 4w^2*(y0-y1)(y1-y2)-(y0-y2)^2 | 602 // K = dot(k, P), L = dot(l, P), M = dot(m, P) |
547 // B = 4w^2*((x0-x1)(y2-y1)+(x1-x2)(y1-y0)) + 2(x0-x2)(y0-y2) | 603 // k, l, m are calculated in function calc_conic_klm |
548 // C = 4w^2(x0-x1)(x1-x2) - (x0-x2)^2 | 604 void set_conic_coeffs(const SkPoint p[3], Vertex verts[kVertsPerQuad], const flo
at weight) { |
549 // D = 4w^2((x0y1-x1y0)(y1-y2)+(x1y2-x2y1)(y0-y1)) + 2(y2-y0)(x0y2-x2y0) | 605 SkScalar k[3]; |
550 // E = 4w^2((y0x1-y1x0)(x1-x2)+(y1x2-y2x1)(x0-x1)) + 2(x2-x0)(y0x2-y2x0) | 606 SkScalar l[3]; |
551 // F = 4w^2(x1y2-x2y1)(x0y1-x1y0) - (x2y0-x0y2)^2 | 607 SkScalar m[3]; |
552 | 608 |
553 void set_conic_coeffs(const SkPoint p[3], Vertex verts[kVertsPerQuad], const flo
at weight) { | 609 calc_conic_klm(p, weight, k, l, m); |
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 | 610 |
571 for (int i = 0; i < kVertsPerQuad; ++i) { | 611 for (int i = 0; i < kVertsPerQuad; ++i) { |
572 verts[i].fConic.fA = a/f; | 612 const SkPoint pnt = verts[i].fPos; |
573 verts[i].fConic.fB = b/f; | 613 verts[i].fConic.fK = pnt.fX * k[0] + pnt.fY * k[1] + k[2]; |
574 verts[i].fConic.fC = c/f; | 614 verts[i].fConic.fL = pnt.fX * l[0] + pnt.fY * l[1] + l[2]; |
575 verts[i].fConic.fD = d/f; | 615 verts[i].fConic.fM = pnt.fX * m[0] + pnt.fY * m[1] + m[2]; |
576 verts[i].fConic.fE = e/f; | |
577 verts[i].fConic.fF = f/f; | |
578 } | 616 } |
579 } | 617 } |
580 | 618 |
581 void add_conics(const SkPoint p[3], | 619 void add_conics(const SkPoint p[3], |
582 float weight, | 620 float weight, |
583 const SkMatrix* toDevice, | 621 const SkMatrix* toDevice, |
584 const SkMatrix* toSrc, | 622 const SkMatrix* toSrc, |
585 Vertex** vert, | 623 Vertex** vert, |
586 SkRect* devBounds) { | 624 SkRect* devBounds) { |
587 bloat_quad(p, toDevice, toSrc, *vert, devBounds); | 625 bloat_quad(p, toDevice, toSrc, *vert, devBounds); |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
644 (*vert)[2].fPos.set(SK_ScalarMax, SK_ScalarMax); | 682 (*vert)[2].fPos.set(SK_ScalarMax, SK_ScalarMax); |
645 (*vert)[3].fPos.set(SK_ScalarMax, SK_ScalarMax); | 683 (*vert)[3].fPos.set(SK_ScalarMax, SK_ScalarMax); |
646 } | 684 } |
647 | 685 |
648 *vert += kVertsPerLineSeg; | 686 *vert += kVertsPerLineSeg; |
649 } | 687 } |
650 | 688 |
651 } | 689 } |
652 | 690 |
653 /** | 691 /** |
| 692 * Shader is based off of Loop-Blinn Quadratic GPU Rendering |
654 * The output of this effect is a hairline edge for conics. | 693 * 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. | 694 * Conics specified by implicit equation K^2 - LM. |
656 * A, B, C, D are the first vec4 of vertex attributes and | 695 * K, L, and M, are the first three values of the vertex attribute, |
657 * E and F are the vec2 attached to 2nd vertex attrribute. | 696 * the fourth value is not used. Distance is calculated using a |
| 697 * first order approximation from the taylor series. |
658 * Coverage is max(0, 1-distance). | 698 * Coverage is max(0, 1-distance). |
659 */ | 699 */ |
| 700 |
| 701 /** |
| 702 * Test were also run using a second order distance approximation. |
| 703 * There were two versions of the second order approx. The first version |
| 704 * is of roughly the form: |
| 705 * f(q) = |f(p)| - ||f'(p)||*||q-p|| - ||f''(p)||*||q-p||^2. |
| 706 * The second is similar: |
| 707 * f(q) = |f(p)| + ||f'(p)||*||q-p|| + ||f''(p)||*||q-p||^2. |
| 708 * The exact version of the equations can be found in the paper |
| 709 * "Distance Approximations for Rasterizing Implicit Curves" by Gabriel Taubin |
| 710 * |
| 711 * In both versions we solve the quadratic for ||q-p||. |
| 712 * Version 1: |
| 713 * gFM is magnitude of first partials and gFM2 is magnitude of 2nd partials (as
derived from paper) |
| 714 * builder->fsCodeAppend("\t\tedgeAlpha = (sqrt(gFM*gFM+4.0*func*gF2M) - gFM)/(2
.0*gF2M);\n"); |
| 715 * Version 2: |
| 716 * builder->fsCodeAppend("\t\tedgeAlpha = (gFM - sqrt(gFM*gFM-4.0*func*gF2M))/(2
.0*gF2M);\n"); |
| 717 * |
| 718 * Also note that 2nd partials of k,l,m are zero |
| 719 * |
| 720 * When comparing the two second order approximations to the first order approxi
mations, |
| 721 * the following results were found. Version 1 tends to underestimate the distan
ces, thus it |
| 722 * basically increases all the error that we were already seeing in the first or
der |
| 723 * approx. So this version is not the one to use. Version 2 has the opposite eff
ect |
| 724 * and tends to overestimate the distances. This is much closer to what we are |
| 725 * looking for. It is able to render ellipses (even thin ones) without the need
to chop. |
| 726 * However, it can not handle thin hyperbolas well and thus would still rely on |
| 727 * chopping to tighten the clipping. Another side effect of the overestimating i
s |
| 728 * that the curves become much thinner and "ropey". If all that was ever rendere
d |
| 729 * were "not too thin" curves and ellipses then 2nd order may have an advantage
since |
| 730 * only one geometry would need to be rendered. However no benches were run comp
aring |
| 731 * chopped first order and non chopped 2nd order. |
| 732 */ |
660 class HairConicEdgeEffect : public GrEffect { | 733 class HairConicEdgeEffect : public GrEffect { |
661 public: | 734 public: |
662 static GrEffectRef* Create() { | 735 static GrEffectRef* Create() { |
663 GR_CREATE_STATIC_EFFECT(gHairConicEdgeEffect, HairConicEdgeEffect, ()); | 736 GR_CREATE_STATIC_EFFECT(gHairConicEdgeEffect, HairConicEdgeEffect, ()); |
664 gHairConicEdgeEffect->ref(); | 737 gHairConicEdgeEffect->ref(); |
665 return gHairConicEdgeEffect; | 738 return gHairConicEdgeEffect; |
666 } | 739 } |
667 | 740 |
668 virtual ~HairConicEdgeEffect() {} | 741 virtual ~HairConicEdgeEffect() {} |
669 | 742 |
(...skipping 12 matching lines...) Expand all Loading... |
682 public: | 755 public: |
683 GLEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&) | 756 GLEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&) |
684 : INHERITED (factory) {} | 757 : INHERITED (factory) {} |
685 | 758 |
686 virtual void emitCode(GrGLShaderBuilder* builder, | 759 virtual void emitCode(GrGLShaderBuilder* builder, |
687 const GrDrawEffect& drawEffect, | 760 const GrDrawEffect& drawEffect, |
688 EffectKey key, | 761 EffectKey key, |
689 const char* outputColor, | 762 const char* outputColor, |
690 const char* inputColor, | 763 const char* inputColor, |
691 const TextureSamplerArray& samplers) SK_OVERRIDE { | 764 const TextureSamplerArray& samplers) SK_OVERRIDE { |
692 const char *vsCoeffABCDName, *fsCoeffABCDName; | 765 const char *vsName, *fsName; |
693 const char *vsCoeffEFName, *fsCoeffEFName; | |
694 | 766 |
695 SkAssertResult(builder->enableFeature( | 767 SkAssertResult(builder->enableFeature( |
696 GrGLShaderBuilder::kStandardDerivatives_GLSLFeature)); | 768 GrGLShaderBuilder::kStandardDerivatives_GLSLFeature)); |
697 builder->addVarying(kVec4f_GrSLType, "ConicCoeffsABCD", | 769 builder->addVarying(kVec4f_GrSLType, "ConicCoeffs", |
698 &vsCoeffABCDName, &fsCoeffABCDName); | 770 &vsName, &fsName); |
699 const SkString* attr0Name = | 771 const SkString* attr0Name = |
700 builder->getEffectAttributeName(drawEffect.getVertexAttribIndice
s()[0]); | 772 builder->getEffectAttributeName(drawEffect.getVertexAttribIndice
s()[0]); |
701 builder->vsCodeAppendf("\t%s = %s;\n", vsCoeffABCDName, attr0Name->c
_str()); | 773 builder->vsCodeAppendf("\t%s = %s;\n", vsName, attr0Name->c_str()); |
702 | 774 |
703 builder->addVarying(kVec2f_GrSLType, "ConicCoeffsEF", | 775 builder->fsCodeAppend("\t\tfloat edgeAlpha;\n"); |
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 | 776 |
709 // Based on Gustavson 2006: "Beyond the Pixel: towards infinite reso
lution textures" | 777 builder->fsCodeAppendf("\t\tvec3 dklmdx = dFdx(%s.xyz);\n", fsName); |
710 builder->fsCodeAppendf("\t\tfloat edgeAlpha;\n"); | 778 builder->fsCodeAppendf("\t\tvec3 dklmdy = dFdy(%s.xyz);\n", fsName); |
711 | 779 builder->fsCodeAppendf("\t\tfloat dfdx =\n" |
712 builder->fsCodeAppendf("\t\tvec3 uv1 = vec3(%s.xy, 1);\n", builder->
fragmentPosition()); | 780 "\t\t\t2.0*%s.x*dklmdx.x - %s.y*dklmdx.z - %s
.z*dklmdx.y;\n", |
713 builder->fsCodeAppend("\t\tvec3 u2uvv2 = uv1.xxy * uv1.xyy;\n"); | 781 fsName, fsName, fsName); |
714 builder->fsCodeAppendf("\t\tvec3 ABC = %s.xyz;\n", fsCoeffABCDName); | 782 builder->fsCodeAppendf("\t\tfloat dfdy =\n" |
715 builder->fsCodeAppendf("\t\tvec3 DEF = vec3(%s.w, %s.xy);\n", | 783 "\t\t\t2.0*%s.x*dklmdy.x - %s.y*dklmdy.z - %s
.z*dklmdy.y;\n", |
716 fsCoeffABCDName, fsCoeffEFName); | 784 fsName, fsName, fsName); |
717 | 785 builder->fsCodeAppend("\t\tvec2 gF = vec2(dfdx, dfdy);\n"); |
718 builder->fsCodeAppend("\t\tfloat dfdx = dot(uv1,vec3(2.0*ABC.x,ABC.y
,DEF.x));\n"); | 786 builder->fsCodeAppend("\t\tfloat gFM = sqrt(dot(gF, gF));\n"); |
719 builder->fsCodeAppend("\t\tfloat dfdy = dot(uv1,vec3(ABC.y, 2.0*ABC.
z,DEF.y));\n"); | 787 builder->fsCodeAppendf("\t\tfloat func = abs(%s.x*%s.x - %s.y*%s.z);
\n", fsName, fsName, |
720 builder->fsCodeAppend("\t\tfloat gF = dfdx*dfdx + dfdy*dfdy;\n"); | 788 fsName, fsName); |
721 builder->fsCodeAppend("\t\tedgeAlpha = dot(ABC,u2uvv2) + dot(DEF,uv1
);\n"); | 789 builder->fsCodeAppend("\t\tedgeAlpha = func / gFM;\n"); |
722 builder->fsCodeAppend("\t\tedgeAlpha = sqrt(edgeAlpha*edgeAlpha / gF
);\n"); | 790 builder->fsCodeAppend("\t\tedgeAlpha = max(1.0 - edgeAlpha, 0.0);\n"
); |
723 builder->fsCodeAppend("\t\tedgeAlpha = max((1.0 - edgeAlpha), 0.0);\
n"); | |
724 // Add line below for smooth cubic ramp | 791 // Add line below for smooth cubic ramp |
725 // builder->fsCodeAppend("\t\tedgeAlpha = edgeAlpha*edgeAlpha*(3.0-2
.0*edgeAlpha);\n"); | 792 // builder->fsCodeAppend("\t\tedgeAlpha = edgeAlpha*edgeAlpha*(3.0-2
.0*edgeAlpha);\n"); |
726 | 793 |
727 SkString modulate; | 794 SkString modulate; |
728 GrGLSLModulatef<4>(&modulate, inputColor, "edgeAlpha"); | 795 GrGLSLModulatef<4>(&modulate, inputColor, "edgeAlpha"); |
729 builder->fsCodeAppendf("\t%s = %s;\n", outputColor, modulate.c_str()
); | 796 builder->fsCodeAppendf("\t%s = %s;\n", outputColor, modulate.c_str()
); |
730 } | 797 } |
731 | 798 |
732 static inline EffectKey GenKey(const GrDrawEffect& drawEffect, const GrG
LCaps&) { | 799 static inline EffectKey GenKey(const GrDrawEffect& drawEffect, const GrG
LCaps&) { |
733 return 0x0; | 800 return 0x0; |
734 } | 801 } |
735 | 802 |
736 virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_
OVERRIDE {} | 803 virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_
OVERRIDE {} |
737 | 804 |
738 private: | 805 private: |
739 typedef GrGLEffect INHERITED; | 806 typedef GrGLEffect INHERITED; |
740 }; | 807 }; |
741 | 808 |
742 private: | 809 private: |
743 HairConicEdgeEffect() { | 810 HairConicEdgeEffect() { |
744 this->addVertexAttrib(kVec4f_GrSLType); | 811 this->addVertexAttrib(kVec4f_GrSLType); |
745 this->addVertexAttrib(kVec2f_GrSLType); | |
746 this->setWillReadFragmentPosition(); | |
747 } | 812 } |
748 | 813 |
749 virtual bool onIsEqual(const GrEffect& other) const SK_OVERRIDE { | 814 virtual bool onIsEqual(const GrEffect& other) const SK_OVERRIDE { |
750 return true; | 815 return true; |
751 } | 816 } |
752 | 817 |
753 GR_DECLARE_EFFECT_TEST; | 818 GR_DECLARE_EFFECT_TEST; |
754 | 819 |
755 typedef GrEffect INHERITED; | 820 typedef GrEffect INHERITED; |
756 }; | 821 }; |
757 | 822 |
758 GR_DEFINE_EFFECT_TEST(HairConicEdgeEffect); | 823 GR_DEFINE_EFFECT_TEST(HairConicEdgeEffect); |
759 | 824 |
760 GrEffectRef* HairConicEdgeEffect::TestCreate(SkMWCRandom* random, | 825 GrEffectRef* HairConicEdgeEffect::TestCreate(SkMWCRandom* random, |
761 GrContext*, | 826 GrContext*, |
762 const GrDrawTargetCaps& caps, | 827 const GrDrawTargetCaps& caps, |
763 GrTexture*[]) { | 828 GrTexture*[]) { |
764 return HairConicEdgeEffect::Create(); | 829 return caps.shaderDerivativeSupport() ? HairConicEdgeEffect::Create() : NULL
; |
765 } | 830 } |
766 /////////////////////////////////////////////////////////////////////////////// | |
767 | 831 |
768 /** | 832 /** |
769 * The output of this effect is a hairline edge for quadratics. | 833 * The output of this effect is a hairline edge for quadratics. |
770 * Quadratic specified by 0=u^2-v canonical coords. u and v are the first | 834 * Quadratic specified by 0=u^2-v canonical coords. u and v are the first |
771 * two components of the vertex attribute. Uses unsigned distance. | 835 * two components of the vertex attribute. Uses unsigned distance. |
772 * Coverage is min(0, 1-distance). 3rd & 4th component unused. | 836 * Coverage is min(0, 1-distance). 3rd & 4th component unused. |
773 * Requires shader derivative instruction support. | 837 * Requires shader derivative instruction support. |
774 */ | 838 */ |
775 class HairQuadEdgeEffect : public GrEffect { | 839 class HairQuadEdgeEffect : public GrEffect { |
776 public: | 840 public: |
(...skipping 181 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
958 | 1022 |
959 /////////////////////////////////////////////////////////////////////////////// | 1023 /////////////////////////////////////////////////////////////////////////////// |
960 | 1024 |
961 namespace { | 1025 namespace { |
962 | 1026 |
963 // position + edge | 1027 // position + edge |
964 extern const GrVertexAttrib gHairlineAttribs[] = { | 1028 extern const GrVertexAttrib gHairlineAttribs[] = { |
965 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBind
ing}, | 1029 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBind
ing}, |
966 {kVec4f_GrVertexAttribType, sizeof(GrPoint), kEffect_GrVertexAttribBindin
g} | 1030 {kVec4f_GrVertexAttribType, sizeof(GrPoint), kEffect_GrVertexAttribBindin
g} |
967 }; | 1031 }; |
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 }; | |
976 }; | 1032 }; |
977 | 1033 |
978 bool GrAAHairLinePathRenderer::createGeom( | 1034 bool GrAAHairLinePathRenderer::createGeom( |
979 const SkPath& path, | 1035 const SkPath& path, |
980 GrDrawTarget* target, | 1036 GrDrawTarget* target, |
981 int* lineCnt, | 1037 int* lineCnt, |
982 int* quadCnt, | 1038 int* quadCnt, |
983 int* conicCnt, | 1039 int* conicCnt, |
984 GrDrawTarget::AutoReleaseGeometry* arg, | 1040 GrDrawTarget::AutoReleaseGeometry* arg, |
985 SkRect* devBounds) { | 1041 SkRect* devBounds) { |
(...skipping 18 matching lines...) Expand all Loading... |
1004 IntArray qSubdivs; | 1060 IntArray qSubdivs; |
1005 FloatArray cWeights; | 1061 FloatArray cWeights; |
1006 *quadCnt = generate_lines_and_quads(path, viewM, devClipBounds, | 1062 *quadCnt = generate_lines_and_quads(path, viewM, devClipBounds, |
1007 &lines, &quads, &conics, &qSubdivs, &cWe
ights); | 1063 &lines, &quads, &conics, &qSubdivs, &cWe
ights); |
1008 | 1064 |
1009 *lineCnt = lines.count() / 2; | 1065 *lineCnt = lines.count() / 2; |
1010 *conicCnt = conics.count() / 3; | 1066 *conicCnt = conics.count() / 3; |
1011 int vertCnt = kVertsPerLineSeg * *lineCnt + kVertsPerQuad * *quadCnt + | 1067 int vertCnt = kVertsPerLineSeg * *lineCnt + kVertsPerQuad * *quadCnt + |
1012 kVertsPerQuad * *conicCnt; | 1068 kVertsPerQuad * *conicCnt; |
1013 | 1069 |
1014 target->drawState()->setVertexAttribs<gConicVertexAttribs>(SK_ARRAY_COUNT(gC
onicVertexAttribs)); | 1070 target->drawState()->setVertexAttribs<gHairlineAttribs>(SK_ARRAY_COUNT(gHair
lineAttribs)); |
1015 GrAssert(sizeof(Vertex) == target->getDrawState().getVertexSize()); | 1071 GrAssert(sizeof(Vertex) == target->getDrawState().getVertexSize()); |
1016 | 1072 |
1017 if (!arg->set(target, vertCnt, 0)) { | 1073 if (!arg->set(target, vertCnt, 0)) { |
1018 return false; | 1074 return false; |
1019 } | 1075 } |
1020 | 1076 |
1021 Vertex* verts = reinterpret_cast<Vertex*>(arg->vertices()); | 1077 Vertex* verts = reinterpret_cast<Vertex*>(arg->vertices()); |
1022 | 1078 |
1023 const SkMatrix* toDevice = NULL; | 1079 const SkMatrix* toDevice = NULL; |
1024 const SkMatrix* toSrc = NULL; | 1080 const SkMatrix* toSrc = NULL; |
(...skipping 24 matching lines...) Expand all Loading... |
1049 } | 1105 } |
1050 | 1106 |
1051 bool GrAAHairLinePathRenderer::canDrawPath(const SkPath& path, | 1107 bool GrAAHairLinePathRenderer::canDrawPath(const SkPath& path, |
1052 const SkStrokeRec& stroke, | 1108 const SkStrokeRec& stroke, |
1053 const GrDrawTarget* target, | 1109 const GrDrawTarget* target, |
1054 bool antiAlias) const { | 1110 bool antiAlias) const { |
1055 if (!stroke.isHairlineStyle() || !antiAlias) { | 1111 if (!stroke.isHairlineStyle() || !antiAlias) { |
1056 return false; | 1112 return false; |
1057 } | 1113 } |
1058 | 1114 |
1059 static const uint32_t gReqDerivMask = SkPath::kCubic_SegmentMask | | 1115 if (SkPath::kLine_SegmentMask == path.getSegmentMasks() || |
1060 SkPath::kQuad_SegmentMask; | 1116 target->caps()->shaderDerivativeSupport()) { |
1061 if (!target->caps()->shaderDerivativeSupport() && | 1117 return true; |
1062 (gReqDerivMask & path.getSegmentMasks())) { | |
1063 return false; | |
1064 } | 1118 } |
1065 return true; | 1119 return false; |
1066 } | 1120 } |
1067 | 1121 |
1068 bool GrAAHairLinePathRenderer::onDrawPath(const SkPath& path, | 1122 bool GrAAHairLinePathRenderer::onDrawPath(const SkPath& path, |
1069 const SkStrokeRec&, | 1123 const SkStrokeRec&, |
1070 GrDrawTarget* target, | 1124 GrDrawTarget* target, |
1071 bool antiAlias) { | 1125 bool antiAlias) { |
1072 | 1126 |
1073 int lineCnt; | 1127 int lineCnt; |
1074 int quadCnt; | 1128 int quadCnt; |
1075 int conicCnt; | 1129 int conicCnt; |
(...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1181 kVertsPerQuad*n, // vCount | 1235 kVertsPerQuad*n, // vCount |
1182 kIdxsPerQuad*n, // iCount | 1236 kIdxsPerQuad*n, // iCount |
1183 &devBounds); | 1237 &devBounds); |
1184 conics += n; | 1238 conics += n; |
1185 } | 1239 } |
1186 } | 1240 } |
1187 target->resetIndexSource(); | 1241 target->resetIndexSource(); |
1188 | 1242 |
1189 return true; | 1243 return true; |
1190 } | 1244 } |
OLD | NEW |