OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright 2015 Google Inc. | |
3 * | |
4 * Use of this source code is governed by a BSD-style license that can be | |
5 * found in the LICENSE file. | |
6 */ | |
7 | |
8 #include "GrPLSPathRenderer.h" | |
9 | |
10 #include "SkChunkAlloc.h" | |
11 #include "SkGeometry.h" | |
12 #include "SkPathPriv.h" | |
13 #include "SkString.h" | |
14 #include "SkTSort.h" | |
15 #include "SkTraceEvent.h" | |
16 #include "GrBatchFlushState.h" | |
17 #include "GrBatchTest.h" | |
18 #include "GrCaps.h" | |
19 #include "GrContext.h" | |
20 #include "GrDefaultGeoProcFactory.h" | |
21 #include "GrPLSGeometryProcessor.h" | |
22 #include "GrInvariantOutput.h" | |
23 #include "GrPathUtils.h" | |
24 #include "GrProcessor.h" | |
25 #include "GrPipelineBuilder.h" | |
26 #include "GrStrokeInfo.h" | |
27 #include "GrTessellator.h" | |
28 #include "batches/GrVertexBatch.h" | |
29 #include "glsl/GrGLSLGeometryProcessor.h" | |
30 #include "gl/builders/GrGLProgramBuilder.h" | |
31 #include "glsl/GrGLSLPLSPathRendering.h" | |
32 | |
33 GrPLSPathRenderer::GrPLSPathRenderer() { | |
34 } | |
35 | |
36 struct PLSVertex { | |
37 SkPoint fPos; | |
38 // for triangles, these are the three triangle vertices | |
39 // for quads, vert1 is the texture UV coords, and vert2 and vert3 are the li
ne segment | |
40 // comprising the flat edge of the quad | |
41 SkPoint fVert1; | |
42 SkPoint fVert2; | |
43 SkPoint fVert3; | |
44 int fWinding; | |
45 }; | |
46 typedef SkTArray<PLSVertex, true> PLSVertices; | |
47 | |
48 typedef SkTArray<SkPoint, true> FinishVertices; | |
49 | |
50 static const float kCubicTolerance = 0.5f; | |
51 static const float kConicTolerance = 0.5f; | |
52 | |
53 static const float kBloatSize = 1.0f; | |
54 | |
55 static const float kBloatLimit = 640000.0f; | |
56 | |
57 #define kQuadNumVertices 5 | |
58 static void add_quad(SkPoint pts[3], PLSVertices& vertices) { | |
59 SkPoint normal = SkPoint::Make(pts[0].fY - pts[2].fY, | |
60 pts[2].fX - pts[0].fX); | |
61 normal.setLength(kBloatSize); | |
62 SkScalar cross = (pts[1] - pts[0]).cross(pts[2] - pts[0]); | |
63 if (cross < 0) { | |
64 normal = -normal; | |
65 } | |
66 PLSVertex quad[kQuadNumVertices]; | |
67 quad[0].fPos = pts[0] + normal; | |
68 quad[1].fPos = pts[0] - normal; | |
69 quad[2].fPos = pts[1] - normal; | |
70 quad[3].fPos = pts[2] - normal; | |
71 quad[4].fPos = pts[2] + normal; | |
72 for (int i = 0; i < kQuadNumVertices; i++) { | |
73 quad[i].fWinding = cross < 0 ? 1 : -1; | |
74 if (cross > 0.0) { | |
75 quad[i].fVert2 = pts[0]; | |
76 quad[i].fVert3 = pts[2]; | |
77 } | |
78 else { | |
79 quad[i].fVert2 = pts[2]; | |
80 quad[i].fVert3 = pts[0]; | |
81 } | |
82 } | |
83 GrPathUtils::QuadUVMatrix DevToUV(pts); | |
84 DevToUV.apply<kQuadNumVertices, sizeof(PLSVertex), sizeof(SkPoint)>(quad); | |
85 for (int i = 2; i < kQuadNumVertices; i++) { | |
86 vertices.push_back(quad[0]); | |
87 vertices.push_back(quad[i - 1]); | |
88 vertices.push_back(quad[i]); | |
89 } | |
90 } | |
91 | |
92 /* Used by bloat_tri; outsets a single point. */ | |
93 static bool outset(SkPoint* p1, SkPoint line1, SkPoint line2) { | |
94 // rotate the two line vectors 90 degrees to form the normals, and compute | |
95 // the dot product of the normals | |
96 SkScalar dotProd = line1.fY * line2.fY + line1.fX * line2.fX; | |
97 SkScalar lengthSq = 1.0f / ((1.0f - dotProd) / 2.0f); | |
98 if (lengthSq > kBloatLimit) { | |
99 return false; | |
100 } | |
101 SkPoint bisector = line1 + line2; | |
102 bisector.setLength(SkScalarSqrt(lengthSq) * kBloatSize); | |
103 *p1 += bisector; | |
104 return true; | |
105 } | |
106 | |
107 /* Bloats a triangle so as to create a border kBloatSize pixels wide all around
it. */ | |
108 static bool bloat_tri(SkPoint pts[3]) { | |
109 SkPoint line1 = pts[0] - pts[1]; | |
110 line1.normalize(); | |
111 SkPoint line2 = pts[0] - pts[2]; | |
112 line2.normalize(); | |
113 SkPoint line3 = pts[1] - pts[2]; | |
114 line3.normalize(); | |
115 | |
116 SkPoint result[3]; | |
117 result[0] = pts[0]; | |
118 if (!outset(&result[0], line1, line2)) { | |
119 return false; | |
120 } | |
121 result[1] = pts[1]; | |
122 if (!outset(&result[1], -line1, line3)) { | |
123 return false; | |
124 } | |
125 result[2] = pts[2]; | |
126 if (!outset(&result[2], -line3, -line2)) { | |
127 return false; | |
128 } | |
129 pts[0] = result[0]; | |
130 pts[1] = result[1]; | |
131 pts[2] = result[2]; | |
132 return true; | |
133 } | |
134 | |
135 static bool get_geometry(const SkPath& path, const SkMatrix& m, PLSVertices& tri
Vertices, | |
136 PLSVertices& quadVertices, GrResourceProvider* resource
Provider, | |
137 SkRect bounds) { | |
138 SkScalar screenSpaceTol = GrPathUtils::kDefaultTolerance; | |
139 SkScalar tol = GrPathUtils::scaleToleranceToSrc(screenSpaceTol, m, bounds); | |
140 int contourCnt; | |
141 int maxPts = GrPathUtils::worstCasePointCount(path, &contourCnt, tol); | |
142 if (maxPts <= 0) { | |
143 return 0; | |
144 } | |
145 SkPath linesOnlyPath; | |
146 linesOnlyPath.setFillType(path.getFillType()); | |
147 SkSTArray<15, SkPoint, true> quadPoints; | |
148 SkPathPriv::FirstDirection dir = SkPathPriv::FirstDirection::kUnknown_FirstD
irection; | |
149 SkPath::Iter iter(path, true); | |
150 bool done = false; | |
151 while (!done) { | |
152 SkPoint pts[4]; | |
153 SkPath::Verb verb = iter.next(pts); | |
154 switch (verb) { | |
155 case SkPath::kMove_Verb: | |
156 SkASSERT(quadPoints.count() % 3 == 0); | |
157 for (int i = 0; i < quadPoints.count(); i += 3) { | |
158 add_quad(&quadPoints[i], quadVertices); | |
159 } | |
160 quadPoints.reset(); | |
161 m.mapPoints(&pts[0], 1); | |
162 linesOnlyPath.moveTo(pts[0]); | |
163 break; | |
164 case SkPath::kLine_Verb: | |
165 m.mapPoints(&pts[1], 1); | |
166 linesOnlyPath.lineTo(pts[1]); | |
167 break; | |
168 case SkPath::kQuad_Verb: | |
169 m.mapPoints(pts, 3); | |
170 linesOnlyPath.lineTo(pts[2]); | |
171 quadPoints.push_back(pts[0]); | |
172 quadPoints.push_back(pts[1]); | |
173 quadPoints.push_back(pts[2]); | |
174 break; | |
175 case SkPath::kCubic_Verb: { | |
176 m.mapPoints(pts, 4); | |
177 SkSTArray<15, SkPoint, true> quads; | |
178 GrPathUtils::convertCubicToQuads(pts, kCubicTolerance, false, di
r, &quads); | |
179 int count = quads.count(); | |
180 for (int q = 0; q < count; q += 3) { | |
181 linesOnlyPath.lineTo(quads[q + 2]); | |
182 quadPoints.push_back(quads[q]); | |
183 quadPoints.push_back(quads[q + 1]); | |
184 quadPoints.push_back(quads[q + 2]); | |
185 } | |
186 break; | |
187 } | |
188 case SkPath::kConic_Verb: { | |
189 m.mapPoints(pts, 3); | |
190 SkScalar weight = iter.conicWeight(); | |
191 SkAutoConicToQuads converter; | |
192 const SkPoint* quads = converter.computeQuads(pts, weight, kConi
cTolerance); | |
193 int count = converter.countQuads(); | |
194 for (int i = 0; i < count; ++i) { | |
195 linesOnlyPath.lineTo(quads[2 * i + 2]); | |
196 quadPoints.push_back(quads[2 * i]); | |
197 quadPoints.push_back(quads[2 * i + 1]); | |
198 quadPoints.push_back(quads[2 * i + 2]); | |
199 } | |
200 break; | |
201 } | |
202 case SkPath::kClose_Verb: | |
203 linesOnlyPath.close(); | |
204 break; | |
205 case SkPath::kDone_Verb: | |
206 done = true; | |
207 break; | |
208 default: SkASSERT(false); | |
209 } | |
210 } | |
211 SkASSERT(quadPoints.count() % 3 == 0); | |
212 for (int i = 0; i < quadPoints.count(); i += 3) { | |
213 add_quad(&quadPoints[i], quadVertices); | |
214 } | |
215 | |
216 static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain(); | |
217 GrUniqueKey key; | |
218 GrUniqueKey::Builder builder(&key, kDomain, 2); | |
219 builder[0] = path.getGenerationID(); | |
220 builder[1] = path.getFillType(); | |
221 builder.finish(); | |
222 GrTessellator::WindingVertex* windingVertices; | |
223 int triVertexCount = GrTessellator::PathToVertices(linesOnlyPath, 0, bounds,
&windingVertices); | |
224 if (triVertexCount > 0) { | |
225 for (int i = 0; i < triVertexCount; i += 3) { | |
226 SkPoint p1 = windingVertices[i].fPos; | |
227 SkPoint p2 = windingVertices[i + 1].fPos; | |
228 SkPoint p3 = windingVertices[i + 2].fPos; | |
229 int winding = windingVertices[i].fWinding; | |
230 SkASSERT(windingVertices[i + 1].fWinding == winding); | |
231 SkASSERT(windingVertices[i + 2].fWinding == winding); | |
232 SkScalar cross = (p2 - p1).cross(p3 - p1); | |
233 SkPoint bloated[3] = { p1, p2, p3 }; | |
234 if (cross < 0.0f) { | |
235 SkTSwap(p1, p3); | |
236 } | |
237 if (bloat_tri(bloated)) { | |
238 triVertices.push_back({ bloated[0], p1, p2, p3, winding }); | |
239 triVertices.push_back({ bloated[1], p1, p2, p3, winding }); | |
240 triVertices.push_back({ bloated[2], p1, p2, p3, winding }); | |
241 } | |
242 else { | |
243 SkScalar minX = SkTMin(p1.fX, SkTMin(p2.fX, p3.fX)) - 1.0f; | |
244 SkScalar minY = SkTMin(p1.fY, SkTMin(p2.fY, p3.fY)) - 1.0f; | |
245 SkScalar maxX = SkTMax(p1.fX, SkTMax(p2.fX, p3.fX)) + 1.0f; | |
246 SkScalar maxY = SkTMax(p1.fY, SkTMax(p2.fY, p3.fY)) + 1.0f; | |
247 triVertices.push_back({ { minX, minY }, p1, p2, p3, winding }); | |
248 triVertices.push_back({ { maxX, minY }, p1, p2, p3, winding }); | |
249 triVertices.push_back({ { minX, maxY }, p1, p2, p3, winding }); | |
250 triVertices.push_back({ { maxX, minY }, p1, p2, p3, winding }); | |
251 triVertices.push_back({ { maxX, maxY }, p1, p2, p3, winding }); | |
252 triVertices.push_back({ { minX, maxY }, p1, p2, p3, winding }); | |
253 } | |
254 } | |
255 delete[] windingVertices; | |
256 } | |
257 return triVertexCount > 0 || quadVertices.count() > 0; | |
258 } | |
259 | |
260 class PLSAATriangleEffect : public GrPLSGeometryProcessor { | |
261 public: | |
262 | |
263 static GrPLSGeometryProcessor* Create(const SkMatrix& localMatrix, | |
264 bool usesLocalCoords) { | |
265 return new PLSAATriangleEffect(localMatrix, usesLocalCoords); | |
266 } | |
267 | |
268 virtual ~PLSAATriangleEffect() {} | |
269 | |
270 const char* name() const override { return "PLSAATriangle"; } | |
271 | |
272 const Attribute* inPosition() const { return fInPosition; } | |
273 const Attribute* inVertex1() const { return fInVertex1; } | |
274 const Attribute* inVertex2() const { return fInVertex2; } | |
275 const Attribute* inVertex3() const { return fInVertex3; } | |
276 const Attribute* inWindings() const { return fInWindings; } | |
277 const SkMatrix& localMatrix() const { return fLocalMatrix; } | |
278 bool usesLocalCoords() const { return fUsesLocalCoords; } | |
279 | |
280 class GLSLProcessor : public GrGLSLGeometryProcessor { | |
281 public: | |
282 GLSLProcessor(const GrGeometryProcessor&) {} | |
283 | |
284 void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override { | |
285 const PLSAATriangleEffect& te = args.fGP.cast<PLSAATriangleEffect>()
; | |
286 GrGLSLVertexBuilder* vsBuilder = args.fVertBuilder; | |
287 GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler; | |
288 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; | |
289 | |
290 varyingHandler->emitAttributes(te); | |
291 | |
292 this->setupPosition(vsBuilder, gpArgs, te.inPosition()->fName); | |
293 | |
294 GrGLSLVertToFrag v1(kVec2f_GrSLType); | |
295 varyingHandler->addVarying("Vertex1", &v1, kHigh_GrSLPrecision); | |
296 vsBuilder->codeAppendf("%s = vec2(%s.x, %s.y);", | |
297 v1.vsOut(), | |
298 te.inVertex1()->fName, | |
299 te.inVertex1()->fName); | |
300 | |
301 GrGLSLVertToFrag v2(kVec2f_GrSLType); | |
302 varyingHandler->addVarying("Vertex2", &v2, kHigh_GrSLPrecision); | |
303 vsBuilder->codeAppendf("%s = vec2(%s.x, %s.y);", | |
304 v2.vsOut(), | |
305 te.inVertex2()->fName, | |
306 te.inVertex2()->fName); | |
307 | |
308 GrGLSLVertToFrag v3(kVec2f_GrSLType); | |
309 varyingHandler->addVarying("Vertex3", &v3, kHigh_GrSLPrecision); | |
310 vsBuilder->codeAppendf("%s = vec2(%s.x, %s.y);", | |
311 v3.vsOut(), | |
312 te.inVertex3()->fName, | |
313 te.inVertex3()->fName); | |
314 | |
315 GrGLSLVertToFrag delta1(kVec2f_GrSLType); | |
316 varyingHandler->addVarying("delta1", &delta1, kHigh_GrSLPrecision); | |
317 vsBuilder->codeAppendf("%s = vec2(%s.x - %s.x, %s.y - %s.y) * 0.5;",
| |
318 delta1.vsOut(), v1.vsOut(), v2.vsOut(), v2.vs
Out(), v1.vsOut()); | |
319 | |
320 GrGLSLVertToFrag delta2(kVec2f_GrSLType); | |
321 varyingHandler->addVarying("delta2", &delta2, kHigh_GrSLPrecision); | |
322 vsBuilder->codeAppendf("%s = vec2(%s.x - %s.x, %s.y - %s.y) * 0.5;",
| |
323 delta2.vsOut(), v2.vsOut(), v3.vsOut(), v3.vs
Out(), v2.vsOut()); | |
324 | |
325 GrGLSLVertToFrag delta3(kVec2f_GrSLType); | |
326 varyingHandler->addVarying("delta3", &delta3, kHigh_GrSLPrecision); | |
327 vsBuilder->codeAppendf("%s = vec2(%s.x - %s.x, %s.y - %s.y) * 0.5;",
| |
328 delta3.vsOut(), v3.vsOut(), v1.vsOut(), v1.vs
Out(), v3.vsOut()); | |
329 | |
330 GrGLSLVertToFrag windings(kInt_GrSLType); | |
331 varyingHandler->addVarying("windings", &windings, kLow_GrSLPrecision
); | |
332 vsBuilder->codeAppendf("%s = %s;", | |
333 windings.vsOut(), te.inWindings()->fName); | |
334 | |
335 // emit transforms | |
336 this->emitTransforms(vsBuilder, varyingHandler, uniformHandler, gpAr
gs->fPositionVar, | |
337 te.inPosition()->fName, te.localMatrix(), args.
fTransformsIn, | |
338 args.fTransformsOut); | |
339 | |
340 GrGLSLFragmentBuilder* fsBuilder = args.fFragBuilder; | |
341 SkAssertResult(fsBuilder->enableFeature( | |
342 GrGLSLFragmentShaderBuilder::kPixelLocalStorage_GLSLF
eature)); | |
343 SkAssertResult(fsBuilder->enableFeature( | |
344 GrGLSLFragmentShaderBuilder::kStandardDerivatives_GLSLFeatur
e)); | |
345 fsBuilder->declAppendf(GR_GL_PLS_PATH_DATA_DECL); | |
346 // Compute four subsamples, each shifted a quarter pixel along x and
y from | |
347 // gl_FragCoord. The oriented box positioning of the subsamples is o
f course not | |
348 // optimal, but it greatly simplifies the math and this simplificati
on is necessary for | |
349 // performance reasons. | |
350 fsBuilder->codeAppendf("highp vec2 firstSample = %s.xy - vec2(0.25);
", | |
351 fsBuilder->fragmentPosition()); | |
352 fsBuilder->codeAppendf("highp vec2 delta1 = %s;", delta1.fsIn()); | |
353 fsBuilder->codeAppendf("highp vec2 delta2 = %s;", delta2.fsIn()); | |
354 fsBuilder->codeAppendf("highp vec2 delta3 = %s;", delta3.fsIn()); | |
355 // Check whether first sample is inside the triangle by computing th
ree dot products. If | |
356 // all are < 0, we're inside. The first vector in each case is half
of what it is | |
357 // "supposed" to be, because we re-use them later as adjustment fact
ors for which half | |
358 // is the correct value, so we multiply the dots by two to compensat
e. | |
359 fsBuilder->codeAppendf("highp float d1 = dot(delta1, (firstSample -
%s).yx) * 2.0;", | |
360 v1.fsIn()); | |
361 fsBuilder->codeAppendf("highp float d2 = dot(delta2, (firstSample -
%s).yx) * 2.0;", | |
362 v2.fsIn()); | |
363 fsBuilder->codeAppendf("highp float d3 = dot(delta3, (firstSample -
%s).yx) * 2.0;", | |
364 v3.fsIn()); | |
365 fsBuilder->codeAppend("highp float dmax = max(d1, max(d2, d3));"); | |
366 fsBuilder->codeAppendf("pls.windings[0] += (dmax <= 0.0) ? %s : 0;",
windings.fsIn()); | |
367 // for subsequent samples, we don't recalculate the entire dot produ
ct -- just adjust it | |
368 // to the value it would have if we did recompute it. | |
369 fsBuilder->codeAppend("d1 += delta1.x;"); | |
370 fsBuilder->codeAppend("d2 += delta2.x;"); | |
371 fsBuilder->codeAppend("d3 += delta3.x;"); | |
372 fsBuilder->codeAppend("dmax = max(d1, max(d2, d3));"); | |
373 fsBuilder->codeAppendf("pls.windings[1] += (dmax <= 0.0) ? %s : 0;",
windings.fsIn()); | |
374 fsBuilder->codeAppend("d1 += delta1.y;"); | |
375 fsBuilder->codeAppend("d2 += delta2.y;"); | |
376 fsBuilder->codeAppend("d3 += delta3.y;"); | |
377 fsBuilder->codeAppend("dmax = max(d1, max(d2, d3));"); | |
378 fsBuilder->codeAppendf("pls.windings[2] += (dmax <= 0.0) ? %s : 0;",
windings.fsIn()); | |
379 fsBuilder->codeAppend("d1 -= delta1.x;"); | |
380 fsBuilder->codeAppend("d2 -= delta2.x;"); | |
381 fsBuilder->codeAppend("d3 -= delta3.x;"); | |
382 fsBuilder->codeAppend("dmax = max(d1, max(d2, d3));"); | |
383 fsBuilder->codeAppendf("pls.windings[3] += (dmax <= 0.0) ? %s : 0;",
windings.fsIn()); | |
384 } | |
385 | |
386 static inline void GenKey(const GrGeometryProcessor& gp, | |
387 const GrGLSLCaps&, | |
388 GrProcessorKeyBuilder* b) { | |
389 const PLSAATriangleEffect& te = gp.cast<PLSAATriangleEffect>(); | |
390 uint32_t key = 0; | |
391 key |= te.localMatrix().hasPerspective() ? 0x1 : 0x0; | |
392 b->add32(key); | |
393 } | |
394 | |
395 virtual void setData(const GrGLSLProgramDataManager& pdman, | |
396 const GrPrimitiveProcessor& gp) override { | |
397 } | |
398 | |
399 void setTransformData(const GrPrimitiveProcessor& primProc, | |
400 const GrGLSLProgramDataManager& pdman, | |
401 int index, | |
402 const SkTArray<const GrCoordTransform*, true>& tra
nsforms) override { | |
403 this->setTransformDataHelper<PLSAATriangleEffect>(primProc, pdman, i
ndex, transforms); | |
404 } | |
405 | |
406 private: | |
407 typedef GrGLSLGeometryProcessor INHERITED; | |
408 }; | |
409 | |
410 virtual void getGLSLProcessorKey(const GrGLSLCaps& caps, | |
411 GrProcessorKeyBuilder* b) const override { | |
412 GLSLProcessor::GenKey(*this, caps, b); | |
413 } | |
414 | |
415 virtual GrGLSLPrimitiveProcessor* createGLSLInstance(const GrGLSLCaps&) cons
t override { | |
416 return new GLSLProcessor(*this); | |
417 } | |
418 | |
419 private: | |
420 PLSAATriangleEffect(const SkMatrix& localMatrix, bool usesLocalCoords) | |
421 : fLocalMatrix(localMatrix) | |
422 , fUsesLocalCoords(usesLocalCoords) { | |
423 this->initClassID<PLSAATriangleEffect>(); | |
424 fInPosition = &this->addVertexAttrib(Attribute("inPosition", kVec2f_GrVe
rtexAttribType, | |
425 kHigh_GrSLPrecision)); | |
426 fInVertex1 = &this->addVertexAttrib(Attribute("inVertex1", kVec2f_GrVert
exAttribType, | |
427 kHigh_GrSLPrecision)); | |
428 fInVertex2 = &this->addVertexAttrib(Attribute("inVertex2", kVec2f_GrVert
exAttribType, | |
429 kHigh_GrSLPrecision)); | |
430 fInVertex3 = &this->addVertexAttrib(Attribute("inVertex3", kVec2f_GrVert
exAttribType, | |
431 kHigh_GrSLPrecision)); | |
432 fInWindings = &this->addVertexAttrib(Attribute("inWindings", kInt_GrVert
exAttribType, | |
433 kLow_GrSLPrecision)); | |
434 this->setWillReadFragmentPosition(); | |
435 } | |
436 | |
437 const Attribute* fInPosition; | |
438 const Attribute* fInVertex1; | |
439 const Attribute* fInVertex2; | |
440 const Attribute* fInVertex3; | |
441 const Attribute* fInWindings; | |
442 SkMatrix fLocalMatrix; | |
443 bool fUsesLocalCoords; | |
444 | |
445 GR_DECLARE_GEOMETRY_PROCESSOR_TEST; | |
446 | |
447 typedef GrGeometryProcessor INHERITED; | |
448 }; | |
449 | |
450 /////////////////////////////////////////////////////////////////////////////// | |
451 | |
452 /* | |
453 * Quadratic specified by 0=u^2-v canonical coords. u and v are the first | |
454 * two components of the vertex attribute. Coverage is based on signed | |
455 * distance with negative being inside, positive outside. The edge is specified
in | |
456 * window space (y-down). If either the third or fourth component of the interpo
lated | |
457 * vertex coord is > 0 then the pixel is considered outside the edge. This is us
ed to | |
458 * attempt to trim to a portion of the infinite quad. | |
459 * Requires shader derivative instruction support. | |
460 */ | |
461 | |
462 class PLSQuadEdgeEffect : public GrPLSGeometryProcessor { | |
463 public: | |
464 | |
465 static GrPLSGeometryProcessor* Create(const SkMatrix& localMatrix, | |
466 bool usesLocalCoords) { | |
467 return new PLSQuadEdgeEffect(localMatrix, usesLocalCoords); | |
468 } | |
469 | |
470 virtual ~PLSQuadEdgeEffect() {} | |
471 | |
472 const char* name() const override { return "PLSQuadEdge"; } | |
473 | |
474 const Attribute* inPosition() const { return fInPosition; } | |
475 const Attribute* inUV() const { return fInUV; } | |
476 const Attribute* inEndpoint1() const { return fInEndpoint1; } | |
477 const Attribute* inEndpoint2() const { return fInEndpoint2; } | |
478 const Attribute* inWindings() const { return fInWindings; } | |
479 const SkMatrix& localMatrix() const { return fLocalMatrix; } | |
480 bool usesLocalCoords() const { return fUsesLocalCoords; } | |
481 | |
482 class GLSLProcessor : public GrGLSLGeometryProcessor { | |
483 public: | |
484 GLSLProcessor(const GrGeometryProcessor&) {} | |
485 | |
486 void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override { | |
487 const PLSQuadEdgeEffect& qe = args.fGP.cast<PLSQuadEdgeEffect>(); | |
488 GrGLSLVertexBuilder* vsBuilder = args.fVertBuilder; | |
489 GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler; | |
490 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; | |
491 | |
492 // emit attributes | |
493 varyingHandler->emitAttributes(qe); | |
494 | |
495 GrGLSLVertToFrag uv(kVec2f_GrSLType); | |
496 varyingHandler->addVarying("uv", &uv, kHigh_GrSLPrecision); | |
497 vsBuilder->codeAppendf("%s = %s;", uv.vsOut(), qe.inUV()->fName); | |
498 | |
499 GrGLSLVertToFrag ep1(kVec2f_GrSLType); | |
500 varyingHandler->addVarying("endpoint1", &ep1, kHigh_GrSLPrecision); | |
501 vsBuilder->codeAppendf("%s = vec2(%s.x, %s.y);", ep1.vsOut(), | |
502 qe.inEndpoint1()->fName, qe.inEndpoint1()->fNa
me); | |
503 | |
504 GrGLSLVertToFrag ep2(kVec2f_GrSLType); | |
505 varyingHandler->addVarying("endpoint2", &ep2, kHigh_GrSLPrecision); | |
506 vsBuilder->codeAppendf("%s = vec2(%s.x, %s.y);", ep2.vsOut(), | |
507 qe.inEndpoint2()->fName, qe.inEndpoint2()->fNa
me); | |
508 | |
509 GrGLSLVertToFrag delta(kVec2f_GrSLType); | |
510 varyingHandler->addVarying("delta", &delta, kHigh_GrSLPrecision); | |
511 vsBuilder->codeAppendf("%s = vec2(%s.x - %s.x, %s.y - %s.y) * 0.5;",
| |
512 delta.vsOut(), ep1.vsOut(), ep2.vsOut(), ep2.
vsOut(), | |
513 ep1.vsOut()); | |
514 | |
515 GrGLSLVertToFrag windings(kInt_GrSLType); | |
516 varyingHandler->addVarying("windings", &windings, kLow_GrSLPrecision
); | |
517 vsBuilder->codeAppendf("%s = %s;", | |
518 windings.vsOut(), qe.inWindings()->fName); | |
519 | |
520 // Setup position | |
521 this->setupPosition(vsBuilder, gpArgs, qe.inPosition()->fName); | |
522 | |
523 // emit transforms | |
524 this->emitTransforms(vsBuilder, varyingHandler, uniformHandler, gpAr
gs->fPositionVar, | |
525 qe.inPosition()->fName, qe.localMatrix(), args.
fTransformsIn, | |
526 args.fTransformsOut); | |
527 | |
528 GrGLSLFragmentBuilder* fsBuilder = args.fFragBuilder; | |
529 SkAssertResult(fsBuilder->enableFeature( | |
530 GrGLSLFragmentShaderBuilder::kPixelLocalStorage_GLSLF
eature)); | |
531 SkAssertResult(fsBuilder->enableFeature( | |
532 GrGLSLFragmentShaderBuilder::kStandardDerivatives_GLSLFeatur
e)); | |
533 static const int QUAD_ARGS = 2; | |
534 GrGLSLShaderVar inQuadArgs[QUAD_ARGS] = { | |
535 GrGLSLShaderVar("dot", kFloat_GrSLType, 0, kHigh_GrSLPrecision), | |
536 GrGLSLShaderVar("uv", kVec2f_GrSLType, 0, kHigh_GrSLPrecision) | |
537 }; | |
538 SkString inQuadName; | |
539 | |
540 const char* inQuadCode = "if (uv.x * uv.x <= uv.y) {" | |
541 "return dot >= 0.0;" | |
542 "} else {" | |
543 "return false;" | |
544 "}"; | |
545 fsBuilder->emitFunction(kBool_GrSLType, "in_quad", QUAD_ARGS, inQuad
Args, inQuadCode, | |
546 &inQuadName); | |
547 fsBuilder->declAppendf(GR_GL_PLS_PATH_DATA_DECL); | |
548 // keep the derivative instructions outside the conditional | |
549 fsBuilder->codeAppendf("highp vec2 uvdX = dFdx(%s);", uv.fsIn()); | |
550 fsBuilder->codeAppendf("highp vec2 uvdY = dFdy(%s);", uv.fsIn()); | |
551 fsBuilder->codeAppend("highp vec2 uvIncX = uvdX * 0.45 + uvdY * -0.1
;"); | |
552 fsBuilder->codeAppend("highp vec2 uvIncY = uvdX * 0.1 + uvdY * 0.55;
"); | |
553 fsBuilder->codeAppendf("highp vec2 uv = %s.xy - uvdX * 0.35 - uvdY *
0.25;", | |
554 uv.fsIn()); | |
555 fsBuilder->codeAppendf("highp vec2 firstSample = %s.xy - vec2(0.25);
", | |
556 fsBuilder->fragmentPosition()); | |
557 fsBuilder->codeAppendf("highp float d = dot(%s, (firstSample - %s).y
x) * 2.0;", | |
558 delta.fsIn(), ep1.fsIn()); | |
559 fsBuilder->codeAppendf("pls.windings[0] += %s(d, uv) ? %s : 0;", inQ
uadName.c_str(), | |
560 windings.fsIn()); | |
561 fsBuilder->codeAppend("uv += uvIncX;"); | |
562 fsBuilder->codeAppendf("d += %s.x;", delta.fsIn()); | |
563 fsBuilder->codeAppendf("pls.windings[1] += %s(d, uv) ? %s : 0;", inQ
uadName.c_str(), | |
564 windings.fsIn()); | |
565 fsBuilder->codeAppend("uv += uvIncY;"); | |
566 fsBuilder->codeAppendf("d += %s.y;", delta.fsIn()); | |
567 fsBuilder->codeAppendf("pls.windings[2] += %s(d, uv) ? %s : 0;", inQ
uadName.c_str(), | |
568 windings.fsIn()); | |
569 fsBuilder->codeAppend("uv -= uvIncX;"); | |
570 fsBuilder->codeAppendf("d -= %s.x;", delta.fsIn()); | |
571 fsBuilder->codeAppendf("pls.windings[3] += %s(d, uv) ? %s : 0;", inQ
uadName.c_str(), | |
572 windings.fsIn()); | |
573 } | |
574 | |
575 static inline void GenKey(const GrGeometryProcessor& gp, | |
576 const GrGLSLCaps&, | |
577 GrProcessorKeyBuilder* b) { | |
578 const PLSQuadEdgeEffect& qee = gp.cast<PLSQuadEdgeEffect>(); | |
579 uint32_t key = 0; | |
580 key |= qee.usesLocalCoords() && qee.localMatrix().hasPerspective() ?
0x1 : 0x0; | |
581 b->add32(key); | |
582 } | |
583 | |
584 virtual void setData(const GrGLSLProgramDataManager& pdman, | |
585 const GrPrimitiveProcessor& gp) override { | |
586 } | |
587 | |
588 void setTransformData(const GrPrimitiveProcessor& primProc, | |
589 const GrGLSLProgramDataManager& pdman, | |
590 int index, | |
591 const SkTArray<const GrCoordTransform*, true>& tra
nsforms) override { | |
592 this->setTransformDataHelper<PLSQuadEdgeEffect>(primProc, pdman, ind
ex, transforms); | |
593 } | |
594 | |
595 private: | |
596 typedef GrGLSLGeometryProcessor INHERITED; | |
597 }; | |
598 | |
599 virtual void getGLSLProcessorKey(const GrGLSLCaps& caps, | |
600 GrProcessorKeyBuilder* b) const override { | |
601 GLSLProcessor::GenKey(*this, caps, b); | |
602 } | |
603 | |
604 virtual GrGLSLPrimitiveProcessor* createGLSLInstance(const GrGLSLCaps&) cons
t override { | |
605 return new GLSLProcessor(*this); | |
606 } | |
607 | |
608 private: | |
609 PLSQuadEdgeEffect(const SkMatrix& localMatrix, bool usesLocalCoords) | |
610 : fLocalMatrix(localMatrix) | |
611 , fUsesLocalCoords(usesLocalCoords) { | |
612 this->initClassID<PLSQuadEdgeEffect>(); | |
613 fInPosition = &this->addVertexAttrib(Attribute("inPosition", kVec2f_GrVe
rtexAttribType, | |
614 kHigh_GrSLPrecision)); | |
615 fInUV = &this->addVertexAttrib(Attribute("inUV", kVec2f_GrVertexAttribTy
pe, | |
616 kHigh_GrSLPrecision)); | |
617 fInEndpoint1 = &this->addVertexAttrib(Attribute("inEndpoint1", kVec2f_Gr
VertexAttribType, | |
618 kHigh_GrSLPrecision)); | |
619 fInEndpoint2 = &this->addVertexAttrib(Attribute("inEndpoint2", kVec2f_Gr
VertexAttribType, | |
620 kHigh_GrSLPrecision)); | |
621 fInWindings = &this->addVertexAttrib(Attribute("inWindings", kInt_GrVer
texAttribType, | |
622 kLow_GrSLPrecision)); | |
623 this->setWillReadFragmentPosition(); | |
624 } | |
625 | |
626 const Attribute* fInPosition; | |
627 const Attribute* fInUV; | |
628 const Attribute* fInEndpoint1; | |
629 const Attribute* fInEndpoint2; | |
630 const Attribute* fInWindings; | |
631 SkMatrix fLocalMatrix; | |
632 bool fUsesLocalCoords; | |
633 | |
634 GR_DECLARE_GEOMETRY_PROCESSOR_TEST; | |
635 | |
636 typedef GrGeometryProcessor INHERITED; | |
637 }; | |
638 | |
639 class PLSFinishEffect : public GrGeometryProcessor { | |
640 public: | |
641 | |
642 static GrGeometryProcessor* Create(GrColor color, bool useEvenOdd, const SkM
atrix& localMatrix, | |
643 bool usesLocalCoords) { | |
644 return new PLSFinishEffect(color, useEvenOdd, localMatrix, usesLocalCoor
ds); | |
645 } | |
646 | |
647 virtual ~PLSFinishEffect() {} | |
648 | |
649 const char* name() const override { return "PLSFinish"; } | |
650 | |
651 const Attribute* inPosition() const { return fInPosition; } | |
652 GrColor color() const { return fColor; } | |
653 bool colorIgnored() const { return GrColor_ILLEGAL == fColor; } | |
654 const SkMatrix& localMatrix() const { return fLocalMatrix; } | |
655 bool usesLocalCoords() const { return fUsesLocalCoords; } | |
656 | |
657 GrPixelLocalStorageState getPixelLocalStorageState() const override { | |
658 return GrPixelLocalStorageState::kFinish_GrPixelLocalStorageState; | |
659 } | |
660 | |
661 const char* getDestColorOverride() const override { | |
662 return GR_GL_PLS_DSTCOLOR_NAME; | |
663 } | |
664 | |
665 class GLSLProcessor : public GrGLSLGeometryProcessor { | |
666 public: | |
667 GLSLProcessor(const GrGeometryProcessor&) {} | |
668 | |
669 void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override { | |
670 const PLSFinishEffect& fe = args.fGP.cast<PLSFinishEffect>(); | |
671 GrGLSLVertexBuilder* vsBuilder = args.fVertBuilder; | |
672 GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler; | |
673 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; | |
674 | |
675 fUseEvenOdd = uniformHandler->addUniform(GrGLUniformHandler::kFragme
nt_Visibility, | |
676 kFloat_GrSLType, kLow_GrSLPr
ecision, | |
677 "useEvenOdd"); | |
678 const char* useEvenOdd = uniformHandler->getUniformCStr(fUseEvenOdd)
; | |
679 | |
680 varyingHandler->emitAttributes(fe); | |
681 this->setupPosition(vsBuilder, gpArgs, fe.inPosition()->fName); | |
682 this->emitTransforms(vsBuilder, varyingHandler, uniformHandler, gpAr
gs->fPositionVar, | |
683 fe.inPosition()->fName, fe.localMatrix(), args.
fTransformsIn, | |
684 args.fTransformsOut); | |
685 | |
686 GrGLSLFragmentBuilder* fsBuilder = args.fFragBuilder; | |
687 SkAssertResult(fsBuilder->enableFeature( | |
688 GrGLSLFragmentShaderBuilder::kPixelLocalStorage_GLSLF
eature)); | |
689 fsBuilder->declAppendf(GR_GL_PLS_PATH_DATA_DECL); | |
690 fsBuilder->codeAppend("float coverage;"); | |
691 fsBuilder->codeAppendf("if (%s != 0.0) {", useEvenOdd); | |
692 fsBuilder->codeAppend("coverage = float(abs(pls.windings[0]) % 2) *
0.25;"); | |
693 fsBuilder->codeAppend("coverage += float(abs(pls.windings[1]) % 2) *
0.25;"); | |
694 fsBuilder->codeAppend("coverage += float(abs(pls.windings[2]) % 2) *
0.25;"); | |
695 fsBuilder->codeAppend("coverage += float(abs(pls.windings[3]) % 2) *
0.25;"); | |
696 fsBuilder->codeAppend("} else {"); | |
697 fsBuilder->codeAppend("coverage = pls.windings[0] != 0 ? 0.25 : 0.0;
"); | |
698 fsBuilder->codeAppend("coverage += pls.windings[1] != 0 ? 0.25 : 0.0
;"); | |
699 fsBuilder->codeAppend("coverage += pls.windings[2] != 0 ? 0.25 : 0.0
;"); | |
700 fsBuilder->codeAppend("coverage += pls.windings[3] != 0 ? 0.25 : 0.0
;"); | |
701 fsBuilder->codeAppend("}"); | |
702 if (!fe.colorIgnored()) { | |
703 this->setupUniformColor(fsBuilder, uniformHandler, args.fOutputC
olor, | |
704 &fColorUniform); | |
705 } | |
706 fsBuilder->codeAppendf("%s = vec4(coverage);", args.fOutputCoverage)
; | |
707 } | |
708 | |
709 static inline void GenKey(const GrGeometryProcessor& gp, | |
710 const GrGLSLCaps&, | |
711 GrProcessorKeyBuilder* b) { | |
712 const PLSFinishEffect& fe = gp.cast<PLSFinishEffect>(); | |
713 uint32_t key = 0; | |
714 key |= fe.usesLocalCoords() && fe.localMatrix().hasPerspective() ? 0
x1 : 0x0; | |
715 b->add32(key); | |
716 } | |
717 | |
718 virtual void setData(const GrGLSLProgramDataManager& pdman, | |
719 const GrPrimitiveProcessor& gp) override { | |
720 const PLSFinishEffect& fe = gp.cast<PLSFinishEffect>(); | |
721 pdman.set1f(fUseEvenOdd, fe.fUseEvenOdd); | |
722 if (fe.color() != fColor && !fe.colorIgnored()) { | |
723 GrGLfloat c[4]; | |
724 GrColorToRGBAFloat(fe.color(), c); | |
725 pdman.set4fv(fColorUniform, 1, c); | |
726 fColor = fe.color(); | |
727 } | |
728 } | |
729 | |
730 void setTransformData(const GrPrimitiveProcessor& primProc, | |
731 const GrGLSLProgramDataManager& pdman, | |
732 int index, | |
733 const SkTArray<const GrCoordTransform*, true>& tra
nsforms) override { | |
734 this->setTransformDataHelper<PLSFinishEffect>(primProc, pdman, index
, transforms); | |
735 } | |
736 | |
737 private: | |
738 GrColor fColor; | |
739 UniformHandle fColorUniform; | |
740 UniformHandle fUseEvenOdd; | |
741 | |
742 typedef GrGLSLGeometryProcessor INHERITED; | |
743 }; | |
744 | |
745 virtual void getGLSLProcessorKey(const GrGLSLCaps& caps, | |
746 GrProcessorKeyBuilder* b) const override { | |
747 GLSLProcessor::GenKey(*this, caps, b); | |
748 } | |
749 | |
750 virtual GrGLSLPrimitiveProcessor* createGLSLInstance(const GrGLSLCaps&) cons
t override { | |
751 return new GLSLProcessor(*this); | |
752 } | |
753 | |
754 private: | |
755 PLSFinishEffect(GrColor color, bool useEvenOdd, const SkMatrix& localMatrix,
| |
756 bool usesLocalCoords) | |
757 : fColor(color) | |
758 , fUseEvenOdd(useEvenOdd) | |
759 , fLocalMatrix(localMatrix) | |
760 , fUsesLocalCoords(usesLocalCoords) { | |
761 this->initClassID<PLSFinishEffect>(); | |
762 fInPosition = &this->addVertexAttrib(Attribute("inPosition", kVec2f_GrVe
rtexAttribType, | |
763 kHigh_GrSLPrecision)); | |
764 } | |
765 | |
766 const Attribute* fInPosition; | |
767 GrColor fColor; | |
768 bool fUseEvenOdd; | |
769 SkMatrix fLocalMatrix; | |
770 bool fUsesLocalCoords; | |
771 | |
772 typedef GrGeometryProcessor INHERITED; | |
773 }; | |
774 | |
775 /////////////////////////////////////////////////////////////////////////////// | |
776 | |
777 bool GrPLSPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const { | |
778 // We have support for even-odd rendering, but are having some troublesome | |
779 // seams. Disable in the presence of even-odd for now. | |
780 return args.fShaderCaps->shaderDerivativeSupport() && args.fAntiAlias && | |
781 args.fStroke->isFillStyle() && !args.fPath->isInverseFillType() && | |
782 args.fPath->getFillType() == SkPath::FillType::kWinding_FillType; | |
783 } | |
784 | |
785 class PLSPathBatch : public GrVertexBatch { | |
786 public: | |
787 DEFINE_BATCH_CLASS_ID | |
788 struct Geometry { | |
789 GrColor fColor; | |
790 SkMatrix fViewMatrix; | |
791 SkPath fPath; | |
792 }; | |
793 | |
794 static GrDrawBatch* Create(const Geometry& geometry) { | |
795 return new PLSPathBatch(geometry); | |
796 } | |
797 | |
798 const char* name() const override { return "PLSBatch"; } | |
799 | |
800 void computePipelineOptimizations(GrInitInvariantOutput* color, | |
801 GrInitInvariantOutput* coverage, | |
802 GrBatchToXPOverrides* overrides) const ove
rride { | |
803 // When this is called on a batch, there is only one geometry bundle | |
804 color->setKnownFourComponents(fGeoData[0].fColor); | |
805 coverage->setUnknownSingleComponent(); | |
806 overrides->fUsePLSDstRead = true; | |
807 } | |
808 | |
809 void initBatchTracker(const GrXPOverridesForBatch& overrides) override { | |
810 // Handle any color overrides | |
811 if (!overrides.readsColor()) { | |
812 fGeoData[0].fColor = GrColor_ILLEGAL; | |
813 } | |
814 overrides.getOverrideColorIfSet(&fGeoData[0].fColor); | |
815 | |
816 // setup batch properties | |
817 fBatch.fColorIgnored = !overrides.readsColor(); | |
818 fBatch.fColor = fGeoData[0].fColor; | |
819 fBatch.fUsesLocalCoords = overrides.readsLocalCoords(); | |
820 fBatch.fCoverageIgnored = !overrides.readsCoverage(); | |
821 fBatch.fCanTweakAlphaForCoverage = overrides.canTweakAlphaForCoverage(); | |
822 } | |
823 | |
824 void onPrepareDraws(Target* target) const override { | |
825 int instanceCount = fGeoData.count(); | |
826 | |
827 SkMatrix invert; | |
828 if (this->usesLocalCoords() && !this->viewMatrix().invert(&invert)) { | |
829 SkDebugf("Could not invert viewmatrix\n"); | |
830 return; | |
831 } | |
832 | |
833 // Setup GrGeometryProcessors | |
834 SkAutoTUnref<GrPLSGeometryProcessor> triangleProcessor( | |
835 PLSAATriangleEffect::Create(invert, this->usesLocalCoords())); | |
836 SkAutoTUnref<GrPLSGeometryProcessor> quadProcessor( | |
837 PLSQuadEdgeEffect::Create(invert, this->usesLocalCoords())); | |
838 | |
839 GrResourceProvider* rp = target->resourceProvider(); | |
840 for (int i = 0; i < instanceCount; ++i) { | |
841 const Geometry& args = fGeoData[i]; | |
842 SkRect bounds = args.fPath.getBounds(); | |
843 args.fViewMatrix.mapRect(&bounds); | |
844 bounds.fLeft = SkScalarFloorToScalar(bounds.fLeft); | |
845 bounds.fTop = SkScalarFloorToScalar(bounds.fTop); | |
846 bounds.fRight = SkScalarCeilToScalar(bounds.fRight); | |
847 bounds.fBottom = SkScalarCeilToScalar(bounds.fBottom); | |
848 triangleProcessor->setBounds(bounds); | |
849 quadProcessor->setBounds(bounds); | |
850 | |
851 // We use the fact that SkPath::transform path does subdivision base
d on | |
852 // perspective. Otherwise, we apply the view matrix when copying to
the | |
853 // segment representation. | |
854 const SkMatrix* viewMatrix = &args.fViewMatrix; | |
855 | |
856 // We avoid initializing the path unless we have to | |
857 const SkPath* pathPtr = &args.fPath; | |
858 SkTLazy<SkPath> tmpPath; | |
859 if (viewMatrix->hasPerspective()) { | |
860 SkPath* tmpPathPtr = tmpPath.init(*pathPtr); | |
861 tmpPathPtr->setIsVolatile(true); | |
862 tmpPathPtr->transform(*viewMatrix); | |
863 viewMatrix = &SkMatrix::I(); | |
864 pathPtr = tmpPathPtr; | |
865 } | |
866 | |
867 GrVertices grVertices; | |
868 | |
869 PLSVertices triVertices; | |
870 PLSVertices quadVertices; | |
871 if (!get_geometry(*pathPtr, *viewMatrix, triVertices, quadVertices,
rp, bounds)) { | |
872 continue; | |
873 } | |
874 | |
875 if (triVertices.count()) { | |
876 const GrVertexBuffer* triVertexBuffer; | |
877 int firstTriVertex; | |
878 size_t triStride = triangleProcessor->getVertexStride(); | |
879 PLSVertex* triVerts = reinterpret_cast<PLSVertex*>(target->makeV
ertexSpace( | |
880 triStride, triVertices.count(), &triVertexBuffer, &first
TriVertex)); | |
881 if (!triVerts) { | |
882 SkDebugf("Could not allocate vertices\n"); | |
883 return; | |
884 } | |
885 for (int i = 0; i < triVertices.count(); ++i) { | |
886 triVerts[i] = triVertices[i]; | |
887 } | |
888 grVertices.init(kTriangles_GrPrimitiveType, triVertexBuffer, fir
stTriVertex, | |
889 triVertices.count()); | |
890 target->initDraw(triangleProcessor, this->pipeline()); | |
891 target->draw(grVertices); | |
892 } | |
893 | |
894 if (quadVertices.count()) { | |
895 const GrVertexBuffer* quadVertexBuffer; | |
896 int firstQuadVertex; | |
897 size_t quadStride = quadProcessor->getVertexStride(); | |
898 PLSVertex* quadVerts = reinterpret_cast<PLSVertex*>(target->make
VertexSpace( | |
899 quadStride, quadVertices.count(), &quadVertexBuffer, &fi
rstQuadVertex)); | |
900 if (!quadVerts) { | |
901 SkDebugf("Could not allocate vertices\n"); | |
902 return; | |
903 } | |
904 for (int i = 0; i < quadVertices.count(); ++i) { | |
905 quadVerts[i] = quadVertices[i]; | |
906 } | |
907 grVertices.init(kTriangles_GrPrimitiveType, quadVertexBuffer, fi
rstQuadVertex, | |
908 quadVertices.count()); | |
909 target->initDraw(quadProcessor, this->pipeline()); | |
910 target->draw(grVertices); | |
911 } | |
912 | |
913 SkAutoTUnref<GrGeometryProcessor> finishProcessor( | |
914 PLSFinishEffect::Create(this->color(), | |
915 pathPtr->getFillType() == | |
916 SkPath::FillType
::kEvenOdd_FillType, | |
917 invert, | |
918 this->usesLocalCoords())); | |
919 const GrVertexBuffer* rectVertexBuffer; | |
920 size_t finishStride = finishProcessor->getVertexStride(); | |
921 int firstRectVertex; | |
922 static const int kRectVertexCount = 6; | |
923 SkPoint* rectVerts = reinterpret_cast<SkPoint*>(target->makeVertexSp
ace( | |
924 finishStride, kRectVertexCount, &rectVertexBuffer, &firstRec
tVertex)); | |
925 if (!rectVerts) { | |
926 SkDebugf("Could not allocate vertices\n"); | |
927 return; | |
928 } | |
929 rectVerts[0] = { bounds.fLeft, bounds.fTop }; | |
930 rectVerts[1] = { bounds.fLeft, bounds.fBottom }; | |
931 rectVerts[2] = { bounds.fRight, bounds.fBottom }; | |
932 rectVerts[3] = { bounds.fLeft, bounds.fTop }; | |
933 rectVerts[4] = { bounds.fRight, bounds.fTop }; | |
934 rectVerts[5] = { bounds.fRight, bounds.fBottom }; | |
935 | |
936 grVertices.init(kTriangles_GrPrimitiveType, rectVertexBuffer, firstR
ectVertex, | |
937 kRectVertexCount); | |
938 target->initDraw(finishProcessor, this->pipeline()); | |
939 target->draw(grVertices); | |
940 } | |
941 } | |
942 | |
943 SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; } | |
944 | |
945 private: | |
946 PLSPathBatch(const Geometry& geometry) : INHERITED(ClassID()) { | |
947 fGeoData.push_back(geometry); | |
948 | |
949 // compute bounds | |
950 fBounds = geometry.fPath.getBounds(); | |
951 geometry.fViewMatrix.mapRect(&fBounds); | |
952 } | |
953 | |
954 bool onCombineIfPossible(GrBatch* t, const GrCaps& caps) override { | |
955 return false; | |
956 } | |
957 | |
958 GrColor color() const { return fBatch.fColor; } | |
959 bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; } | |
960 bool canTweakAlphaForCoverage() const { return fBatch.fCanTweakAlphaForCover
age; } | |
961 const SkMatrix& viewMatrix() const { return fGeoData[0].fViewMatrix; } | |
962 bool coverageIgnored() const { return fBatch.fCoverageIgnored; } | |
963 | |
964 struct BatchTracker { | |
965 GrColor fColor; | |
966 bool fUsesLocalCoords; | |
967 bool fColorIgnored; | |
968 bool fCoverageIgnored; | |
969 bool fCanTweakAlphaForCoverage; | |
970 }; | |
971 | |
972 BatchTracker fBatch; | |
973 SkSTArray<1, Geometry, true> fGeoData; | |
974 | |
975 typedef GrVertexBatch INHERITED; | |
976 }; | |
977 | |
978 SkDEBUGCODE(bool inPLSDraw = false;) | |
979 bool GrPLSPathRenderer::onDrawPath(const DrawPathArgs& args) { | |
980 if (args.fPath->isEmpty()) { | |
981 return true; | |
982 } | |
983 SkASSERT(!inPLSDraw); | |
984 SkDEBUGCODE(inPLSDraw = true;) | |
985 PLSPathBatch::Geometry geometry; | |
986 geometry.fColor = args.fColor; | |
987 geometry.fViewMatrix = *args.fViewMatrix; | |
988 geometry.fPath = *args.fPath; | |
989 | |
990 SkAutoTUnref<GrDrawBatch> batch(PLSPathBatch::Create(geometry)); | |
991 args.fTarget->drawBatch(*args.fPipelineBuilder, batch); | |
992 | |
993 SkDEBUGCODE(inPLSDraw = false;) | |
994 return true; | |
995 | |
996 } | |
997 | |
998 ////////////////////////////////////////////////////////////////////////////////
/////////////////// | |
999 | |
1000 #ifdef GR_TEST_UTILS | |
1001 | |
1002 DRAW_BATCH_TEST_DEFINE(PLSPathBatch) { | |
1003 PLSPathBatch::Geometry geometry; | |
1004 geometry.fColor = GrRandomColor(random); | |
1005 geometry.fViewMatrix = GrTest::TestMatrixInvertible(random); | |
1006 geometry.fPath = GrTest::TestPathConvex(random); | |
1007 | |
1008 return PLSPathBatch::Create(geometry); | |
1009 } | |
1010 | |
1011 #endif | |
OLD | NEW |