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