OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2011 Google Inc. | 2 * Copyright 2011 Google Inc. |
3 * | 3 * |
4 * 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 |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
8 #include "GrAAHairLinePathRenderer.h" | 8 #include "GrAAHairLinePathRenderer.h" |
9 | 9 |
10 #include "GrContext.h" | 10 #include "GrContext.h" |
(...skipping 11 matching lines...) Expand all Loading... |
22 #include "gl/GrGLEffect.h" | 22 #include "gl/GrGLEffect.h" |
23 #include "gl/GrGLSL.h" | 23 #include "gl/GrGLSL.h" |
24 | 24 |
25 namespace { | 25 namespace { |
26 // quadratics are rendered as 5-sided polys in order to bound the | 26 // quadratics are rendered as 5-sided polys in order to bound the |
27 // AA stroke around the center-curve. See comments in push_quad_index_buffer and | 27 // AA stroke around the center-curve. See comments in push_quad_index_buffer and |
28 // bloat_quad. Quadratics and conics share an index buffer | 28 // bloat_quad. Quadratics and conics share an index buffer |
29 static const int kVertsPerQuad = 5; | 29 static const int kVertsPerQuad = 5; |
30 static const int kIdxsPerQuad = 9; | 30 static const int kIdxsPerQuad = 9; |
31 | 31 |
| 32 static const int kVertsPerCubic = 4; |
| 33 static const int kIdxsPerCubic = 6; |
| 34 |
32 static const int kVertsPerLineSeg = 4; | 35 static const int kVertsPerLineSeg = 4; |
33 static const int kIdxsPerLineSeg = 6; | 36 static const int kIdxsPerLineSeg = 6; |
34 | 37 |
35 static const int kNumQuadsInIdxBuffer = 256; | 38 static const int kNumQuadsInIdxBuffer = 256; |
36 static const size_t kQuadIdxSBufize = kIdxsPerQuad * | 39 static const size_t kQuadIdxSBufize = kIdxsPerQuad * |
37 sizeof(uint16_t) * | 40 sizeof(uint16_t) * |
38 kNumQuadsInIdxBuffer; | 41 kNumQuadsInIdxBuffer; |
39 | 42 |
| 43 static const int kNumCubicsInIdxBuffer = 256; |
| 44 static const size_t kCubicIdxSBufize = kIdxsPerCubic * |
| 45 sizeof(uint16_t) * |
| 46 kNumCubicsInIdxBuffer; |
| 47 |
| 48 bool push_cubic_index_data(GrIndexBuffer* cIdxBuffer) { |
| 49 uint16_t* data = (uint16_t*) cIdxBuffer->lock(); |
| 50 bool tempData = NULL == data; |
| 51 if (tempData) { |
| 52 data = SkNEW_ARRAY(uint16_t, kNumCubicsInIdxBuffer * kIdxsPerCubic); |
| 53 } |
| 54 for (int i = 0; i < kNumCubicsInIdxBuffer; ++i) { |
| 55 |
| 56 int baseIdx = i * kIdxsPerCubic; |
| 57 uint16_t baseVert = (uint16_t)(i * kVertsPerCubic); |
| 58 |
| 59 data[0 + baseIdx] = baseVert + 0; |
| 60 data[1 + baseIdx] = baseVert + 1; |
| 61 data[2 + baseIdx] = baseVert + 2; |
| 62 data[3 + baseIdx] = baseVert + 2; |
| 63 data[4 + baseIdx] = baseVert + 3; |
| 64 data[5 + baseIdx] = baseVert + 0; |
| 65 } |
| 66 if (tempData) { |
| 67 bool ret = cIdxBuffer->updateData(data, kCubicIdxSBufize); |
| 68 delete[] data; |
| 69 return ret; |
| 70 } else { |
| 71 cIdxBuffer->unlock(); |
| 72 return true; |
| 73 } |
| 74 } |
| 75 |
40 bool push_quad_index_data(GrIndexBuffer* qIdxBuffer) { | 76 bool push_quad_index_data(GrIndexBuffer* qIdxBuffer) { |
41 uint16_t* data = (uint16_t*) qIdxBuffer->lock(); | 77 uint16_t* data = (uint16_t*) qIdxBuffer->lock(); |
42 bool tempData = NULL == data; | 78 bool tempData = NULL == data; |
43 if (tempData) { | 79 if (tempData) { |
44 data = SkNEW_ARRAY(uint16_t, kNumQuadsInIdxBuffer * kIdxsPerQuad); | 80 data = SkNEW_ARRAY(uint16_t, kNumQuadsInIdxBuffer * kIdxsPerQuad); |
45 } | 81 } |
46 for (int i = 0; i < kNumQuadsInIdxBuffer; ++i) { | 82 for (int i = 0; i < kNumQuadsInIdxBuffer; ++i) { |
47 | 83 |
48 // Each quadratic is rendered as a five sided polygon. This poly bounds | 84 // Each quadratic is rendered as a five sided polygon. This poly bounds |
49 // the quadratic's bounding triangle but has been expanded so that the | 85 // the quadratic's bounding triangle but has been expanded so that the |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
85 if (NULL == lIdxBuffer) { | 121 if (NULL == lIdxBuffer) { |
86 return NULL; | 122 return NULL; |
87 } | 123 } |
88 GrGpu* gpu = context->getGpu(); | 124 GrGpu* gpu = context->getGpu(); |
89 GrIndexBuffer* qIdxBuf = gpu->createIndexBuffer(kQuadIdxSBufize, false); | 125 GrIndexBuffer* qIdxBuf = gpu->createIndexBuffer(kQuadIdxSBufize, false); |
90 SkAutoTUnref<GrIndexBuffer> qIdxBuffer(qIdxBuf); | 126 SkAutoTUnref<GrIndexBuffer> qIdxBuffer(qIdxBuf); |
91 if (NULL == qIdxBuf || | 127 if (NULL == qIdxBuf || |
92 !push_quad_index_data(qIdxBuf)) { | 128 !push_quad_index_data(qIdxBuf)) { |
93 return NULL; | 129 return NULL; |
94 } | 130 } |
| 131 GrIndexBuffer* cIdxBuf = gpu->createIndexBuffer(kCubicIdxSBufize, false); |
| 132 SkAutoTUnref<GrIndexBuffer> cIdxBuffer(cIdxBuf); |
| 133 if (NULL == cIdxBuf || |
| 134 !push_cubic_index_data(cIdxBuf)) { |
| 135 return NULL; |
| 136 } |
95 return SkNEW_ARGS(GrAAHairLinePathRenderer, | 137 return SkNEW_ARGS(GrAAHairLinePathRenderer, |
96 (context, lIdxBuffer, qIdxBuf)); | 138 (context, lIdxBuffer, qIdxBuf, cIdxBuf)); |
97 } | 139 } |
98 | 140 |
99 GrAAHairLinePathRenderer::GrAAHairLinePathRenderer( | 141 GrAAHairLinePathRenderer::GrAAHairLinePathRenderer( |
100 const GrContext* context, | 142 const GrContext* context, |
101 const GrIndexBuffer* linesIndexBuffer, | 143 const GrIndexBuffer* linesIndexBuffer, |
102 const GrIndexBuffer* quadsIndexBuffer) { | 144 const GrIndexBuffer* quadsIndexBuffer, |
| 145 const GrIndexBuffer* cubicsIndexBuffer)
{ |
103 fLinesIndexBuffer = linesIndexBuffer; | 146 fLinesIndexBuffer = linesIndexBuffer; |
104 linesIndexBuffer->ref(); | 147 linesIndexBuffer->ref(); |
105 fQuadsIndexBuffer = quadsIndexBuffer; | 148 fQuadsIndexBuffer = quadsIndexBuffer; |
106 quadsIndexBuffer->ref(); | 149 quadsIndexBuffer->ref(); |
| 150 fCubicsIndexBuffer = cubicsIndexBuffer; |
| 151 cubicsIndexBuffer->ref(); |
107 } | 152 } |
108 | 153 |
109 GrAAHairLinePathRenderer::~GrAAHairLinePathRenderer() { | 154 GrAAHairLinePathRenderer::~GrAAHairLinePathRenderer() { |
110 fLinesIndexBuffer->unref(); | 155 fLinesIndexBuffer->unref(); |
111 fQuadsIndexBuffer->unref(); | 156 fQuadsIndexBuffer->unref(); |
| 157 fCubicsIndexBuffer->unref(); |
112 } | 158 } |
113 | 159 |
114 namespace { | 160 namespace { |
115 | 161 |
116 typedef SkTArray<SkPoint, true> PtArray; | 162 typedef SkTArray<SkPoint, true> PtArray; |
117 #define PREALLOC_PTARRAY(N) SkSTArray<(N),SkPoint, true> | 163 #define PREALLOC_PTARRAY(N) SkSTArray<(N),SkPoint, true> |
118 typedef SkTArray<int, true> IntArray; | 164 typedef SkTArray<int, true> IntArray; |
119 typedef SkTArray<float, true> FloatArray; | 165 typedef SkTArray<float, true> FloatArray; |
120 | 166 |
121 // Takes 178th time of logf on Z600 / VC2010 | 167 // Takes 178th time of logf on Z600 / VC2010 |
(...skipping 13 matching lines...) Expand all Loading... |
135 GrAssert(get_float_exp(100.f) == 6); | 181 GrAssert(get_float_exp(100.f) == 6); |
136 GrAssert(get_float_exp(1000.f) == 9); | 182 GrAssert(get_float_exp(1000.f) == 9); |
137 GrAssert(get_float_exp(1024.f) == 10); | 183 GrAssert(get_float_exp(1024.f) == 10); |
138 GrAssert(get_float_exp(3000000.f) == 21); | 184 GrAssert(get_float_exp(3000000.f) == 21); |
139 } | 185 } |
140 #endif | 186 #endif |
141 const int* iptr = (const int*)&x; | 187 const int* iptr = (const int*)&x; |
142 return (((*iptr) & 0x7f800000) >> 23) - 127; | 188 return (((*iptr) & 0x7f800000) >> 23) - 127; |
143 } | 189 } |
144 | 190 |
| 191 //int chop_cubic_at_loop_intersection(const SkPoint src[4], SkPoint dst[10], SkS
calar k[3] = NULL, |
| 192 // SkScalar l[3] = NULL, SkScalar m[3] = NULL
); |
| 193 |
145 // Uses the max curvature function for quads to estimate | 194 // Uses the max curvature function for quads to estimate |
146 // where to chop the conic. If the max curvature is not | 195 // where to chop the conic. If the max curvature is not |
147 // found along the curve segment it will return 1 and | 196 // found along the curve segment it will return 1 and |
148 // dst[0] is the original conic. If it returns 2 the dst[0] | 197 // dst[0] is the original conic. If it returns 2 the dst[0] |
149 // and dst[1] are the two new conics. | 198 // and dst[1] are the two new conics. |
150 int split_conic(const SkPoint src[3], SkConic dst[2], const SkScalar weight) { | 199 int split_conic(const SkPoint src[3], SkConic dst[2], const SkScalar weight) { |
151 SkScalar t = SkFindQuadMaxCurvature(src); | 200 SkScalar t = SkFindQuadMaxCurvature(src); |
152 if (t == 0) { | 201 if (t == 0) { |
153 if (dst) { | 202 if (dst) { |
154 dst[0].set(src, weight); | 203 dst[0].set(src, weight); |
(...skipping 17 matching lines...) Expand all Loading... |
172 int conicCnt = split_conic(src, dstTemp, weight); | 221 int conicCnt = split_conic(src, dstTemp, weight); |
173 if (2 == conicCnt) { | 222 if (2 == conicCnt) { |
174 int conicCnt2 = split_conic(dstTemp[0].fPts, dst, dstTemp[0].fW); | 223 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); | 224 conicCnt = conicCnt2 + split_conic(dstTemp[1].fPts, &dst[conicCnt2], dst
Temp[1].fW); |
176 } else { | 225 } else { |
177 dst[0] = dstTemp[0]; | 226 dst[0] = dstTemp[0]; |
178 } | 227 } |
179 return conicCnt; | 228 return conicCnt; |
180 } | 229 } |
181 | 230 |
| 231 int is_degen_cubic(const SkPoint p[4]) { |
| 232 static const SkScalar gDegenerateToLineTol = SK_Scalar1; |
| 233 static const SkScalar gDegenerateToLineTolSqd = |
| 234 SkScalarMul(gDegenerateToLineTol, gDegenerateToLineTol); |
| 235 |
| 236 if (p[0].distanceToSqd(p[3]) < gDegenerateToLineTolSqd && |
| 237 p[1].distanceToSqd(p[2]) < gDegenerateToLineTolSqd) { |
| 238 return 1; |
| 239 } |
| 240 |
| 241 // if the points are all close to being colinear |
| 242 SkScalar dsqd1= p[1].distanceToLineBetweenSqd(p[0], p[3]); |
| 243 SkScalar dsqd2= p[2].distanceToLineBetweenSqd(p[0], p[3]); |
| 244 if (dsqd1 < gDegenerateToLineTolSqd && dsqd2 < gDegenerateToLineTolSqd) { |
| 245 return 1; |
| 246 } |
| 247 |
| 248 return 0; |
| 249 |
| 250 } |
| 251 |
182 // returns 0 if quad/conic is degen or close to it | 252 // returns 0 if quad/conic is degen or close to it |
183 // in this case approx the path with lines | 253 // in this case approx the path with lines |
184 // otherwise returns 1 | 254 // otherwise returns 1 |
185 int is_degen_quad_or_conic(const SkPoint p[3]) { | 255 int is_degen_quad_or_conic(const SkPoint p[3]) { |
186 static const SkScalar gDegenerateToLineTol = SK_Scalar1; | 256 static const SkScalar gDegenerateToLineTol = SK_Scalar1; |
187 static const SkScalar gDegenerateToLineTolSqd = | 257 static const SkScalar gDegenerateToLineTolSqd = |
188 SkScalarMul(gDegenerateToLineTol, gDegenerateToLineTol); | 258 SkScalarMul(gDegenerateToLineTol, gDegenerateToLineTol); |
189 | 259 |
190 if (p[0].distanceToSqd(p[1]) < gDegenerateToLineTolSqd || | 260 if (p[0].distanceToSqd(p[1]) < gDegenerateToLineTolSqd || |
191 p[1].distanceToSqd(p[2]) < gDegenerateToLineTolSqd) { | 261 p[1].distanceToSqd(p[2]) < gDegenerateToLineTolSqd) { |
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
262 * perspective, then in they are in src space. We do this because we will | 332 * perspective, then in they are in src space. We do this because we will |
263 * subdivide large quads to reduce over-fill. This subdivision has to be | 333 * subdivide large quads to reduce over-fill. This subdivision has to be |
264 * performed before applying the perspective matrix. | 334 * performed before applying the perspective matrix. |
265 */ | 335 */ |
266 int generate_lines_and_quads(const SkPath& path, | 336 int generate_lines_and_quads(const SkPath& path, |
267 const SkMatrix& m, | 337 const SkMatrix& m, |
268 const SkIRect& devClipBounds, | 338 const SkIRect& devClipBounds, |
269 PtArray* lines, | 339 PtArray* lines, |
270 PtArray* quads, | 340 PtArray* quads, |
271 PtArray* conics, | 341 PtArray* conics, |
| 342 PtArray* cubics, |
272 IntArray* quadSubdivCnts, | 343 IntArray* quadSubdivCnts, |
273 FloatArray* conicWeights) { | 344 FloatArray* conicWeights, |
| 345 FloatArray* cubicKLM) { |
274 SkPath::Iter iter(path, false); | 346 SkPath::Iter iter(path, false); |
275 | 347 |
276 int totalQuadCount = 0; | 348 int totalQuadCount = 0; |
277 SkRect bounds; | 349 SkRect bounds; |
278 SkIRect ibounds; | 350 SkIRect ibounds; |
279 | 351 |
280 bool persp = m.hasPerspective(); | 352 bool persp = m.hasPerspective(); |
281 | 353 |
282 for (;;) { | 354 for (;;) { |
283 GrPoint pathPts[4]; | 355 GrPoint pathPts[4]; |
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
360 pts[0] = qPts[0]; | 432 pts[0] = qPts[0]; |
361 pts[1] = qPts[1]; | 433 pts[1] = qPts[1]; |
362 pts[2] = qPts[2]; | 434 pts[2] = qPts[2]; |
363 quadSubdivCnts->push_back() = subdiv; | 435 quadSubdivCnts->push_back() = subdiv; |
364 totalQuadCount += 1 << subdiv; | 436 totalQuadCount += 1 << subdiv; |
365 } | 437 } |
366 } | 438 } |
367 } | 439 } |
368 break; | 440 break; |
369 } | 441 } |
370 case SkPath::kCubic_Verb: | 442 case SkPath::kCubic_Verb: { |
| 443 SkPoint dst[10]; |
| 444 SkScalar klm[9]; |
| 445 SkScalar klm_rev[3]; |
371 m.mapPoints(devPts, pathPts, 4); | 446 m.mapPoints(devPts, pathPts, 4); |
372 bounds.setBounds(devPts, 4); | 447 int cubicCnt = GrPathUtils::chopCubicAtLoopIntersection(pathPts,
dst, klm, |
373 bounds.outset(SK_Scalar1, SK_Scalar1); | 448 klm_rev,
devPts); |
374 bounds.roundOut(&ibounds); | 449 for (int i = 0; i < cubicCnt; ++i) { |
375 if (SkIRect::Intersects(devClipBounds, ibounds)) { | 450 SkPoint* chopPnts = &dst[i*3]; |
376 PREALLOC_PTARRAY(32) q; | 451 m.mapPoints(devPts, chopPnts, 4); |
377 // we don't need a direction if we aren't constraining the s
ubdivision | 452 bounds.setBounds(devPts, 4); |
378 static const SkPath::Direction kDummyDir = SkPath::kCCW_Dire
ction; | 453 bounds.outset(SK_Scalar1, SK_Scalar1); |
379 // We convert cubics to quadratics (for now). | 454 bounds.roundOut(&ibounds); |
380 // In perspective have to do conversion in src space. | 455 if (SkIRect::Intersects(devClipBounds, ibounds)) { |
381 if (persp) { | 456 if (is_degen_cubic(devPts)) { |
382 SkScalar tolScale = | 457 SkPoint* pts = lines->push_back_n(6); |
383 GrPathUtils::scaleToleranceToSrc(SK_Scalar1, m, | 458 pts[0] = devPts[0]; |
384 path.getBounds()); | 459 pts[1] = devPts[1]; |
385 GrPathUtils::convertCubicToQuads(pathPts, tolScale, fals
e, kDummyDir, &q); | 460 pts[2] = devPts[1]; |
386 } else { | 461 pts[3] = devPts[2]; |
387 GrPathUtils::convertCubicToQuads(devPts, SK_Scalar1, fal
se, kDummyDir, &q); | 462 pts[4] = devPts[2]; |
388 } | 463 pts[5] = devPts[3]; |
389 for (int i = 0; i < q.count(); i += 3) { | |
390 SkPoint* qInDevSpace; | |
391 // bounds has to be calculated in device space, but q is | |
392 // in src space when there is perspective. | |
393 if (persp) { | |
394 m.mapPoints(devPts, &q[i], 3); | |
395 bounds.setBounds(devPts, 3); | |
396 qInDevSpace = devPts; | |
397 } else { | 464 } else { |
398 bounds.setBounds(&q[i], 3); | 465 // when in perspective keep conics in src space |
399 qInDevSpace = &q[i]; | 466 SkPoint* cPts = persp ? chopPnts : devPts; |
400 } | 467 SkPoint* pts = cubics->push_back_n(4); |
401 bounds.outset(SK_Scalar1, SK_Scalar1); | 468 pts[0] = cPts[0]; |
402 bounds.roundOut(&ibounds); | 469 pts[1] = cPts[1]; |
403 if (SkIRect::Intersects(devClipBounds, ibounds)) { | 470 pts[2] = cPts[2]; |
404 int subdiv = num_quad_subdivs(qInDevSpace); | 471 pts[3] = cPts[3]; |
405 GrAssert(subdiv >= -1); | 472 SkScalar* klms = cubicKLM->push_back_n(9); |
406 if (-1 == subdiv) { | 473 // set sub sections klm to equal klm of whole curve
and |
407 SkPoint* pts = lines->push_back_n(4); | 474 // flip the signs of k, l if needed |
408 // lines should always be in device coords | 475 memcpy(klms, klm, 9 * sizeof(SkScalar)); |
409 pts[0] = qInDevSpace[0]; | 476 for (int j = 0; j < 6; ++j) { |
410 pts[1] = qInDevSpace[1]; | 477 klms[j] *= klm_rev[i]; |
411 pts[2] = qInDevSpace[1]; | |
412 pts[3] = qInDevSpace[2]; | |
413 } else { | |
414 SkPoint* pts = quads->push_back_n(3); | |
415 // q is already in src space when there is no | |
416 // perspective and dev coords otherwise. | |
417 pts[0] = q[0 + i]; | |
418 pts[1] = q[1 + i]; | |
419 pts[2] = q[2 + i]; | |
420 quadSubdivCnts->push_back() = subdiv; | |
421 totalQuadCount += 1 << subdiv; | |
422 } | 478 } |
423 } | 479 } |
424 } | 480 } |
425 } | 481 } |
426 break; | 482 break; |
| 483 } |
427 case SkPath::kClose_Verb: | 484 case SkPath::kClose_Verb: |
428 break; | 485 break; |
429 case SkPath::kDone_Verb: | 486 case SkPath::kDone_Verb: |
430 return totalQuadCount; | 487 return totalQuadCount; |
431 } | 488 } |
432 } | 489 } |
433 } | 490 } |
434 | 491 |
435 struct Vertex { | 492 struct Vertex { |
436 GrPoint fPos; | 493 GrPoint fPos; |
437 union { | 494 union { |
438 struct { | 495 struct { |
439 SkScalar fA; | 496 SkScalar fA; |
440 SkScalar fB; | 497 SkScalar fB; |
441 SkScalar fC; | 498 SkScalar fC; |
442 } fLine; | 499 } fLine; |
443 struct { | 500 struct { |
444 SkScalar fK; | 501 SkScalar fK; |
445 SkScalar fL; | 502 SkScalar fL; |
446 SkScalar fM; | 503 SkScalar fM; |
447 } fConic; | 504 } fBezier; |
448 GrVec fQuadCoord; | 505 GrVec fQuadCoord; |
449 struct { | 506 struct { |
450 SkScalar fBogus[4]; | 507 SkScalar fBogus[4]; |
451 }; | 508 }; |
452 }; | 509 }; |
453 }; | 510 }; |
454 | 511 |
455 GR_STATIC_ASSERT(sizeof(Vertex) == 3 * sizeof(GrPoint)); | 512 GR_STATIC_ASSERT(sizeof(Vertex) == 3 * sizeof(GrPoint)); |
456 | 513 |
457 void intersect_lines(const SkPoint& ptA, const SkVector& normA, | 514 void intersect_lines(const SkPoint& ptA, const SkVector& normA, |
(...skipping 13 matching lines...) Expand all Loading... |
471 result->fY = SkScalarMul(lineAW, normB.fX) - SkScalarMul(normA.fX, lineBW); | 528 result->fY = SkScalarMul(lineAW, normB.fX) - SkScalarMul(normA.fX, lineBW); |
472 result->fY = SkScalarMul(result->fY, wInv); | 529 result->fY = SkScalarMul(result->fY, wInv); |
473 } | 530 } |
474 | 531 |
475 void set_uv_quad(const SkPoint qpts[3], Vertex verts[kVertsPerQuad]) { | 532 void set_uv_quad(const SkPoint qpts[3], Vertex verts[kVertsPerQuad]) { |
476 // this should be in the src space, not dev coords, when we have perspective | 533 // this should be in the src space, not dev coords, when we have perspective |
477 GrPathUtils::QuadUVMatrix DevToUV(qpts); | 534 GrPathUtils::QuadUVMatrix DevToUV(qpts); |
478 DevToUV.apply<kVertsPerQuad, sizeof(Vertex), sizeof(GrPoint)>(verts); | 535 DevToUV.apply<kVertsPerQuad, sizeof(Vertex), sizeof(GrPoint)>(verts); |
479 } | 536 } |
480 | 537 |
| 538 // Set verts to be bounding box around the control points cpts bloated |
| 539 // out by 1 in each direcition |
| 540 void bloat_cubic(const SkPoint cpts[4], const SkMatrix* toDevice, |
| 541 const SkMatrix* toSrc, Vertex verts[kVertsPerCubic], |
| 542 SkRect* devBounds) { |
| 543 GrAssert(!toDevice == !toSrc); |
| 544 // original cubic is specified by quad a,b,c,d |
| 545 SkPoint a = cpts[0]; |
| 546 SkPoint b = cpts[1]; |
| 547 SkPoint c = cpts[2]; |
| 548 SkPoint d = cpts[3]; |
| 549 |
| 550 if (toDevice) { |
| 551 toDevice->mapPoints(&a, 1); |
| 552 toDevice->mapPoints(&b, 1); |
| 553 toDevice->mapPoints(&c, 1); |
| 554 toDevice->mapPoints(&d, 1); |
| 555 } |
| 556 |
| 557 SkScalar minX = cpts[0].fX; |
| 558 SkScalar maxX = cpts[0].fX; |
| 559 SkScalar minY = cpts[0].fY; |
| 560 SkScalar maxY = cpts[0].fY; |
| 561 |
| 562 for (int i = 1; i < 4; ++i) { |
| 563 minX = SkMinScalar(minX, cpts[i].fX); |
| 564 maxX = SkMaxScalar(maxX, cpts[i].fX); |
| 565 minY = SkMinScalar(minY, cpts[i].fY); |
| 566 maxY = SkMaxScalar(maxY, cpts[i].fY); |
| 567 } |
| 568 |
| 569 minX -= 1.0f; |
| 570 maxX += 1.0f; |
| 571 minY -= 1.0f; |
| 572 maxY += 1.0f; |
| 573 |
| 574 Vertex& a1 = verts[0]; |
| 575 Vertex& b1 = verts[1]; |
| 576 Vertex& c1 = verts[2]; |
| 577 Vertex& d1 = verts[3]; |
| 578 |
| 579 a1.fPos.fX = minX; |
| 580 a1.fPos.fY = minY; |
| 581 b1.fPos.fX = maxX; |
| 582 b1.fPos.fY = minY; |
| 583 c1.fPos.fX = maxX; |
| 584 c1.fPos.fY = maxY; |
| 585 d1.fPos.fX = minX; |
| 586 d1.fPos.fY = maxY; |
| 587 |
| 588 devBounds->growToInclude(a1.fPos.fX, a1.fPos.fY); |
| 589 devBounds->growToInclude(b1.fPos.fX, b1.fPos.fY); |
| 590 devBounds->growToInclude(c1.fPos.fX, c1.fPos.fY); |
| 591 devBounds->growToInclude(d1.fPos.fX, d1.fPos.fY); |
| 592 |
| 593 if (toSrc) { |
| 594 toSrc->mapPointsWithStride(&verts[0].fPos, sizeof(Vertex), kVertsPerCubi
c); |
| 595 } |
| 596 } |
| 597 |
481 void bloat_quad(const SkPoint qpts[3], const SkMatrix* toDevice, | 598 void bloat_quad(const SkPoint qpts[3], const SkMatrix* toDevice, |
482 const SkMatrix* toSrc, Vertex verts[kVertsPerQuad], | 599 const SkMatrix* toSrc, Vertex verts[kVertsPerQuad], |
483 SkRect* devBounds) { | 600 SkRect* devBounds) { |
484 GrAssert(!toDevice == !toSrc); | 601 GrAssert(!toDevice == !toSrc); |
485 // original quad is specified by tri a,b,c | 602 // original quad is specified by tri a,b,c |
486 SkPoint a = qpts[0]; | 603 SkPoint a = qpts[0]; |
487 SkPoint b = qpts[1]; | 604 SkPoint b = qpts[1]; |
488 SkPoint c = qpts[2]; | 605 SkPoint c = qpts[2]; |
489 | 606 |
490 if (toDevice) { | 607 if (toDevice) { |
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
577 k[2] = (p[2].fX - p[0].fX) * p[0].fY - (p[2].fY - p[0].fY) * p[0].fX; | 694 k[2] = (p[2].fX - p[0].fX) * p[0].fY - (p[2].fY - p[0].fY) * p[0].fX; |
578 | 695 |
579 // scale the max absolute value of coeffs to 10 | 696 // scale the max absolute value of coeffs to 10 |
580 SkScalar scale = 0.0f; | 697 SkScalar scale = 0.0f; |
581 for (int i = 0; i < 3; ++i) { | 698 for (int i = 0; i < 3; ++i) { |
582 scale = SkMaxScalar(scale, SkScalarAbs(k[i])); | 699 scale = SkMaxScalar(scale, SkScalarAbs(k[i])); |
583 scale = SkMaxScalar(scale, SkScalarAbs(l[i])); | 700 scale = SkMaxScalar(scale, SkScalarAbs(l[i])); |
584 scale = SkMaxScalar(scale, SkScalarAbs(m[i])); | 701 scale = SkMaxScalar(scale, SkScalarAbs(m[i])); |
585 } | 702 } |
586 GrAssert(scale > 0); | 703 GrAssert(scale > 0); |
587 scale /= 10.0f; | 704 scale = 10.0f / scale; |
588 k[0] /= scale; | 705 k[0] *= scale; |
589 k[1] /= scale; | 706 k[1] *= scale; |
590 k[2] /= scale; | 707 k[2] *= scale; |
591 l[0] /= scale; | 708 l[0] *= scale; |
592 l[1] /= scale; | 709 l[1] *= scale; |
593 l[2] /= scale; | 710 l[2] *= scale; |
594 m[0] /= scale; | 711 m[0] *= scale; |
595 m[1] /= scale; | 712 m[1] *= scale; |
596 m[2] /= scale; | 713 m[2] *= scale; |
597 } | 714 } |
598 | 715 |
599 // Equations based off of Loop-Blinn Quadratic GPU Rendering | 716 // Equations based off of Loop-Blinn Quadratic GPU Rendering |
600 // Input Parametric: | 717 // Input Parametric: |
601 // 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) | 718 // 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) |
602 // Output Implicit: | 719 // Output Implicit: |
603 // f(x, y, w) = f(P) = K^2 - LM | 720 // f(x, y, w) = f(P) = K^2 - LM |
604 // K = dot(k, P), L = dot(l, P), M = dot(m, P) | 721 // K = dot(k, P), L = dot(l, P), M = dot(m, P) |
605 // k, l, m are calculated in function calc_conic_klm | 722 // k, l, m are calculated in function calc_conic_klm |
606 void set_conic_coeffs(const SkPoint p[3], Vertex verts[kVertsPerQuad], const flo
at weight) { | 723 void set_conic_klm(const SkPoint p[3], Vertex verts[kVertsPerQuad], const float
weight) { |
607 SkScalar k[3]; | 724 SkScalar k[3]; |
608 SkScalar l[3]; | 725 SkScalar l[3]; |
609 SkScalar m[3]; | 726 SkScalar m[3]; |
610 | 727 |
611 calc_conic_klm(p, weight, k, l, m); | 728 calc_conic_klm(p, weight, k, l, m); |
612 | 729 |
613 for (int i = 0; i < kVertsPerQuad; ++i) { | 730 for (int i = 0; i < kVertsPerQuad; ++i) { |
614 const SkPoint pnt = verts[i].fPos; | 731 const SkPoint pnt = verts[i].fPos; |
615 verts[i].fConic.fK = pnt.fX * k[0] + pnt.fY * k[1] + k[2]; | 732 verts[i].fBezier.fK = pnt.fX * k[0] + pnt.fY * k[1] + k[2]; |
616 verts[i].fConic.fL = pnt.fX * l[0] + pnt.fY * l[1] + l[2]; | 733 verts[i].fBezier.fL = pnt.fX * l[0] + pnt.fY * l[1] + l[2]; |
617 verts[i].fConic.fM = pnt.fX * m[0] + pnt.fY * m[1] + m[2]; | 734 verts[i].fBezier.fM = pnt.fX * m[0] + pnt.fY * m[1] + m[2]; |
618 } | 735 } |
619 } | 736 } |
620 | 737 |
| 738 void set_cubic_klm(const SkPoint p[4], Vertex verts[kVertsPerCubic], const SkSca
lar klm[9]) { |
| 739 for (int i = 0; i < kVertsPerCubic; ++i) { |
| 740 const SkPoint pnt = verts[i].fPos; |
| 741 verts[i].fBezier.fK = pnt.fX * klm[0] + pnt.fY * klm[1] + klm[2]; |
| 742 verts[i].fBezier.fL = pnt.fX * klm[3] + pnt.fY * klm[4] + klm[5]; |
| 743 verts[i].fBezier.fM = pnt.fX * klm[6] + pnt.fY * klm[7] + klm[8]; |
| 744 } |
| 745 } |
| 746 |
| 747 void add_cubics(const SkPoint p[3], |
| 748 const SkScalar klm[9], |
| 749 const SkMatrix* toDevice, |
| 750 const SkMatrix* toSrc, |
| 751 Vertex** vert, |
| 752 SkRect* devBounds) { |
| 753 bloat_cubic(p, toDevice, toSrc, *vert, devBounds); |
| 754 set_cubic_klm(p, *vert, klm); |
| 755 *vert += kVertsPerCubic; |
| 756 } |
| 757 |
621 void add_conics(const SkPoint p[3], | 758 void add_conics(const SkPoint p[3], |
622 float weight, | 759 float weight, |
623 const SkMatrix* toDevice, | 760 const SkMatrix* toDevice, |
624 const SkMatrix* toSrc, | 761 const SkMatrix* toSrc, |
625 Vertex** vert, | 762 Vertex** vert, |
626 SkRect* devBounds) { | 763 SkRect* devBounds) { |
627 bloat_quad(p, toDevice, toSrc, *vert, devBounds); | 764 bloat_quad(p, toDevice, toSrc, *vert, devBounds); |
628 set_conic_coeffs(p, *vert, weight); | 765 set_conic_klm(p, *vert, weight); |
629 *vert += kVertsPerQuad; | 766 *vert += kVertsPerQuad; |
630 } | 767 } |
631 | 768 |
632 void add_quads(const SkPoint p[3], | 769 void add_quads(const SkPoint p[3], |
633 int subdiv, | 770 int subdiv, |
634 const SkMatrix* toDevice, | 771 const SkMatrix* toDevice, |
635 const SkMatrix* toSrc, | 772 const SkMatrix* toSrc, |
636 Vertex** vert, | 773 Vertex** vert, |
637 SkRect* devBounds) { | 774 SkRect* devBounds) { |
638 GrAssert(subdiv >= 0); | 775 GrAssert(subdiv >= 0); |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
685 (*vert)[2].fPos.set(SK_ScalarMax, SK_ScalarMax); | 822 (*vert)[2].fPos.set(SK_ScalarMax, SK_ScalarMax); |
686 (*vert)[3].fPos.set(SK_ScalarMax, SK_ScalarMax); | 823 (*vert)[3].fPos.set(SK_ScalarMax, SK_ScalarMax); |
687 } | 824 } |
688 | 825 |
689 *vert += kVertsPerLineSeg; | 826 *vert += kVertsPerLineSeg; |
690 } | 827 } |
691 | 828 |
692 } | 829 } |
693 | 830 |
694 /** | 831 /** |
| 832 * Shader is based off of "Resolution Independent Curve Rendering using |
| 833 * Programmable Graphics Hardware" by Loop and Blinn. |
| 834 * The output of this effect is a hairline edge for non rational cubics. |
| 835 * Cubics are specified by implicit equation K^3 - LM. |
| 836 * K, L, and M, are the first three values of the vertex attribute, |
| 837 * the fourth value is not used. Distance is calculated using a |
| 838 * first order approximation from the taylor series. |
| 839 * Coverage is max(0, 1-distance). |
| 840 */ |
| 841 class HairCubicEdgeEffect : public GrEffect { |
| 842 public: |
| 843 static GrEffectRef* Create() { |
| 844 GR_CREATE_STATIC_EFFECT(gHairCubicEdgeEffect, HairCubicEdgeEffect, ()); |
| 845 gHairCubicEdgeEffect->ref(); |
| 846 return gHairCubicEdgeEffect; |
| 847 } |
| 848 |
| 849 virtual ~HairCubicEdgeEffect() {} |
| 850 |
| 851 static const char* Name() { return "HairCubicEdge"; } |
| 852 |
| 853 virtual void getConstantColorComponents(GrColor* color, |
| 854 uint32_t* validFlags) const SK_OVERR
IDE { |
| 855 *validFlags = 0; |
| 856 } |
| 857 |
| 858 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE { |
| 859 return GrTBackendEffectFactory<HairCubicEdgeEffect>::getInstance(); |
| 860 } |
| 861 |
| 862 class GLEffect : public GrGLEffect { |
| 863 public: |
| 864 GLEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&) |
| 865 : INHERITED (factory) {} |
| 866 |
| 867 virtual void emitCode(GrGLShaderBuilder* builder, |
| 868 const GrDrawEffect& drawEffect, |
| 869 EffectKey key, |
| 870 const char* outputColor, |
| 871 const char* inputColor, |
| 872 const TextureSamplerArray& samplers) SK_OVERRIDE { |
| 873 const char *vsName, *fsName; |
| 874 |
| 875 SkAssertResult(builder->enableFeature( |
| 876 GrGLShaderBuilder::kStandardDerivatives_GLSLFeature)); |
| 877 builder->addVarying(kVec4f_GrSLType, "CubicCoeffs", |
| 878 &vsName, &fsName); |
| 879 const SkString* attr0Name = |
| 880 builder->getEffectAttributeName(drawEffect.getVertexAttribIndice
s()[0]); |
| 881 builder->vsCodeAppendf("\t%s = %s;\n", vsName, attr0Name->c_str()); |
| 882 |
| 883 builder->fsCodeAppend("\t\tfloat edgeAlpha;\n"); |
| 884 |
| 885 builder->fsCodeAppendf("\t\tvec3 dklmdx = dFdx(%s.xyz);\n", fsName); |
| 886 builder->fsCodeAppendf("\t\tvec3 dklmdy = dFdy(%s.xyz);\n", fsName); |
| 887 builder->fsCodeAppendf("\t\tfloat dfdx =\n" |
| 888 "\t\t3.0*%s.x*%s.x*dklmdx.x - %s.y*dklmdx.z -
%s.z*dklmdx.y;\n", |
| 889 fsName, fsName, fsName, fsName); |
| 890 builder->fsCodeAppendf("\t\tfloat dfdy =\n" |
| 891 "\t\t3.0*%s.x*%s.x*dklmdy.x - %s.y*dklmdy.z -
%s.z*dklmdy.y;\n", |
| 892 fsName, fsName, fsName, fsName); |
| 893 builder->fsCodeAppend("\t\tvec2 gF = vec2(dfdx, dfdy);\n"); |
| 894 builder->fsCodeAppend("\t\tfloat gFM = sqrt(dot(gF, gF));\n"); |
| 895 builder->fsCodeAppendf("\t\tfloat func = abs(%s.x*%s.x*%s.x - %s.y*%
s.z);\n", |
| 896 fsName, fsName, fsName, fsName, fsName); |
| 897 builder->fsCodeAppend("\t\tedgeAlpha = func / gFM;\n"); |
| 898 builder->fsCodeAppend("\t\tedgeAlpha = max(1.0 - edgeAlpha, 0.0);\n"
); |
| 899 // Add line below for smooth cubic ramp |
| 900 // builder->fsCodeAppend("\t\tedgeAlpha = edgeAlpha*edgeAlpha*(3.0-2
.0*edgeAlpha);\n"); |
| 901 |
| 902 SkString modulate; |
| 903 GrGLSLModulatef<4>(&modulate, inputColor, "edgeAlpha"); |
| 904 builder->fsCodeAppendf("\t%s = %s;\n", outputColor, modulate.c_str()
); |
| 905 } |
| 906 |
| 907 static inline EffectKey GenKey(const GrDrawEffect& drawEffect, const GrG
LCaps&) { |
| 908 return 0x0; |
| 909 } |
| 910 |
| 911 virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_
OVERRIDE {} |
| 912 |
| 913 private: |
| 914 typedef GrGLEffect INHERITED; |
| 915 }; |
| 916 |
| 917 private: |
| 918 HairCubicEdgeEffect() { |
| 919 this->addVertexAttrib(kVec4f_GrSLType); |
| 920 } |
| 921 |
| 922 virtual bool onIsEqual(const GrEffect& other) const SK_OVERRIDE { |
| 923 return true; |
| 924 } |
| 925 |
| 926 GR_DECLARE_EFFECT_TEST; |
| 927 |
| 928 typedef GrEffect INHERITED; |
| 929 }; |
| 930 /** |
695 * Shader is based off of Loop-Blinn Quadratic GPU Rendering | 931 * Shader is based off of Loop-Blinn Quadratic GPU Rendering |
696 * The output of this effect is a hairline edge for conics. | 932 * The output of this effect is a hairline edge for conics. |
697 * Conics specified by implicit equation K^2 - LM. | 933 * Conics specified by implicit equation K^2 - LM. |
698 * K, L, and M, are the first three values of the vertex attribute, | 934 * K, L, and M, are the first three values of the vertex attribute, |
699 * the fourth value is not used. Distance is calculated using a | 935 * the fourth value is not used. Distance is calculated using a |
700 * first order approximation from the taylor series. | 936 * first order approximation from the taylor series. |
701 * Coverage is max(0, 1-distance). | 937 * Coverage is max(0, 1-distance). |
702 */ | 938 */ |
703 | 939 |
704 /** | 940 /** |
(...skipping 328 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1033 {kVec4f_GrVertexAttribType, sizeof(GrPoint), kEffect_GrVertexAttribBindin
g} | 1269 {kVec4f_GrVertexAttribType, sizeof(GrPoint), kEffect_GrVertexAttribBindin
g} |
1034 }; | 1270 }; |
1035 }; | 1271 }; |
1036 | 1272 |
1037 bool GrAAHairLinePathRenderer::createGeom( | 1273 bool GrAAHairLinePathRenderer::createGeom( |
1038 const SkPath& path, | 1274 const SkPath& path, |
1039 GrDrawTarget* target, | 1275 GrDrawTarget* target, |
1040 int* lineCnt, | 1276 int* lineCnt, |
1041 int* quadCnt, | 1277 int* quadCnt, |
1042 int* conicCnt, | 1278 int* conicCnt, |
| 1279 int* cubicCnt, |
1043 GrDrawTarget::AutoReleaseGeometry* arg, | 1280 GrDrawTarget::AutoReleaseGeometry* arg, |
1044 SkRect* devBounds) { | 1281 SkRect* devBounds) { |
1045 GrDrawState* drawState = target->drawState(); | 1282 GrDrawState* drawState = target->drawState(); |
1046 int rtHeight = drawState->getRenderTarget()->height(); | 1283 int rtHeight = drawState->getRenderTarget()->height(); |
1047 | 1284 |
1048 SkIRect devClipBounds; | 1285 SkIRect devClipBounds; |
1049 target->getClip()->getConservativeBounds(drawState->getRenderTarget(), &devC
lipBounds); | 1286 target->getClip()->getConservativeBounds(drawState->getRenderTarget(), &devC
lipBounds); |
1050 | 1287 |
1051 SkMatrix viewM = drawState->getViewMatrix(); | 1288 SkMatrix viewM = drawState->getViewMatrix(); |
1052 | 1289 |
1053 // All the vertices that we compute are within 1 of path control points with
the exception of | 1290 // All the vertices that we compute are within 1 of path control points with
the exception of |
1054 // one of the bounding vertices for each quad. The add_quads() function will
update the bounds | 1291 // one of the bounding vertices for each quad. The add_quads() function will
update the bounds |
1055 // for each quad added. | 1292 // for each quad added. |
1056 *devBounds = path.getBounds(); | 1293 *devBounds = path.getBounds(); |
1057 viewM.mapRect(devBounds); | 1294 viewM.mapRect(devBounds); |
1058 devBounds->outset(SK_Scalar1, SK_Scalar1); | 1295 devBounds->outset(SK_Scalar1, SK_Scalar1); |
1059 | 1296 |
1060 PREALLOC_PTARRAY(128) lines; | 1297 PREALLOC_PTARRAY(128) lines; |
1061 PREALLOC_PTARRAY(128) quads; | 1298 PREALLOC_PTARRAY(128) quads; |
1062 PREALLOC_PTARRAY(128) conics; | 1299 PREALLOC_PTARRAY(128) conics; |
| 1300 PREALLOC_PTARRAY(128) cubics; |
1063 IntArray qSubdivs; | 1301 IntArray qSubdivs; |
1064 FloatArray cWeights; | 1302 FloatArray cWeights; |
| 1303 FloatArray cubicKLM; |
1065 *quadCnt = generate_lines_and_quads(path, viewM, devClipBounds, | 1304 *quadCnt = generate_lines_and_quads(path, viewM, devClipBounds, |
1066 &lines, &quads, &conics, &qSubdivs, &cWe
ights); | 1305 &lines, &quads, &conics, &cubics, |
| 1306 &qSubdivs, &cWeights, &cubicKLM); |
1067 | 1307 |
1068 *lineCnt = lines.count() / 2; | 1308 *lineCnt = lines.count() / 2; |
1069 *conicCnt = conics.count() / 3; | 1309 *conicCnt = conics.count() / 3; |
| 1310 *cubicCnt = cubics.count() / 4; |
1070 int vertCnt = kVertsPerLineSeg * *lineCnt + kVertsPerQuad * *quadCnt + | 1311 int vertCnt = kVertsPerLineSeg * *lineCnt + kVertsPerQuad * *quadCnt + |
1071 kVertsPerQuad * *conicCnt; | 1312 kVertsPerQuad * *conicCnt + kVertsPerCubic * *cubicCnt; |
1072 | 1313 |
1073 target->drawState()->setVertexAttribs<gHairlineAttribs>(SK_ARRAY_COUNT(gHair
lineAttribs)); | 1314 target->drawState()->setVertexAttribs<gHairlineAttribs>(SK_ARRAY_COUNT(gHair
lineAttribs)); |
1074 GrAssert(sizeof(Vertex) == target->getDrawState().getVertexSize()); | 1315 GrAssert(sizeof(Vertex) == target->getDrawState().getVertexSize()); |
1075 | 1316 |
1076 if (!arg->set(target, vertCnt, 0)) { | 1317 if (!arg->set(target, vertCnt, 0)) { |
1077 return false; | 1318 return false; |
1078 } | 1319 } |
1079 | 1320 |
1080 Vertex* verts = reinterpret_cast<Vertex*>(arg->vertices()); | 1321 Vertex* verts = reinterpret_cast<Vertex*>(arg->vertices()); |
1081 | 1322 |
(...skipping 11 matching lines...) Expand all Loading... |
1093 for (int i = 0; i < *lineCnt; ++i) { | 1334 for (int i = 0; i < *lineCnt; ++i) { |
1094 add_line(&lines[2*i], rtHeight, toSrc, &verts); | 1335 add_line(&lines[2*i], rtHeight, toSrc, &verts); |
1095 } | 1336 } |
1096 | 1337 |
1097 int unsubdivQuadCnt = quads.count() / 3; | 1338 int unsubdivQuadCnt = quads.count() / 3; |
1098 for (int i = 0; i < unsubdivQuadCnt; ++i) { | 1339 for (int i = 0; i < unsubdivQuadCnt; ++i) { |
1099 GrAssert(qSubdivs[i] >= 0); | 1340 GrAssert(qSubdivs[i] >= 0); |
1100 add_quads(&quads[3*i], qSubdivs[i], toDevice, toSrc, &verts, devBounds); | 1341 add_quads(&quads[3*i], qSubdivs[i], toDevice, toSrc, &verts, devBounds); |
1101 } | 1342 } |
1102 | 1343 |
1103 // Start Conics | |
1104 for (int i = 0; i < *conicCnt; ++i) { | 1344 for (int i = 0; i < *conicCnt; ++i) { |
1105 add_conics(&conics[3*i], cWeights[i], toDevice, toSrc, &verts, devBounds
); | 1345 add_conics(&conics[3*i], cWeights[i], toDevice, toSrc, &verts, devBounds
); |
1106 } | 1346 } |
| 1347 |
| 1348 for (int i = 0; i < *cubicCnt; ++i) { |
| 1349 add_cubics(&cubics[4*i], &cubicKLM[9*i], toDevice, toSrc, &verts, devBou
nds); |
| 1350 } |
1107 return true; | 1351 return true; |
1108 } | 1352 } |
1109 | 1353 |
1110 bool GrAAHairLinePathRenderer::canDrawPath(const SkPath& path, | 1354 bool GrAAHairLinePathRenderer::canDrawPath(const SkPath& path, |
1111 const SkStrokeRec& stroke, | 1355 const SkStrokeRec& stroke, |
1112 const GrDrawTarget* target, | 1356 const GrDrawTarget* target, |
1113 bool antiAlias) const { | 1357 bool antiAlias) const { |
1114 if (!stroke.isHairlineStyle() || !antiAlias) { | 1358 if (!stroke.isHairlineStyle() || !antiAlias) { |
1115 return false; | 1359 return false; |
1116 } | 1360 } |
1117 | 1361 |
1118 if (SkPath::kLine_SegmentMask == path.getSegmentMasks() || | 1362 if (SkPath::kLine_SegmentMask == path.getSegmentMasks() || |
1119 target->caps()->shaderDerivativeSupport()) { | 1363 target->caps()->shaderDerivativeSupport()) { |
1120 return true; | 1364 return true; |
1121 } | 1365 } |
1122 return false; | 1366 return false; |
1123 } | 1367 } |
1124 | 1368 |
1125 bool GrAAHairLinePathRenderer::onDrawPath(const SkPath& path, | 1369 bool GrAAHairLinePathRenderer::onDrawPath(const SkPath& path, |
1126 const SkStrokeRec&, | 1370 const SkStrokeRec&, |
1127 GrDrawTarget* target, | 1371 GrDrawTarget* target, |
1128 bool antiAlias) { | 1372 bool antiAlias) { |
1129 | 1373 |
1130 int lineCnt; | 1374 int lineCnt; |
1131 int quadCnt; | 1375 int quadCnt; |
1132 int conicCnt; | 1376 int conicCnt; |
| 1377 int cubicCnt; |
1133 GrDrawTarget::AutoReleaseGeometry arg; | 1378 GrDrawTarget::AutoReleaseGeometry arg; |
1134 SkRect devBounds; | 1379 SkRect devBounds; |
1135 | 1380 |
1136 if (!this->createGeom(path, | 1381 if (!this->createGeom(path, |
1137 target, | 1382 target, |
1138 &lineCnt, | 1383 &lineCnt, |
1139 &quadCnt, | 1384 &quadCnt, |
1140 &conicCnt, | 1385 &conicCnt, |
| 1386 &cubicCnt, |
1141 &arg, | 1387 &arg, |
1142 &devBounds)) { | 1388 &devBounds)) { |
1143 return false; | 1389 return false; |
1144 } | 1390 } |
1145 | 1391 |
1146 GrDrawTarget::AutoStateRestore asr; | 1392 GrDrawTarget::AutoStateRestore asr; |
1147 | 1393 |
1148 // createGeom transforms the geometry to device space when the matrix does n
ot have | 1394 // createGeom transforms the geometry to device space when the matrix does n
ot have |
1149 // perspective. | 1395 // perspective. |
1150 if (target->getDrawState().getViewMatrix().hasPerspective()) { | 1396 if (target->getDrawState().getViewMatrix().hasPerspective()) { |
1151 asr.set(target, GrDrawTarget::kPreserve_ASRInit); | 1397 asr.set(target, GrDrawTarget::kPreserve_ASRInit); |
1152 } else if (!asr.setIdentity(target, GrDrawTarget::kPreserve_ASRInit)) { | 1398 } else if (!asr.setIdentity(target, GrDrawTarget::kPreserve_ASRInit)) { |
1153 return false; | 1399 return false; |
1154 } | 1400 } |
1155 GrDrawState* drawState = target->drawState(); | 1401 GrDrawState* drawState = target->drawState(); |
1156 | 1402 |
1157 // TODO: See whether rendering lines as degenerate quads improves perf | 1403 // TODO: See whether rendering lines as degenerate quads improves perf |
1158 // when we have a mix | 1404 // when we have a mix |
1159 | 1405 |
1160 static const int kEdgeAttrIndex = 1; | 1406 static const int kEdgeAttrIndex = 1; |
1161 | 1407 |
1162 GrEffectRef* hairLineEffect = HairLineEdgeEffect::Create(); | 1408 GrEffectRef* hairLineEffect = HairLineEdgeEffect::Create(); |
1163 GrEffectRef* hairQuadEffect = HairQuadEdgeEffect::Create(); | 1409 GrEffectRef* hairQuadEffect = HairQuadEdgeEffect::Create(); |
1164 GrEffectRef* hairConicEffect = HairConicEdgeEffect::Create(); | 1410 GrEffectRef* hairConicEffect = HairConicEdgeEffect::Create(); |
| 1411 GrEffectRef* hairCubicEffect = HairCubicEdgeEffect::Create(); |
1165 | 1412 |
1166 // Check devBounds | 1413 // Check devBounds |
1167 #if GR_DEBUG | 1414 #if GR_DEBUG |
1168 SkRect tolDevBounds = devBounds; | 1415 SkRect tolDevBounds = devBounds; |
1169 tolDevBounds.outset(SK_Scalar1 / 10000, SK_Scalar1 / 10000); | 1416 tolDevBounds.outset(SK_Scalar1 / 10000, SK_Scalar1 / 10000); |
1170 SkRect actualBounds; | 1417 SkRect actualBounds; |
1171 Vertex* verts = reinterpret_cast<Vertex*>(arg.vertices()); | 1418 Vertex* verts = reinterpret_cast<Vertex*>(arg.vertices()); |
1172 int vCount = kVertsPerLineSeg * lineCnt + kVertsPerQuad * quadCnt + kVertsPe
rQuad * conicCnt; | 1419 int vCount = kVertsPerLineSeg * lineCnt + kVertsPerQuad * quadCnt + kVertsPe
rQuad * conicCnt; |
1173 bool first = true; | 1420 bool first = true; |
1174 for (int i = 0; i < vCount; ++i) { | 1421 for (int i = 0; i < vCount; ++i) { |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1221 kVertsPerQuad*n,
// vCount | 1468 kVertsPerQuad*n,
// vCount |
1222 kIdxsPerQuad*n,
// iCount | 1469 kIdxsPerQuad*n,
// iCount |
1223 &devBounds); | 1470 &devBounds); |
1224 quads += n; | 1471 quads += n; |
1225 } | 1472 } |
1226 } | 1473 } |
1227 | 1474 |
1228 { | 1475 { |
1229 GrDrawState::AutoRestoreEffects are(drawState); | 1476 GrDrawState::AutoRestoreEffects are(drawState); |
1230 int conics = 0; | 1477 int conics = 0; |
1231 drawState->addCoverageEffect(hairConicEffect, 1, 2)->unref(); | 1478 drawState->addCoverageEffect(hairConicEffect, kEdgeAttrIndex)->unref(); |
1232 while (conics < conicCnt) { | 1479 while (conics < conicCnt) { |
1233 int n = GrMin(conicCnt - conics, kNumQuadsInIdxBuffer); | 1480 int n = GrMin(conicCnt - conics, kNumQuadsInIdxBuffer); |
1234 target->drawIndexed(kTriangles_GrPrimitiveType, | 1481 target->drawIndexed(kTriangles_GrPrimitiveType, |
1235 kVertsPerLineSeg*lineCnt + | 1482 kVertsPerLineSeg*lineCnt + |
1236 kVertsPerQuad*(quadCnt + conics), // startV | 1483 kVertsPerQuad*(quadCnt + conics), // startV |
1237 0, // startI | 1484 0, // startI |
1238 kVertsPerQuad*n, // vCount | 1485 kVertsPerQuad*n, // vCount |
1239 kIdxsPerQuad*n, // iCount | 1486 kIdxsPerQuad*n, // iCount |
1240 &devBounds); | 1487 &devBounds); |
1241 conics += n; | 1488 conics += n; |
1242 } | 1489 } |
1243 } | 1490 } |
| 1491 |
| 1492 { |
| 1493 GrDrawState::AutoRestoreEffects are(drawState); |
| 1494 target->setIndexSourceToBuffer(fCubicsIndexBuffer); |
| 1495 int cubics = 0; |
| 1496 drawState->addCoverageEffect(hairCubicEffect, kEdgeAttrIndex)->unref(); |
| 1497 while (cubics < cubicCnt) { |
| 1498 int n = GrMin(cubicCnt - cubics, kNumCubicsInIdxBuffer); |
| 1499 target->drawIndexed(kTriangles_GrPrimitiveType, |
| 1500 kVertsPerLineSeg * lineCnt + |
| 1501 kVertsPerQuad * (quadCnt + conicCnt) + |
| 1502 kVertsPerCubic * cubics,
// startV |
| 1503 0,
// startI |
| 1504 kVertsPerCubic*n,
// vCount |
| 1505 kIdxsPerCubic*n,
// iCount |
| 1506 &devBounds); |
| 1507 cubics += n; |
| 1508 } |
| 1509 } |
1244 target->resetIndexSource(); | 1510 target->resetIndexSource(); |
1245 | 1511 |
1246 return true; | 1512 return true; |
1247 } | 1513 } |
OLD | NEW |