OLD | NEW |
---|---|
1 | 1 |
2 /* | 2 /* |
3 * Copyright 2011 Google Inc. | 3 * Copyright 2011 Google Inc. |
4 * | 4 * |
5 * Use of this source code is governed by a BSD-style license that can be | 5 * Use of this source code is governed by a BSD-style license that can be |
6 * found in the LICENSE file. | 6 * found in the LICENSE file. |
7 */ | 7 */ |
8 | 8 |
9 #include "GrAAHairLinePathRenderer.h" | 9 #include "GrAAHairLinePathRenderer.h" |
10 | 10 |
(...skipping 12 matching lines...) Expand all Loading... | |
23 #include "gl/GrGLEffect.h" | 23 #include "gl/GrGLEffect.h" |
24 #include "gl/GrGLSL.h" | 24 #include "gl/GrGLSL.h" |
25 | 25 |
26 namespace { | 26 namespace { |
27 // quadratics are rendered as 5-sided polys in order to bound the | 27 // quadratics are rendered as 5-sided polys in order to bound the |
28 // AA stroke around the center-curve. See comments in push_quad_index_buffer and | 28 // AA stroke around the center-curve. See comments in push_quad_index_buffer and |
29 // bloat_quad. | 29 // bloat_quad. |
30 static const int kVertsPerQuad = 5; | 30 static const int kVertsPerQuad = 5; |
31 static const int kIdxsPerQuad = 9; | 31 static const int kIdxsPerQuad = 9; |
32 | 32 |
33 static const int kVertsPerConic = 5; | |
34 static const int kIdxsPerConic = 9; | |
35 | |
33 static const int kVertsPerLineSeg = 4; | 36 static const int kVertsPerLineSeg = 4; |
34 static const int kIdxsPerLineSeg = 6; | 37 static const int kIdxsPerLineSeg = 6; |
35 | 38 |
36 static const int kNumQuadsInIdxBuffer = 256; | 39 static const int kNumQuadsInIdxBuffer = 256; |
37 static const size_t kQuadIdxSBufize = kIdxsPerQuad * | 40 static const size_t kQuadIdxSBufize = kIdxsPerQuad * |
38 sizeof(uint16_t) * | 41 sizeof(uint16_t) * |
39 kNumQuadsInIdxBuffer; | 42 kNumQuadsInIdxBuffer; |
43 static const int kNumConicsInIdxBuffer = 256; | |
44 static const size_t kConicIdxSBufize = kIdxsPerConic * | |
45 sizeof(uint16_t) * | |
46 kNumConicsInIdxBuffer; | |
40 | 47 |
41 bool push_quad_index_data(GrIndexBuffer* qIdxBuffer) { | 48 bool push_quad_index_data(GrIndexBuffer* qIdxBuffer) { |
42 uint16_t* data = (uint16_t*) qIdxBuffer->lock(); | 49 uint16_t* data = (uint16_t*) qIdxBuffer->lock(); |
43 bool tempData = NULL == data; | 50 bool tempData = NULL == data; |
44 if (tempData) { | 51 if (tempData) { |
45 data = SkNEW_ARRAY(uint16_t, kNumQuadsInIdxBuffer * kIdxsPerQuad); | 52 data = SkNEW_ARRAY(uint16_t, kNumQuadsInIdxBuffer * kIdxsPerQuad); |
46 } | 53 } |
47 for (int i = 0; i < kNumQuadsInIdxBuffer; ++i) { | 54 for (int i = 0; i < kNumQuadsInIdxBuffer; ++i) { |
48 | 55 |
49 // Each quadratic is rendered as a five sided polygon. This poly bounds | 56 // Each quadratic is rendered as a five sided polygon. This poly bounds |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
86 if (NULL == lIdxBuffer) { | 93 if (NULL == lIdxBuffer) { |
87 return NULL; | 94 return NULL; |
88 } | 95 } |
89 GrGpu* gpu = context->getGpu(); | 96 GrGpu* gpu = context->getGpu(); |
90 GrIndexBuffer* qIdxBuf = gpu->createIndexBuffer(kQuadIdxSBufize, false); | 97 GrIndexBuffer* qIdxBuf = gpu->createIndexBuffer(kQuadIdxSBufize, false); |
91 SkAutoTUnref<GrIndexBuffer> qIdxBuffer(qIdxBuf); | 98 SkAutoTUnref<GrIndexBuffer> qIdxBuffer(qIdxBuf); |
92 if (NULL == qIdxBuf || | 99 if (NULL == qIdxBuf || |
93 !push_quad_index_data(qIdxBuf)) { | 100 !push_quad_index_data(qIdxBuf)) { |
94 return NULL; | 101 return NULL; |
95 } | 102 } |
103 GrIndexBuffer* cIdxBuf = gpu->createIndexBuffer(kConicIdxSBufize, false); | |
104 if (NULL == cIdxBuf || | |
105 !push_quad_index_data(cIdxBuf)) { | |
bsalomon
2013/07/10 15:14:36
can't we just use one idx buffer then?
egdaniel
2013/07/10 20:34:18
I'm assuming you mean for the quad and conic corre
| |
106 return NULL; | |
107 } | |
96 return SkNEW_ARGS(GrAAHairLinePathRenderer, | 108 return SkNEW_ARGS(GrAAHairLinePathRenderer, |
97 (context, lIdxBuffer, qIdxBuf)); | 109 (context, lIdxBuffer, qIdxBuf, cIdxBuf)); |
98 } | 110 } |
99 | 111 |
100 GrAAHairLinePathRenderer::GrAAHairLinePathRenderer( | 112 GrAAHairLinePathRenderer::GrAAHairLinePathRenderer( |
101 const GrContext* context, | 113 const GrContext* context, |
102 const GrIndexBuffer* linesIndexBuffer, | 114 const GrIndexBuffer* linesIndexBuffer, |
103 const GrIndexBuffer* quadsIndexBuffer) { | 115 const GrIndexBuffer* quadsIndexBuffer, |
116 const GrIndexBuffer* conicIndexBuffer) { | |
104 fLinesIndexBuffer = linesIndexBuffer; | 117 fLinesIndexBuffer = linesIndexBuffer; |
105 linesIndexBuffer->ref(); | 118 linesIndexBuffer->ref(); |
106 fQuadsIndexBuffer = quadsIndexBuffer; | 119 fQuadsIndexBuffer = quadsIndexBuffer; |
107 quadsIndexBuffer->ref(); | 120 quadsIndexBuffer->ref(); |
121 fConicsIndexBuffer = conicIndexBuffer; | |
122 conicIndexBuffer->ref(); | |
108 } | 123 } |
109 | 124 |
110 GrAAHairLinePathRenderer::~GrAAHairLinePathRenderer() { | 125 GrAAHairLinePathRenderer::~GrAAHairLinePathRenderer() { |
111 fLinesIndexBuffer->unref(); | 126 fLinesIndexBuffer->unref(); |
112 fQuadsIndexBuffer->unref(); | 127 fQuadsIndexBuffer->unref(); |
128 fConicsIndexBuffer->unref(); | |
113 } | 129 } |
114 | 130 |
115 namespace { | 131 namespace { |
116 | 132 |
117 typedef SkTArray<SkPoint, true> PtArray; | 133 typedef SkTArray<SkPoint, true> PtArray; |
118 #define PREALLOC_PTARRAY(N) SkSTArray<(N),SkPoint, true> | 134 #define PREALLOC_PTARRAY(N) SkSTArray<(N),SkPoint, true> |
119 typedef SkTArray<int, true> IntArray; | 135 typedef SkTArray<int, true> IntArray; |
136 typedef SkTArray<float, true> FloatArray; | |
120 | 137 |
121 // Takes 178th time of logf on Z600 / VC2010 | 138 // Takes 178th time of logf on Z600 / VC2010 |
122 int get_float_exp(float x) { | 139 int get_float_exp(float x) { |
123 GR_STATIC_ASSERT(sizeof(int) == sizeof(float)); | 140 GR_STATIC_ASSERT(sizeof(int) == sizeof(float)); |
124 #if GR_DEBUG | 141 #if GR_DEBUG |
125 static bool tested; | 142 static bool tested; |
126 if (!tested) { | 143 if (!tested) { |
127 tested = true; | 144 tested = true; |
128 GrAssert(get_float_exp(0.25f) == -2); | 145 GrAssert(get_float_exp(0.25f) == -2); |
129 GrAssert(get_float_exp(0.3f) == -2); | 146 GrAssert(get_float_exp(0.3f) == -2); |
130 GrAssert(get_float_exp(0.5f) == -1); | 147 GrAssert(get_float_exp(0.5f) == -1); |
131 GrAssert(get_float_exp(1.f) == 0); | 148 GrAssert(get_float_exp(1.f) == 0); |
132 GrAssert(get_float_exp(2.f) == 1); | 149 GrAssert(get_float_exp(2.f) == 1); |
133 GrAssert(get_float_exp(2.5f) == 1); | 150 GrAssert(get_float_exp(2.5f) == 1); |
134 GrAssert(get_float_exp(8.f) == 3); | 151 GrAssert(get_float_exp(8.f) == 3); |
135 GrAssert(get_float_exp(100.f) == 6); | 152 GrAssert(get_float_exp(100.f) == 6); |
136 GrAssert(get_float_exp(1000.f) == 9); | 153 GrAssert(get_float_exp(1000.f) == 9); |
137 GrAssert(get_float_exp(1024.f) == 10); | 154 GrAssert(get_float_exp(1024.f) == 10); |
138 GrAssert(get_float_exp(3000000.f) == 21); | 155 GrAssert(get_float_exp(3000000.f) == 21); |
139 } | 156 } |
140 #endif | 157 #endif |
141 const int* iptr = (const int*)&x; | 158 const int* iptr = (const int*)&x; |
142 return (((*iptr) & 0x7f800000) >> 23) - 127; | 159 return (((*iptr) & 0x7f800000) >> 23) - 127; |
143 } | 160 } |
144 | 161 |
162 | |
163 // returns 0 if quad/conic is degen or close to it | |
164 // in this case approx the path with lines | |
165 // otherwise returns 1 | |
166 int is_degen_quad_conic(const SkPoint p[3]) { | |
bsalomon
2013/07/10 15:14:36
quad_or_conic?
| |
167 | |
168 static const SkScalar gDegenerateToLineTol = SK_Scalar1; | |
169 static const SkScalar gDegenerateToLineTolSqd = | |
170 SkScalarMul(gDegenerateToLineTol, gDegenerateToLineTol); | |
171 | |
172 if (p[0].distanceToSqd(p[1]) < gDegenerateToLineTolSqd || | |
173 p[1].distanceToSqd(p[2]) < gDegenerateToLineTolSqd) { | |
174 return 1; | |
175 } | |
176 | |
177 SkScalar dsqd = p[1].distanceToLineBetweenSqd(p[0], p[2]); | |
178 if (dsqd < gDegenerateToLineTolSqd) { | |
179 return 1; | |
180 } | |
181 | |
182 if (p[2].distanceToLineBetweenSqd(p[1], p[0]) < gDegenerateToLineTolSqd) { | |
183 return 1; | |
184 } | |
185 return 0; | |
186 } | |
187 | |
145 // we subdivide the quads to avoid huge overfill | 188 // we subdivide the quads to avoid huge overfill |
146 // if it returns -1 then should be drawn as lines | 189 // if it returns -1 then should be drawn as lines |
147 int num_quad_subdivs(const SkPoint p[3]) { | 190 int num_quad_subdivs(const SkPoint p[3]) { |
148 static const SkScalar gDegenerateToLineTol = SK_Scalar1; | 191 static const SkScalar gDegenerateToLineTol = SK_Scalar1; |
149 static const SkScalar gDegenerateToLineTolSqd = | 192 static const SkScalar gDegenerateToLineTolSqd = |
150 SkScalarMul(gDegenerateToLineTol, gDegenerateToLineTol); | 193 SkScalarMul(gDegenerateToLineTol, gDegenerateToLineTol); |
151 | 194 |
152 if (p[0].distanceToSqd(p[1]) < gDegenerateToLineTolSqd || | 195 if (p[0].distanceToSqd(p[1]) < gDegenerateToLineTolSqd || |
153 p[1].distanceToSqd(p[2]) < gDegenerateToLineTolSqd) { | 196 p[1].distanceToSqd(p[2]) < gDegenerateToLineTolSqd) { |
154 return -1; | 197 return -1; |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
200 * Quads are recorded in device space unless m contains | 243 * Quads are recorded in device space unless m contains |
201 * perspective, then in they are in src space. We do this because we will | 244 * perspective, then in they are in src space. We do this because we will |
202 * subdivide large quads to reduce over-fill. This subdivision has to be | 245 * subdivide large quads to reduce over-fill. This subdivision has to be |
203 * performed before applying the perspective matrix. | 246 * performed before applying the perspective matrix. |
204 */ | 247 */ |
205 int generate_lines_and_quads(const SkPath& path, | 248 int generate_lines_and_quads(const SkPath& path, |
206 const SkMatrix& m, | 249 const SkMatrix& m, |
207 const GrIRect& devClipBounds, | 250 const GrIRect& devClipBounds, |
208 PtArray* lines, | 251 PtArray* lines, |
209 PtArray* quads, | 252 PtArray* quads, |
210 IntArray* quadSubdivCnts) { | 253 PtArray* conics, |
254 IntArray* quadSubdivCnts, | |
255 FloatArray* conicWeights) { | |
211 SkPath::Iter iter(path, false); | 256 SkPath::Iter iter(path, false); |
212 | 257 |
213 int totalQuadCount = 0; | 258 int totalQuadCount = 0; |
214 GrRect bounds; | 259 GrRect bounds; |
215 GrIRect ibounds; | 260 GrIRect ibounds; |
216 | 261 |
217 bool persp = m.hasPerspective(); | 262 bool persp = m.hasPerspective(); |
218 | 263 |
219 for (;;) { | 264 for (;;) { |
220 GrPoint pathPts[4]; | 265 GrPoint pathPts[4]; |
221 GrPoint devPts[4]; | 266 GrPoint devPts[4]; |
222 SkPath::Verb verb = iter.next(pathPts); | 267 SkPath::Verb verb = iter.next(pathPts); |
223 switch (verb) { | 268 switch (verb) { |
224 case SkPath::kConic_Verb: | 269 case SkPath::kConic_Verb: { |
225 SkASSERT(0); | 270 SkScalar t = SkGetTQuadAtMaxCurvature(pathPts); |
bsalomon
2013/07/10 15:14:36
maybe this whole bit up to the for should be added
| |
271 int conicCnt = 1; | |
272 SkConic dst[2]; | |
273 if (t == 0) | |
274 { | |
bsalomon
2013/07/10 15:14:36
move {s up to prev line
| |
275 dst[0].set(pathPts, iter.conicWeight()); | |
276 } | |
277 else | |
278 { | |
279 SkConic conic; | |
280 conic.set(pathPts, iter.conicWeight()); | |
281 conic.chopAt(t, dst); | |
282 conicCnt = 2; | |
283 } | |
284 for (int i = 0; i < conicCnt; ++i) { | |
285 SkPoint* chopPnts = dst[i].fPts; | |
286 m.mapPoints(devPts, chopPnts, 3); | |
287 bounds.setBounds(devPts, 3); | |
288 bounds.outset(SK_Scalar1, SK_Scalar1); | |
289 bounds.roundOut(&ibounds); | |
290 if (SkIRect::Intersects(devClipBounds, ibounds)) { | |
291 if (is_degen_quad_conic(devPts)) { | |
292 SkPoint* pts = lines->push_back_n(4); | |
293 pts[0] = devPts[0]; | |
294 pts[1] = devPts[1]; | |
295 pts[2] = devPts[1]; | |
296 pts[3] = devPts[2]; | |
297 } else { | |
298 // when in perspective keep conics in src space ??? | |
bsalomon
2013/07/10 15:14:36
should test this... but yes. The later chopping th
| |
299 SkPoint* cPts = persp ? chopPnts : devPts; | |
300 SkPoint* pts = conics->push_back_n(3); | |
301 pts[0] = cPts[0]; | |
302 pts[1] = cPts[1]; | |
303 pts[2] = cPts[2]; | |
304 conicWeights->push_back() = dst[i].fW; | |
305 } | |
306 } | |
307 } | |
308 } | |
226 break; | 309 break; |
227 case SkPath::kMove_Verb: | 310 case SkPath::kMove_Verb: |
228 break; | 311 break; |
229 case SkPath::kLine_Verb: | 312 case SkPath::kLine_Verb: |
230 m.mapPoints(devPts, pathPts, 2); | 313 m.mapPoints(devPts, pathPts, 2); |
231 bounds.setBounds(devPts, 2); | 314 bounds.setBounds(devPts, 2); |
232 bounds.outset(SK_Scalar1, SK_Scalar1); | 315 bounds.outset(SK_Scalar1, SK_Scalar1); |
233 bounds.roundOut(&ibounds); | 316 bounds.roundOut(&ibounds); |
234 if (SkIRect::Intersects(devClipBounds, ibounds)) { | 317 if (SkIRect::Intersects(devClipBounds, ibounds)) { |
235 SkPoint* pts = lines->push_back_n(2); | 318 SkPoint* pts = lines->push_back_n(2); |
236 pts[0] = devPts[0]; | 319 pts[0] = devPts[0]; |
237 pts[1] = devPts[1]; | 320 pts[1] = devPts[1]; |
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
341 } | 424 } |
342 | 425 |
343 struct Vertex { | 426 struct Vertex { |
344 GrPoint fPos; | 427 GrPoint fPos; |
345 union { | 428 union { |
346 struct { | 429 struct { |
347 SkScalar fA; | 430 SkScalar fA; |
348 SkScalar fB; | 431 SkScalar fB; |
349 SkScalar fC; | 432 SkScalar fC; |
350 } fLine; | 433 } fLine; |
434 struct { | |
435 SkScalar fA; | |
436 SkScalar fB; | |
437 SkScalar fC; | |
438 SkScalar fD; | |
439 SkScalar fE; | |
440 SkScalar fF; | |
441 } fConic; | |
351 GrVec fQuadCoord; | 442 GrVec fQuadCoord; |
352 struct { | 443 struct { |
353 SkScalar fBogus[4]; | 444 SkScalar fBogus[6]; |
354 }; | 445 }; |
355 }; | 446 }; |
356 }; | 447 }; |
357 GR_STATIC_ASSERT(sizeof(Vertex) == 3 * sizeof(GrPoint)); | 448 |
449 GR_STATIC_ASSERT(sizeof(Vertex) == 4 * sizeof(GrPoint)); | |
358 | 450 |
359 void intersect_lines(const SkPoint& ptA, const SkVector& normA, | 451 void intersect_lines(const SkPoint& ptA, const SkVector& normA, |
360 const SkPoint& ptB, const SkVector& normB, | 452 const SkPoint& ptB, const SkVector& normB, |
361 SkPoint* result) { | 453 SkPoint* result) { |
362 | 454 |
363 SkScalar lineAW = -normA.dot(ptA); | 455 SkScalar lineAW = -normA.dot(ptA); |
364 SkScalar lineBW = -normB.dot(ptB); | 456 SkScalar lineBW = -normB.dot(ptB); |
365 | 457 |
366 SkScalar wInv = SkScalarMul(normA.fX, normB.fY) - | 458 SkScalar wInv = SkScalarMul(normA.fX, normB.fY) - |
367 SkScalarMul(normA.fY, normB.fX); | 459 SkScalarMul(normA.fY, normB.fX); |
368 wInv = SkScalarInvert(wInv); | 460 wInv = SkScalarInvert(wInv); |
369 | 461 |
370 result->fX = SkScalarMul(normA.fY, lineBW) - SkScalarMul(lineAW, normB.fY); | 462 result->fX = SkScalarMul(normA.fY, lineBW) - SkScalarMul(lineAW, normB.fY); |
371 result->fX = SkScalarMul(result->fX, wInv); | 463 result->fX = SkScalarMul(result->fX, wInv); |
372 | 464 |
373 result->fY = SkScalarMul(lineAW, normB.fX) - SkScalarMul(normA.fX, lineBW); | 465 result->fY = SkScalarMul(lineAW, normB.fX) - SkScalarMul(normA.fX, lineBW); |
374 result->fY = SkScalarMul(result->fY, wInv); | 466 result->fY = SkScalarMul(result->fY, wInv); |
375 } | 467 } |
376 | 468 |
377 void bloat_quad(const SkPoint qpts[3], const SkMatrix* toDevice, | 469 void bloat_quad(const SkPoint qpts[3], const SkMatrix* toDevice, |
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
447 // include it. | 539 // include it. |
448 intersect_lines(a0.fPos, abN, c0.fPos, cbN, &b0.fPos); | 540 intersect_lines(a0.fPos, abN, c0.fPos, cbN, &b0.fPos); |
449 devBounds->growToInclude(b0.fPos.fX, b0.fPos.fY); | 541 devBounds->growToInclude(b0.fPos.fX, b0.fPos.fY); |
450 | 542 |
451 if (toSrc) { | 543 if (toSrc) { |
452 toSrc->mapPointsWithStride(&verts[0].fPos, sizeof(Vertex), kVertsPerQuad ); | 544 toSrc->mapPointsWithStride(&verts[0].fPos, sizeof(Vertex), kVertsPerQuad ); |
453 } | 545 } |
454 DevToUV.apply<kVertsPerQuad, sizeof(Vertex), sizeof(GrPoint)>(verts); | 546 DevToUV.apply<kVertsPerQuad, sizeof(Vertex), sizeof(GrPoint)>(verts); |
455 } | 547 } |
456 | 548 |
549 | |
550 // Input Parametric: | |
551 // 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) | |
552 // Output Implicit: | |
553 // Ax^2 + Bxy + Cy^2 + Dx + Ey + F = 0 | |
554 // A = 4w^2*(y0-y1)(y1-y2)-(y0-y2)^2 | |
555 // B = 4w^2*((x0-x1)(y2-y1)+(x1-x2)(y1-y0)) + 2(x0-x2)(y0-y2) | |
556 // C = 4w^2(x0-x1)(x1-x2) - (x0-x2)^2 | |
557 // D = 4w^2((x0y1-x1y0)(y1-y2)+(x1y2-x2y1)(y0-y1)) + 2(y2-y0)(x0y2-x2y0) | |
558 // E = 4w^2((y0x1-y1x0)(x1-x2)+(y1x2-y2x1)(x0-x1)) + 2(x2-x0)(y0x2-y2x0) | |
559 // F = 4w^2(x1y2-x2y1)(x0y1-x1y0) - (x2y0-x0y2)^2 | |
560 | |
561 void set_conic_coeffs(const SkPoint p[3], Vertex verts[kVertsPerConic], const fl oat weight) { | |
562 const float ww4 = 4 * weight * weight; | |
563 const float x0Mx1 = p[0].fX - p[1].fX; | |
564 const float x1Mx2 = p[1].fX - p[2].fX; | |
565 const float x0Mx2 = p[0].fX - p[2].fX; | |
566 const float y0My1 = p[0].fY - p[1].fY; | |
567 const float y1My2 = p[1].fY - p[2].fY; | |
568 const float y0My2 = p[0].fY - p[2].fY; | |
569 const float x0y1Mx1y0 = p[0].fX*p[1].fY - p[1].fX*p[0].fY; | |
570 const float x1y2Mx2y1 = p[1].fX*p[2].fY - p[2].fX*p[1].fY; | |
571 const float x0y2Mx2y0 = p[0].fX*p[2].fY - p[2].fX*p[0].fY; | |
572 const float a = ww4 * y0My1 * y1My2 - y0My2 * y0My2; | |
573 const float b = -ww4 * (x0Mx1 * y1My2 + x1Mx2 * y0My1) + 2 * x0Mx2 * y0My2; | |
574 const float c = ww4 * x0Mx1 * x1Mx2 - x0Mx2 * x0Mx2; | |
575 const float d = ww4 * (x0y1Mx1y0 * y1My2 + x1y2Mx2y1 * y0My1) - 2 * y0My2 * x0y2Mx2y0; | |
576 const float e = -ww4 * (x0y1Mx1y0 * x1Mx2 + x1y2Mx2y1 * x0Mx1) + 2 * x0Mx2 * x0y2Mx2y0; | |
577 const float f = ww4 * x1y2Mx2y1 * x0y1Mx1y0 - x0y2Mx2y0 * x0y2Mx2y0; | |
578 | |
579 for (int i = 0; i < kVertsPerConic; ++i) { | |
580 verts[i].fConic.fA = a/f; | |
581 verts[i].fConic.fB = b/f; | |
582 verts[i].fConic.fC = c/f; | |
583 verts[i].fConic.fD = d/f; | |
584 verts[i].fConic.fE = e/f; | |
585 verts[i].fConic.fF = f/f; | |
586 } | |
587 } | |
588 | |
589 void add_conics(const SkPoint p[3], | |
590 float weight, | |
591 const SkMatrix* toDevice, | |
592 const SkMatrix* toSrc, | |
593 Vertex** vert, | |
594 SkRect* devBounds) { | |
595 bloat_quad(p, toDevice, toSrc, *vert, devBounds); | |
596 set_conic_coeffs(p, *vert, weight); | |
597 *vert += kVertsPerConic; | |
598 } | |
599 | |
457 void add_quads(const SkPoint p[3], | 600 void add_quads(const SkPoint p[3], |
458 int subdiv, | 601 int subdiv, |
459 const SkMatrix* toDevice, | 602 const SkMatrix* toDevice, |
460 const SkMatrix* toSrc, | 603 const SkMatrix* toSrc, |
461 Vertex** vert, | 604 Vertex** vert, |
462 SkRect* devBounds) { | 605 SkRect* devBounds) { |
463 GrAssert(subdiv >= 0); | 606 GrAssert(subdiv >= 0); |
464 if (subdiv) { | 607 if (subdiv) { |
465 SkPoint newP[5]; | 608 SkPoint newP[5]; |
466 SkChopQuadAtHalf(p, newP); | 609 SkChopQuadAtHalf(p, newP); |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
508 (*vert)[1].fPos.set(SK_ScalarMax, SK_ScalarMax); | 651 (*vert)[1].fPos.set(SK_ScalarMax, SK_ScalarMax); |
509 (*vert)[2].fPos.set(SK_ScalarMax, SK_ScalarMax); | 652 (*vert)[2].fPos.set(SK_ScalarMax, SK_ScalarMax); |
510 (*vert)[3].fPos.set(SK_ScalarMax, SK_ScalarMax); | 653 (*vert)[3].fPos.set(SK_ScalarMax, SK_ScalarMax); |
511 } | 654 } |
512 | 655 |
513 *vert += kVertsPerLineSeg; | 656 *vert += kVertsPerLineSeg; |
514 } | 657 } |
515 | 658 |
516 } | 659 } |
517 | 660 |
661 /** | |
662 * The output of this effect is a hairline edge for conics. | |
663 * Conics specified by implicit equation Ax^2 + Bxy + Cy^2 + Dx + Ey + F = 0. | |
664 * A, B, C, D are the first vec4 of vertex attributes and | |
665 * E and F are the vec2 attached to 2nd vertex attrribute. | |
666 * Coverage is max(0, 1-distance). | |
667 */ | |
668 class HairConicEdgeEffect : public GrEffect { | |
669 public: | |
670 | |
671 static GrEffectRef* Create() { | |
672 GR_CREATE_STATIC_EFFECT(gHairConicEdgeEffect, HairConicEdgeEffect, ()); | |
673 gHairConicEdgeEffect->ref(); | |
674 return gHairConicEdgeEffect; | |
675 } | |
676 | |
677 virtual ~HairConicEdgeEffect() {} | |
678 | |
679 static const char* Name() { return "HairConicEdge"; } | |
680 | |
681 virtual void getConstantColorComponents(GrColor* color, | |
682 uint32_t* validFlags) const SK_OVERR IDE { | |
683 *validFlags = 0; | |
684 } | |
685 | |
686 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE { | |
687 return GrTBackendEffectFactory<HairConicEdgeEffect>::getInstance(); | |
688 } | |
689 | |
690 class GLEffect : public GrGLEffect { | |
691 public: | |
692 GLEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&) | |
693 : INHERITED (factory) {} | |
694 | |
695 virtual void emitCode(GrGLShaderBuilder* builder, | |
696 const GrDrawEffect& drawEffect, | |
697 EffectKey key, | |
698 const char* outputColor, | |
699 const char* inputColor, | |
700 const TextureSamplerArray& samplers) SK_OVERRIDE { | |
701 const char *vsCoeffABCDName, *fsCoeffABCDName; | |
702 const char *vsCoeffEFName, *fsCoeffEFName; | |
703 | |
704 SkAssertResult(builder->enableFeature( | |
705 GrGLShaderBuilder::kStandardDerivatives_GLSLFeature)); | |
706 builder->addVarying(kVec4f_GrSLType, "ConicCoeffsABCD", | |
707 &vsCoeffABCDName, &fsCoeffABCDName); | |
708 const SkString* attr0Name = | |
709 builder->getEffectAttributeName(drawEffect.getVertexAttribIndice s()[0]); | |
710 builder->vsCodeAppendf("\t%s = %s;\n", vsCoeffABCDName, attr0Name->c _str()); | |
711 | |
712 builder->addVarying(kVec2f_GrSLType, "ConicCoeffsEF", | |
713 &vsCoeffEFName, &fsCoeffEFName); | |
714 const SkString* attr1Name = | |
715 builder->getEffectAttributeName(drawEffect.getVertexAttribIndice s()[1]); | |
716 builder->vsCodeAppendf("\t%s = %s;\n", vsCoeffEFName, attr1Name->c_s tr()); | |
717 | |
718 // Based on Gustavson 2006: "Beyond the Pixel: towards infinite reso lution textures" | |
719 builder->fsCodeAppendf("\t\tfloat edgeAlpha;\n"); | |
720 | |
721 builder->fsCodeAppendf("\t\tvec3 uv1 = vec3(%s.xy, 1);\n", builder-> fragmentPosition()); | |
722 builder->fsCodeAppend("\t\tvec3 u2uvv2 = uv1.xxy * uv1.xyy;\n"); | |
723 builder->fsCodeAppendf("\t\tvec3 ABC = %s.xyz;\n", fsCoeffABCDName); | |
724 builder->fsCodeAppendf("\t\tvec3 DEF = vec3(%s.w, %s.xy);\n", | |
725 fsCoeffABCDName, fsCoeffEFName); | |
726 | |
727 builder->fsCodeAppend("\t\tfloat dfdx = dot(uv1,vec3(2.0*ABC.x,ABC.y ,DEF.x));\n"); | |
728 builder->fsCodeAppend("\t\tfloat dfdy = dot(uv1,vec3(ABC.y, 2.0*ABC. z,DEF.y));\n"); | |
729 builder->fsCodeAppend("\t\tfloat gF = dfdx*dfdx + dfdy*dfdy;\n"); | |
730 builder->fsCodeAppend("\t\tedgeAlpha = dot(ABC,u2uvv2) + dot(DEF,uv1 );\n"); | |
731 builder->fsCodeAppend("\t\tedgeAlpha = sqrt(edgeAlpha*edgeAlpha / gF );\n"); | |
732 builder->fsCodeAppend("\t\tedgeAlpha = max((1.0 - edgeAlpha), 0.0);\ n"); | |
733 // Add line below for smooth cubic ramp | |
734 // builder->fsCodeAppend("\t\tedgeAlpha = edgeAlpha*edgeAlpha*(3.0-2 .0*edgeAlpha);\n"); | |
735 | |
736 SkString modulate; | |
737 GrGLSLModulatef<4>(&modulate, inputColor, "edgeAlpha"); | |
738 builder->fsCodeAppendf("\t%s = %s;\n", outputColor, modulate.c_str() ); | |
739 | |
740 } | |
741 | |
742 static inline EffectKey GenKey(const GrDrawEffect& drawEffect, const GrG LCaps&) { | |
743 return 0x0; | |
744 } | |
745 | |
746 virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_ OVERRIDE {} | |
747 | |
748 private: | |
749 typedef GrGLEffect INHERITED; | |
750 }; | |
751 | |
752 private: | |
753 HairConicEdgeEffect() { | |
754 this->addVertexAttrib(kVec4f_GrSLType); | |
755 this->addVertexAttrib(kVec2f_GrSLType); | |
756 this->setWillReadFragmentPosition(); | |
757 } | |
758 | |
759 virtual bool onIsEqual(const GrEffect& other) const SK_OVERRIDE { | |
760 return true; | |
761 } | |
762 | |
763 GR_DECLARE_EFFECT_TEST; | |
764 | |
765 typedef GrEffect INHERITED; | |
766 }; | |
767 | |
768 GR_DEFINE_EFFECT_TEST(HairConicEdgeEffect); | |
769 | |
770 GrEffectRef* HairConicEdgeEffect::TestCreate(SkMWCRandom* random, | |
771 GrContext*, | |
772 const GrDrawTargetCaps& caps, | |
773 GrTexture*[]) { | |
774 return HairConicEdgeEffect::Create(); | |
775 } | |
518 /////////////////////////////////////////////////////////////////////////////// | 776 /////////////////////////////////////////////////////////////////////////////// |
519 | 777 |
520 /** | 778 /** |
521 * The output of this effect is a hairline edge for quadratics. | 779 * The output of this effect is a hairline edge for quadratics. |
522 * Quadratic specified by 0=u^2-v canonical coords. u and v are the first | 780 * Quadratic specified by 0=u^2-v canonical coords. u and v are the first |
523 * two components of the vertex attribute. Uses unsigned distance. | 781 * two components of the vertex attribute. Uses unsigned distance. |
524 * Coverage is min(0, 1-distance). 3rd & 4th component unused. | 782 * Coverage is min(0, 1-distance). 3rd & 4th component unused. |
525 * Requires shader derivative instruction support. | 783 * Requires shader derivative instruction support. |
526 */ | 784 */ |
527 class HairQuadEdgeEffect : public GrEffect { | 785 class HairQuadEdgeEffect : public GrEffect { |
(...skipping 28 matching lines...) Expand all Loading... | |
556 EffectKey key, | 814 EffectKey key, |
557 const char* outputColor, | 815 const char* outputColor, |
558 const char* inputColor, | 816 const char* inputColor, |
559 const TextureSamplerArray& samplers) SK_OVERRIDE { | 817 const TextureSamplerArray& samplers) SK_OVERRIDE { |
560 const char *vsName, *fsName; | 818 const char *vsName, *fsName; |
561 const SkString* attrName = | 819 const SkString* attrName = |
562 builder->getEffectAttributeName(drawEffect.getVertexAttribIndice s()[0]); | 820 builder->getEffectAttributeName(drawEffect.getVertexAttribIndice s()[0]); |
563 builder->fsCodeAppendf("\t\tfloat edgeAlpha;\n"); | 821 builder->fsCodeAppendf("\t\tfloat edgeAlpha;\n"); |
564 | 822 |
565 SkAssertResult(builder->enableFeature( | 823 SkAssertResult(builder->enableFeature( |
566 GrGLShaderBuilder::kStandardDeriva tives_GLSLFeature)); | 824 GrGLShaderBuilder::kStandardDerivatives_GLSLFeature)); |
567 builder->addVarying(kVec4f_GrSLType, "HairQuadEdge", &vsName, &fsNam e); | 825 builder->addVarying(kVec4f_GrSLType, "HairQuadEdge", &vsName, &fsNam e); |
568 | 826 |
569 builder->fsCodeAppendf("\t\tvec2 duvdx = dFdx(%s.xy);\n", fsName); | 827 builder->fsCodeAppendf("\t\tvec2 duvdx = dFdx(%s.xy);\n", fsName); |
570 builder->fsCodeAppendf("\t\tvec2 duvdy = dFdy(%s.xy);\n", fsName); | 828 builder->fsCodeAppendf("\t\tvec2 duvdy = dFdy(%s.xy);\n", fsName); |
571 builder->fsCodeAppendf("\t\tvec2 gF = vec2(2.0*%s.x*duvdx.x - duvdx. y,\n" | 829 builder->fsCodeAppendf("\t\tvec2 gF = vec2(2.0*%s.x*duvdx.x - duvdx. y,\n" |
572 "\t\t 2.0*%s.x*duvdy.x - duvdy. y);\n", | 830 "\t\t 2.0*%s.x*duvdy.x - duvdy. y);\n", |
573 fsName, fsName); | 831 fsName, fsName); |
574 builder->fsCodeAppendf("\t\tedgeAlpha = (%s.x*%s.x - %s.y);\n", fsNa me, fsName, | 832 builder->fsCodeAppendf("\t\tedgeAlpha = (%s.x*%s.x - %s.y);\n", fsNa me, fsName, |
575 fsName); | 833 fsName); |
576 builder->fsCodeAppend("\t\tedgeAlpha = sqrt(edgeAlpha*edgeAlpha / do t(gF, gF));\n"); | 834 builder->fsCodeAppend("\t\tedgeAlpha = sqrt(edgeAlpha*edgeAlpha / do t(gF, gF));\n"); |
(...skipping 30 matching lines...) Expand all Loading... | |
607 typedef GrEffect INHERITED; | 865 typedef GrEffect INHERITED; |
608 }; | 866 }; |
609 | 867 |
610 GR_DEFINE_EFFECT_TEST(HairQuadEdgeEffect); | 868 GR_DEFINE_EFFECT_TEST(HairQuadEdgeEffect); |
611 | 869 |
612 GrEffectRef* HairQuadEdgeEffect::TestCreate(SkMWCRandom* random, | 870 GrEffectRef* HairQuadEdgeEffect::TestCreate(SkMWCRandom* random, |
613 GrContext*, | 871 GrContext*, |
614 const GrDrawTargetCaps& caps, | 872 const GrDrawTargetCaps& caps, |
615 GrTexture*[]) { | 873 GrTexture*[]) { |
616 // Doesn't work without derivative instructions. | 874 // Doesn't work without derivative instructions. |
617 return caps.shaderDerivativeSupport() ? HairQuadEdgeEffect::Create() : NULL; } | 875 return caps.shaderDerivativeSupport() ? HairQuadEdgeEffect::Create() : NULL; |
876 } | |
618 | 877 |
619 /////////////////////////////////////////////////////////////////////////////// | 878 /////////////////////////////////////////////////////////////////////////////// |
620 | 879 |
621 /** | 880 /** |
622 * The output of this effect is a 1-pixel wide line. | 881 * The output of this effect is a 1-pixel wide line. |
623 * Input is 2D implicit device coord line eq (a*x + b*y +c = 0). 4th component u nused. | 882 * Input is 2D implicit device coord line eq (a*x + b*y +c = 0). 4th component u nused. |
624 */ | 883 */ |
625 class HairLineEdgeEffect : public GrEffect { | 884 class HairLineEdgeEffect : public GrEffect { |
626 public: | 885 public: |
627 | 886 |
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
710 /////////////////////////////////////////////////////////////////////////////// | 969 /////////////////////////////////////////////////////////////////////////////// |
711 | 970 |
712 namespace { | 971 namespace { |
713 | 972 |
714 // position + edge | 973 // position + edge |
715 extern const GrVertexAttrib gHairlineAttribs[] = { | 974 extern const GrVertexAttrib gHairlineAttribs[] = { |
716 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBind ing}, | 975 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBind ing}, |
717 {kVec4f_GrVertexAttribType, sizeof(GrPoint), kEffect_GrVertexAttribBindin g} | 976 {kVec4f_GrVertexAttribType, sizeof(GrPoint), kEffect_GrVertexAttribBindin g} |
718 }; | 977 }; |
719 | 978 |
979 // Conic | |
980 // position + ABCD + EF | |
981 extern const GrVertexAttrib gConicVertexAttribs[] = { | |
982 { kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBind ing }, | |
983 { kVec4f_GrVertexAttribType, sizeof(GrPoint), kEffect_GrVertexAttribBindin g }, | |
984 { kVec2f_GrVertexAttribType, 3*sizeof(GrPoint), kEffect_GrVertexAttribBindin g } | |
985 }; | |
720 }; | 986 }; |
721 | 987 |
722 bool GrAAHairLinePathRenderer::createGeom( | 988 bool GrAAHairLinePathRenderer::createGeom( |
723 const SkPath& path, | 989 const SkPath& path, |
724 GrDrawTarget* target, | 990 GrDrawTarget* target, |
725 int* lineCnt, | 991 int* lineCnt, |
726 int* quadCnt, | 992 int* quadCnt, |
993 int* conicCnt, | |
727 GrDrawTarget::AutoReleaseGeometry* arg, | 994 GrDrawTarget::AutoReleaseGeometry* arg, |
728 SkRect* devBounds) { | 995 SkRect* devBounds) { |
729 GrDrawState* drawState = target->drawState(); | 996 GrDrawState* drawState = target->drawState(); |
730 int rtHeight = drawState->getRenderTarget()->height(); | 997 int rtHeight = drawState->getRenderTarget()->height(); |
731 | 998 |
732 GrIRect devClipBounds; | 999 GrIRect devClipBounds; |
733 target->getClip()->getConservativeBounds(drawState->getRenderTarget(), &devC lipBounds); | 1000 target->getClip()->getConservativeBounds(drawState->getRenderTarget(), &devC lipBounds); |
734 | 1001 |
735 SkMatrix viewM = drawState->getViewMatrix(); | 1002 SkMatrix viewM = drawState->getViewMatrix(); |
736 | 1003 |
737 // All the vertices that we compute are within 1 of path control points with the exception of | 1004 // All the vertices that we compute are within 1 of path control points with the exception of |
738 // one of the bounding vertices for each quad. The add_quads() function will update the bounds | 1005 // one of the bounding vertices for each quad. The add_quads() function will update the bounds |
739 // for each quad added. | 1006 // for each quad added. |
740 *devBounds = path.getBounds(); | 1007 *devBounds = path.getBounds(); |
741 viewM.mapRect(devBounds); | 1008 viewM.mapRect(devBounds); |
742 devBounds->outset(SK_Scalar1, SK_Scalar1); | 1009 devBounds->outset(SK_Scalar1, SK_Scalar1); |
743 | 1010 |
744 PREALLOC_PTARRAY(128) lines; | 1011 PREALLOC_PTARRAY(128) lines; |
745 PREALLOC_PTARRAY(128) quads; | 1012 PREALLOC_PTARRAY(128) quads; |
1013 PREALLOC_PTARRAY(128) conics; | |
746 IntArray qSubdivs; | 1014 IntArray qSubdivs; |
1015 FloatArray cWeights; | |
747 *quadCnt = generate_lines_and_quads(path, viewM, devClipBounds, | 1016 *quadCnt = generate_lines_and_quads(path, viewM, devClipBounds, |
748 &lines, &quads, &qSubdivs); | 1017 &lines, &quads, &conics, &qSubdivs, &cWe ights); |
749 | 1018 |
750 *lineCnt = lines.count() / 2; | 1019 *lineCnt = lines.count() / 2; |
751 int vertCnt = kVertsPerLineSeg * *lineCnt + kVertsPerQuad * *quadCnt; | 1020 *conicCnt = conics.count() / 3; |
1021 int vertCnt = kVertsPerLineSeg * *lineCnt + kVertsPerQuad * *quadCnt + | |
1022 kVertsPerConic * *conicCnt; | |
752 | 1023 |
753 target->drawState()->setVertexAttribs<gHairlineAttribs>(SK_ARRAY_COUNT(gHair lineAttribs)); | 1024 target->drawState()->setVertexAttribs<gConicVertexAttribs>(SK_ARRAY_COUNT(gC onicVertexAttribs)); |
754 GrAssert(sizeof(Vertex) == target->getDrawState().getVertexSize()); | 1025 GrAssert(sizeof(Vertex) == target->getDrawState().getVertexSize()); |
755 | 1026 |
756 if (!arg->set(target, vertCnt, 0)) { | 1027 if (!arg->set(target, vertCnt, 0)) { |
757 return false; | 1028 return false; |
758 } | 1029 } |
759 | 1030 |
760 Vertex* verts = reinterpret_cast<Vertex*>(arg->vertices()); | 1031 Vertex* verts = reinterpret_cast<Vertex*>(arg->vertices()); |
761 | 1032 |
762 const SkMatrix* toDevice = NULL; | 1033 const SkMatrix* toDevice = NULL; |
763 const SkMatrix* toSrc = NULL; | 1034 const SkMatrix* toSrc = NULL; |
764 SkMatrix ivm; | 1035 SkMatrix ivm; |
765 | 1036 |
766 if (viewM.hasPerspective()) { | 1037 if (viewM.hasPerspective()) { |
767 if (viewM.invert(&ivm)) { | 1038 if (viewM.invert(&ivm)) { |
768 toDevice = &viewM; | 1039 toDevice = &viewM; |
769 toSrc = &ivm; | 1040 toSrc = &ivm; |
770 } | 1041 } |
771 } | 1042 } |
772 | 1043 |
773 for (int i = 0; i < *lineCnt; ++i) { | 1044 for (int i = 0; i < *lineCnt; ++i) { |
774 add_line(&lines[2*i], rtHeight, toSrc, &verts); | 1045 add_line(&lines[2*i], rtHeight, toSrc, &verts); |
775 } | 1046 } |
776 | 1047 |
777 int unsubdivQuadCnt = quads.count() / 3; | 1048 int unsubdivQuadCnt = quads.count() / 3; |
778 for (int i = 0; i < unsubdivQuadCnt; ++i) { | 1049 for (int i = 0; i < unsubdivQuadCnt; ++i) { |
779 GrAssert(qSubdivs[i] >= 0); | 1050 GrAssert(qSubdivs[i] >= 0); |
780 add_quads(&quads[3*i], qSubdivs[i], toDevice, toSrc, &verts, devBounds); | 1051 add_quads(&quads[3*i], qSubdivs[i], toDevice, toSrc, &verts, devBounds); |
781 } | 1052 } |
782 | 1053 |
1054 // Start Conics | |
1055 for (int i = 0; i < *conicCnt; ++i) { | |
1056 add_conics(&conics[3*i], cWeights[i], toDevice, toSrc, &verts, devBounds ); | |
1057 } | |
783 return true; | 1058 return true; |
784 } | 1059 } |
785 | 1060 |
786 bool GrAAHairLinePathRenderer::canDrawPath(const SkPath& path, | 1061 bool GrAAHairLinePathRenderer::canDrawPath(const SkPath& path, |
787 const SkStrokeRec& stroke, | 1062 const SkStrokeRec& stroke, |
788 const GrDrawTarget* target, | 1063 const GrDrawTarget* target, |
789 bool antiAlias) const { | 1064 bool antiAlias) const { |
790 if (!stroke.isHairlineStyle() || !antiAlias) { | 1065 if (!stroke.isHairlineStyle() || !antiAlias) { |
791 return false; | 1066 return false; |
792 } | 1067 } |
793 | 1068 |
794 static const uint32_t gReqDerivMask = SkPath::kCubic_SegmentMask | | 1069 static const uint32_t gReqDerivMask = SkPath::kCubic_SegmentMask | |
795 SkPath::kQuad_SegmentMask; | 1070 SkPath::kQuad_SegmentMask; |
796 if (!target->caps()->shaderDerivativeSupport() && | 1071 if (!target->caps()->shaderDerivativeSupport() && |
797 (gReqDerivMask & path.getSegmentMasks())) { | 1072 (gReqDerivMask & path.getSegmentMasks())) { |
798 return false; | 1073 return false; |
799 } | 1074 } |
800 return true; | 1075 return true; |
801 } | 1076 } |
802 | 1077 |
803 bool GrAAHairLinePathRenderer::onDrawPath(const SkPath& path, | 1078 bool GrAAHairLinePathRenderer::onDrawPath(const SkPath& path, |
804 const SkStrokeRec&, | 1079 const SkStrokeRec&, |
805 GrDrawTarget* target, | 1080 GrDrawTarget* target, |
806 bool antiAlias) { | 1081 bool antiAlias) { |
807 | 1082 |
808 int lineCnt; | 1083 int lineCnt; |
809 int quadCnt; | 1084 int quadCnt; |
1085 int conicCnt; | |
810 GrDrawTarget::AutoReleaseGeometry arg; | 1086 GrDrawTarget::AutoReleaseGeometry arg; |
811 SkRect devBounds; | 1087 SkRect devBounds; |
812 | 1088 |
813 if (!this->createGeom(path, | 1089 if (!this->createGeom(path, |
814 target, | 1090 target, |
815 &lineCnt, | 1091 &lineCnt, |
816 &quadCnt, | 1092 &quadCnt, |
1093 &conicCnt, | |
817 &arg, | 1094 &arg, |
818 &devBounds)) { | 1095 &devBounds)) { |
819 return false; | 1096 return false; |
820 } | 1097 } |
821 | 1098 |
822 GrDrawTarget::AutoStateRestore asr; | 1099 GrDrawTarget::AutoStateRestore asr; |
823 | 1100 |
824 // createGeom transforms the geometry to device space when the matrix does n ot have | 1101 // createGeom transforms the geometry to device space when the matrix does n ot have |
825 // perspective. | 1102 // perspective. |
826 if (target->getDrawState().getViewMatrix().hasPerspective()) { | 1103 if (target->getDrawState().getViewMatrix().hasPerspective()) { |
827 asr.set(target, GrDrawTarget::kPreserve_ASRInit); | 1104 asr.set(target, GrDrawTarget::kPreserve_ASRInit); |
828 } else if (!asr.setIdentity(target, GrDrawTarget::kPreserve_ASRInit)) { | 1105 } else if (!asr.setIdentity(target, GrDrawTarget::kPreserve_ASRInit)) { |
829 return false; | 1106 return false; |
830 } | 1107 } |
831 GrDrawState* drawState = target->drawState(); | 1108 GrDrawState* drawState = target->drawState(); |
832 | 1109 |
833 // TODO: See whether rendering lines as degenerate quads improves perf | 1110 // TODO: See whether rendering lines as degenerate quads improves perf |
834 // when we have a mix | 1111 // when we have a mix |
835 | 1112 |
836 enum { | 1113 enum { |
837 // the edge effects share this stage with glyph rendering | 1114 // the edge effects share this stage with glyph rendering |
838 // (kGlyphMaskStage in GrTextContext) && SW path rendering | 1115 // (kGlyphMaskStage in GrTextContext) && SW path rendering |
839 // (kPathMaskStage in GrSWMaskHelper) | 1116 // (kPathMaskStage in GrSWMaskHelper) |
840 kEdgeEffectStage = GrPaint::kTotalStages, | 1117 kEdgeEffectStage = GrPaint::kTotalStages, |
841 }; | 1118 }; |
842 static const int kEdgeAttrIndex = 1; | 1119 static const int kEdgeAttrIndex = 1; |
843 | 1120 |
844 GrEffectRef* hairLineEffect = HairLineEdgeEffect::Create(); | 1121 GrEffectRef* hairLineEffect = HairLineEdgeEffect::Create(); |
845 GrEffectRef* hairQuadEffect = HairQuadEdgeEffect::Create(); | 1122 GrEffectRef* hairQuadEffect = HairQuadEdgeEffect::Create(); |
1123 GrEffectRef* hairConicEffect = HairConicEdgeEffect::Create(); | |
846 | 1124 |
847 // Check devBounds | 1125 // Check devBounds |
848 #if GR_DEBUG | 1126 #if GR_DEBUG |
849 SkRect tolDevBounds = devBounds; | 1127 SkRect tolDevBounds = devBounds; |
850 tolDevBounds.outset(SK_Scalar1 / 10000, SK_Scalar1 / 10000); | 1128 tolDevBounds.outset(SK_Scalar1 / 10000, SK_Scalar1 / 10000); |
851 SkRect actualBounds; | 1129 SkRect actualBounds; |
852 Vertex* verts = reinterpret_cast<Vertex*>(arg.vertices()); | 1130 Vertex* verts = reinterpret_cast<Vertex*>(arg.vertices()); |
853 int vCount = kVertsPerLineSeg * lineCnt + kVertsPerQuad * quadCnt; | 1131 int vCount = kVertsPerLineSeg * lineCnt + kVertsPerQuad * quadCnt + kVertsPe rConic * conicCnt; |
854 bool first = true; | 1132 bool first = true; |
855 for (int i = 0; i < vCount; ++i) { | 1133 for (int i = 0; i < vCount; ++i) { |
856 SkPoint pos = verts[i].fPos; | 1134 SkPoint pos = verts[i].fPos; |
857 // This is a hack to workaround the fact that we move some degenerate se gments offscreen. | 1135 // This is a hack to workaround the fact that we move some degenerate se gments offscreen. |
858 if (SK_ScalarMax == pos.fX) { | 1136 if (SK_ScalarMax == pos.fX) { |
859 continue; | 1137 continue; |
860 } | 1138 } |
861 drawState->getViewMatrix().mapPoints(&pos, 1); | 1139 drawState->getViewMatrix().mapPoints(&pos, 1); |
862 if (first) { | 1140 if (first) { |
863 actualBounds.set(pos.fX, pos.fY, pos.fX, pos.fY); | 1141 actualBounds.set(pos.fX, pos.fY, pos.fX, pos.fY); |
(...skipping 18 matching lines...) Expand all Loading... | |
882 target->drawIndexed(kTriangles_GrPrimitiveType, | 1160 target->drawIndexed(kTriangles_GrPrimitiveType, |
883 kVertsPerLineSeg*lines, // startV | 1161 kVertsPerLineSeg*lines, // startV |
884 0, // startI | 1162 0, // startI |
885 kVertsPerLineSeg*n, // vCount | 1163 kVertsPerLineSeg*n, // vCount |
886 kIdxsPerLineSeg*n, | 1164 kIdxsPerLineSeg*n, |
887 &devBounds); // iCount | 1165 &devBounds); // iCount |
888 lines += n; | 1166 lines += n; |
889 } | 1167 } |
890 } | 1168 } |
891 | 1169 |
892 target->setIndexSourceToBuffer(fQuadsIndexBuffer); | 1170 { |
893 int quads = 0; | 1171 GrDrawState::AutoRestoreEffects are(drawState); |
894 drawState->addCoverageEffect(hairQuadEffect, kEdgeAttrIndex)->unref(); | 1172 target->setIndexSourceToBuffer(fQuadsIndexBuffer); |
895 while (quads < quadCnt) { | 1173 int quads = 0; |
896 int n = GrMin(quadCnt - quads, kNumQuadsInIdxBuffer); | 1174 drawState->addCoverageEffect(hairQuadEffect, kEdgeAttrIndex)->unref(); |
897 target->drawIndexed(kTriangles_GrPrimitiveType, | 1175 while (quads < quadCnt) { |
898 4 * lineCnt + kVertsPerQuad*quads, // startV | 1176 int n = GrMin(quadCnt - quads, kNumQuadsInIdxBuffer); |
899 0, // startI | 1177 target->drawIndexed(kTriangles_GrPrimitiveType, |
900 kVertsPerQuad*n, // vCount | 1178 kVertsPerLineSeg * lineCnt + kVertsPerQuad*quads , // startV |
901 kIdxsPerQuad*n, // iCount | 1179 0, // startI |
902 &devBounds); | 1180 kVertsPerQuad*n, // vCount |
903 quads += n; | 1181 kIdxsPerQuad*n, // iCount |
1182 &devBounds); | |
1183 quads += n; | |
1184 } | |
1185 } | |
1186 | |
1187 { | |
1188 GrDrawState::AutoRestoreEffects are(drawState); | |
1189 target->setIndexSourceToBuffer(fConicsIndexBuffer); | |
1190 int conics = 0; | |
1191 drawState->addCoverageEffect(hairConicEffect, 1, 2)->unref(); | |
1192 // drawState->addCoverageEffect(hairConicEffect, kEdgeAttrIndex)->unref( ); | |
1193 while (conics < conicCnt) { | |
1194 int n = GrMin(conicCnt - conics, kNumConicsInIdxBuffer); | |
1195 target->drawIndexed(kTriangles_GrPrimitiveType, | |
1196 kVertsPerLineSeg*lineCnt + kVertsPerQuad*quadCnt + | |
1197 kVertsPerConic*conics, // startV | |
1198 0, // startI | |
1199 kVertsPerConic*n, // vCount | |
1200 kIdxsPerConic*n, // iCount | |
1201 &devBounds); | |
1202 conics += n; | |
1203 } | |
904 } | 1204 } |
905 target->resetIndexSource(); | 1205 target->resetIndexSource(); |
906 | 1206 |
907 return true; | 1207 return true; |
908 } | 1208 } |
1209 | |
OLD | NEW |