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 kVertsPerLineSeg = 4; | 32 static const int kVertsPerLineSeg = 6; |
33 static const int kIdxsPerLineSeg = 6; | 33 static const int kIdxsPerLineSeg = 12; |
34 | 34 |
35 static const int kNumQuadsInIdxBuffer = 256; | 35 static const int kNumQuadsInIdxBuffer = 256; |
36 static const size_t kQuadIdxSBufize = kIdxsPerQuad * | 36 static const size_t kQuadIdxSBufize = kIdxsPerQuad * |
37 sizeof(uint16_t) * | 37 sizeof(uint16_t) * |
38 kNumQuadsInIdxBuffer; | 38 kNumQuadsInIdxBuffer; |
39 | 39 |
40 bool push_quad_index_data(GrIndexBuffer* qIdxBuffer) { | 40 static const int kNumLineSegsInIdxBuffer = 256; |
| 41 static const size_t kLineSegIdxSBufize = kIdxsPerLineSeg * |
| 42 sizeof(uint16_t) * |
| 43 kNumLineSegsInIdxBuffer; |
| 44 |
| 45 static bool push_quad_index_data(GrIndexBuffer* qIdxBuffer) { |
41 uint16_t* data = (uint16_t*) qIdxBuffer->lock(); | 46 uint16_t* data = (uint16_t*) qIdxBuffer->lock(); |
42 bool tempData = NULL == data; | 47 bool tempData = NULL == data; |
43 if (tempData) { | 48 if (tempData) { |
44 data = SkNEW_ARRAY(uint16_t, kNumQuadsInIdxBuffer * kIdxsPerQuad); | 49 data = SkNEW_ARRAY(uint16_t, kNumQuadsInIdxBuffer * kIdxsPerQuad); |
45 } | 50 } |
46 for (int i = 0; i < kNumQuadsInIdxBuffer; ++i) { | 51 for (int i = 0; i < kNumQuadsInIdxBuffer; ++i) { |
47 | 52 |
48 // Each quadratic is rendered as a five sided polygon. This poly bounds | 53 // 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 | 54 // the quadratic's bounding triangle but has been expanded so that the |
50 // 1-pixel wide area around the curve is inside the poly. | 55 // 1-pixel wide area around the curve is inside the poly. |
(...skipping 20 matching lines...) Expand all Loading... |
71 } | 76 } |
72 if (tempData) { | 77 if (tempData) { |
73 bool ret = qIdxBuffer->updateData(data, kQuadIdxSBufize); | 78 bool ret = qIdxBuffer->updateData(data, kQuadIdxSBufize); |
74 delete[] data; | 79 delete[] data; |
75 return ret; | 80 return ret; |
76 } else { | 81 } else { |
77 qIdxBuffer->unlock(); | 82 qIdxBuffer->unlock(); |
78 return true; | 83 return true; |
79 } | 84 } |
80 } | 85 } |
| 86 |
| 87 static bool push_line_index_data(GrIndexBuffer* lIdxBuffer) { |
| 88 uint16_t* data = (uint16_t*) lIdxBuffer->lock(); |
| 89 bool tempData = NULL == data; |
| 90 if (tempData) { |
| 91 data = SkNEW_ARRAY(uint16_t, kNumLineSegsInIdxBuffer * kIdxsPerLineSeg); |
| 92 } |
| 93 for (int i = 0; i < kNumLineSegsInIdxBuffer; ++i) { |
| 94 // Each line segment is rendered as two quads, with alpha = 1 along the |
| 95 // spine of the segment, and alpha = 0 along the outer edges, represente
d |
| 96 // horizontally (i.e., the line equation is t*(p1-p0) + p0) |
| 97 // |
| 98 // p4 p5 |
| 99 // p0 p1 |
| 100 // p2 p3 |
| 101 // |
| 102 // Each is drawn as four triangles specified by these 12 indices: |
| 103 int baseIdx = i * kIdxsPerLineSeg; |
| 104 uint16_t baseVert = (uint16_t)(i * kVertsPerLineSeg); |
| 105 data[0 + baseIdx] = baseVert + 0; // p0 |
| 106 data[1 + baseIdx] = baseVert + 1; // p1 |
| 107 data[2 + baseIdx] = baseVert + 2; // p2 |
| 108 |
| 109 data[3 + baseIdx] = baseVert + 2; // p2 |
| 110 data[4 + baseIdx] = baseVert + 1; // p1 |
| 111 data[5 + baseIdx] = baseVert + 3; // p3 |
| 112 |
| 113 data[6 + baseIdx] = baseVert + 0; // p0 |
| 114 data[7 + baseIdx] = baseVert + 5; // p5 |
| 115 data[8 + baseIdx] = baseVert + 1; // p1 |
| 116 |
| 117 data[9 + baseIdx] = baseVert + 0; // p0 |
| 118 data[10+ baseIdx] = baseVert + 4; // p4 |
| 119 data[11+ baseIdx] = baseVert + 5; // p5 |
| 120 } |
| 121 if (tempData) { |
| 122 bool ret = lIdxBuffer->updateData(data, kLineSegIdxSBufize); |
| 123 delete[] data; |
| 124 return ret; |
| 125 } else { |
| 126 lIdxBuffer->unlock(); |
| 127 return true; |
| 128 } |
| 129 } |
81 } | 130 } |
82 | 131 |
83 GrPathRenderer* GrAAHairLinePathRenderer::Create(GrContext* context) { | 132 GrPathRenderer* GrAAHairLinePathRenderer::Create(GrContext* context) { |
84 const GrIndexBuffer* lIdxBuffer = context->getQuadIndexBuffer(); | |
85 if (NULL == lIdxBuffer) { | |
86 return NULL; | |
87 } | |
88 GrGpu* gpu = context->getGpu(); | 133 GrGpu* gpu = context->getGpu(); |
89 GrIndexBuffer* qIdxBuf = gpu->createIndexBuffer(kQuadIdxSBufize, false); | 134 GrIndexBuffer* qIdxBuf = gpu->createIndexBuffer(kQuadIdxSBufize, false); |
90 SkAutoTUnref<GrIndexBuffer> qIdxBuffer(qIdxBuf); | 135 SkAutoTUnref<GrIndexBuffer> qIdxBuffer(qIdxBuf); |
91 if (NULL == qIdxBuf || | 136 if (NULL == qIdxBuf || !push_quad_index_data(qIdxBuf)) { |
92 !push_quad_index_data(qIdxBuf)) { | 137 return NULL; |
| 138 } |
| 139 GrIndexBuffer* lIdxBuf = gpu->createIndexBuffer(kLineSegIdxSBufize, false); |
| 140 SkAutoTUnref<GrIndexBuffer> lIdxBuffer(lIdxBuf); |
| 141 if (NULL == lIdxBuf || !push_line_index_data(lIdxBuf)) { |
93 return NULL; | 142 return NULL; |
94 } | 143 } |
95 return SkNEW_ARGS(GrAAHairLinePathRenderer, | 144 return SkNEW_ARGS(GrAAHairLinePathRenderer, |
96 (context, lIdxBuffer, qIdxBuf)); | 145 (context, lIdxBuf, qIdxBuf)); |
97 } | 146 } |
98 | 147 |
99 GrAAHairLinePathRenderer::GrAAHairLinePathRenderer( | 148 GrAAHairLinePathRenderer::GrAAHairLinePathRenderer( |
100 const GrContext* context, | 149 const GrContext* context, |
101 const GrIndexBuffer* linesIndexBuffer, | 150 const GrIndexBuffer* linesIndexBuffer, |
102 const GrIndexBuffer* quadsIndexBuffer) { | 151 const GrIndexBuffer* quadsIndexBuffer) { |
103 fLinesIndexBuffer = linesIndexBuffer; | 152 fLinesIndexBuffer = linesIndexBuffer; |
104 linesIndexBuffer->ref(); | 153 linesIndexBuffer->ref(); |
105 fQuadsIndexBuffer = quadsIndexBuffer; | 154 fQuadsIndexBuffer = quadsIndexBuffer; |
106 quadsIndexBuffer->ref(); | 155 quadsIndexBuffer->ref(); |
107 } | 156 } |
108 | 157 |
109 GrAAHairLinePathRenderer::~GrAAHairLinePathRenderer() { | 158 GrAAHairLinePathRenderer::~GrAAHairLinePathRenderer() { |
110 fLinesIndexBuffer->unref(); | 159 fLinesIndexBuffer->unref(); |
111 fQuadsIndexBuffer->unref(); | 160 fQuadsIndexBuffer->unref(); |
112 } | 161 } |
113 | 162 |
114 namespace { | 163 namespace { |
115 | 164 |
116 typedef SkTArray<SkPoint, true> PtArray; | |
117 #define PREALLOC_PTARRAY(N) SkSTArray<(N),SkPoint, true> | 165 #define PREALLOC_PTARRAY(N) SkSTArray<(N),SkPoint, true> |
118 typedef SkTArray<int, true> IntArray; | |
119 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 |
122 int get_float_exp(float x) { | 168 int get_float_exp(float x) { |
123 GR_STATIC_ASSERT(sizeof(int) == sizeof(float)); | 169 GR_STATIC_ASSERT(sizeof(int) == sizeof(float)); |
124 #if GR_DEBUG | 170 #if GR_DEBUG |
125 static bool tested; | 171 static bool tested; |
126 if (!tested) { | 172 if (!tested) { |
127 tested = true; | 173 tested = true; |
128 GrAssert(get_float_exp(0.25f) == -2); | 174 GrAssert(get_float_exp(0.25f) == -2); |
129 GrAssert(get_float_exp(0.3f) == -2); | 175 GrAssert(get_float_exp(0.3f) == -2); |
(...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
259 * device space. We will do a device space bloat to account for the 1pixel | 305 * device space. We will do a device space bloat to account for the 1pixel |
260 * thickness. | 306 * thickness. |
261 * Quads are recorded in device space unless m contains | 307 * Quads are recorded in device space unless m contains |
262 * perspective, then in they are in src space. We do this because we will | 308 * 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 | 309 * subdivide large quads to reduce over-fill. This subdivision has to be |
264 * performed before applying the perspective matrix. | 310 * performed before applying the perspective matrix. |
265 */ | 311 */ |
266 int generate_lines_and_quads(const SkPath& path, | 312 int generate_lines_and_quads(const SkPath& path, |
267 const SkMatrix& m, | 313 const SkMatrix& m, |
268 const SkIRect& devClipBounds, | 314 const SkIRect& devClipBounds, |
269 PtArray* lines, | 315 GrAAHairLinePathRenderer::PtArray* lines, |
270 PtArray* quads, | 316 GrAAHairLinePathRenderer::PtArray* quads, |
271 PtArray* conics, | 317 GrAAHairLinePathRenderer::PtArray* conics, |
272 IntArray* quadSubdivCnts, | 318 GrAAHairLinePathRenderer::IntArray* quadSubdivCnts, |
273 FloatArray* conicWeights) { | 319 GrAAHairLinePathRenderer::FloatArray* conicWeights)
{ |
274 SkPath::Iter iter(path, false); | 320 SkPath::Iter iter(path, false); |
275 | 321 |
276 int totalQuadCount = 0; | 322 int totalQuadCount = 0; |
277 SkRect bounds; | 323 SkRect bounds; |
278 SkIRect ibounds; | 324 SkIRect ibounds; |
279 | 325 |
280 bool persp = m.hasPerspective(); | 326 bool persp = m.hasPerspective(); |
281 | 327 |
282 for (;;) { | 328 for (;;) { |
283 GrPoint pathPts[4]; | 329 GrPoint pathPts[4]; |
(...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
425 } | 471 } |
426 break; | 472 break; |
427 case SkPath::kClose_Verb: | 473 case SkPath::kClose_Verb: |
428 break; | 474 break; |
429 case SkPath::kDone_Verb: | 475 case SkPath::kDone_Verb: |
430 return totalQuadCount; | 476 return totalQuadCount; |
431 } | 477 } |
432 } | 478 } |
433 } | 479 } |
434 | 480 |
435 struct Vertex { | 481 struct LineVertex { |
| 482 GrPoint fPos; |
| 483 GrColor fCoverage; |
| 484 }; |
| 485 |
| 486 struct BezierVertex { |
436 GrPoint fPos; | 487 GrPoint fPos; |
437 union { | 488 union { |
438 struct { | 489 struct { |
439 SkScalar fA; | |
440 SkScalar fB; | |
441 SkScalar fC; | |
442 } fLine; | |
443 struct { | |
444 SkScalar fK; | 490 SkScalar fK; |
445 SkScalar fL; | 491 SkScalar fL; |
446 SkScalar fM; | 492 SkScalar fM; |
447 } fConic; | 493 } fConic; |
448 GrVec fQuadCoord; | 494 GrVec fQuadCoord; |
449 struct { | 495 struct { |
450 SkScalar fBogus[4]; | 496 SkScalar fBogus[4]; |
451 }; | 497 }; |
452 }; | 498 }; |
453 }; | 499 }; |
454 | 500 |
455 GR_STATIC_ASSERT(sizeof(Vertex) == 3 * sizeof(GrPoint)); | 501 GR_STATIC_ASSERT(sizeof(BezierVertex) == 3 * sizeof(GrPoint)); |
456 | 502 |
457 void intersect_lines(const SkPoint& ptA, const SkVector& normA, | 503 void intersect_lines(const SkPoint& ptA, const SkVector& normA, |
458 const SkPoint& ptB, const SkVector& normB, | 504 const SkPoint& ptB, const SkVector& normB, |
459 SkPoint* result) { | 505 SkPoint* result) { |
460 | 506 |
461 SkScalar lineAW = -normA.dot(ptA); | 507 SkScalar lineAW = -normA.dot(ptA); |
462 SkScalar lineBW = -normB.dot(ptB); | 508 SkScalar lineBW = -normB.dot(ptB); |
463 | 509 |
464 SkScalar wInv = SkScalarMul(normA.fX, normB.fY) - | 510 SkScalar wInv = SkScalarMul(normA.fX, normB.fY) - |
465 SkScalarMul(normA.fY, normB.fX); | 511 SkScalarMul(normA.fY, normB.fX); |
466 wInv = SkScalarInvert(wInv); | 512 wInv = SkScalarInvert(wInv); |
467 | 513 |
468 result->fX = SkScalarMul(normA.fY, lineBW) - SkScalarMul(lineAW, normB.fY); | 514 result->fX = SkScalarMul(normA.fY, lineBW) - SkScalarMul(lineAW, normB.fY); |
469 result->fX = SkScalarMul(result->fX, wInv); | 515 result->fX = SkScalarMul(result->fX, wInv); |
470 | 516 |
471 result->fY = SkScalarMul(lineAW, normB.fX) - SkScalarMul(normA.fX, lineBW); | 517 result->fY = SkScalarMul(lineAW, normB.fX) - SkScalarMul(normA.fX, lineBW); |
472 result->fY = SkScalarMul(result->fY, wInv); | 518 result->fY = SkScalarMul(result->fY, wInv); |
473 } | 519 } |
474 | 520 |
475 void set_uv_quad(const SkPoint qpts[3], Vertex verts[kVertsPerQuad]) { | 521 void set_uv_quad(const SkPoint qpts[3], BezierVertex verts[kVertsPerQuad]) { |
476 // this should be in the src space, not dev coords, when we have perspective | 522 // this should be in the src space, not dev coords, when we have perspective |
477 GrPathUtils::QuadUVMatrix DevToUV(qpts); | 523 GrPathUtils::QuadUVMatrix DevToUV(qpts); |
478 DevToUV.apply<kVertsPerQuad, sizeof(Vertex), sizeof(GrPoint)>(verts); | 524 DevToUV.apply<kVertsPerQuad, sizeof(BezierVertex), sizeof(GrPoint)>(verts); |
479 } | 525 } |
480 | 526 |
481 void bloat_quad(const SkPoint qpts[3], const SkMatrix* toDevice, | 527 void bloat_quad(const SkPoint qpts[3], const SkMatrix* toDevice, |
482 const SkMatrix* toSrc, Vertex verts[kVertsPerQuad], | 528 const SkMatrix* toSrc, BezierVertex verts[kVertsPerQuad], |
483 SkRect* devBounds) { | 529 SkRect* devBounds) { |
484 GrAssert(!toDevice == !toSrc); | 530 GrAssert(!toDevice == !toSrc); |
485 // original quad is specified by tri a,b,c | 531 // original quad is specified by tri a,b,c |
486 SkPoint a = qpts[0]; | 532 SkPoint a = qpts[0]; |
487 SkPoint b = qpts[1]; | 533 SkPoint b = qpts[1]; |
488 SkPoint c = qpts[2]; | 534 SkPoint c = qpts[2]; |
489 | 535 |
490 if (toDevice) { | 536 if (toDevice) { |
491 toDevice->mapPoints(&a, 1); | 537 toDevice->mapPoints(&a, 1); |
492 toDevice->mapPoints(&b, 1); | 538 toDevice->mapPoints(&b, 1); |
493 toDevice->mapPoints(&c, 1); | 539 toDevice->mapPoints(&c, 1); |
494 } | 540 } |
495 // make a new poly where we replace a and c by a 1-pixel wide edges orthog | 541 // make a new poly where we replace a and c by a 1-pixel wide edges orthog |
496 // to edges ab and bc: | 542 // to edges ab and bc: |
497 // | 543 // |
498 // before | after | 544 // before | after |
499 // | b0 | 545 // | b0 |
500 // b | | 546 // b | |
501 // | | 547 // | |
502 // | a0 c0 | 548 // | a0 c0 |
503 // a c | a1 c1 | 549 // a c | a1 c1 |
504 // | 550 // |
505 // edges a0->b0 and b0->c0 are parallel to original edges a->b and b->c, | 551 // edges a0->b0 and b0->c0 are parallel to original edges a->b and b->c, |
506 // respectively. | 552 // respectively. |
507 Vertex& a0 = verts[0]; | 553 BezierVertex& a0 = verts[0]; |
508 Vertex& a1 = verts[1]; | 554 BezierVertex& a1 = verts[1]; |
509 Vertex& b0 = verts[2]; | 555 BezierVertex& b0 = verts[2]; |
510 Vertex& c0 = verts[3]; | 556 BezierVertex& c0 = verts[3]; |
511 Vertex& c1 = verts[4]; | 557 BezierVertex& c1 = verts[4]; |
512 | 558 |
513 SkVector ab = b; | 559 SkVector ab = b; |
514 ab -= a; | 560 ab -= a; |
515 SkVector ac = c; | 561 SkVector ac = c; |
516 ac -= a; | 562 ac -= a; |
517 SkVector cb = b; | 563 SkVector cb = b; |
518 cb -= c; | 564 cb -= c; |
519 | 565 |
520 // We should have already handled degenerates | 566 // We should have already handled degenerates |
521 GrAssert(ab.length() > 0 && cb.length() > 0); | 567 GrAssert(ab.length() > 0 && cb.length() > 0); |
(...skipping 21 matching lines...) Expand all Loading... |
543 c0.fPos += cbN; | 589 c0.fPos += cbN; |
544 c1.fPos = c; | 590 c1.fPos = c; |
545 c1.fPos -= cbN; | 591 c1.fPos -= cbN; |
546 | 592 |
547 // This point may not be within 1 pixel of a control point. We update the bo
unding box to | 593 // This point may not be within 1 pixel of a control point. We update the bo
unding box to |
548 // include it. | 594 // include it. |
549 intersect_lines(a0.fPos, abN, c0.fPos, cbN, &b0.fPos); | 595 intersect_lines(a0.fPos, abN, c0.fPos, cbN, &b0.fPos); |
550 devBounds->growToInclude(b0.fPos.fX, b0.fPos.fY); | 596 devBounds->growToInclude(b0.fPos.fX, b0.fPos.fY); |
551 | 597 |
552 if (toSrc) { | 598 if (toSrc) { |
553 toSrc->mapPointsWithStride(&verts[0].fPos, sizeof(Vertex), kVertsPerQuad
); | 599 toSrc->mapPointsWithStride(&verts[0].fPos, sizeof(BezierVertex), kVertsP
erQuad); |
554 } | 600 } |
555 } | 601 } |
556 | 602 |
557 // Input: | 603 // Input: |
558 // Three control points: p[0], p[1], p[2] and weight: w | 604 // Three control points: p[0], p[1], p[2] and weight: w |
559 // Output: | 605 // Output: |
560 // Let: | 606 // Let: |
561 // l = (2*w * (y1 - y0), 2*w * (x0 - x1), 2*w * (x1*y0 - x0*y1)) | 607 // l = (2*w * (y1 - y0), 2*w * (x0 - x1), 2*w * (x1*y0 - x0*y1)) |
562 // m = (2*w * (y2 - y1), 2*w * (x1 - x2), 2*w * (x2*y1 - x1*y2)) | 608 // m = (2*w * (y2 - y1), 2*w * (x1 - x2), 2*w * (x2*y1 - x1*y2)) |
563 // k = (y2 - y0, x0 - x2, (x2 - x0)*y0 - (y2 - y0)*x0 ) | 609 // k = (y2 - y0, x0 - x2, (x2 - x0)*y0 - (y2 - y0)*x0 ) |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
596 m[2] /= scale; | 642 m[2] /= scale; |
597 } | 643 } |
598 | 644 |
599 // Equations based off of Loop-Blinn Quadratic GPU Rendering | 645 // Equations based off of Loop-Blinn Quadratic GPU Rendering |
600 // Input Parametric: | 646 // 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) | 647 // 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: | 648 // Output Implicit: |
603 // f(x, y, w) = f(P) = K^2 - LM | 649 // f(x, y, w) = f(P) = K^2 - LM |
604 // K = dot(k, P), L = dot(l, P), M = dot(m, P) | 650 // K = dot(k, P), L = dot(l, P), M = dot(m, P) |
605 // k, l, m are calculated in function calc_conic_klm | 651 // 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) { | 652 void set_conic_coeffs(const SkPoint p[3], BezierVertex verts[kVertsPerQuad], con
st float weight) { |
607 SkScalar k[3]; | 653 SkScalar k[3]; |
608 SkScalar l[3]; | 654 SkScalar l[3]; |
609 SkScalar m[3]; | 655 SkScalar m[3]; |
610 | 656 |
611 calc_conic_klm(p, weight, k, l, m); | 657 calc_conic_klm(p, weight, k, l, m); |
612 | 658 |
613 for (int i = 0; i < kVertsPerQuad; ++i) { | 659 for (int i = 0; i < kVertsPerQuad; ++i) { |
614 const SkPoint pnt = verts[i].fPos; | 660 const SkPoint pnt = verts[i].fPos; |
615 verts[i].fConic.fK = pnt.fX * k[0] + pnt.fY * k[1] + k[2]; | 661 verts[i].fConic.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]; | 662 verts[i].fConic.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]; | 663 verts[i].fConic.fM = pnt.fX * m[0] + pnt.fY * m[1] + m[2]; |
618 } | 664 } |
619 } | 665 } |
620 | 666 |
621 void add_conics(const SkPoint p[3], | 667 void add_conics(const SkPoint p[3], |
622 float weight, | 668 float weight, |
623 const SkMatrix* toDevice, | 669 const SkMatrix* toDevice, |
624 const SkMatrix* toSrc, | 670 const SkMatrix* toSrc, |
625 Vertex** vert, | 671 BezierVertex** vert, |
626 SkRect* devBounds) { | 672 SkRect* devBounds) { |
627 bloat_quad(p, toDevice, toSrc, *vert, devBounds); | 673 bloat_quad(p, toDevice, toSrc, *vert, devBounds); |
628 set_conic_coeffs(p, *vert, weight); | 674 set_conic_coeffs(p, *vert, weight); |
629 *vert += kVertsPerQuad; | 675 *vert += kVertsPerQuad; |
630 } | 676 } |
631 | 677 |
632 void add_quads(const SkPoint p[3], | 678 void add_quads(const SkPoint p[3], |
633 int subdiv, | 679 int subdiv, |
634 const SkMatrix* toDevice, | 680 const SkMatrix* toDevice, |
635 const SkMatrix* toSrc, | 681 const SkMatrix* toSrc, |
636 Vertex** vert, | 682 BezierVertex** vert, |
637 SkRect* devBounds) { | 683 SkRect* devBounds) { |
638 GrAssert(subdiv >= 0); | 684 GrAssert(subdiv >= 0); |
639 if (subdiv) { | 685 if (subdiv) { |
640 SkPoint newP[5]; | 686 SkPoint newP[5]; |
641 SkChopQuadAtHalf(p, newP); | 687 SkChopQuadAtHalf(p, newP); |
642 add_quads(newP + 0, subdiv-1, toDevice, toSrc, vert, devBounds); | 688 add_quads(newP + 0, subdiv-1, toDevice, toSrc, vert, devBounds); |
643 add_quads(newP + 2, subdiv-1, toDevice, toSrc, vert, devBounds); | 689 add_quads(newP + 2, subdiv-1, toDevice, toSrc, vert, devBounds); |
644 } else { | 690 } else { |
645 bloat_quad(p, toDevice, toSrc, *vert, devBounds); | 691 bloat_quad(p, toDevice, toSrc, *vert, devBounds); |
646 set_uv_quad(p, *vert); | 692 set_uv_quad(p, *vert); |
647 *vert += kVertsPerQuad; | 693 *vert += kVertsPerQuad; |
648 } | 694 } |
649 } | 695 } |
650 | 696 |
651 void add_line(const SkPoint p[2], | 697 void add_line(const SkPoint p[2], |
652 int rtHeight, | 698 int rtHeight, |
653 const SkMatrix* toSrc, | 699 const SkMatrix* toSrc, |
654 Vertex** vert) { | 700 GrColor coverage, |
| 701 LineVertex** vert) { |
655 const SkPoint& a = p[0]; | 702 const SkPoint& a = p[0]; |
656 const SkPoint& b = p[1]; | 703 const SkPoint& b = p[1]; |
657 | 704 |
658 SkVector orthVec = b; | 705 SkVector orthVec = b; |
659 orthVec -= a; | 706 orthVec -= a; |
660 | 707 |
661 if (orthVec.setLength(SK_Scalar1)) { | 708 if (orthVec.setLength(SK_Scalar1)) { |
662 orthVec.setOrthog(orthVec); | 709 orthVec.setOrthog(orthVec); |
663 | 710 |
664 SkScalar lineC = -(a.dot(orthVec)); | |
665 for (int i = 0; i < kVertsPerLineSeg; ++i) { | 711 for (int i = 0; i < kVertsPerLineSeg; ++i) { |
666 (*vert)[i].fPos = (i < 2) ? a : b; | 712 (*vert)[i].fPos = (i & 0x1) ? b : a; |
667 if (0 == i || 3 == i) { | 713 if (i & 0x2) { |
| 714 (*vert)[i].fPos += orthVec; |
| 715 (*vert)[i].fCoverage = 0; |
| 716 } else if (i & 0x4) { |
668 (*vert)[i].fPos -= orthVec; | 717 (*vert)[i].fPos -= orthVec; |
| 718 (*vert)[i].fCoverage = 0; |
669 } else { | 719 } else { |
670 (*vert)[i].fPos += orthVec; | 720 (*vert)[i].fCoverage = coverage; |
671 } | 721 } |
672 (*vert)[i].fLine.fA = orthVec.fX; | |
673 (*vert)[i].fLine.fB = orthVec.fY; | |
674 (*vert)[i].fLine.fC = lineC; | |
675 } | 722 } |
676 if (NULL != toSrc) { | 723 if (NULL != toSrc) { |
677 toSrc->mapPointsWithStride(&(*vert)->fPos, | 724 toSrc->mapPointsWithStride(&(*vert)->fPos, |
678 sizeof(Vertex), | 725 sizeof(LineVertex), |
679 kVertsPerLineSeg); | 726 kVertsPerLineSeg); |
680 } | 727 } |
681 } else { | 728 } else { |
682 // just make it degenerate and likely offscreen | 729 // just make it degenerate and likely offscreen |
683 (*vert)[0].fPos.set(SK_ScalarMax, SK_ScalarMax); | 730 for (int i = 0; i < kVertsPerLineSeg; ++i) { |
684 (*vert)[1].fPos.set(SK_ScalarMax, SK_ScalarMax); | 731 (*vert)[i].fPos.set(SK_ScalarMax, SK_ScalarMax); |
685 (*vert)[2].fPos.set(SK_ScalarMax, SK_ScalarMax); | 732 } |
686 (*vert)[3].fPos.set(SK_ScalarMax, SK_ScalarMax); | |
687 } | 733 } |
688 | 734 |
689 *vert += kVertsPerLineSeg; | 735 *vert += kVertsPerLineSeg; |
690 } | 736 } |
691 | 737 |
692 } | 738 } |
693 | 739 |
694 /** | 740 /** |
695 * Shader is based off of Loop-Blinn Quadratic GPU Rendering | 741 * Shader is based off of Loop-Blinn Quadratic GPU Rendering |
696 * The output of this effect is a hairline edge for conics. | 742 * The output of this effect is a hairline edge for conics. |
(...skipping 230 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
927 GrEffectRef* HairQuadEdgeEffect::TestCreate(SkMWCRandom* random, | 973 GrEffectRef* HairQuadEdgeEffect::TestCreate(SkMWCRandom* random, |
928 GrContext*, | 974 GrContext*, |
929 const GrDrawTargetCaps& caps, | 975 const GrDrawTargetCaps& caps, |
930 GrTexture*[]) { | 976 GrTexture*[]) { |
931 // Doesn't work without derivative instructions. | 977 // Doesn't work without derivative instructions. |
932 return caps.shaderDerivativeSupport() ? HairQuadEdgeEffect::Create() : NULL; | 978 return caps.shaderDerivativeSupport() ? HairQuadEdgeEffect::Create() : NULL; |
933 } | 979 } |
934 | 980 |
935 /////////////////////////////////////////////////////////////////////////////// | 981 /////////////////////////////////////////////////////////////////////////////// |
936 | 982 |
937 /** | |
938 * The output of this effect is a 1-pixel wide line. | |
939 * Input is 2D implicit device coord line eq (a*x + b*y +c = 0). 4th component u
nused. | |
940 */ | |
941 class HairLineEdgeEffect : public GrEffect { | |
942 public: | |
943 | |
944 static GrEffectRef* Create() { | |
945 GR_CREATE_STATIC_EFFECT(gHairLineEdge, HairLineEdgeEffect, ()); | |
946 gHairLineEdge->ref(); | |
947 return gHairLineEdge; | |
948 } | |
949 | |
950 virtual ~HairLineEdgeEffect() {} | |
951 | |
952 static const char* Name() { return "HairLineEdge"; } | |
953 | |
954 virtual void getConstantColorComponents(GrColor* color, | |
955 uint32_t* validFlags) const SK_OVERR
IDE { | |
956 *validFlags = 0; | |
957 } | |
958 | |
959 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE { | |
960 return GrTBackendEffectFactory<HairLineEdgeEffect>::getInstance(); | |
961 } | |
962 | |
963 class GLEffect : public GrGLEffect { | |
964 public: | |
965 GLEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&) | |
966 : INHERITED (factory) {} | |
967 | |
968 virtual void emitCode(GrGLShaderBuilder* builder, | |
969 const GrDrawEffect& drawEffect, | |
970 EffectKey key, | |
971 const char* outputColor, | |
972 const char* inputColor, | |
973 const TextureSamplerArray& samplers) SK_OVERRIDE { | |
974 const char *vsName, *fsName; | |
975 const SkString* attrName = | |
976 builder->getEffectAttributeName(drawEffect.getVertexAttribIndice
s()[0]); | |
977 builder->fsCodeAppendf("\t\tfloat edgeAlpha;\n"); | |
978 | |
979 builder->addVarying(kVec4f_GrSLType, "HairLineEdge", &vsName, &fsNam
e); | |
980 | |
981 builder->fsCodeAppendf("\t\tedgeAlpha = abs(dot(vec3(%s.xy,1), %s.xy
z));\n", | |
982 builder->fragmentPosition(), fsName); | |
983 builder->fsCodeAppendf("\t\tedgeAlpha = max(1.0 - edgeAlpha, 0.0);\n
"); | |
984 | |
985 SkString modulate; | |
986 GrGLSLModulatef<4>(&modulate, inputColor, "edgeAlpha"); | |
987 builder->fsCodeAppendf("\t%s = %s;\n", outputColor, modulate.c_str()
); | |
988 | |
989 builder->vsCodeAppendf("\t%s = %s;\n", vsName, attrName->c_str()); | |
990 } | |
991 | |
992 static inline EffectKey GenKey(const GrDrawEffect& drawEffect, const GrG
LCaps&) { | |
993 return 0x0; | |
994 } | |
995 | |
996 virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_
OVERRIDE {} | |
997 | |
998 private: | |
999 typedef GrGLEffect INHERITED; | |
1000 }; | |
1001 | |
1002 private: | |
1003 HairLineEdgeEffect() { | |
1004 this->addVertexAttrib(kVec4f_GrSLType); | |
1005 this->setWillReadFragmentPosition(); | |
1006 } | |
1007 | |
1008 virtual bool onIsEqual(const GrEffect& other) const SK_OVERRIDE { | |
1009 return true; | |
1010 } | |
1011 | |
1012 GR_DECLARE_EFFECT_TEST; | |
1013 | |
1014 typedef GrEffect INHERITED; | |
1015 }; | |
1016 | |
1017 GR_DEFINE_EFFECT_TEST(HairLineEdgeEffect); | |
1018 | |
1019 GrEffectRef* HairLineEdgeEffect::TestCreate(SkMWCRandom* random, | |
1020 GrContext*, | |
1021 const GrDrawTargetCaps& caps, | |
1022 GrTexture*[]) { | |
1023 return HairLineEdgeEffect::Create(); | |
1024 } | |
1025 | |
1026 /////////////////////////////////////////////////////////////////////////////// | |
1027 | |
1028 namespace { | 983 namespace { |
1029 | 984 |
1030 // position + edge | 985 // position + edge |
1031 extern const GrVertexAttrib gHairlineAttribs[] = { | 986 extern const GrVertexAttrib gHairlineBezierAttribs[] = { |
1032 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBind
ing}, | 987 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBind
ing}, |
1033 {kVec4f_GrVertexAttribType, sizeof(GrPoint), kEffect_GrVertexAttribBindin
g} | 988 {kVec4f_GrVertexAttribType, sizeof(GrPoint), kEffect_GrVertexAttribBindin
g} |
1034 }; | 989 }; |
| 990 |
| 991 // position + coverage |
| 992 extern const GrVertexAttrib gHairlineLineAttribs[] = { |
| 993 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBindin
g}, |
| 994 {kVec4ub_GrVertexAttribType, sizeof(GrPoint), kCoverage_GrVertexAttribBindin
g}, |
1035 }; | 995 }; |
1036 | 996 |
1037 bool GrAAHairLinePathRenderer::createGeom( | 997 }; |
| 998 |
| 999 bool GrAAHairLinePathRenderer::createLineGeom( |
1038 const SkPath& path, | 1000 const SkPath& path, |
1039 GrDrawTarget* target, | 1001 GrDrawTarget* target, |
1040 int* lineCnt, | 1002 const PtArray& lines, |
1041 int* quadCnt, | 1003 int lineCnt, |
1042 int* conicCnt, | |
1043 GrDrawTarget::AutoReleaseGeometry* arg, | 1004 GrDrawTarget::AutoReleaseGeometry* arg, |
1044 SkRect* devBounds) { | 1005 SkRect* devBounds) { |
1045 GrDrawState* drawState = target->drawState(); | 1006 GrDrawState* drawState = target->drawState(); |
1046 int rtHeight = drawState->getRenderTarget()->height(); | 1007 int rtHeight = drawState->getRenderTarget()->height(); |
1047 | 1008 |
1048 SkIRect devClipBounds; | 1009 const SkMatrix& viewM = drawState->getViewMatrix(); |
1049 target->getClip()->getConservativeBounds(drawState->getRenderTarget(), &devC
lipBounds); | |
1050 | 1010 |
1051 SkMatrix viewM = drawState->getViewMatrix(); | 1011 *devBounds = path.getBounds(); |
| 1012 viewM.mapRect(devBounds); |
| 1013 devBounds->outset(SK_Scalar1, SK_Scalar1); |
1052 | 1014 |
| 1015 int vertCnt = kVertsPerLineSeg * lineCnt; |
| 1016 |
| 1017 target->drawState()->setVertexAttribs<gHairlineLineAttribs>(SK_ARRAY_COUNT(g
HairlineLineAttribs)); |
| 1018 GrAssert(sizeof(LineVertex) == target->getDrawState().getVertexSize()); |
| 1019 |
| 1020 if (!arg->set(target, vertCnt, 0)) { |
| 1021 return false; |
| 1022 } |
| 1023 |
| 1024 LineVertex* verts = reinterpret_cast<LineVertex*>(arg->vertices()); |
| 1025 |
| 1026 const SkMatrix* toSrc = NULL; |
| 1027 SkMatrix ivm; |
| 1028 |
| 1029 if (viewM.hasPerspective()) { |
| 1030 if (viewM.invert(&ivm)) { |
| 1031 toSrc = &ivm; |
| 1032 } |
| 1033 } |
| 1034 |
| 1035 for (int i = 0; i < lineCnt; ++i) { |
| 1036 add_line(&lines[2*i], rtHeight, toSrc, drawState->getCoverage(), &verts)
; |
| 1037 } |
| 1038 |
| 1039 return true; |
| 1040 } |
| 1041 |
| 1042 bool GrAAHairLinePathRenderer::createBezierGeom( |
| 1043 const SkPath& path, |
| 1044 GrDrawTarget* target, |
| 1045 const PtArray& quads, |
| 1046 int quadCnt, |
| 1047 const PtArray& conics, |
| 1048 int conicCnt, |
| 1049 const IntArray& qSubdivs, |
| 1050 const FloatArray& cWeights, |
| 1051 GrDrawTarget::AutoReleaseGeometry* arg
, |
| 1052 SkRect* devBounds) { |
| 1053 GrDrawState* drawState = target->drawState(); |
| 1054 |
| 1055 const SkMatrix& viewM = drawState->getViewMatrix(); |
| 1056 |
1053 // All the vertices that we compute are within 1 of path control points with
the exception of | 1057 // 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 | 1058 // one of the bounding vertices for each quad. The add_quads() function will
update the bounds |
1055 // for each quad added. | 1059 // for each quad added. |
1056 *devBounds = path.getBounds(); | 1060 *devBounds = path.getBounds(); |
1057 viewM.mapRect(devBounds); | 1061 viewM.mapRect(devBounds); |
1058 devBounds->outset(SK_Scalar1, SK_Scalar1); | 1062 devBounds->outset(SK_Scalar1, SK_Scalar1); |
1059 | 1063 |
1060 PREALLOC_PTARRAY(128) lines; | 1064 int vertCnt = kVertsPerQuad * quadCnt + kVertsPerQuad * conicCnt; |
1061 PREALLOC_PTARRAY(128) quads; | 1065 |
1062 PREALLOC_PTARRAY(128) conics; | 1066 target->drawState()->setVertexAttribs<gHairlineBezierAttribs>(SK_ARRAY_COUNT
(gHairlineBezierAttribs)); |
1063 IntArray qSubdivs; | 1067 GrAssert(sizeof(BezierVertex) == target->getDrawState().getVertexSize()); |
1064 FloatArray cWeights; | 1068 |
1065 *quadCnt = generate_lines_and_quads(path, viewM, devClipBounds, | |
1066 &lines, &quads, &conics, &qSubdivs, &cWe
ights); | |
1067 | |
1068 *lineCnt = lines.count() / 2; | |
1069 *conicCnt = conics.count() / 3; | |
1070 int vertCnt = kVertsPerLineSeg * *lineCnt + kVertsPerQuad * *quadCnt + | |
1071 kVertsPerQuad * *conicCnt; | |
1072 | |
1073 target->drawState()->setVertexAttribs<gHairlineAttribs>(SK_ARRAY_COUNT(gHair
lineAttribs)); | |
1074 GrAssert(sizeof(Vertex) == target->getDrawState().getVertexSize()); | |
1075 | |
1076 if (!arg->set(target, vertCnt, 0)) { | 1069 if (!arg->set(target, vertCnt, 0)) { |
1077 return false; | 1070 return false; |
1078 } | 1071 } |
1079 | 1072 |
1080 Vertex* verts = reinterpret_cast<Vertex*>(arg->vertices()); | 1073 BezierVertex* verts = reinterpret_cast<BezierVertex*>(arg->vertices()); |
1081 | 1074 |
1082 const SkMatrix* toDevice = NULL; | 1075 const SkMatrix* toDevice = NULL; |
1083 const SkMatrix* toSrc = NULL; | 1076 const SkMatrix* toSrc = NULL; |
1084 SkMatrix ivm; | 1077 SkMatrix ivm; |
1085 | 1078 |
1086 if (viewM.hasPerspective()) { | 1079 if (viewM.hasPerspective()) { |
1087 if (viewM.invert(&ivm)) { | 1080 if (viewM.invert(&ivm)) { |
1088 toDevice = &viewM; | 1081 toDevice = &viewM; |
1089 toSrc = &ivm; | 1082 toSrc = &ivm; |
1090 } | 1083 } |
1091 } | 1084 } |
1092 | 1085 |
1093 for (int i = 0; i < *lineCnt; ++i) { | |
1094 add_line(&lines[2*i], rtHeight, toSrc, &verts); | |
1095 } | |
1096 | |
1097 int unsubdivQuadCnt = quads.count() / 3; | 1086 int unsubdivQuadCnt = quads.count() / 3; |
1098 for (int i = 0; i < unsubdivQuadCnt; ++i) { | 1087 for (int i = 0; i < unsubdivQuadCnt; ++i) { |
1099 GrAssert(qSubdivs[i] >= 0); | 1088 GrAssert(qSubdivs[i] >= 0); |
1100 add_quads(&quads[3*i], qSubdivs[i], toDevice, toSrc, &verts, devBounds); | 1089 add_quads(&quads[3*i], qSubdivs[i], toDevice, toSrc, &verts, devBounds); |
1101 } | 1090 } |
1102 | 1091 |
1103 // Start Conics | 1092 // Start Conics |
1104 for (int i = 0; i < *conicCnt; ++i) { | 1093 for (int i = 0; i < conicCnt; ++i) { |
1105 add_conics(&conics[3*i], cWeights[i], toDevice, toSrc, &verts, devBounds
); | 1094 add_conics(&conics[3*i], cWeights[i], toDevice, toSrc, &verts, devBounds
); |
1106 } | 1095 } |
1107 return true; | 1096 return true; |
1108 } | 1097 } |
1109 | 1098 |
1110 bool GrAAHairLinePathRenderer::canDrawPath(const SkPath& path, | 1099 bool GrAAHairLinePathRenderer::canDrawPath(const SkPath& path, |
1111 const SkStrokeRec& stroke, | 1100 const SkStrokeRec& stroke, |
1112 const GrDrawTarget* target, | 1101 const GrDrawTarget* target, |
1113 bool antiAlias) const { | 1102 bool antiAlias) const { |
1114 if (!stroke.isHairlineStyle() || !antiAlias) { | 1103 if (!stroke.isHairlineStyle() || !antiAlias) { |
1115 return false; | 1104 return false; |
1116 } | 1105 } |
1117 | 1106 |
1118 if (SkPath::kLine_SegmentMask == path.getSegmentMasks() || | 1107 if (SkPath::kLine_SegmentMask == path.getSegmentMasks() || |
1119 target->caps()->shaderDerivativeSupport()) { | 1108 target->caps()->shaderDerivativeSupport()) { |
1120 return true; | 1109 return true; |
1121 } | 1110 } |
1122 return false; | 1111 return false; |
1123 } | 1112 } |
1124 | 1113 |
1125 bool GrAAHairLinePathRenderer::onDrawPath(const SkPath& path, | 1114 template <class VertexType> |
1126 const SkStrokeRec&, | 1115 bool check_bounds(GrDrawState* drawState, const SkRect& devBounds, void* vertice
s, int vCount) |
1127 GrDrawTarget* target, | 1116 { |
1128 bool antiAlias) { | |
1129 | |
1130 int lineCnt; | |
1131 int quadCnt; | |
1132 int conicCnt; | |
1133 GrDrawTarget::AutoReleaseGeometry arg; | |
1134 SkRect devBounds; | |
1135 | |
1136 if (!this->createGeom(path, | |
1137 target, | |
1138 &lineCnt, | |
1139 &quadCnt, | |
1140 &conicCnt, | |
1141 &arg, | |
1142 &devBounds)) { | |
1143 return false; | |
1144 } | |
1145 | |
1146 GrDrawTarget::AutoStateRestore asr; | |
1147 | |
1148 // createGeom transforms the geometry to device space when the matrix does n
ot have | |
1149 // perspective. | |
1150 if (target->getDrawState().getViewMatrix().hasPerspective()) { | |
1151 asr.set(target, GrDrawTarget::kPreserve_ASRInit); | |
1152 } else if (!asr.setIdentity(target, GrDrawTarget::kPreserve_ASRInit)) { | |
1153 return false; | |
1154 } | |
1155 GrDrawState* drawState = target->drawState(); | |
1156 | |
1157 // TODO: See whether rendering lines as degenerate quads improves perf | |
1158 // when we have a mix | |
1159 | |
1160 static const int kEdgeAttrIndex = 1; | |
1161 | |
1162 GrEffectRef* hairLineEffect = HairLineEdgeEffect::Create(); | |
1163 GrEffectRef* hairQuadEffect = HairQuadEdgeEffect::Create(); | |
1164 GrEffectRef* hairConicEffect = HairConicEdgeEffect::Create(); | |
1165 | |
1166 // Check devBounds | |
1167 #if GR_DEBUG | |
1168 SkRect tolDevBounds = devBounds; | 1117 SkRect tolDevBounds = devBounds; |
1169 tolDevBounds.outset(SK_Scalar1 / 10000, SK_Scalar1 / 10000); | 1118 tolDevBounds.outset(SK_Scalar1 / 10000, SK_Scalar1 / 10000); |
1170 SkRect actualBounds; | 1119 SkRect actualBounds; |
1171 Vertex* verts = reinterpret_cast<Vertex*>(arg.vertices()); | 1120 |
1172 int vCount = kVertsPerLineSeg * lineCnt + kVertsPerQuad * quadCnt + kVertsPe
rQuad * conicCnt; | 1121 VertexType* verts = reinterpret_cast<VertexType*>(vertices); |
1173 bool first = true; | 1122 bool first = true; |
1174 for (int i = 0; i < vCount; ++i) { | 1123 for (int i = 0; i < vCount; ++i) { |
1175 SkPoint pos = verts[i].fPos; | 1124 SkPoint pos = verts[i].fPos; |
1176 // 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. |
1177 if (SK_ScalarMax == pos.fX) { | 1126 if (SK_ScalarMax == pos.fX) { |
1178 continue; | 1127 continue; |
1179 } | 1128 } |
1180 drawState->getViewMatrix().mapPoints(&pos, 1); | 1129 drawState->getViewMatrix().mapPoints(&pos, 1); |
1181 if (first) { | 1130 if (first) { |
1182 actualBounds.set(pos.fX, pos.fY, pos.fX, pos.fY); | 1131 actualBounds.set(pos.fX, pos.fY, pos.fX, pos.fY); |
1183 first = false; | 1132 first = false; |
1184 } else { | 1133 } else { |
1185 actualBounds.growToInclude(pos.fX, pos.fY); | 1134 actualBounds.growToInclude(pos.fX, pos.fY); |
1186 } | 1135 } |
1187 } | 1136 } |
1188 if (!first) { | 1137 if (!first) { |
1189 GrAssert(tolDevBounds.contains(actualBounds)); | 1138 return tolDevBounds.contains(actualBounds); |
1190 } | 1139 } |
1191 #endif | 1140 |
| 1141 return true; |
| 1142 } |
1192 | 1143 |
| 1144 bool GrAAHairLinePathRenderer::onDrawPath(const SkPath& path, |
| 1145 const SkStrokeRec&, |
| 1146 GrDrawTarget* target, |
| 1147 bool antiAlias) { |
| 1148 |
| 1149 GrDrawState* drawState = target->drawState(); |
| 1150 |
| 1151 SkIRect devClipBounds; |
| 1152 target->getClip()->getConservativeBounds(drawState->getRenderTarget(), &devC
lipBounds); |
| 1153 |
| 1154 int lineCnt; |
| 1155 int quadCnt; |
| 1156 int conicCnt; |
| 1157 PREALLOC_PTARRAY(128) lines; |
| 1158 PREALLOC_PTARRAY(128) quads; |
| 1159 PREALLOC_PTARRAY(128) conics; |
| 1160 IntArray qSubdivs; |
| 1161 FloatArray cWeights; |
| 1162 quadCnt = generate_lines_and_quads(path, drawState->getViewMatrix(), devClip
Bounds, |
| 1163 &lines, &quads, &conics, &qSubdivs, &cWei
ghts); |
| 1164 lineCnt = lines.count() / 2; |
| 1165 conicCnt = conics.count() / 3; |
| 1166 |
| 1167 // do lines first |
1193 { | 1168 { |
1194 GrDrawState::AutoRestoreEffects are(drawState); | 1169 GrDrawTarget::AutoReleaseGeometry arg; |
1195 target->setIndexSourceToBuffer(fLinesIndexBuffer); | 1170 SkRect devBounds; |
1196 int lines = 0; | 1171 |
1197 int nBufLines = fLinesIndexBuffer->maxQuads(); | 1172 if (!this->createLineGeom(path, |
1198 drawState->addCoverageEffect(hairLineEffect, kEdgeAttrIndex)->unref(); | 1173 target, |
1199 while (lines < lineCnt) { | 1174 lines, |
1200 int n = GrMin(lineCnt - lines, nBufLines); | 1175 lineCnt, |
1201 target->drawIndexed(kTriangles_GrPrimitiveType, | 1176 &arg, |
1202 kVertsPerLineSeg*lines, // startV | 1177 &devBounds)) { |
1203 0, // startI | 1178 return false; |
1204 kVertsPerLineSeg*n, // vCount | 1179 } |
1205 kIdxsPerLineSeg*n, | 1180 |
1206 &devBounds); // iCount | 1181 GrDrawTarget::AutoStateRestore asr; |
1207 lines += n; | 1182 |
| 1183 // createGeom transforms the geometry to device space when the matrix do
es not have |
| 1184 // perspective. |
| 1185 if (target->getDrawState().getViewMatrix().hasPerspective()) { |
| 1186 asr.set(target, GrDrawTarget::kPreserve_ASRInit); |
| 1187 } else if (!asr.setIdentity(target, GrDrawTarget::kPreserve_ASRInit)) { |
| 1188 return false; |
| 1189 } |
| 1190 GrDrawState* drawState = target->drawState(); |
| 1191 |
| 1192 // Check devBounds |
| 1193 SkASSERT(check_bounds<LineVertex>(drawState, devBounds, arg.vertices(), |
| 1194 kVertsPerLineSeg * lineCnt)); |
| 1195 |
| 1196 { |
| 1197 GrDrawState::AutoRestoreEffects are(drawState); |
| 1198 target->setIndexSourceToBuffer(fLinesIndexBuffer); |
| 1199 int lines = 0; |
| 1200 while (lines < lineCnt) { |
| 1201 int n = GrMin(lineCnt - lines, kNumLineSegsInIdxBuffer); |
| 1202 target->drawIndexed(kTriangles_GrPrimitiveType, |
| 1203 kVertsPerLineSeg*lines, // startV |
| 1204 0, // startI |
| 1205 kVertsPerLineSeg*n, // vCount |
| 1206 kIdxsPerLineSeg*n, |
| 1207 &devBounds); // iCount |
| 1208 lines += n; |
| 1209 } |
1208 } | 1210 } |
1209 } | 1211 } |
| 1212 |
| 1213 // then quadratics/conics |
| 1214 { |
| 1215 GrDrawTarget::AutoReleaseGeometry arg; |
| 1216 SkRect devBounds; |
| 1217 |
| 1218 if (!this->createBezierGeom(path, |
| 1219 target, |
| 1220 quads, |
| 1221 quadCnt, |
| 1222 conics, |
| 1223 conicCnt, |
| 1224 qSubdivs, |
| 1225 cWeights, |
| 1226 &arg, |
| 1227 &devBounds)) { |
| 1228 return false; |
| 1229 } |
| 1230 |
| 1231 GrDrawTarget::AutoStateRestore asr; |
| 1232 |
| 1233 // createGeom transforms the geometry to device space when the matrix do
es not have |
| 1234 // perspective. |
| 1235 if (target->getDrawState().getViewMatrix().hasPerspective()) { |
| 1236 asr.set(target, GrDrawTarget::kPreserve_ASRInit); |
| 1237 } else if (!asr.setIdentity(target, GrDrawTarget::kPreserve_ASRInit)) { |
| 1238 return false; |
| 1239 } |
| 1240 GrDrawState* drawState = target->drawState(); |
1210 | 1241 |
1211 { | 1242 static const int kEdgeAttrIndex = 1; |
1212 GrDrawState::AutoRestoreEffects are(drawState); | 1243 |
1213 target->setIndexSourceToBuffer(fQuadsIndexBuffer); | 1244 GrEffectRef* hairQuadEffect = HairQuadEdgeEffect::Create(); |
1214 int quads = 0; | 1245 GrEffectRef* hairConicEffect = HairConicEdgeEffect::Create(); |
1215 drawState->addCoverageEffect(hairQuadEffect, kEdgeAttrIndex)->unref(); | 1246 |
1216 while (quads < quadCnt) { | 1247 // Check devBounds |
1217 int n = GrMin(quadCnt - quads, kNumQuadsInIdxBuffer); | 1248 SkASSERT(check_bounds<BezierVertex>(drawState, devBounds, arg.vertices()
, |
1218 target->drawIndexed(kTriangles_GrPrimitiveType, | 1249 kVertsPerQuad * quadCnt + kVertsPerQ
uad * conicCnt)); |
1219 kVertsPerLineSeg * lineCnt + kVertsPerQuad*quads
, // startV | 1250 |
1220 0,
// startI | 1251 { |
1221 kVertsPerQuad*n,
// vCount | 1252 GrDrawState::AutoRestoreEffects are(drawState); |
1222 kIdxsPerQuad*n,
// iCount | 1253 target->setIndexSourceToBuffer(fQuadsIndexBuffer); |
1223 &devBounds); | 1254 int quads = 0; |
1224 quads += n; | 1255 drawState->addCoverageEffect(hairQuadEffect, kEdgeAttrIndex)->unref(
); |
| 1256 while (quads < quadCnt) { |
| 1257 int n = GrMin(quadCnt - quads, kNumQuadsInIdxBuffer); |
| 1258 target->drawIndexed(kTriangles_GrPrimitiveType, |
| 1259 kVertsPerQuad*quads, // startV |
| 1260 0, // startI |
| 1261 kVertsPerQuad*n, // vCount |
| 1262 kIdxsPerQuad*n, // iCount |
| 1263 &devBounds); |
| 1264 quads += n; |
| 1265 } |
| 1266 } |
| 1267 |
| 1268 { |
| 1269 GrDrawState::AutoRestoreEffects are(drawState); |
| 1270 int conics = 0; |
| 1271 drawState->addCoverageEffect(hairConicEffect, 1, 2)->unref(); |
| 1272 while (conics < conicCnt) { |
| 1273 int n = GrMin(conicCnt - conics, kNumQuadsInIdxBuffer); |
| 1274 target->drawIndexed(kTriangles_GrPrimitiveType, |
| 1275 kVertsPerQuad*(quadCnt + conics), // startV |
| 1276 0, // startI |
| 1277 kVertsPerQuad*n, // vCount |
| 1278 kIdxsPerQuad*n, // iCount |
| 1279 &devBounds); |
| 1280 conics += n; |
| 1281 } |
1225 } | 1282 } |
1226 } | 1283 } |
1227 | 1284 |
1228 { | |
1229 GrDrawState::AutoRestoreEffects are(drawState); | |
1230 int conics = 0; | |
1231 drawState->addCoverageEffect(hairConicEffect, 1, 2)->unref(); | |
1232 while (conics < conicCnt) { | |
1233 int n = GrMin(conicCnt - conics, kNumQuadsInIdxBuffer); | |
1234 target->drawIndexed(kTriangles_GrPrimitiveType, | |
1235 kVertsPerLineSeg*lineCnt + | |
1236 kVertsPerQuad*(quadCnt + conics), // startV | |
1237 0, // startI | |
1238 kVertsPerQuad*n, // vCount | |
1239 kIdxsPerQuad*n, // iCount | |
1240 &devBounds); | |
1241 conics += n; | |
1242 } | |
1243 } | |
1244 target->resetIndexSource(); | 1285 target->resetIndexSource(); |
1245 | 1286 |
1246 return true; | 1287 return true; |
1247 } | 1288 } |
OLD | NEW |