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

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

Issue 22486003: Fix hairline pathrenderer for Nexus-10. Switches to passing in an offset and using that to compute … (Closed) Base URL: https://skia.googlecode.com/svn/trunk
Patch Set: More view matrix cleanup Created 7 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/gpu/GrAAHairLinePathRenderer.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * 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
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
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
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
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
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
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
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 }
1140
1141 return true;
1142 }
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
1168 {
1169 GrDrawTarget::AutoReleaseGeometry arg;
1170 SkRect devBounds;
1171
1172 if (!this->createLineGeom(path,
1173 target,
1174 lines,
1175 lineCnt,
1176 &arg,
1177 &devBounds)) {
1178 return false;
1179 }
1180
1181 GrDrawTarget::AutoStateRestore asr;
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 #if GR_DEBUG
bsalomon 2013/08/13 15:14:22 We can remove the #if now that the call is in an a
1194 GrAssert(check_bounds<LineVertex>(drawState, devBounds, arg.vertices(),
1195 kVertsPerLineSeg * lineCnt));
1191 #endif 1196 #endif
1192 1197
1193 { 1198 {
1194 GrDrawState::AutoRestoreEffects are(drawState); 1199 GrDrawState::AutoRestoreEffects are(drawState);
1195 target->setIndexSourceToBuffer(fLinesIndexBuffer); 1200 target->setIndexSourceToBuffer(fLinesIndexBuffer);
1196 int lines = 0; 1201 int lines = 0;
1197 int nBufLines = fLinesIndexBuffer->maxQuads(); 1202 while (lines < lineCnt) {
1198 drawState->addCoverageEffect(hairLineEffect, kEdgeAttrIndex)->unref(); 1203 int n = GrMin(lineCnt - lines, kNumLineSegsInIdxBuffer);
1199 while (lines < lineCnt) { 1204 target->drawIndexed(kTriangles_GrPrimitiveType,
1200 int n = GrMin(lineCnt - lines, nBufLines); 1205 kVertsPerLineSeg*lines, // startV
1201 target->drawIndexed(kTriangles_GrPrimitiveType, 1206 0, // startI
1202 kVertsPerLineSeg*lines, // startV 1207 kVertsPerLineSeg*n, // vCount
1203 0, // startI 1208 kIdxsPerLineSeg*n,
1204 kVertsPerLineSeg*n, // vCount 1209 &devBounds); // iCount
1205 kIdxsPerLineSeg*n, 1210 lines += n;
1206 &devBounds); // iCount 1211 }
1207 lines += n;
1208 } 1212 }
1209 } 1213 }
1214
1215 // then quadratics/conics
1216 {
1217 GrDrawTarget::AutoReleaseGeometry arg;
1218 SkRect devBounds;
1219
1220 if (!this->createBezierGeom(path,
1221 target,
1222 quads,
1223 quadCnt,
1224 conics,
1225 conicCnt,
1226 qSubdivs,
1227 cWeights,
1228 &arg,
1229 &devBounds)) {
1230 return false;
1231 }
1232
1233 GrDrawTarget::AutoStateRestore asr;
1234
1235 // createGeom transforms the geometry to device space when the matrix do es not have
1236 // perspective.
1237 if (target->getDrawState().getViewMatrix().hasPerspective()) {
1238 asr.set(target, GrDrawTarget::kPreserve_ASRInit);
1239 } else if (!asr.setIdentity(target, GrDrawTarget::kPreserve_ASRInit)) {
1240 return false;
1241 }
1242 GrDrawState* drawState = target->drawState();
1210 1243
1211 { 1244 static const int kEdgeAttrIndex = 1;
1212 GrDrawState::AutoRestoreEffects are(drawState); 1245
1213 target->setIndexSourceToBuffer(fQuadsIndexBuffer); 1246 GrEffectRef* hairQuadEffect = HairQuadEdgeEffect::Create();
1214 int quads = 0; 1247 GrEffectRef* hairConicEffect = HairConicEdgeEffect::Create();
1215 drawState->addCoverageEffect(hairQuadEffect, kEdgeAttrIndex)->unref(); 1248
1216 while (quads < quadCnt) { 1249 // Check devBounds
1217 int n = GrMin(quadCnt - quads, kNumQuadsInIdxBuffer); 1250 #if GR_DEBUG
bsalomon 2013/08/13 15:14:22 and here
1218 target->drawIndexed(kTriangles_GrPrimitiveType, 1251 GrAssert(check_bounds<BezierVertex>(drawState, devBounds, arg.vertices() ,
1219 kVertsPerLineSeg * lineCnt + kVertsPerQuad*quads , // startV 1252 kVertsPerQuad * quadCnt + kVertsPerQ uad * conicCnt));
1220 0, // startI 1253 #endif
1221 kVertsPerQuad*n, // vCount 1254
1222 kIdxsPerQuad*n, // iCount 1255 {
1223 &devBounds); 1256 GrDrawState::AutoRestoreEffects are(drawState);
1224 quads += n; 1257 target->setIndexSourceToBuffer(fQuadsIndexBuffer);
1258 int quads = 0;
1259 drawState->addCoverageEffect(hairQuadEffect, kEdgeAttrIndex)->unref( );
1260 while (quads < quadCnt) {
1261 int n = GrMin(quadCnt - quads, kNumQuadsInIdxBuffer);
1262 target->drawIndexed(kTriangles_GrPrimitiveType,
1263 kVertsPerQuad*quads, // startV
1264 0, // startI
1265 kVertsPerQuad*n, // vCount
1266 kIdxsPerQuad*n, // iCount
1267 &devBounds);
1268 quads += n;
1269 }
1270 }
1271
1272 {
1273 GrDrawState::AutoRestoreEffects are(drawState);
1274 int conics = 0;
1275 drawState->addCoverageEffect(hairConicEffect, 1, 2)->unref();
1276 while (conics < conicCnt) {
1277 int n = GrMin(conicCnt - conics, kNumQuadsInIdxBuffer);
1278 target->drawIndexed(kTriangles_GrPrimitiveType,
1279 kVertsPerQuad*(quadCnt + conics), // startV
1280 0, // startI
1281 kVertsPerQuad*n, // vCount
1282 kIdxsPerQuad*n, // iCount
1283 &devBounds);
1284 conics += n;
1285 }
1225 } 1286 }
1226 } 1287 }
1227 1288
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(); 1289 target->resetIndexSource();
1245 1290
1246 return true; 1291 return true;
1247 } 1292 }
OLDNEW
« no previous file with comments | « src/gpu/GrAAHairLinePathRenderer.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698