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

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

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

Powered by Google App Engine
This is Rietveld 408576698