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

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: Split hairline vertex buffer into buffer for line segments and buffer for quadratics 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
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 295 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 {
bsalomon 2013/08/12 17:25:43 Would it make sense to just have k,l,m and get rid
jvanverth1 2013/08/13 15:04:10 I think that's a question for Greg. Greg?
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
robertphillips 2013/08/12 17:27:01 Do we need one of these for LineVertex now?
jvanverth1 2013/08/13 15:04:10 I'll turn this around and ask: Do we need this for
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
robertphillips 2013/08/12 17:27:01 Would this be clearer as a loop over kVertsPerLine
jvanverth1 2013/08/13 15:04:10 Done.
683 (*vert)[0].fPos.set(SK_ScalarMax, SK_ScalarMax); 730 (*vert)[0].fPos.set(SK_ScalarMax, SK_ScalarMax);
684 (*vert)[1].fPos.set(SK_ScalarMax, SK_ScalarMax); 731 (*vert)[1].fPos.set(SK_ScalarMax, SK_ScalarMax);
685 (*vert)[2].fPos.set(SK_ScalarMax, SK_ScalarMax); 732 (*vert)[2].fPos.set(SK_ScalarMax, SK_ScalarMax);
686 (*vert)[3].fPos.set(SK_ScalarMax, SK_ScalarMax); 733 (*vert)[3].fPos.set(SK_ScalarMax, SK_ScalarMax);
734 (*vert)[4].fPos.set(SK_ScalarMax, SK_ScalarMax);
735 (*vert)[5].fPos.set(SK_ScalarMax, SK_ScalarMax);
687 } 736 }
688 737
689 *vert += kVertsPerLineSeg; 738 *vert += kVertsPerLineSeg;
690 } 739 }
691 740
692 } 741 }
693 742
694 /** 743 /**
695 * Shader is based off of Loop-Blinn Quadratic GPU Rendering 744 * Shader is based off of Loop-Blinn Quadratic GPU Rendering
696 * The output of this effect is a hairline edge for conics. 745 * 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, 976 GrEffectRef* HairQuadEdgeEffect::TestCreate(SkMWCRandom* random,
928 GrContext*, 977 GrContext*,
929 const GrDrawTargetCaps& caps, 978 const GrDrawTargetCaps& caps,
930 GrTexture*[]) { 979 GrTexture*[]) {
931 // Doesn't work without derivative instructions. 980 // Doesn't work without derivative instructions.
932 return caps.shaderDerivativeSupport() ? HairQuadEdgeEffect::Create() : NULL; 981 return caps.shaderDerivativeSupport() ? HairQuadEdgeEffect::Create() : NULL;
933 } 982 }
934 983
935 /////////////////////////////////////////////////////////////////////////////// 984 ///////////////////////////////////////////////////////////////////////////////
936 985
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 { 986 namespace {
1029 987
1030 // position + edge 988 // position + edge
1031 extern const GrVertexAttrib gHairlineAttribs[] = { 989 extern const GrVertexAttrib gHairlineBezierAttribs[] = {
1032 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBind ing}, 990 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBind ing},
1033 {kVec4f_GrVertexAttribType, sizeof(GrPoint), kEffect_GrVertexAttribBindin g} 991 {kVec4f_GrVertexAttribType, sizeof(GrPoint), kEffect_GrVertexAttribBindin g}
1034 }; 992 };
993
994 // position + coverage
995 extern const GrVertexAttrib gHairlineLineAttribs[] = {
996 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBindin g},
997 {kVec4ub_GrVertexAttribType, sizeof(GrPoint), kCoverage_GrVertexAttribBindin g},
1035 }; 998 };
1036 999
1037 bool GrAAHairLinePathRenderer::createGeom( 1000 };
1001
1002 bool GrAAHairLinePathRenderer::createLineGeom(
1038 const SkPath& path, 1003 const SkPath& path,
1039 GrDrawTarget* target, 1004 GrDrawTarget* target,
1040 int* lineCnt, 1005 const PtArray& lines,
1041 int* quadCnt, 1006 int lineCnt,
1042 int* conicCnt,
1043 GrDrawTarget::AutoReleaseGeometry* arg, 1007 GrDrawTarget::AutoReleaseGeometry* arg,
1044 SkRect* devBounds) { 1008 SkRect* devBounds) {
1045 GrDrawState* drawState = target->drawState(); 1009 GrDrawState* drawState = target->drawState();
1046 int rtHeight = drawState->getRenderTarget()->height(); 1010 int rtHeight = drawState->getRenderTarget()->height();
1047 1011
robertphillips 2013/08/12 17:27:01 const SkMatrix& viewM?
jvanverth1 2013/08/13 15:04:10 Done.
1048 SkIRect devClipBounds;
1049 target->getClip()->getConservativeBounds(drawState->getRenderTarget(), &devC lipBounds);
1050
1051 SkMatrix viewM = drawState->getViewMatrix(); 1012 SkMatrix viewM = drawState->getViewMatrix();
1052 1013
robertphillips 2013/08/12 17:27:01 This comment seems out of date
jvanverth1 2013/08/13 15:04:10 Done.
1053 // All the vertices that we compute are within 1 of path control points with the exception of 1014 // 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 1015 // one of the bounding vertices for each quad. The add_quads() function will update the bounds
1055 // for each quad added. 1016 // for each quad added.
1056 *devBounds = path.getBounds(); 1017 *devBounds = path.getBounds();
1057 viewM.mapRect(devBounds); 1018 viewM.mapRect(devBounds);
robertphillips 2013/08/12 17:27:01 Do we still need to go out 1 here (can we go out .
jvanverth1 2013/08/13 15:04:10 I think we still do -- the line geometry bounds ex
1058 devBounds->outset(SK_Scalar1, SK_Scalar1); 1019 devBounds->outset(SK_Scalar1, SK_Scalar1);
1059 1020
1060 PREALLOC_PTARRAY(128) lines;
1061 PREALLOC_PTARRAY(128) quads;
1062 PREALLOC_PTARRAY(128) conics;
1063 IntArray qSubdivs; 1021 IntArray qSubdivs;
1064 FloatArray cWeights; 1022 FloatArray cWeights;
1065 *quadCnt = generate_lines_and_quads(path, viewM, devClipBounds,
1066 &lines, &quads, &conics, &qSubdivs, &cWe ights);
1067 1023
1068 *lineCnt = lines.count() / 2; 1024 int vertCnt = kVertsPerLineSeg * lineCnt;
1069 *conicCnt = conics.count() / 3;
1070 int vertCnt = kVertsPerLineSeg * *lineCnt + kVertsPerQuad * *quadCnt +
1071 kVertsPerQuad * *conicCnt;
1072 1025
1073 target->drawState()->setVertexAttribs<gHairlineAttribs>(SK_ARRAY_COUNT(gHair lineAttribs)); 1026 target->drawState()->setVertexAttribs<gHairlineLineAttribs>(SK_ARRAY_COUNT(g HairlineLineAttribs));
1074 GrAssert(sizeof(Vertex) == target->getDrawState().getVertexSize()); 1027 GrAssert(sizeof(LineVertex) == target->getDrawState().getVertexSize());
1075 1028
1076 if (!arg->set(target, vertCnt, 0)) { 1029 if (!arg->set(target, vertCnt, 0)) {
1077 return false; 1030 return false;
1078 } 1031 }
1079 1032
1080 Vertex* verts = reinterpret_cast<Vertex*>(arg->vertices()); 1033 LineVertex* verts = reinterpret_cast<LineVertex*>(arg->vertices());
1081 1034
robertphillips 2013/08/12 17:27:01 Do we still need toDevice?
jvanverth1 2013/08/13 15:04:10 Done.
1082 const SkMatrix* toDevice = NULL; 1035 const SkMatrix* toDevice = NULL;
1083 const SkMatrix* toSrc = NULL; 1036 const SkMatrix* toSrc = NULL;
1084 SkMatrix ivm; 1037 SkMatrix ivm;
1085 1038
1086 if (viewM.hasPerspective()) { 1039 if (viewM.hasPerspective()) {
1087 if (viewM.invert(&ivm)) { 1040 if (viewM.invert(&ivm)) {
1088 toDevice = &viewM; 1041 toDevice = &viewM;
1089 toSrc = &ivm; 1042 toSrc = &ivm;
1090 } 1043 }
1091 } 1044 }
1092 1045
1093 for (int i = 0; i < *lineCnt; ++i) { 1046 for (int i = 0; i < lineCnt; ++i) {
1094 add_line(&lines[2*i], rtHeight, toSrc, &verts); 1047 add_line(&lines[2*i], rtHeight, toSrc, drawState->getCoverage(), &verts) ;
1095 } 1048 }
1096 1049
1050 return true;
1051 }
1052
1053 bool GrAAHairLinePathRenderer::createBezierGeom(
1054 const SkPath& path,
1055 GrDrawTarget* target,
1056 const PtArray& quads,
1057 int quadCnt,
1058 const PtArray& conics,
1059 int conicCnt,
1060 const IntArray& qSubdivs,
1061 const FloatArray& cWeights,
1062 GrDrawTarget::AutoReleaseGeometry* arg ,
1063 SkRect* devBounds) {
1064 GrDrawState* drawState = target->drawState();
1065
robertphillips 2013/08/12 17:27:01 const SkMatrix& viewM?
jvanverth1 2013/08/13 15:04:10 Done.
1066 SkMatrix viewM = drawState->getViewMatrix();
1067
1068 // All the vertices that we compute are within 1 of path control points with the exception of
1069 // one of the bounding vertices for each quad. The add_quads() function will update the bounds
1070 // for each quad added.
1071 *devBounds = path.getBounds();
1072 viewM.mapRect(devBounds);
1073 devBounds->outset(SK_Scalar1, SK_Scalar1);
1074
1075 int vertCnt = kVertsPerQuad * quadCnt + kVertsPerQuad * conicCnt;
1076
1077 target->drawState()->setVertexAttribs<gHairlineBezierAttribs>(SK_ARRAY_COUNT (gHairlineBezierAttribs));
1078 GrAssert(sizeof(BezierVertex) == target->getDrawState().getVertexSize());
1079
1080 if (!arg->set(target, vertCnt, 0)) {
1081 return false;
1082 }
1083
1084 BezierVertex* verts = reinterpret_cast<BezierVertex*>(arg->vertices());
1085
1086 const SkMatrix* toDevice = NULL;
1087 const SkMatrix* toSrc = NULL;
1088 SkMatrix ivm;
1089
1090 if (viewM.hasPerspective()) {
1091 if (viewM.invert(&ivm)) {
1092 toDevice = &viewM;
1093 toSrc = &ivm;
1094 }
1095 }
1096
1097 int unsubdivQuadCnt = quads.count() / 3; 1097 int unsubdivQuadCnt = quads.count() / 3;
1098 for (int i = 0; i < unsubdivQuadCnt; ++i) { 1098 for (int i = 0; i < unsubdivQuadCnt; ++i) {
1099 GrAssert(qSubdivs[i] >= 0); 1099 GrAssert(qSubdivs[i] >= 0);
1100 add_quads(&quads[3*i], qSubdivs[i], toDevice, toSrc, &verts, devBounds); 1100 add_quads(&quads[3*i], qSubdivs[i], toDevice, toSrc, &verts, devBounds);
1101 } 1101 }
1102 1102
1103 // Start Conics 1103 // Start Conics
1104 for (int i = 0; i < *conicCnt; ++i) { 1104 for (int i = 0; i < conicCnt; ++i) {
1105 add_conics(&conics[3*i], cWeights[i], toDevice, toSrc, &verts, devBounds ); 1105 add_conics(&conics[3*i], cWeights[i], toDevice, toSrc, &verts, devBounds );
1106 } 1106 }
1107 return true; 1107 return true;
1108 } 1108 }
1109 1109
1110 bool GrAAHairLinePathRenderer::canDrawPath(const SkPath& path, 1110 bool GrAAHairLinePathRenderer::canDrawPath(const SkPath& path,
1111 const SkStrokeRec& stroke, 1111 const SkStrokeRec& stroke,
1112 const GrDrawTarget* target, 1112 const GrDrawTarget* target,
1113 bool antiAlias) const { 1113 bool antiAlias) const {
1114 if (!stroke.isHairlineStyle() || !antiAlias) { 1114 if (!stroke.isHairlineStyle() || !antiAlias) {
1115 return false; 1115 return false;
1116 } 1116 }
1117 1117
1118 if (SkPath::kLine_SegmentMask == path.getSegmentMasks() || 1118 if (SkPath::kLine_SegmentMask == path.getSegmentMasks() ||
1119 target->caps()->shaderDerivativeSupport()) { 1119 target->caps()->shaderDerivativeSupport()) {
1120 return true; 1120 return true;
1121 } 1121 }
1122 return false; 1122 return false;
1123 } 1123 }
1124 1124
1125 bool GrAAHairLinePathRenderer::onDrawPath(const SkPath& path, 1125 bool GrAAHairLinePathRenderer::onDrawPath(const SkPath& path,
1126 const SkStrokeRec&, 1126 const SkStrokeRec&,
1127 GrDrawTarget* target, 1127 GrDrawTarget* target,
1128 bool antiAlias) { 1128 bool antiAlias) {
1129
1130 GrDrawState* drawState = target->drawState();
1131
1132 SkIRect devClipBounds;
1133 target->getClip()->getConservativeBounds(drawState->getRenderTarget(), &devC lipBounds);
1134
1135 SkMatrix viewM = drawState->getViewMatrix();
1129 1136
1130 int lineCnt; 1137 int lineCnt;
1131 int quadCnt; 1138 int quadCnt;
1132 int conicCnt; 1139 int conicCnt;
1133 GrDrawTarget::AutoReleaseGeometry arg; 1140 PREALLOC_PTARRAY(128) lines;
1134 SkRect devBounds; 1141 PREALLOC_PTARRAY(128) quads;
1142 PREALLOC_PTARRAY(128) conics;
1143 IntArray qSubdivs;
1144 FloatArray cWeights;
1145 quadCnt = generate_lines_and_quads(path, viewM, devClipBounds,
1146 &lines, &quads, &conics, &qSubdivs, &cWei ghts);
1147 lineCnt = lines.count() / 2;
1148 conicCnt = conics.count() / 3;
1149
1150 // do lines first
1151 {
1152 GrDrawTarget::AutoReleaseGeometry arg;
1153 SkRect devBounds;
1135 1154
1136 if (!this->createGeom(path, 1155 if (!this->createLineGeom(path,
1137 target, 1156 target,
1138 &lineCnt, 1157 lines,
1139 &quadCnt, 1158 lineCnt,
1140 &conicCnt, 1159 &arg,
1141 &arg, 1160 &devBounds)) {
1142 &devBounds)) { 1161 return false;
1143 return false; 1162 }
1144 }
1145 1163
1146 GrDrawTarget::AutoStateRestore asr; 1164 GrDrawTarget::AutoStateRestore asr;
1147 1165
1148 // createGeom transforms the geometry to device space when the matrix does n ot have 1166 // createGeom transforms the geometry to device space when the matrix do es not have
1149 // perspective. 1167 // perspective.
1150 if (target->getDrawState().getViewMatrix().hasPerspective()) { 1168 if (target->getDrawState().getViewMatrix().hasPerspective()) {
1151 asr.set(target, GrDrawTarget::kPreserve_ASRInit); 1169 asr.set(target, GrDrawTarget::kPreserve_ASRInit);
1152 } else if (!asr.setIdentity(target, GrDrawTarget::kPreserve_ASRInit)) { 1170 } else if (!asr.setIdentity(target, GrDrawTarget::kPreserve_ASRInit)) {
1153 return false; 1171 return false;
1154 } 1172 }
1155 GrDrawState* drawState = target->drawState(); 1173 GrDrawState* drawState = target->drawState();
1156 1174
1157 // TODO: See whether rendering lines as degenerate quads improves perf 1175 // Check devBounds
1158 // when we have a mix 1176 #if GR_DEBUG
bsalomon 2013/08/12 17:25:43 #if shouldn't be indented
robertphillips 2013/08/12 17:27:01 Could this test be a sub routine?
jvanverth1 2013/08/13 15:04:10 Done.
jvanverth1 2013/08/13 15:04:10 Done.
1177 SkRect tolDevBounds = devBounds;
1178 tolDevBounds.outset(SK_Scalar1 / 10000, SK_Scalar1 / 10000);
1179 SkRect actualBounds;
1180
1181 LineVertex* verts = reinterpret_cast<LineVertex*>(arg.vertices());
1182 int vCount = kVertsPerLineSeg * lineCnt;
1183 bool first = true;
1184 for (int i = 0; i < vCount; ++i) {
1185 SkPoint pos = verts[i].fPos;
1186 // This is a hack to workaround the fact that we move some degenerat e segments offscreen.
1187 if (SK_ScalarMax == pos.fX) {
1188 continue;
1189 }
1190 drawState->getViewMatrix().mapPoints(&pos, 1);
1191 if (first) {
1192 actualBounds.set(pos.fX, pos.fY, pos.fX, pos.fY);
1193 first = false;
1194 } else {
1195 actualBounds.growToInclude(pos.fX, pos.fY);
1196 }
1197 }
1198 if (!first) {
1199 GrAssert(tolDevBounds.contains(actualBounds));
1200 }
1201 #endif
1159 1202
1160 static const int kEdgeAttrIndex = 1; 1203 {
1161 1204 GrDrawState::AutoRestoreEffects are(drawState);
1162 GrEffectRef* hairLineEffect = HairLineEdgeEffect::Create(); 1205 target->setIndexSourceToBuffer(fLinesIndexBuffer);
1163 GrEffectRef* hairQuadEffect = HairQuadEdgeEffect::Create(); 1206 int lines = 0;
1164 GrEffectRef* hairConicEffect = HairConicEdgeEffect::Create(); 1207 while (lines < lineCnt) {
1165 1208 int n = GrMin(lineCnt - lines, kNumLineSegsInIdxBuffer);
1166 // Check devBounds 1209 target->drawIndexed(kTriangles_GrPrimitiveType,
1167 #if GR_DEBUG 1210 kVertsPerLineSeg*lines, // startV
1168 SkRect tolDevBounds = devBounds; 1211 0, // startI
1169 tolDevBounds.outset(SK_Scalar1 / 10000, SK_Scalar1 / 10000); 1212 kVertsPerLineSeg*n, // vCount
1170 SkRect actualBounds; 1213 kIdxsPerLineSeg*n,
1171 Vertex* verts = reinterpret_cast<Vertex*>(arg.vertices()); 1214 &devBounds); // iCount
1172 int vCount = kVertsPerLineSeg * lineCnt + kVertsPerQuad * quadCnt + kVertsPe rQuad * conicCnt; 1215 lines += n;
1173 bool first = true; 1216 }
1174 for (int i = 0; i < vCount; ++i) {
1175 SkPoint pos = verts[i].fPos;
1176 // This is a hack to workaround the fact that we move some degenerate se gments offscreen.
1177 if (SK_ScalarMax == pos.fX) {
1178 continue;
1179 }
1180 drawState->getViewMatrix().mapPoints(&pos, 1);
1181 if (first) {
1182 actualBounds.set(pos.fX, pos.fY, pos.fX, pos.fY);
1183 first = false;
1184 } else {
1185 actualBounds.growToInclude(pos.fX, pos.fY);
1186 } 1217 }
1187 } 1218 }
1188 if (!first) { 1219
1189 GrAssert(tolDevBounds.contains(actualBounds)); 1220 // then quadratics/conics
1190 } 1221 {
1222 GrDrawTarget::AutoReleaseGeometry arg;
1223 SkRect devBounds;
1224
1225 if (!this->createBezierGeom(path,
1226 target,
1227 quads,
1228 quadCnt,
1229 conics,
1230 conicCnt,
1231 qSubdivs,
1232 cWeights,
1233 &arg,
1234 &devBounds)) {
1235 return false;
1236 }
1237
1238 GrDrawTarget::AutoStateRestore asr;
1239
1240 // createGeom transforms the geometry to device space when the matrix do es not have
1241 // perspective.
1242 if (target->getDrawState().getViewMatrix().hasPerspective()) {
1243 asr.set(target, GrDrawTarget::kPreserve_ASRInit);
1244 } else if (!asr.setIdentity(target, GrDrawTarget::kPreserve_ASRInit)) {
1245 return false;
1246 }
1247 GrDrawState* drawState = target->drawState();
1248
1249 // TODO: See whether rendering lines as degenerate quads improves perf
bsalomon 2013/08/12 17:25:43 Let's axe this comment.. I don't think it makes se
jvanverth1 2013/08/13 15:04:10 Done.
1250 // when we have a mix
1251
1252 static const int kEdgeAttrIndex = 1;
1253
1254 GrEffectRef* hairQuadEffect = HairQuadEdgeEffect::Create();
1255 GrEffectRef* hairConicEffect = HairConicEdgeEffect::Create();
1256
1257 // Check devBounds
1258 #if GR_DEBUG
robertphillips 2013/08/12 17:27:01 Make this a sub routine too?
jvanverth1 2013/08/13 15:04:10 Done.
1259 SkRect tolDevBounds = devBounds;
1260 tolDevBounds.outset(SK_Scalar1 / 10000, SK_Scalar1 / 10000);
1261 SkRect actualBounds;
1262
1263 //*** do this for line verts first, then bezier verts
1264 BezierVertex* verts = reinterpret_cast<BezierVertex*>(arg.vertices());
1265 int vCount = kVertsPerQuad * quadCnt + kVertsPerQuad * conicCnt;
1266 bool first = true;
1267 for (int i = 0; i < vCount; ++i) {
1268 SkPoint pos = verts[i].fPos;
1269 // This is a hack to workaround the fact that we move some degenerat e segments offscreen.
1270 if (SK_ScalarMax == pos.fX) {
1271 continue;
1272 }
1273 drawState->getViewMatrix().mapPoints(&pos, 1);
1274 if (first) {
1275 actualBounds.set(pos.fX, pos.fY, pos.fX, pos.fY);
1276 first = false;
1277 } else {
1278 actualBounds.growToInclude(pos.fX, pos.fY);
1279 }
1280 }
1281 if (!first) {
1282 GrAssert(tolDevBounds.contains(actualBounds));
1283 }
1191 #endif 1284 #endif
1192 1285
1193 { 1286 {
1194 GrDrawState::AutoRestoreEffects are(drawState); 1287 GrDrawState::AutoRestoreEffects are(drawState);
1195 target->setIndexSourceToBuffer(fLinesIndexBuffer); 1288 target->setIndexSourceToBuffer(fQuadsIndexBuffer);
1196 int lines = 0; 1289 int quads = 0;
1197 int nBufLines = fLinesIndexBuffer->maxQuads(); 1290 drawState->addCoverageEffect(hairQuadEffect, kEdgeAttrIndex)->unref( );
1198 drawState->addCoverageEffect(hairLineEffect, kEdgeAttrIndex)->unref(); 1291 while (quads < quadCnt) {
1199 while (lines < lineCnt) { 1292 int n = GrMin(quadCnt - quads, kNumQuadsInIdxBuffer);
1200 int n = GrMin(lineCnt - lines, nBufLines); 1293 target->drawIndexed(kTriangles_GrPrimitiveType,
1201 target->drawIndexed(kTriangles_GrPrimitiveType, 1294 kVertsPerQuad*quads, // startV
1202 kVertsPerLineSeg*lines, // startV 1295 0, // startI
1203 0, // startI 1296 kVertsPerQuad*n, // vCount
1204 kVertsPerLineSeg*n, // vCount 1297 kIdxsPerQuad*n, // iCount
1205 kIdxsPerLineSeg*n, 1298 &devBounds);
1206 &devBounds); // iCount 1299 quads += n;
1207 lines += n; 1300 }
1301 }
1302
1303 {
1304 GrDrawState::AutoRestoreEffects are(drawState);
1305 int conics = 0;
1306 drawState->addCoverageEffect(hairConicEffect, 1, 2)->unref();
1307 while (conics < conicCnt) {
1308 int n = GrMin(conicCnt - conics, kNumQuadsInIdxBuffer);
1309 target->drawIndexed(kTriangles_GrPrimitiveType,
1310 kVertsPerQuad*(quadCnt + conics), // startV
1311 0, // startI
1312 kVertsPerQuad*n, // vCount
1313 kIdxsPerQuad*n, // iCount
1314 &devBounds);
1315 conics += n;
1316 }
1208 } 1317 }
1209 } 1318 }
1210 1319
1211 {
1212 GrDrawState::AutoRestoreEffects are(drawState);
1213 target->setIndexSourceToBuffer(fQuadsIndexBuffer);
1214 int quads = 0;
1215 drawState->addCoverageEffect(hairQuadEffect, kEdgeAttrIndex)->unref();
1216 while (quads < quadCnt) {
1217 int n = GrMin(quadCnt - quads, kNumQuadsInIdxBuffer);
1218 target->drawIndexed(kTriangles_GrPrimitiveType,
1219 kVertsPerLineSeg * lineCnt + kVertsPerQuad*quads , // startV
1220 0, // startI
1221 kVertsPerQuad*n, // vCount
1222 kIdxsPerQuad*n, // iCount
1223 &devBounds);
1224 quads += n;
1225 }
1226 }
1227
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(); 1320 target->resetIndexSource();
1245 1321
1246 return true; 1322 return true;
1247 } 1323 }
OLDNEW
« src/gpu/GrAAHairLinePathRenderer.h ('K') | « src/gpu/GrAAHairLinePathRenderer.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698