OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2011 Google Inc. | 2 * Copyright 2011 Google Inc. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
8 #include "GrAAHairLinePathRenderer.h" | 8 #include "GrAAHairLinePathRenderer.h" |
9 | 9 |
10 #include "GrBatch.h" | 10 #include "GrBatch.h" |
11 #include "GrBatchTarget.h" | 11 #include "GrBatchTarget.h" |
12 #include "GrBatchTest.h" | 12 #include "GrBatchTest.h" |
13 #include "GrBufferAllocPool.h" | 13 #include "GrBufferAllocPool.h" |
14 #include "GrContext.h" | 14 #include "GrContext.h" |
15 #include "GrDefaultGeoProcFactory.h" | 15 #include "GrDefaultGeoProcFactory.h" |
16 #include "GrDrawTargetCaps.h" | 16 #include "GrDrawTargetCaps.h" |
17 #include "GrGpu.h" | |
18 #include "GrIndexBuffer.h" | 17 #include "GrIndexBuffer.h" |
19 #include "GrPathUtils.h" | 18 #include "GrPathUtils.h" |
20 #include "GrPipelineBuilder.h" | 19 #include "GrPipelineBuilder.h" |
21 #include "GrProcessor.h" | 20 #include "GrProcessor.h" |
| 21 #include "GrResourceProvider.h" |
22 #include "GrVertexBuffer.h" | 22 #include "GrVertexBuffer.h" |
23 #include "SkGeometry.h" | 23 #include "SkGeometry.h" |
24 #include "SkStroke.h" | 24 #include "SkStroke.h" |
25 #include "SkTemplates.h" | 25 #include "SkTemplates.h" |
26 | 26 |
27 #include "effects/GrBezierEffect.h" | 27 #include "effects/GrBezierEffect.h" |
28 | 28 |
| 29 #define PREALLOC_PTARRAY(N) SkSTArray<(N),SkPoint, true> |
| 30 |
29 // quadratics are rendered as 5-sided polys in order to bound the | 31 // quadratics are rendered as 5-sided polys in order to bound the |
30 // AA stroke around the center-curve. See comments in push_quad_index_buffer and | 32 // AA stroke around the center-curve. See comments in push_quad_index_buffer and |
31 // bloat_quad. Quadratics and conics share an index buffer | 33 // bloat_quad. Quadratics and conics share an index buffer |
32 | 34 |
33 // lines are rendered as: | 35 // lines are rendered as: |
34 // *______________* | 36 // *______________* |
35 // |\ -_______ /| | 37 // |\ -_______ /| |
36 // | \ \ / | | 38 // | \ \ / | |
37 // | *--------* | | 39 // | *--------* | |
38 // | / ______/ \ | | 40 // | / ______/ \ | |
(...skipping 15 matching lines...) Expand all Loading... |
54 // specified by these 9 indices: | 56 // specified by these 9 indices: |
55 static const uint16_t kQuadIdxBufPattern[] = { | 57 static const uint16_t kQuadIdxBufPattern[] = { |
56 0, 1, 2, | 58 0, 1, 2, |
57 2, 4, 3, | 59 2, 4, 3, |
58 1, 4, 2 | 60 1, 4, 2 |
59 }; | 61 }; |
60 | 62 |
61 static const int kIdxsPerQuad = SK_ARRAY_COUNT(kQuadIdxBufPattern); | 63 static const int kIdxsPerQuad = SK_ARRAY_COUNT(kQuadIdxBufPattern); |
62 static const int kQuadNumVertices = 5; | 64 static const int kQuadNumVertices = 5; |
63 static const int kQuadsNumInIdxBuffer = 256; | 65 static const int kQuadsNumInIdxBuffer = 256; |
| 66 GR_DECLARE_STATIC_UNIQUE_KEY(gQuadsIndexBufferKey); |
| 67 |
| 68 static const GrIndexBuffer* ref_quads_index_buffer(GrResourceProvider* resourceP
rovider) { |
| 69 GR_DEFINE_STATIC_UNIQUE_KEY(gQuadsIndexBufferKey); |
| 70 return resourceProvider->refOrCreateInstancedIndexBuffer( |
| 71 kQuadIdxBufPattern, kIdxsPerQuad, kQuadsNumInIdxBuffer, kQuadNumVertices
, |
| 72 gQuadsIndexBufferKey); |
| 73 } |
64 | 74 |
65 | 75 |
66 // Each line segment is rendered as two quads and two triangles. | 76 // Each line segment is rendered as two quads and two triangles. |
67 // p0 and p1 have alpha = 1 while all other points have alpha = 0. | 77 // p0 and p1 have alpha = 1 while all other points have alpha = 0. |
68 // The four external points are offset 1 pixel perpendicular to the | 78 // The four external points are offset 1 pixel perpendicular to the |
69 // line and half a pixel parallel to the line. | 79 // line and half a pixel parallel to the line. |
70 // | 80 // |
71 // p4 p5 | 81 // p4 p5 |
72 // p0 p1 | 82 // p0 p1 |
73 // p2 p3 | 83 // p2 p3 |
74 // | 84 // |
75 // Each is drawn as six triangles specified by these 18 indices: | 85 // Each is drawn as six triangles specified by these 18 indices: |
76 | 86 |
77 static const uint16_t kLineSegIdxBufPattern[] = { | 87 static const uint16_t kLineSegIdxBufPattern[] = { |
78 0, 1, 3, | 88 0, 1, 3, |
79 0, 3, 2, | 89 0, 3, 2, |
80 0, 4, 5, | 90 0, 4, 5, |
81 0, 5, 1, | 91 0, 5, 1, |
82 0, 2, 4, | 92 0, 2, 4, |
83 1, 5, 3 | 93 1, 5, 3 |
84 }; | 94 }; |
85 | 95 |
86 static const int kIdxsPerLineSeg = SK_ARRAY_COUNT(kLineSegIdxBufPattern); | 96 static const int kIdxsPerLineSeg = SK_ARRAY_COUNT(kLineSegIdxBufPattern); |
87 static const int kLineSegNumVertices = 6; | 97 static const int kLineSegNumVertices = 6; |
88 static const int kLineSegsNumInIdxBuffer = 256; | 98 static const int kLineSegsNumInIdxBuffer = 256; |
89 | 99 |
90 GrPathRenderer* GrAAHairLinePathRenderer::Create(GrContext* context) { | 100 GR_DECLARE_STATIC_UNIQUE_KEY(gLinesIndexBufferKey); |
91 GrGpu* gpu = context->getGpu(); | 101 |
92 GrIndexBuffer* qIdxBuf = gpu->createInstancedIndexBuffer(kQuadIdxBufPattern, | 102 static const GrIndexBuffer* ref_lines_index_buffer(GrResourceProvider* resourceP
rovider) { |
93 kIdxsPerQuad, | 103 GR_DEFINE_STATIC_UNIQUE_KEY(gLinesIndexBufferKey); |
94 kQuadsNumInIdxBuffe
r, | 104 return resourceProvider->refOrCreateInstancedIndexBuffer( |
95 kQuadNumVertices); | 105 kLineSegIdxBufPattern, kIdxsPerLineSeg, kLineSegsNumInIdxBuffer, kLineS
egNumVertices, |
96 SkAutoTUnref<GrIndexBuffer> qIdxBuffer(qIdxBuf); | 106 gLinesIndexBufferKey); |
97 GrIndexBuffer* lIdxBuf = gpu->createInstancedIndexBuffer(kLineSegIdxBufPatte
rn, | |
98 kIdxsPerLineSeg, | |
99 kLineSegsNumInIdxBu
ffer, | |
100 kLineSegNumVertices
); | |
101 SkAutoTUnref<GrIndexBuffer> lIdxBuffer(lIdxBuf); | |
102 return SkNEW_ARGS(GrAAHairLinePathRenderer, | |
103 (context, lIdxBuf, qIdxBuf)); | |
104 } | 107 } |
105 | 108 |
106 GrAAHairLinePathRenderer::GrAAHairLinePathRenderer( | |
107 const GrContext* context, | |
108 const GrIndexBuffer* linesIndexBuffer, | |
109 const GrIndexBuffer* quadsIndexBuffer) { | |
110 fLinesIndexBuffer = linesIndexBuffer; | |
111 linesIndexBuffer->ref(); | |
112 fQuadsIndexBuffer = quadsIndexBuffer; | |
113 quadsIndexBuffer->ref(); | |
114 } | |
115 | |
116 GrAAHairLinePathRenderer::~GrAAHairLinePathRenderer() { | |
117 fLinesIndexBuffer->unref(); | |
118 fQuadsIndexBuffer->unref(); | |
119 } | |
120 | |
121 namespace { | |
122 | |
123 #define PREALLOC_PTARRAY(N) SkSTArray<(N),SkPoint, true> | |
124 | |
125 // Takes 178th time of logf on Z600 / VC2010 | 109 // Takes 178th time of logf on Z600 / VC2010 |
126 int get_float_exp(float x) { | 110 static int get_float_exp(float x) { |
127 GR_STATIC_ASSERT(sizeof(int) == sizeof(float)); | 111 GR_STATIC_ASSERT(sizeof(int) == sizeof(float)); |
128 #ifdef SK_DEBUG | 112 #ifdef SK_DEBUG |
129 static bool tested; | 113 static bool tested; |
130 if (!tested) { | 114 if (!tested) { |
131 tested = true; | 115 tested = true; |
132 SkASSERT(get_float_exp(0.25f) == -2); | 116 SkASSERT(get_float_exp(0.25f) == -2); |
133 SkASSERT(get_float_exp(0.3f) == -2); | 117 SkASSERT(get_float_exp(0.3f) == -2); |
134 SkASSERT(get_float_exp(0.5f) == -1); | 118 SkASSERT(get_float_exp(0.5f) == -1); |
135 SkASSERT(get_float_exp(1.f) == 0); | 119 SkASSERT(get_float_exp(1.f) == 0); |
136 SkASSERT(get_float_exp(2.f) == 1); | 120 SkASSERT(get_float_exp(2.f) == 1); |
137 SkASSERT(get_float_exp(2.5f) == 1); | 121 SkASSERT(get_float_exp(2.5f) == 1); |
138 SkASSERT(get_float_exp(8.f) == 3); | 122 SkASSERT(get_float_exp(8.f) == 3); |
139 SkASSERT(get_float_exp(100.f) == 6); | 123 SkASSERT(get_float_exp(100.f) == 6); |
140 SkASSERT(get_float_exp(1000.f) == 9); | 124 SkASSERT(get_float_exp(1000.f) == 9); |
141 SkASSERT(get_float_exp(1024.f) == 10); | 125 SkASSERT(get_float_exp(1024.f) == 10); |
142 SkASSERT(get_float_exp(3000000.f) == 21); | 126 SkASSERT(get_float_exp(3000000.f) == 21); |
143 } | 127 } |
144 #endif | 128 #endif |
145 const int* iptr = (const int*)&x; | 129 const int* iptr = (const int*)&x; |
146 return (((*iptr) & 0x7f800000) >> 23) - 127; | 130 return (((*iptr) & 0x7f800000) >> 23) - 127; |
147 } | 131 } |
148 | 132 |
149 // Uses the max curvature function for quads to estimate | 133 // Uses the max curvature function for quads to estimate |
150 // where to chop the conic. If the max curvature is not | 134 // where to chop the conic. If the max curvature is not |
151 // found along the curve segment it will return 1 and | 135 // found along the curve segment it will return 1 and |
152 // dst[0] is the original conic. If it returns 2 the dst[0] | 136 // dst[0] is the original conic. If it returns 2 the dst[0] |
153 // and dst[1] are the two new conics. | 137 // and dst[1] are the two new conics. |
154 int split_conic(const SkPoint src[3], SkConic dst[2], const SkScalar weight) { | 138 static int split_conic(const SkPoint src[3], SkConic dst[2], const SkScalar weig
ht) { |
155 SkScalar t = SkFindQuadMaxCurvature(src); | 139 SkScalar t = SkFindQuadMaxCurvature(src); |
156 if (t == 0) { | 140 if (t == 0) { |
157 if (dst) { | 141 if (dst) { |
158 dst[0].set(src, weight); | 142 dst[0].set(src, weight); |
159 } | 143 } |
160 return 1; | 144 return 1; |
161 } else { | 145 } else { |
162 if (dst) { | 146 if (dst) { |
163 SkConic conic; | 147 SkConic conic; |
164 conic.set(src, weight); | 148 conic.set(src, weight); |
165 conic.chopAt(t, dst); | 149 conic.chopAt(t, dst); |
166 } | 150 } |
167 return 2; | 151 return 2; |
168 } | 152 } |
169 } | 153 } |
170 | 154 |
171 // Calls split_conic on the entire conic and then once more on each subsection. | 155 // Calls split_conic on the entire conic and then once more on each subsection. |
172 // Most cases will result in either 1 conic (chop point is not within t range) | 156 // Most cases will result in either 1 conic (chop point is not within t range) |
173 // or 3 points (split once and then one subsection is split again). | 157 // or 3 points (split once and then one subsection is split again). |
174 int chop_conic(const SkPoint src[3], SkConic dst[4], const SkScalar weight) { | 158 static int chop_conic(const SkPoint src[3], SkConic dst[4], const SkScalar weigh
t) { |
175 SkConic dstTemp[2]; | 159 SkConic dstTemp[2]; |
176 int conicCnt = split_conic(src, dstTemp, weight); | 160 int conicCnt = split_conic(src, dstTemp, weight); |
177 if (2 == conicCnt) { | 161 if (2 == conicCnt) { |
178 int conicCnt2 = split_conic(dstTemp[0].fPts, dst, dstTemp[0].fW); | 162 int conicCnt2 = split_conic(dstTemp[0].fPts, dst, dstTemp[0].fW); |
179 conicCnt = conicCnt2 + split_conic(dstTemp[1].fPts, &dst[conicCnt2], dst
Temp[1].fW); | 163 conicCnt = conicCnt2 + split_conic(dstTemp[1].fPts, &dst[conicCnt2], dst
Temp[1].fW); |
180 } else { | 164 } else { |
181 dst[0] = dstTemp[0]; | 165 dst[0] = dstTemp[0]; |
182 } | 166 } |
183 return conicCnt; | 167 return conicCnt; |
184 } | 168 } |
185 | 169 |
186 // returns 0 if quad/conic is degen or close to it | 170 // returns 0 if quad/conic is degen or close to it |
187 // in this case approx the path with lines | 171 // in this case approx the path with lines |
188 // otherwise returns 1 | 172 // otherwise returns 1 |
189 int is_degen_quad_or_conic(const SkPoint p[3], SkScalar* dsqd) { | 173 static int is_degen_quad_or_conic(const SkPoint p[3], SkScalar* dsqd) { |
190 static const SkScalar gDegenerateToLineTol = SK_Scalar1; | 174 static const SkScalar gDegenerateToLineTol = SK_Scalar1; |
191 static const SkScalar gDegenerateToLineTolSqd = | 175 static const SkScalar gDegenerateToLineTolSqd = |
192 SkScalarMul(gDegenerateToLineTol, gDegenerateToLineTol); | 176 SkScalarMul(gDegenerateToLineTol, gDegenerateToLineTol); |
193 | 177 |
194 if (p[0].distanceToSqd(p[1]) < gDegenerateToLineTolSqd || | 178 if (p[0].distanceToSqd(p[1]) < gDegenerateToLineTolSqd || |
195 p[1].distanceToSqd(p[2]) < gDegenerateToLineTolSqd) { | 179 p[1].distanceToSqd(p[2]) < gDegenerateToLineTolSqd) { |
196 return 1; | 180 return 1; |
197 } | 181 } |
198 | 182 |
199 *dsqd = p[1].distanceToLineBetweenSqd(p[0], p[2]); | 183 *dsqd = p[1].distanceToLineBetweenSqd(p[0], p[2]); |
200 if (*dsqd < gDegenerateToLineTolSqd) { | 184 if (*dsqd < gDegenerateToLineTolSqd) { |
201 return 1; | 185 return 1; |
202 } | 186 } |
203 | 187 |
204 if (p[2].distanceToLineBetweenSqd(p[1], p[0]) < gDegenerateToLineTolSqd) { | 188 if (p[2].distanceToLineBetweenSqd(p[1], p[0]) < gDegenerateToLineTolSqd) { |
205 return 1; | 189 return 1; |
206 } | 190 } |
207 return 0; | 191 return 0; |
208 } | 192 } |
209 | 193 |
210 int is_degen_quad_or_conic(const SkPoint p[3]) { | 194 static int is_degen_quad_or_conic(const SkPoint p[3]) { |
211 SkScalar dsqd; | 195 SkScalar dsqd; |
212 return is_degen_quad_or_conic(p, &dsqd); | 196 return is_degen_quad_or_conic(p, &dsqd); |
213 } | 197 } |
214 | 198 |
215 // we subdivide the quads to avoid huge overfill | 199 // we subdivide the quads to avoid huge overfill |
216 // if it returns -1 then should be drawn as lines | 200 // if it returns -1 then should be drawn as lines |
217 int num_quad_subdivs(const SkPoint p[3]) { | 201 static int num_quad_subdivs(const SkPoint p[3]) { |
218 SkScalar dsqd; | 202 SkScalar dsqd; |
219 if (is_degen_quad_or_conic(p, &dsqd)) { | 203 if (is_degen_quad_or_conic(p, &dsqd)) { |
220 return -1; | 204 return -1; |
221 } | 205 } |
222 | 206 |
223 // tolerance of triangle height in pixels | 207 // tolerance of triangle height in pixels |
224 // tuned on windows Quadro FX 380 / Z600 | 208 // tuned on windows Quadro FX 380 / Z600 |
225 // trade off of fill vs cpu time on verts | 209 // trade off of fill vs cpu time on verts |
226 // maybe different when do this using gpu (geo or tess shaders) | 210 // maybe different when do this using gpu (geo or tess shaders) |
227 static const SkScalar gSubdivTol = 175 * SK_Scalar1; | 211 static const SkScalar gSubdivTol = 175 * SK_Scalar1; |
(...skipping 15 matching lines...) Expand all Loading... |
243 | 227 |
244 /** | 228 /** |
245 * Generates the lines and quads to be rendered. Lines are always recorded in | 229 * Generates the lines and quads to be rendered. Lines are always recorded in |
246 * device space. We will do a device space bloat to account for the 1pixel | 230 * device space. We will do a device space bloat to account for the 1pixel |
247 * thickness. | 231 * thickness. |
248 * Quads are recorded in device space unless m contains | 232 * Quads are recorded in device space unless m contains |
249 * perspective, then in they are in src space. We do this because we will | 233 * perspective, then in they are in src space. We do this because we will |
250 * subdivide large quads to reduce over-fill. This subdivision has to be | 234 * subdivide large quads to reduce over-fill. This subdivision has to be |
251 * performed before applying the perspective matrix. | 235 * performed before applying the perspective matrix. |
252 */ | 236 */ |
253 int gather_lines_and_quads(const SkPath& path, | 237 static int gather_lines_and_quads(const SkPath& path, |
254 const SkMatrix& m, | 238 const SkMatrix& m, |
255 const SkIRect& devClipBounds, | 239 const SkIRect& devClipBounds, |
256 GrAAHairLinePathRenderer::PtArray* lines, | 240 GrAAHairLinePathRenderer::PtArray* lines, |
257 GrAAHairLinePathRenderer::PtArray* quads, | 241 GrAAHairLinePathRenderer::PtArray* quads, |
258 GrAAHairLinePathRenderer::PtArray* conics, | 242 GrAAHairLinePathRenderer::PtArray* conics, |
259 GrAAHairLinePathRenderer::IntArray* quadSubdivCnts, | 243 GrAAHairLinePathRenderer::IntArray* quadSubdiv
Cnts, |
260 GrAAHairLinePathRenderer::FloatArray* conicWeights) { | 244 GrAAHairLinePathRenderer::FloatArray* conicWei
ghts) { |
261 SkPath::Iter iter(path, false); | 245 SkPath::Iter iter(path, false); |
262 | 246 |
263 int totalQuadCount = 0; | 247 int totalQuadCount = 0; |
264 SkRect bounds; | 248 SkRect bounds; |
265 SkIRect ibounds; | 249 SkIRect ibounds; |
266 | 250 |
267 bool persp = m.hasPerspective(); | 251 bool persp = m.hasPerspective(); |
268 | 252 |
269 for (;;) { | 253 for (;;) { |
270 SkPoint pathPts[4]; | 254 SkPoint pathPts[4]; |
(...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
434 } fConic; | 418 } fConic; |
435 SkVector fQuadCoord; | 419 SkVector fQuadCoord; |
436 struct { | 420 struct { |
437 SkScalar fBogus[4]; | 421 SkScalar fBogus[4]; |
438 }; | 422 }; |
439 }; | 423 }; |
440 }; | 424 }; |
441 | 425 |
442 GR_STATIC_ASSERT(sizeof(BezierVertex) == 3 * sizeof(SkPoint)); | 426 GR_STATIC_ASSERT(sizeof(BezierVertex) == 3 * sizeof(SkPoint)); |
443 | 427 |
444 void intersect_lines(const SkPoint& ptA, const SkVector& normA, | 428 static void intersect_lines(const SkPoint& ptA, const SkVector& normA, |
445 const SkPoint& ptB, const SkVector& normB, | 429 const SkPoint& ptB, const SkVector& normB, |
446 SkPoint* result) { | 430 SkPoint* result) { |
447 | 431 |
448 SkScalar lineAW = -normA.dot(ptA); | 432 SkScalar lineAW = -normA.dot(ptA); |
449 SkScalar lineBW = -normB.dot(ptB); | 433 SkScalar lineBW = -normB.dot(ptB); |
450 | 434 |
451 SkScalar wInv = SkScalarMul(normA.fX, normB.fY) - | 435 SkScalar wInv = SkScalarMul(normA.fX, normB.fY) - |
452 SkScalarMul(normA.fY, normB.fX); | 436 SkScalarMul(normA.fY, normB.fX); |
453 wInv = SkScalarInvert(wInv); | 437 wInv = SkScalarInvert(wInv); |
454 | 438 |
455 result->fX = SkScalarMul(normA.fY, lineBW) - SkScalarMul(lineAW, normB.fY); | 439 result->fX = SkScalarMul(normA.fY, lineBW) - SkScalarMul(lineAW, normB.fY); |
456 result->fX = SkScalarMul(result->fX, wInv); | 440 result->fX = SkScalarMul(result->fX, wInv); |
457 | 441 |
458 result->fY = SkScalarMul(lineAW, normB.fX) - SkScalarMul(normA.fX, lineBW); | 442 result->fY = SkScalarMul(lineAW, normB.fX) - SkScalarMul(normA.fX, lineBW); |
459 result->fY = SkScalarMul(result->fY, wInv); | 443 result->fY = SkScalarMul(result->fY, wInv); |
460 } | 444 } |
461 | 445 |
462 void set_uv_quad(const SkPoint qpts[3], BezierVertex verts[kQuadNumVertices]) { | 446 static void set_uv_quad(const SkPoint qpts[3], BezierVertex verts[kQuadNumVertic
es]) { |
463 // this should be in the src space, not dev coords, when we have perspective | 447 // this should be in the src space, not dev coords, when we have perspective |
464 GrPathUtils::QuadUVMatrix DevToUV(qpts); | 448 GrPathUtils::QuadUVMatrix DevToUV(qpts); |
465 DevToUV.apply<kQuadNumVertices, sizeof(BezierVertex), sizeof(SkPoint)>(verts
); | 449 DevToUV.apply<kQuadNumVertices, sizeof(BezierVertex), sizeof(SkPoint)>(verts
); |
466 } | 450 } |
467 | 451 |
468 void bloat_quad(const SkPoint qpts[3], const SkMatrix* toDevice, | 452 static void bloat_quad(const SkPoint qpts[3], const SkMatrix* toDevice, |
469 const SkMatrix* toSrc, BezierVertex verts[kQuadNumVertices]) { | 453 const SkMatrix* toSrc, BezierVertex verts[kQuadNumVertice
s]) { |
470 SkASSERT(!toDevice == !toSrc); | 454 SkASSERT(!toDevice == !toSrc); |
471 // original quad is specified by tri a,b,c | 455 // original quad is specified by tri a,b,c |
472 SkPoint a = qpts[0]; | 456 SkPoint a = qpts[0]; |
473 SkPoint b = qpts[1]; | 457 SkPoint b = qpts[1]; |
474 SkPoint c = qpts[2]; | 458 SkPoint c = qpts[2]; |
475 | 459 |
476 if (toDevice) { | 460 if (toDevice) { |
477 toDevice->mapPoints(&a, 1); | 461 toDevice->mapPoints(&a, 1); |
478 toDevice->mapPoints(&b, 1); | 462 toDevice->mapPoints(&b, 1); |
479 toDevice->mapPoints(&c, 1); | 463 toDevice->mapPoints(&c, 1); |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
537 } | 521 } |
538 } | 522 } |
539 | 523 |
540 // Equations based off of Loop-Blinn Quadratic GPU Rendering | 524 // Equations based off of Loop-Blinn Quadratic GPU Rendering |
541 // Input Parametric: | 525 // Input Parametric: |
542 // 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) | 526 // 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) |
543 // Output Implicit: | 527 // Output Implicit: |
544 // f(x, y, w) = f(P) = K^2 - LM | 528 // f(x, y, w) = f(P) = K^2 - LM |
545 // K = dot(k, P), L = dot(l, P), M = dot(m, P) | 529 // K = dot(k, P), L = dot(l, P), M = dot(m, P) |
546 // k, l, m are calculated in function GrPathUtils::getConicKLM | 530 // k, l, m are calculated in function GrPathUtils::getConicKLM |
547 void set_conic_coeffs(const SkPoint p[3], BezierVertex verts[kQuadNumVertices], | 531 static void set_conic_coeffs(const SkPoint p[3], BezierVertex verts[kQuadNumVert
ices], |
548 const SkScalar weight) { | 532 const SkScalar weight) { |
549 SkScalar klm[9]; | 533 SkScalar klm[9]; |
550 | 534 |
551 GrPathUtils::getConicKLM(p, weight, klm); | 535 GrPathUtils::getConicKLM(p, weight, klm); |
552 | 536 |
553 for (int i = 0; i < kQuadNumVertices; ++i) { | 537 for (int i = 0; i < kQuadNumVertices; ++i) { |
554 const SkPoint pnt = verts[i].fPos; | 538 const SkPoint pnt = verts[i].fPos; |
555 verts[i].fConic.fK = pnt.fX * klm[0] + pnt.fY * klm[1] + klm[2]; | 539 verts[i].fConic.fK = pnt.fX * klm[0] + pnt.fY * klm[1] + klm[2]; |
556 verts[i].fConic.fL = pnt.fX * klm[3] + pnt.fY * klm[4] + klm[5]; | 540 verts[i].fConic.fL = pnt.fX * klm[3] + pnt.fY * klm[4] + klm[5]; |
557 verts[i].fConic.fM = pnt.fX * klm[6] + pnt.fY * klm[7] + klm[8]; | 541 verts[i].fConic.fM = pnt.fX * klm[6] + pnt.fY * klm[7] + klm[8]; |
558 } | 542 } |
559 } | 543 } |
560 | 544 |
561 void add_conics(const SkPoint p[3], | 545 static void add_conics(const SkPoint p[3], |
562 const SkScalar weight, | 546 const SkScalar weight, |
563 const SkMatrix* toDevice, | 547 const SkMatrix* toDevice, |
564 const SkMatrix* toSrc, | 548 const SkMatrix* toSrc, |
565 BezierVertex** vert) { | 549 BezierVertex** vert) { |
566 bloat_quad(p, toDevice, toSrc, *vert); | 550 bloat_quad(p, toDevice, toSrc, *vert); |
567 set_conic_coeffs(p, *vert, weight); | 551 set_conic_coeffs(p, *vert, weight); |
568 *vert += kQuadNumVertices; | 552 *vert += kQuadNumVertices; |
569 } | 553 } |
570 | 554 |
571 void add_quads(const SkPoint p[3], | 555 static void add_quads(const SkPoint p[3], |
572 int subdiv, | 556 int subdiv, |
573 const SkMatrix* toDevice, | 557 const SkMatrix* toDevice, |
574 const SkMatrix* toSrc, | 558 const SkMatrix* toSrc, |
575 BezierVertex** vert) { | 559 BezierVertex** vert) { |
576 SkASSERT(subdiv >= 0); | 560 SkASSERT(subdiv >= 0); |
577 if (subdiv) { | 561 if (subdiv) { |
578 SkPoint newP[5]; | 562 SkPoint newP[5]; |
579 SkChopQuadAtHalf(p, newP); | 563 SkChopQuadAtHalf(p, newP); |
580 add_quads(newP + 0, subdiv-1, toDevice, toSrc, vert); | 564 add_quads(newP + 0, subdiv-1, toDevice, toSrc, vert); |
581 add_quads(newP + 2, subdiv-1, toDevice, toSrc, vert); | 565 add_quads(newP + 2, subdiv-1, toDevice, toSrc, vert); |
582 } else { | 566 } else { |
583 bloat_quad(p, toDevice, toSrc, *vert); | 567 bloat_quad(p, toDevice, toSrc, *vert); |
584 set_uv_quad(p, *vert); | 568 set_uv_quad(p, *vert); |
585 *vert += kQuadNumVertices; | 569 *vert += kQuadNumVertices; |
586 } | 570 } |
587 } | 571 } |
588 | 572 |
589 void add_line(const SkPoint p[2], | 573 static void add_line(const SkPoint p[2], |
590 const SkMatrix* toSrc, | 574 const SkMatrix* toSrc, |
591 uint8_t coverage, | 575 uint8_t coverage, |
592 LineVertex** vert) { | 576 LineVertex** vert) { |
593 const SkPoint& a = p[0]; | 577 const SkPoint& a = p[0]; |
594 const SkPoint& b = p[1]; | 578 const SkPoint& b = p[1]; |
595 | 579 |
596 SkVector ortho, vec = b; | 580 SkVector ortho, vec = b; |
597 vec -= a; | 581 vec -= a; |
598 | 582 |
599 if (vec.setLength(SK_ScalarHalf)) { | 583 if (vec.setLength(SK_ScalarHalf)) { |
600 // Create a vector orthogonal to 'vec' and of unit length | 584 // Create a vector orthogonal to 'vec' and of unit length |
601 ortho.fX = 2.0f * vec.fY; | 585 ortho.fX = 2.0f * vec.fY; |
602 ortho.fY = -2.0f * vec.fX; | 586 ortho.fY = -2.0f * vec.fX; |
(...skipping 21 matching lines...) Expand all Loading... |
624 } else { | 608 } else { |
625 // just make it degenerate and likely offscreen | 609 // just make it degenerate and likely offscreen |
626 for (int i = 0; i < kLineSegNumVertices; ++i) { | 610 for (int i = 0; i < kLineSegNumVertices; ++i) { |
627 (*vert)[i].fPos.set(SK_ScalarMax, SK_ScalarMax); | 611 (*vert)[i].fPos.set(SK_ScalarMax, SK_ScalarMax); |
628 } | 612 } |
629 } | 613 } |
630 | 614 |
631 *vert += kLineSegNumVertices; | 615 *vert += kLineSegNumVertices; |
632 } | 616 } |
633 | 617 |
634 } | |
635 | |
636 /////////////////////////////////////////////////////////////////////////////// | 618 /////////////////////////////////////////////////////////////////////////////// |
637 | 619 |
638 bool GrAAHairLinePathRenderer::canDrawPath(const GrDrawTarget* target, | 620 bool GrAAHairLinePathRenderer::canDrawPath(const GrDrawTarget* target, |
639 const GrPipelineBuilder* pipelineBuil
der, | 621 const GrPipelineBuilder* pipelineBuil
der, |
640 const SkMatrix& viewMatrix, | 622 const SkMatrix& viewMatrix, |
641 const SkPath& path, | 623 const SkPath& path, |
642 const GrStrokeInfo& stroke, | 624 const GrStrokeInfo& stroke, |
643 bool antiAlias) const { | 625 bool antiAlias) const { |
644 if (!antiAlias) { | 626 if (!antiAlias) { |
645 return false; | 627 return false; |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
696 class AAHairlineBatch : public GrBatch { | 678 class AAHairlineBatch : public GrBatch { |
697 public: | 679 public: |
698 struct Geometry { | 680 struct Geometry { |
699 GrColor fColor; | 681 GrColor fColor; |
700 uint8_t fCoverage; | 682 uint8_t fCoverage; |
701 SkMatrix fViewMatrix; | 683 SkMatrix fViewMatrix; |
702 SkPath fPath; | 684 SkPath fPath; |
703 SkIRect fDevClipBounds; | 685 SkIRect fDevClipBounds; |
704 }; | 686 }; |
705 | 687 |
706 // TODO Batch itself should not hold on to index buffers. Instead, these sh
ould live in the | 688 static GrBatch* Create(const Geometry& geometry) { |
707 // cache. | 689 return SkNEW_ARGS(AAHairlineBatch, (geometry)); |
708 static GrBatch* Create(const Geometry& geometry, const GrIndexBuffer* linesI
ndexBuffer, | |
709 const GrIndexBuffer* quadsIndexBuffer) { | |
710 return SkNEW_ARGS(AAHairlineBatch, (geometry, linesIndexBuffer, quadsInd
exBuffer)); | |
711 } | 690 } |
712 | 691 |
713 const char* name() const override { return "AAHairlineBatch"; } | 692 const char* name() const override { return "AAHairlineBatch"; } |
714 | 693 |
715 void getInvariantOutputColor(GrInitInvariantOutput* out) const override { | 694 void getInvariantOutputColor(GrInitInvariantOutput* out) const override { |
716 // When this is called on a batch, there is only one geometry bundle | 695 // When this is called on a batch, there is only one geometry bundle |
717 out->setKnownFourComponents(fGeoData[0].fColor); | 696 out->setKnownFourComponents(fGeoData[0].fColor); |
718 } | 697 } |
719 void getInvariantOutputCoverage(GrInitInvariantOutput* out) const override { | 698 void getInvariantOutputCoverage(GrInitInvariantOutput* out) const override { |
720 out->setUnknownSingleComponent(); | 699 out->setUnknownSingleComponent(); |
(...skipping 17 matching lines...) Expand all Loading... |
738 | 717 |
739 void generateGeometry(GrBatchTarget* batchTarget, const GrPipeline* pipeline
) override; | 718 void generateGeometry(GrBatchTarget* batchTarget, const GrPipeline* pipeline
) override; |
740 | 719 |
741 SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; } | 720 SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; } |
742 | 721 |
743 private: | 722 private: |
744 typedef SkTArray<SkPoint, true> PtArray; | 723 typedef SkTArray<SkPoint, true> PtArray; |
745 typedef SkTArray<int, true> IntArray; | 724 typedef SkTArray<int, true> IntArray; |
746 typedef SkTArray<float, true> FloatArray; | 725 typedef SkTArray<float, true> FloatArray; |
747 | 726 |
748 AAHairlineBatch(const Geometry& geometry, const GrIndexBuffer* linesIndexBuf
fer, | 727 AAHairlineBatch(const Geometry& geometry) { |
749 const GrIndexBuffer* quadsIndexBuffer) | |
750 : fLinesIndexBuffer(linesIndexBuffer) | |
751 , fQuadsIndexBuffer(quadsIndexBuffer) { | |
752 SkASSERT(linesIndexBuffer && quadsIndexBuffer); | |
753 this->initClassID<AAHairlineBatch>(); | 728 this->initClassID<AAHairlineBatch>(); |
754 fGeoData.push_back(geometry); | 729 fGeoData.push_back(geometry); |
755 | 730 |
756 // compute bounds | 731 // compute bounds |
757 fBounds = geometry.fPath.getBounds(); | 732 fBounds = geometry.fPath.getBounds(); |
758 geometry.fViewMatrix.mapRect(&fBounds); | 733 geometry.fViewMatrix.mapRect(&fBounds); |
759 } | 734 } |
760 | 735 |
761 bool onCombineIfPossible(GrBatch* t) override { | 736 bool onCombineIfPossible(GrBatch* t) override { |
762 AAHairlineBatch* that = t->cast<AAHairlineBatch>(); | 737 AAHairlineBatch* that = t->cast<AAHairlineBatch>(); |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
801 GrColor fColor; | 776 GrColor fColor; |
802 uint8_t fCoverage; | 777 uint8_t fCoverage; |
803 SkRect fDevBounds; | 778 SkRect fDevBounds; |
804 bool fUsesLocalCoords; | 779 bool fUsesLocalCoords; |
805 bool fColorIgnored; | 780 bool fColorIgnored; |
806 bool fCoverageIgnored; | 781 bool fCoverageIgnored; |
807 }; | 782 }; |
808 | 783 |
809 BatchTracker fBatch; | 784 BatchTracker fBatch; |
810 SkSTArray<1, Geometry, true> fGeoData; | 785 SkSTArray<1, Geometry, true> fGeoData; |
811 const GrIndexBuffer* fLinesIndexBuffer; | |
812 const GrIndexBuffer* fQuadsIndexBuffer; | |
813 }; | 786 }; |
814 | 787 |
815 void AAHairlineBatch::generateGeometry(GrBatchTarget* batchTarget, const GrPipel
ine* pipeline) { | 788 void AAHairlineBatch::generateGeometry(GrBatchTarget* batchTarget, const GrPipel
ine* pipeline) { |
816 // Setup the viewmatrix and localmatrix for the GrGeometryProcessor. | 789 // Setup the viewmatrix and localmatrix for the GrGeometryProcessor. |
817 SkMatrix invert; | 790 SkMatrix invert; |
818 if (!this->viewMatrix().invert(&invert)) { | 791 if (!this->viewMatrix().invert(&invert)) { |
819 return; | 792 return; |
820 } | 793 } |
821 | 794 |
822 // we will transform to identity space if the viewmatrix does not have persp
ective | 795 // we will transform to identity space if the viewmatrix does not have persp
ective |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
873 const Geometry& args = fGeoData[i]; | 846 const Geometry& args = fGeoData[i]; |
874 quadCount += gather_lines_and_quads(args.fPath, args.fViewMatrix, args.f
DevClipBounds, | 847 quadCount += gather_lines_and_quads(args.fPath, args.fViewMatrix, args.f
DevClipBounds, |
875 &lines, &quads, &conics, &qSubdivs,
&cWeights); | 848 &lines, &quads, &conics, &qSubdivs,
&cWeights); |
876 } | 849 } |
877 | 850 |
878 int lineCount = lines.count() / 2; | 851 int lineCount = lines.count() / 2; |
879 int conicCount = conics.count() / 3; | 852 int conicCount = conics.count() / 3; |
880 | 853 |
881 // do lines first | 854 // do lines first |
882 if (lineCount) { | 855 if (lineCount) { |
| 856 SkAutoTUnref<const GrIndexBuffer> linesIndexBuffer( |
| 857 ref_lines_index_buffer(batchTarget->resourceProvider())); |
883 batchTarget->initDraw(lineGP, pipeline); | 858 batchTarget->initDraw(lineGP, pipeline); |
884 | 859 |
885 // TODO remove this when batch is everywhere | 860 // TODO remove this when batch is everywhere |
886 GrPipelineInfo init; | 861 GrPipelineInfo init; |
887 init.fColorIgnored = fBatch.fColorIgnored; | 862 init.fColorIgnored = fBatch.fColorIgnored; |
888 init.fOverrideColor = GrColor_ILLEGAL; | 863 init.fOverrideColor = GrColor_ILLEGAL; |
889 init.fCoverageIgnored = fBatch.fCoverageIgnored; | 864 init.fCoverageIgnored = fBatch.fCoverageIgnored; |
890 init.fUsesLocalCoords = this->usesLocalCoords(); | 865 init.fUsesLocalCoords = this->usesLocalCoords(); |
891 lineGP->initBatchTracker(batchTarget->currentBatchTracker(), init); | 866 lineGP->initBatchTracker(batchTarget->currentBatchTracker(), init); |
892 | 867 |
893 const GrVertexBuffer* vertexBuffer; | 868 const GrVertexBuffer* vertexBuffer; |
894 int firstVertex; | 869 int firstVertex; |
895 | 870 |
896 size_t vertexStride = lineGP->getVertexStride(); | 871 size_t vertexStride = lineGP->getVertexStride(); |
897 int vertexCount = kLineSegNumVertices * lineCount; | 872 int vertexCount = kLineSegNumVertices * lineCount; |
898 void *vertices = batchTarget->vertexPool()->makeSpace(vertexStride, | 873 void *vertices = batchTarget->vertexPool()->makeSpace(vertexStride, |
899 vertexCount, | 874 vertexCount, |
900 &vertexBuffer, | 875 &vertexBuffer, |
901 &firstVertex); | 876 &firstVertex); |
902 | 877 |
903 if (!vertices) { | 878 if (!vertices || !linesIndexBuffer) { |
904 SkDebugf("Could not allocate vertices\n"); | 879 SkDebugf("Could not allocate vertices\n"); |
905 return; | 880 return; |
906 } | 881 } |
907 | 882 |
908 SkASSERT(lineGP->getVertexStride() == sizeof(LineVertex)); | 883 SkASSERT(lineGP->getVertexStride() == sizeof(LineVertex)); |
909 | 884 |
910 LineVertex* verts = reinterpret_cast<LineVertex*>(vertices); | 885 LineVertex* verts = reinterpret_cast<LineVertex*>(vertices); |
911 for (int i = 0; i < lineCount; ++i) { | 886 for (int i = 0; i < lineCount; ++i) { |
912 add_line(&lines[2*i], toSrc, this->coverage(), &verts); | 887 add_line(&lines[2*i], toSrc, this->coverage(), &verts); |
913 } | 888 } |
914 | 889 |
915 { | 890 { |
916 GrDrawTarget::DrawInfo info; | 891 GrDrawTarget::DrawInfo info; |
917 info.setVertexBuffer(vertexBuffer); | 892 info.setVertexBuffer(vertexBuffer); |
918 info.setIndexBuffer(fLinesIndexBuffer); | 893 info.setIndexBuffer(linesIndexBuffer); |
919 info.setPrimitiveType(kTriangles_GrPrimitiveType); | 894 info.setPrimitiveType(kTriangles_GrPrimitiveType); |
920 info.setStartIndex(0); | 895 info.setStartIndex(0); |
921 | 896 |
922 int lines = 0; | 897 int lines = 0; |
923 while (lines < lineCount) { | 898 while (lines < lineCount) { |
924 int n = SkTMin(lineCount - lines, kLineSegsNumInIdxBuffer); | 899 int n = SkTMin(lineCount - lines, kLineSegsNumInIdxBuffer); |
925 | 900 |
926 info.setStartVertex(kLineSegNumVertices*lines + firstVertex); | 901 info.setStartVertex(kLineSegNumVertices*lines + firstVertex); |
927 info.setVertexCount(kLineSegNumVertices*n); | 902 info.setVertexCount(kLineSegNumVertices*n); |
928 info.setIndexCount(kIdxsPerLineSeg*n); | 903 info.setIndexCount(kIdxsPerLineSeg*n); |
929 batchTarget->draw(info); | 904 batchTarget->draw(info); |
930 | 905 |
931 lines += n; | 906 lines += n; |
932 } | 907 } |
933 } | 908 } |
934 } | 909 } |
935 | 910 |
936 if (quadCount || conicCount) { | 911 if (quadCount || conicCount) { |
937 const GrVertexBuffer* vertexBuffer; | 912 const GrVertexBuffer* vertexBuffer; |
938 int firstVertex; | 913 int firstVertex; |
939 | 914 |
| 915 SkAutoTUnref<const GrIndexBuffer> quadsIndexBuffer( |
| 916 ref_quads_index_buffer(batchTarget->resourceProvider())); |
| 917 |
940 size_t vertexStride = sizeof(BezierVertex); | 918 size_t vertexStride = sizeof(BezierVertex); |
941 int vertexCount = kQuadNumVertices * quadCount + kQuadNumVertices * coni
cCount; | 919 int vertexCount = kQuadNumVertices * quadCount + kQuadNumVertices * coni
cCount; |
942 void *vertices = batchTarget->vertexPool()->makeSpace(vertexStride, | 920 void *vertices = batchTarget->vertexPool()->makeSpace(vertexStride, |
943 vertexCount, | 921 vertexCount, |
944 &vertexBuffer, | 922 &vertexBuffer, |
945 &firstVertex); | 923 &firstVertex); |
946 | 924 |
947 if (!vertices) { | 925 if (!vertices || !quadsIndexBuffer) { |
948 SkDebugf("Could not allocate vertices\n"); | 926 SkDebugf("Could not allocate vertices\n"); |
949 return; | 927 return; |
950 } | 928 } |
951 | 929 |
952 // Setup vertices | 930 // Setup vertices |
953 BezierVertex* verts = reinterpret_cast<BezierVertex*>(vertices); | 931 BezierVertex* verts = reinterpret_cast<BezierVertex*>(vertices); |
954 | 932 |
955 int unsubdivQuadCnt = quads.count() / 3; | 933 int unsubdivQuadCnt = quads.count() / 3; |
956 for (int i = 0; i < unsubdivQuadCnt; ++i) { | 934 for (int i = 0; i < unsubdivQuadCnt; ++i) { |
957 SkASSERT(qSubdivs[i] >= 0); | 935 SkASSERT(qSubdivs[i] >= 0); |
(...skipping 12 matching lines...) Expand all Loading... |
970 GrPipelineInfo init; | 948 GrPipelineInfo init; |
971 init.fColorIgnored = fBatch.fColorIgnored; | 949 init.fColorIgnored = fBatch.fColorIgnored; |
972 init.fOverrideColor = GrColor_ILLEGAL; | 950 init.fOverrideColor = GrColor_ILLEGAL; |
973 init.fCoverageIgnored = fBatch.fCoverageIgnored; | 951 init.fCoverageIgnored = fBatch.fCoverageIgnored; |
974 init.fUsesLocalCoords = this->usesLocalCoords(); | 952 init.fUsesLocalCoords = this->usesLocalCoords(); |
975 quadGP->initBatchTracker(batchTarget->currentBatchTracker(), init); | 953 quadGP->initBatchTracker(batchTarget->currentBatchTracker(), init); |
976 | 954 |
977 { | 955 { |
978 GrDrawTarget::DrawInfo info; | 956 GrDrawTarget::DrawInfo info; |
979 info.setVertexBuffer(vertexBuffer); | 957 info.setVertexBuffer(vertexBuffer); |
980 info.setIndexBuffer(fQuadsIndexBuffer); | 958 info.setIndexBuffer(quadsIndexBuffer); |
981 info.setPrimitiveType(kTriangles_GrPrimitiveType); | 959 info.setPrimitiveType(kTriangles_GrPrimitiveType); |
982 info.setStartIndex(0); | 960 info.setStartIndex(0); |
983 | 961 |
984 int quads = 0; | 962 int quads = 0; |
985 while (quads < quadCount) { | 963 while (quads < quadCount) { |
986 int n = SkTMin(quadCount - quads, kQuadsNumInIdxBuffer); | 964 int n = SkTMin(quadCount - quads, kQuadsNumInIdxBuffer); |
987 | 965 |
988 info.setStartVertex(kQuadNumVertices*quads + firstVertex); | 966 info.setStartVertex(kQuadNumVertices*quads + firstVertex); |
989 info.setVertexCount(kQuadNumVertices*n); | 967 info.setVertexCount(kQuadNumVertices*n); |
990 info.setIndexCount(kIdxsPerQuad*n); | 968 info.setIndexCount(kIdxsPerQuad*n); |
(...skipping 11 matching lines...) Expand all Loading... |
1002 GrPipelineInfo init; | 980 GrPipelineInfo init; |
1003 init.fColorIgnored = fBatch.fColorIgnored; | 981 init.fColorIgnored = fBatch.fColorIgnored; |
1004 init.fOverrideColor = GrColor_ILLEGAL; | 982 init.fOverrideColor = GrColor_ILLEGAL; |
1005 init.fCoverageIgnored = fBatch.fCoverageIgnored; | 983 init.fCoverageIgnored = fBatch.fCoverageIgnored; |
1006 init.fUsesLocalCoords = this->usesLocalCoords(); | 984 init.fUsesLocalCoords = this->usesLocalCoords(); |
1007 conicGP->initBatchTracker(batchTarget->currentBatchTracker(), init); | 985 conicGP->initBatchTracker(batchTarget->currentBatchTracker(), init); |
1008 | 986 |
1009 { | 987 { |
1010 GrDrawTarget::DrawInfo info; | 988 GrDrawTarget::DrawInfo info; |
1011 info.setVertexBuffer(vertexBuffer); | 989 info.setVertexBuffer(vertexBuffer); |
1012 info.setIndexBuffer(fQuadsIndexBuffer); | 990 info.setIndexBuffer(quadsIndexBuffer); |
1013 info.setPrimitiveType(kTriangles_GrPrimitiveType); | 991 info.setPrimitiveType(kTriangles_GrPrimitiveType); |
1014 info.setStartIndex(0); | 992 info.setStartIndex(0); |
1015 | 993 |
1016 int conics = 0; | 994 int conics = 0; |
1017 while (conics < conicCount) { | 995 while (conics < conicCount) { |
1018 int n = SkTMin(conicCount - conics, kQuadsNumInIdxBuffer); | 996 int n = SkTMin(conicCount - conics, kQuadsNumInIdxBuffer); |
1019 | 997 |
1020 info.setStartVertex(kQuadNumVertices*(quadCount + conics) +
firstVertex); | 998 info.setStartVertex(kQuadNumVertices*(quadCount + conics) +
firstVertex); |
1021 info.setVertexCount(kQuadNumVertices*n); | 999 info.setVertexCount(kQuadNumVertices*n); |
1022 info.setIndexCount(kIdxsPerQuad*n); | 1000 info.setIndexCount(kIdxsPerQuad*n); |
1023 batchTarget->draw(info); | 1001 batchTarget->draw(info); |
1024 | 1002 |
1025 conics += n; | 1003 conics += n; |
1026 } | 1004 } |
1027 } | 1005 } |
1028 } | 1006 } |
1029 } | 1007 } |
1030 } | 1008 } |
1031 | 1009 |
1032 static GrBatch* create_hairline_batch(GrColor color, | 1010 static GrBatch* create_hairline_batch(GrColor color, |
1033 const SkMatrix& viewMatrix, | 1011 const SkMatrix& viewMatrix, |
1034 const SkPath& path, | 1012 const SkPath& path, |
1035 const GrStrokeInfo& stroke, | 1013 const GrStrokeInfo& stroke, |
1036 const SkIRect& devClipBounds, | 1014 const SkIRect& devClipBounds) { |
1037 const GrIndexBuffer* linesIndexBuffer, | |
1038 const GrIndexBuffer* quadsIndexBuffer) { | |
1039 SkScalar hairlineCoverage; | 1015 SkScalar hairlineCoverage; |
1040 uint8_t newCoverage = 0xff; | 1016 uint8_t newCoverage = 0xff; |
1041 if (GrPathRenderer::IsStrokeHairlineOrEquivalent(stroke, viewMatrix, &hairli
neCoverage)) { | 1017 if (GrPathRenderer::IsStrokeHairlineOrEquivalent(stroke, viewMatrix, &hairli
neCoverage)) { |
1042 newCoverage = SkScalarRoundToInt(hairlineCoverage * 0xff); | 1018 newCoverage = SkScalarRoundToInt(hairlineCoverage * 0xff); |
1043 } | 1019 } |
1044 | 1020 |
1045 AAHairlineBatch::Geometry geometry; | 1021 AAHairlineBatch::Geometry geometry; |
1046 geometry.fColor = color; | 1022 geometry.fColor = color; |
1047 geometry.fCoverage = newCoverage; | 1023 geometry.fCoverage = newCoverage; |
1048 geometry.fViewMatrix = viewMatrix; | 1024 geometry.fViewMatrix = viewMatrix; |
1049 geometry.fPath = path; | 1025 geometry.fPath = path; |
1050 geometry.fDevClipBounds = devClipBounds; | 1026 geometry.fDevClipBounds = devClipBounds; |
1051 | 1027 |
1052 return AAHairlineBatch::Create(geometry, linesIndexBuffer, quadsIndexBuffer)
; | 1028 return AAHairlineBatch::Create(geometry); |
1053 } | 1029 } |
1054 | 1030 |
1055 bool GrAAHairLinePathRenderer::onDrawPath(GrDrawTarget* target, | 1031 bool GrAAHairLinePathRenderer::onDrawPath(GrDrawTarget* target, |
1056 GrPipelineBuilder* pipelineBuilder, | 1032 GrPipelineBuilder* pipelineBuilder, |
1057 GrColor color, | 1033 GrColor color, |
1058 const SkMatrix& viewMatrix, | 1034 const SkMatrix& viewMatrix, |
1059 const SkPath& path, | 1035 const SkPath& path, |
1060 const GrStrokeInfo& stroke, | 1036 const GrStrokeInfo& stroke, |
1061 bool) { | 1037 bool) { |
1062 if (!fLinesIndexBuffer || !fQuadsIndexBuffer) { | |
1063 SkDebugf("unable to allocate indices\n"); | |
1064 return false; | |
1065 } | |
1066 | |
1067 SkIRect devClipBounds; | 1038 SkIRect devClipBounds; |
1068 pipelineBuilder->clip().getConservativeBounds(pipelineBuilder->getRenderTarg
et(), | 1039 pipelineBuilder->clip().getConservativeBounds(pipelineBuilder->getRenderTarg
et(), |
1069 &devClipBounds); | 1040 &devClipBounds); |
1070 | 1041 |
1071 SkAutoTUnref<GrBatch> batch(create_hairline_batch(color, viewMatrix, path, s
troke, | 1042 SkAutoTUnref<GrBatch> batch(create_hairline_batch(color, viewMatrix, path, s
troke, |
1072 devClipBounds, fLinesIndex
Buffer, | 1043 devClipBounds)); |
1073 fQuadsIndexBuffer)); | |
1074 target->drawBatch(pipelineBuilder, batch); | 1044 target->drawBatch(pipelineBuilder, batch); |
1075 | 1045 |
1076 return true; | 1046 return true; |
1077 } | 1047 } |
1078 | 1048 |
1079 ////////////////////////////////////////////////////////////////////////////////
/////////////////// | 1049 ////////////////////////////////////////////////////////////////////////////////
/////////////////// |
1080 | 1050 |
1081 #ifdef GR_TEST_UTILS | 1051 #ifdef GR_TEST_UTILS |
1082 | 1052 |
1083 BATCH_TEST_DEFINE(AAHairlineBatch) { | 1053 BATCH_TEST_DEFINE(AAHairlineBatch) { |
1084 // TODO put these in the cache | |
1085 static GrIndexBuffer* gQuadIndexBuffer; | |
1086 static GrIndexBuffer* gLineIndexBuffer; | |
1087 if (!gQuadIndexBuffer) { | |
1088 gQuadIndexBuffer = context->getGpu()->createInstancedIndexBuffer(kQuadId
xBufPattern, | |
1089 kIdxsPe
rQuad, | |
1090 kQuadsN
umInIdxBuffer, | |
1091 kQuadNu
mVertices); | |
1092 gLineIndexBuffer = context->getGpu()->createInstancedIndexBuffer(kLineSe
gIdxBufPattern, | |
1093 kIdxsPe
rLineSeg, | |
1094 kLineSe
gsNumInIdxBuffer, | |
1095 kLineSe
gNumVertices); | |
1096 } | |
1097 | |
1098 GrColor color = GrRandomColor(random); | 1054 GrColor color = GrRandomColor(random); |
1099 SkMatrix viewMatrix = GrTest::TestMatrix(random); | 1055 SkMatrix viewMatrix = GrTest::TestMatrix(random); |
1100 GrStrokeInfo stroke(SkStrokeRec::kHairline_InitStyle); | 1056 GrStrokeInfo stroke(SkStrokeRec::kHairline_InitStyle); |
1101 SkPath path = GrTest::TestPath(random); | 1057 SkPath path = GrTest::TestPath(random); |
1102 SkIRect devClipBounds; | 1058 SkIRect devClipBounds; |
1103 devClipBounds.setEmpty(); | 1059 devClipBounds.setEmpty(); |
1104 return create_hairline_batch(color, viewMatrix, path, stroke, devClipBounds,
gLineIndexBuffer, | 1060 return create_hairline_batch(color, viewMatrix, path, stroke, devClipBounds)
; |
1105 gQuadIndexBuffer); | |
1106 } | 1061 } |
1107 | 1062 |
1108 #endif | 1063 #endif |
OLD | NEW |