OLD | NEW |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 |
OLD | NEW |