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
GrPLSPathRenderer()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 line 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
add_quad(SkPoint pts[3],PLSVertices & vertices)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. */
outset(SkPoint * p1,SkPoint line1,SkPoint line2)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. */
bloat_tri(SkPoint pts[3])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
get_geometry(const SkPath & path,const SkMatrix & m,PLSVertices & triVertices,PLSVertices & quadVertices,GrResourceProvider * resourceProvider,SkRect bounds)135 static bool get_geometry(const SkPath& path, const SkMatrix& m, PLSVertices& triVertices,
136 PLSVertices& quadVertices, GrResourceProvider* resourceProvider,
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 SkPath::Iter iter(path, true);
149 bool done = false;
150 while (!done) {
151 SkPoint pts[4];
152 SkPath::Verb verb = iter.next(pts);
153 switch (verb) {
154 case SkPath::kMove_Verb:
155 SkASSERT(quadPoints.count() % 3 == 0);
156 for (int i = 0; i < quadPoints.count(); i += 3) {
157 add_quad(&quadPoints[i], quadVertices);
158 }
159 quadPoints.reset();
160 m.mapPoints(&pts[0], 1);
161 linesOnlyPath.moveTo(pts[0]);
162 break;
163 case SkPath::kLine_Verb:
164 m.mapPoints(&pts[1], 1);
165 linesOnlyPath.lineTo(pts[1]);
166 break;
167 case SkPath::kQuad_Verb:
168 m.mapPoints(pts, 3);
169 linesOnlyPath.lineTo(pts[2]);
170 quadPoints.push_back(pts[0]);
171 quadPoints.push_back(pts[1]);
172 quadPoints.push_back(pts[2]);
173 break;
174 case SkPath::kCubic_Verb: {
175 m.mapPoints(pts, 4);
176 SkSTArray<15, SkPoint, true> quads;
177 GrPathUtils::convertCubicToQuads(pts, kCubicTolerance, &quads);
178 int count = quads.count();
179 for (int q = 0; q < count; q += 3) {
180 linesOnlyPath.lineTo(quads[q + 2]);
181 quadPoints.push_back(quads[q]);
182 quadPoints.push_back(quads[q + 1]);
183 quadPoints.push_back(quads[q + 2]);
184 }
185 break;
186 }
187 case SkPath::kConic_Verb: {
188 m.mapPoints(pts, 3);
189 SkScalar weight = iter.conicWeight();
190 SkAutoConicToQuads converter;
191 const SkPoint* quads = converter.computeQuads(pts, weight, kConicTolerance);
192 int count = converter.countQuads();
193 for (int i = 0; i < count; ++i) {
194 linesOnlyPath.lineTo(quads[2 * i + 2]);
195 quadPoints.push_back(quads[2 * i]);
196 quadPoints.push_back(quads[2 * i + 1]);
197 quadPoints.push_back(quads[2 * i + 2]);
198 }
199 break;
200 }
201 case SkPath::kClose_Verb:
202 linesOnlyPath.close();
203 break;
204 case SkPath::kDone_Verb:
205 done = true;
206 break;
207 default: SkASSERT(false);
208 }
209 }
210 SkASSERT(quadPoints.count() % 3 == 0);
211 for (int i = 0; i < quadPoints.count(); i += 3) {
212 add_quad(&quadPoints[i], quadVertices);
213 }
214
215 static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain();
216 GrUniqueKey key;
217 GrUniqueKey::Builder builder(&key, kDomain, 2);
218 builder[0] = path.getGenerationID();
219 builder[1] = path.getFillType();
220 builder.finish();
221 GrTessellator::WindingVertex* windingVertices;
222 int triVertexCount = GrTessellator::PathToVertices(linesOnlyPath, 0, bounds, &windingVertices);
223 if (triVertexCount > 0) {
224 for (int i = 0; i < triVertexCount; i += 3) {
225 SkPoint p1 = windingVertices[i].fPos;
226 SkPoint p2 = windingVertices[i + 1].fPos;
227 SkPoint p3 = windingVertices[i + 2].fPos;
228 int winding = windingVertices[i].fWinding;
229 SkASSERT(windingVertices[i + 1].fWinding == winding);
230 SkASSERT(windingVertices[i + 2].fWinding == winding);
231 SkScalar cross = (p2 - p1).cross(p3 - p1);
232 SkPoint bloated[3] = { p1, p2, p3 };
233 if (cross < 0.0f) {
234 SkTSwap(p1, p3);
235 }
236 if (bloat_tri(bloated)) {
237 triVertices.push_back({ bloated[0], p1, p2, p3, winding });
238 triVertices.push_back({ bloated[1], p1, p2, p3, winding });
239 triVertices.push_back({ bloated[2], p1, p2, p3, winding });
240 }
241 else {
242 SkScalar minX = SkTMin(p1.fX, SkTMin(p2.fX, p3.fX)) - 1.0f;
243 SkScalar minY = SkTMin(p1.fY, SkTMin(p2.fY, p3.fY)) - 1.0f;
244 SkScalar maxX = SkTMax(p1.fX, SkTMax(p2.fX, p3.fX)) + 1.0f;
245 SkScalar maxY = SkTMax(p1.fY, SkTMax(p2.fY, p3.fY)) + 1.0f;
246 triVertices.push_back({ { minX, minY }, p1, p2, p3, winding });
247 triVertices.push_back({ { maxX, minY }, p1, p2, p3, winding });
248 triVertices.push_back({ { minX, maxY }, p1, p2, p3, winding });
249 triVertices.push_back({ { maxX, minY }, p1, p2, p3, winding });
250 triVertices.push_back({ { maxX, maxY }, p1, p2, p3, winding });
251 triVertices.push_back({ { minX, maxY }, p1, p2, p3, winding });
252 }
253 }
254 delete[] windingVertices;
255 }
256 return triVertexCount > 0 || quadVertices.count() > 0;
257 }
258
259 class PLSAATriangleEffect : public GrPLSGeometryProcessor {
260 public:
261
Create(const SkMatrix & localMatrix,bool usesLocalCoords)262 static GrPLSGeometryProcessor* Create(const SkMatrix& localMatrix,
263 bool usesLocalCoords) {
264 return new PLSAATriangleEffect(localMatrix, usesLocalCoords);
265 }
266
~PLSAATriangleEffect()267 virtual ~PLSAATriangleEffect() {}
268
name() const269 const char* name() const override { return "PLSAATriangle"; }
270
inPosition() const271 const Attribute* inPosition() const { return fInPosition; }
inVertex1() const272 const Attribute* inVertex1() const { return fInVertex1; }
inVertex2() const273 const Attribute* inVertex2() const { return fInVertex2; }
inVertex3() const274 const Attribute* inVertex3() const { return fInVertex3; }
inWindings() const275 const Attribute* inWindings() const { return fInWindings; }
localMatrix() const276 const SkMatrix& localMatrix() const { return fLocalMatrix; }
usesLocalCoords() const277 bool usesLocalCoords() const { return fUsesLocalCoords; }
278
279 class GLSLProcessor : public GrGLSLGeometryProcessor {
280 public:
GLSLProcessor(const GrGeometryProcessor &)281 GLSLProcessor(const GrGeometryProcessor&) {}
282
onEmitCode(EmitArgs & args,GrGPArgs * gpArgs)283 void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override {
284 const PLSAATriangleEffect& te = args.fGP.cast<PLSAATriangleEffect>();
285 GrGLSLVertexBuilder* vsBuilder = args.fVertBuilder;
286 GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler;
287 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
288
289 varyingHandler->emitAttributes(te);
290
291 this->setupPosition(vsBuilder, gpArgs, te.inPosition()->fName);
292
293 GrGLSLVertToFrag v1(kVec2f_GrSLType);
294 varyingHandler->addVarying("Vertex1", &v1, kHigh_GrSLPrecision);
295 vsBuilder->codeAppendf("%s = vec2(%s.x, %s.y);",
296 v1.vsOut(),
297 te.inVertex1()->fName,
298 te.inVertex1()->fName);
299
300 GrGLSLVertToFrag v2(kVec2f_GrSLType);
301 varyingHandler->addVarying("Vertex2", &v2, kHigh_GrSLPrecision);
302 vsBuilder->codeAppendf("%s = vec2(%s.x, %s.y);",
303 v2.vsOut(),
304 te.inVertex2()->fName,
305 te.inVertex2()->fName);
306
307 GrGLSLVertToFrag v3(kVec2f_GrSLType);
308 varyingHandler->addVarying("Vertex3", &v3, kHigh_GrSLPrecision);
309 vsBuilder->codeAppendf("%s = vec2(%s.x, %s.y);",
310 v3.vsOut(),
311 te.inVertex3()->fName,
312 te.inVertex3()->fName);
313
314 GrGLSLVertToFrag delta1(kVec2f_GrSLType);
315 varyingHandler->addVarying("delta1", &delta1, kHigh_GrSLPrecision);
316 vsBuilder->codeAppendf("%s = vec2(%s.x - %s.x, %s.y - %s.y) * 0.5;",
317 delta1.vsOut(), v1.vsOut(), v2.vsOut(), v2.vsOut(), v1.vsOut());
318
319 GrGLSLVertToFrag delta2(kVec2f_GrSLType);
320 varyingHandler->addVarying("delta2", &delta2, kHigh_GrSLPrecision);
321 vsBuilder->codeAppendf("%s = vec2(%s.x - %s.x, %s.y - %s.y) * 0.5;",
322 delta2.vsOut(), v2.vsOut(), v3.vsOut(), v3.vsOut(), v2.vsOut());
323
324 GrGLSLVertToFrag delta3(kVec2f_GrSLType);
325 varyingHandler->addVarying("delta3", &delta3, kHigh_GrSLPrecision);
326 vsBuilder->codeAppendf("%s = vec2(%s.x - %s.x, %s.y - %s.y) * 0.5;",
327 delta3.vsOut(), v3.vsOut(), v1.vsOut(), v1.vsOut(), v3.vsOut());
328
329 GrGLSLVertToFrag windings(kInt_GrSLType);
330 varyingHandler->addFlatVarying("windings", &windings, kLow_GrSLPrecision);
331 vsBuilder->codeAppendf("%s = %s;",
332 windings.vsOut(), te.inWindings()->fName);
333
334 // emit transforms
335 this->emitTransforms(vsBuilder, varyingHandler, uniformHandler, gpArgs->fPositionVar,
336 te.inPosition()->fName, te.localMatrix(), args.fTransformsIn,
337 args.fTransformsOut);
338
339 GrGLSLPPFragmentBuilder* fsBuilder = args.fFragBuilder;
340 SkAssertResult(fsBuilder->enableFeature(
341 GrGLSLFragmentShaderBuilder::kPixelLocalStorage_GLSLFeature));
342 SkAssertResult(fsBuilder->enableFeature(
343 GrGLSLFragmentShaderBuilder::kStandardDerivatives_GLSLFeature));
344 fsBuilder->declAppendf(GR_GL_PLS_PATH_DATA_DECL);
345 // Compute four subsamples, each shifted a quarter pixel along x and y from
346 // gl_FragCoord. The oriented box positioning of the subsamples is of course not
347 // optimal, but it greatly simplifies the math and this simplification is necessary for
348 // performance reasons.
349 fsBuilder->codeAppendf("highp vec2 firstSample = %s.xy - vec2(0.25);",
350 fsBuilder->fragmentPosition());
351 fsBuilder->codeAppendf("highp vec2 delta1 = %s;", delta1.fsIn());
352 fsBuilder->codeAppendf("highp vec2 delta2 = %s;", delta2.fsIn());
353 fsBuilder->codeAppendf("highp vec2 delta3 = %s;", delta3.fsIn());
354 // Check whether first sample is inside the triangle by computing three dot products. If
355 // all are < 0, we're inside. The first vector in each case is half of what it is
356 // "supposed" to be, because we re-use them later as adjustment factors for which half
357 // is the correct value, so we multiply the dots by two to compensate.
358 fsBuilder->codeAppendf("highp float d1 = dot(delta1, (firstSample - %s).yx) * 2.0;",
359 v1.fsIn());
360 fsBuilder->codeAppendf("highp float d2 = dot(delta2, (firstSample - %s).yx) * 2.0;",
361 v2.fsIn());
362 fsBuilder->codeAppendf("highp float d3 = dot(delta3, (firstSample - %s).yx) * 2.0;",
363 v3.fsIn());
364 fsBuilder->codeAppend("highp float dmax = max(d1, max(d2, d3));");
365 fsBuilder->codeAppendf("pls.windings[0] += (dmax <= 0.0) ? %s : 0;", windings.fsIn());
366 // for subsequent samples, we don't recalculate the entire dot product -- just adjust it
367 // to the value it would have if we did recompute it.
368 fsBuilder->codeAppend("d1 += delta1.x;");
369 fsBuilder->codeAppend("d2 += delta2.x;");
370 fsBuilder->codeAppend("d3 += delta3.x;");
371 fsBuilder->codeAppend("dmax = max(d1, max(d2, d3));");
372 fsBuilder->codeAppendf("pls.windings[1] += (dmax <= 0.0) ? %s : 0;", windings.fsIn());
373 fsBuilder->codeAppend("d1 += delta1.y;");
374 fsBuilder->codeAppend("d2 += delta2.y;");
375 fsBuilder->codeAppend("d3 += delta3.y;");
376 fsBuilder->codeAppend("dmax = max(d1, max(d2, d3));");
377 fsBuilder->codeAppendf("pls.windings[2] += (dmax <= 0.0) ? %s : 0;", windings.fsIn());
378 fsBuilder->codeAppend("d1 -= delta1.x;");
379 fsBuilder->codeAppend("d2 -= delta2.x;");
380 fsBuilder->codeAppend("d3 -= delta3.x;");
381 fsBuilder->codeAppend("dmax = max(d1, max(d2, d3));");
382 fsBuilder->codeAppendf("pls.windings[3] += (dmax <= 0.0) ? %s : 0;", windings.fsIn());
383 }
384
GenKey(const GrGeometryProcessor & gp,const GrGLSLCaps &,GrProcessorKeyBuilder * b)385 static inline void GenKey(const GrGeometryProcessor& gp,
386 const GrGLSLCaps&,
387 GrProcessorKeyBuilder* b) {
388 const PLSAATriangleEffect& te = gp.cast<PLSAATriangleEffect>();
389 uint32_t key = 0;
390 key |= te.localMatrix().hasPerspective() ? 0x1 : 0x0;
391 b->add32(key);
392 }
393
setData(const GrGLSLProgramDataManager & pdman,const GrPrimitiveProcessor & gp)394 virtual void setData(const GrGLSLProgramDataManager& pdman,
395 const GrPrimitiveProcessor& gp) override {
396 }
397
setTransformData(const GrPrimitiveProcessor & primProc,const GrGLSLProgramDataManager & pdman,int index,const SkTArray<const GrCoordTransform *,true> & transforms)398 void setTransformData(const GrPrimitiveProcessor& primProc,
399 const GrGLSLProgramDataManager& pdman,
400 int index,
401 const SkTArray<const GrCoordTransform*, true>& transforms) override {
402 this->setTransformDataHelper<PLSAATriangleEffect>(primProc, pdman, index, transforms);
403 }
404
405 private:
406 typedef GrGLSLGeometryProcessor INHERITED;
407 };
408
getGLSLProcessorKey(const GrGLSLCaps & caps,GrProcessorKeyBuilder * b) const409 virtual void getGLSLProcessorKey(const GrGLSLCaps& caps,
410 GrProcessorKeyBuilder* b) const override {
411 GLSLProcessor::GenKey(*this, caps, b);
412 }
413
createGLSLInstance(const GrGLSLCaps &) const414 virtual GrGLSLPrimitiveProcessor* createGLSLInstance(const GrGLSLCaps&) const override {
415 return new GLSLProcessor(*this);
416 }
417
418 private:
PLSAATriangleEffect(const SkMatrix & localMatrix,bool usesLocalCoords)419 PLSAATriangleEffect(const SkMatrix& localMatrix, bool usesLocalCoords)
420 : fLocalMatrix(localMatrix)
421 , fUsesLocalCoords(usesLocalCoords) {
422 this->initClassID<PLSAATriangleEffect>();
423 fInPosition = &this->addVertexAttrib(Attribute("inPosition", kVec2f_GrVertexAttribType,
424 kHigh_GrSLPrecision));
425 fInVertex1 = &this->addVertexAttrib(Attribute("inVertex1", kVec2f_GrVertexAttribType,
426 kHigh_GrSLPrecision));
427 fInVertex2 = &this->addVertexAttrib(Attribute("inVertex2", kVec2f_GrVertexAttribType,
428 kHigh_GrSLPrecision));
429 fInVertex3 = &this->addVertexAttrib(Attribute("inVertex3", kVec2f_GrVertexAttribType,
430 kHigh_GrSLPrecision));
431 fInWindings = &this->addVertexAttrib(Attribute("inWindings", kInt_GrVertexAttribType,
432 kLow_GrSLPrecision));
433 this->setWillReadFragmentPosition();
434 }
435
436 const Attribute* fInPosition;
437 const Attribute* fInVertex1;
438 const Attribute* fInVertex2;
439 const Attribute* fInVertex3;
440 const Attribute* fInWindings;
441 SkMatrix fLocalMatrix;
442 bool fUsesLocalCoords;
443
444 GR_DECLARE_GEOMETRY_PROCESSOR_TEST;
445
446 typedef GrGeometryProcessor INHERITED;
447 };
448
449 ///////////////////////////////////////////////////////////////////////////////
450
451 /*
452 * Quadratic specified by 0=u^2-v canonical coords. u and v are the first
453 * two components of the vertex attribute. Coverage is based on signed
454 * distance with negative being inside, positive outside. The edge is specified in
455 * window space (y-down). If either the third or fourth component of the interpolated
456 * vertex coord is > 0 then the pixel is considered outside the edge. This is used to
457 * attempt to trim to a portion of the infinite quad.
458 * Requires shader derivative instruction support.
459 */
460
461 class PLSQuadEdgeEffect : public GrPLSGeometryProcessor {
462 public:
463
Create(const SkMatrix & localMatrix,bool usesLocalCoords)464 static GrPLSGeometryProcessor* Create(const SkMatrix& localMatrix,
465 bool usesLocalCoords) {
466 return new PLSQuadEdgeEffect(localMatrix, usesLocalCoords);
467 }
468
~PLSQuadEdgeEffect()469 virtual ~PLSQuadEdgeEffect() {}
470
name() const471 const char* name() const override { return "PLSQuadEdge"; }
472
inPosition() const473 const Attribute* inPosition() const { return fInPosition; }
inUV() const474 const Attribute* inUV() const { return fInUV; }
inEndpoint1() const475 const Attribute* inEndpoint1() const { return fInEndpoint1; }
inEndpoint2() const476 const Attribute* inEndpoint2() const { return fInEndpoint2; }
inWindings() const477 const Attribute* inWindings() const { return fInWindings; }
localMatrix() const478 const SkMatrix& localMatrix() const { return fLocalMatrix; }
usesLocalCoords() const479 bool usesLocalCoords() const { return fUsesLocalCoords; }
480
481 class GLSLProcessor : public GrGLSLGeometryProcessor {
482 public:
GLSLProcessor(const GrGeometryProcessor &)483 GLSLProcessor(const GrGeometryProcessor&) {}
484
onEmitCode(EmitArgs & args,GrGPArgs * gpArgs)485 void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override {
486 const PLSQuadEdgeEffect& qe = args.fGP.cast<PLSQuadEdgeEffect>();
487 GrGLSLVertexBuilder* vsBuilder = args.fVertBuilder;
488 GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler;
489 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
490
491 // emit attributes
492 varyingHandler->emitAttributes(qe);
493
494 GrGLSLVertToFrag uv(kVec2f_GrSLType);
495 varyingHandler->addVarying("uv", &uv, kHigh_GrSLPrecision);
496 vsBuilder->codeAppendf("%s = %s;", uv.vsOut(), qe.inUV()->fName);
497
498 GrGLSLVertToFrag ep1(kVec2f_GrSLType);
499 varyingHandler->addVarying("endpoint1", &ep1, kHigh_GrSLPrecision);
500 vsBuilder->codeAppendf("%s = vec2(%s.x, %s.y);", ep1.vsOut(),
501 qe.inEndpoint1()->fName, qe.inEndpoint1()->fName);
502
503 GrGLSLVertToFrag ep2(kVec2f_GrSLType);
504 varyingHandler->addVarying("endpoint2", &ep2, kHigh_GrSLPrecision);
505 vsBuilder->codeAppendf("%s = vec2(%s.x, %s.y);", ep2.vsOut(),
506 qe.inEndpoint2()->fName, qe.inEndpoint2()->fName);
507
508 GrGLSLVertToFrag delta(kVec2f_GrSLType);
509 varyingHandler->addVarying("delta", &delta, kHigh_GrSLPrecision);
510 vsBuilder->codeAppendf("%s = vec2(%s.x - %s.x, %s.y - %s.y) * 0.5;",
511 delta.vsOut(), ep1.vsOut(), ep2.vsOut(), ep2.vsOut(),
512 ep1.vsOut());
513
514 GrGLSLVertToFrag windings(kInt_GrSLType);
515 varyingHandler->addFlatVarying("windings", &windings, kLow_GrSLPrecision);
516 vsBuilder->codeAppendf("%s = %s;",
517 windings.vsOut(), qe.inWindings()->fName);
518
519 // Setup position
520 this->setupPosition(vsBuilder, gpArgs, qe.inPosition()->fName);
521
522 // emit transforms
523 this->emitTransforms(vsBuilder, varyingHandler, uniformHandler, gpArgs->fPositionVar,
524 qe.inPosition()->fName, qe.localMatrix(), args.fTransformsIn,
525 args.fTransformsOut);
526
527 GrGLSLPPFragmentBuilder* fsBuilder = args.fFragBuilder;
528 SkAssertResult(fsBuilder->enableFeature(
529 GrGLSLFragmentShaderBuilder::kPixelLocalStorage_GLSLFeature));
530 SkAssertResult(fsBuilder->enableFeature(
531 GrGLSLFragmentShaderBuilder::kStandardDerivatives_GLSLFeature));
532 static const int QUAD_ARGS = 2;
533 GrGLSLShaderVar inQuadArgs[QUAD_ARGS] = {
534 GrGLSLShaderVar("dot", kFloat_GrSLType, 0, kHigh_GrSLPrecision),
535 GrGLSLShaderVar("uv", kVec2f_GrSLType, 0, kHigh_GrSLPrecision)
536 };
537 SkString inQuadName;
538
539 const char* inQuadCode = "if (uv.x * uv.x <= uv.y) {"
540 "return dot >= 0.0;"
541 "} else {"
542 "return false;"
543 "}";
544 fsBuilder->emitFunction(kBool_GrSLType, "in_quad", QUAD_ARGS, inQuadArgs, inQuadCode,
545 &inQuadName);
546 fsBuilder->declAppendf(GR_GL_PLS_PATH_DATA_DECL);
547 // keep the derivative instructions outside the conditional
548 fsBuilder->codeAppendf("highp vec2 uvdX = dFdx(%s);", uv.fsIn());
549 fsBuilder->codeAppendf("highp vec2 uvdY = dFdy(%s);", uv.fsIn());
550 fsBuilder->codeAppend("highp vec2 uvIncX = uvdX * 0.45 + uvdY * -0.1;");
551 fsBuilder->codeAppend("highp vec2 uvIncY = uvdX * 0.1 + uvdY * 0.55;");
552 fsBuilder->codeAppendf("highp vec2 uv = %s.xy - uvdX * 0.35 - uvdY * 0.25;",
553 uv.fsIn());
554 fsBuilder->codeAppendf("highp vec2 firstSample = %s.xy - vec2(0.25);",
555 fsBuilder->fragmentPosition());
556 fsBuilder->codeAppendf("highp float d = dot(%s, (firstSample - %s).yx) * 2.0;",
557 delta.fsIn(), ep1.fsIn());
558 fsBuilder->codeAppendf("pls.windings[0] += %s(d, uv) ? %s : 0;", inQuadName.c_str(),
559 windings.fsIn());
560 fsBuilder->codeAppend("uv += uvIncX;");
561 fsBuilder->codeAppendf("d += %s.x;", delta.fsIn());
562 fsBuilder->codeAppendf("pls.windings[1] += %s(d, uv) ? %s : 0;", inQuadName.c_str(),
563 windings.fsIn());
564 fsBuilder->codeAppend("uv += uvIncY;");
565 fsBuilder->codeAppendf("d += %s.y;", delta.fsIn());
566 fsBuilder->codeAppendf("pls.windings[2] += %s(d, uv) ? %s : 0;", inQuadName.c_str(),
567 windings.fsIn());
568 fsBuilder->codeAppend("uv -= uvIncX;");
569 fsBuilder->codeAppendf("d -= %s.x;", delta.fsIn());
570 fsBuilder->codeAppendf("pls.windings[3] += %s(d, uv) ? %s : 0;", inQuadName.c_str(),
571 windings.fsIn());
572 }
573
GenKey(const GrGeometryProcessor & gp,const GrGLSLCaps &,GrProcessorKeyBuilder * b)574 static inline void GenKey(const GrGeometryProcessor& gp,
575 const GrGLSLCaps&,
576 GrProcessorKeyBuilder* b) {
577 const PLSQuadEdgeEffect& qee = gp.cast<PLSQuadEdgeEffect>();
578 uint32_t key = 0;
579 key |= qee.usesLocalCoords() && qee.localMatrix().hasPerspective() ? 0x1 : 0x0;
580 b->add32(key);
581 }
582
setData(const GrGLSLProgramDataManager & pdman,const GrPrimitiveProcessor & gp)583 virtual void setData(const GrGLSLProgramDataManager& pdman,
584 const GrPrimitiveProcessor& gp) override {
585 }
586
setTransformData(const GrPrimitiveProcessor & primProc,const GrGLSLProgramDataManager & pdman,int index,const SkTArray<const GrCoordTransform *,true> & transforms)587 void setTransformData(const GrPrimitiveProcessor& primProc,
588 const GrGLSLProgramDataManager& pdman,
589 int index,
590 const SkTArray<const GrCoordTransform*, true>& transforms) override {
591 this->setTransformDataHelper<PLSQuadEdgeEffect>(primProc, pdman, index, transforms);
592 }
593
594 private:
595 typedef GrGLSLGeometryProcessor INHERITED;
596 };
597
getGLSLProcessorKey(const GrGLSLCaps & caps,GrProcessorKeyBuilder * b) const598 virtual void getGLSLProcessorKey(const GrGLSLCaps& caps,
599 GrProcessorKeyBuilder* b) const override {
600 GLSLProcessor::GenKey(*this, caps, b);
601 }
602
createGLSLInstance(const GrGLSLCaps &) const603 virtual GrGLSLPrimitiveProcessor* createGLSLInstance(const GrGLSLCaps&) const override {
604 return new GLSLProcessor(*this);
605 }
606
607 private:
PLSQuadEdgeEffect(const SkMatrix & localMatrix,bool usesLocalCoords)608 PLSQuadEdgeEffect(const SkMatrix& localMatrix, bool usesLocalCoords)
609 : fLocalMatrix(localMatrix)
610 , fUsesLocalCoords(usesLocalCoords) {
611 this->initClassID<PLSQuadEdgeEffect>();
612 fInPosition = &this->addVertexAttrib(Attribute("inPosition", kVec2f_GrVertexAttribType,
613 kHigh_GrSLPrecision));
614 fInUV = &this->addVertexAttrib(Attribute("inUV", kVec2f_GrVertexAttribType,
615 kHigh_GrSLPrecision));
616 fInEndpoint1 = &this->addVertexAttrib(Attribute("inEndpoint1", kVec2f_GrVertexAttribType,
617 kHigh_GrSLPrecision));
618 fInEndpoint2 = &this->addVertexAttrib(Attribute("inEndpoint2", kVec2f_GrVertexAttribType,
619 kHigh_GrSLPrecision));
620 fInWindings = &this->addVertexAttrib(Attribute("inWindings", kInt_GrVertexAttribType,
621 kLow_GrSLPrecision));
622 this->setWillReadFragmentPosition();
623 }
624
625 const Attribute* fInPosition;
626 const Attribute* fInUV;
627 const Attribute* fInEndpoint1;
628 const Attribute* fInEndpoint2;
629 const Attribute* fInWindings;
630 SkMatrix fLocalMatrix;
631 bool fUsesLocalCoords;
632
633 GR_DECLARE_GEOMETRY_PROCESSOR_TEST;
634
635 typedef GrGeometryProcessor INHERITED;
636 };
637
638 class PLSFinishEffect : public GrGeometryProcessor {
639 public:
640
Create(GrColor color,bool useEvenOdd,const SkMatrix & localMatrix,bool usesLocalCoords)641 static GrGeometryProcessor* Create(GrColor color, bool useEvenOdd, const SkMatrix& localMatrix,
642 bool usesLocalCoords) {
643 return new PLSFinishEffect(color, useEvenOdd, localMatrix, usesLocalCoords);
644 }
645
~PLSFinishEffect()646 virtual ~PLSFinishEffect() {}
647
name() const648 const char* name() const override { return "PLSFinish"; }
649
inPosition() const650 const Attribute* inPosition() const { return fInPosition; }
color() const651 GrColor color() const { return fColor; }
colorIgnored() const652 bool colorIgnored() const { return GrColor_ILLEGAL == fColor; }
localMatrix() const653 const SkMatrix& localMatrix() const { return fLocalMatrix; }
usesLocalCoords() const654 bool usesLocalCoords() const { return fUsesLocalCoords; }
655
getPixelLocalStorageState() const656 GrPixelLocalStorageState getPixelLocalStorageState() const override {
657 return GrPixelLocalStorageState::kFinish_GrPixelLocalStorageState;
658 }
659
getDestColorOverride() const660 const char* getDestColorOverride() const override {
661 return GR_GL_PLS_DSTCOLOR_NAME;
662 }
663
664 class GLSLProcessor : public GrGLSLGeometryProcessor {
665 public:
GLSLProcessor(const GrGeometryProcessor &)666 GLSLProcessor(const GrGeometryProcessor&) {}
667
onEmitCode(EmitArgs & args,GrGPArgs * gpArgs)668 void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override {
669 const PLSFinishEffect& fe = args.fGP.cast<PLSFinishEffect>();
670 GrGLSLVertexBuilder* vsBuilder = args.fVertBuilder;
671 GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler;
672 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
673
674 fUseEvenOdd = uniformHandler->addUniform(kFragment_GrShaderFlag,
675 kFloat_GrSLType, kLow_GrSLPrecision,
676 "useEvenOdd");
677 const char* useEvenOdd = uniformHandler->getUniformCStr(fUseEvenOdd);
678
679 varyingHandler->emitAttributes(fe);
680 this->setupPosition(vsBuilder, gpArgs, fe.inPosition()->fName);
681 this->emitTransforms(vsBuilder, varyingHandler, uniformHandler, gpArgs->fPositionVar,
682 fe.inPosition()->fName, fe.localMatrix(), args.fTransformsIn,
683 args.fTransformsOut);
684
685 GrGLSLPPFragmentBuilder* fsBuilder = args.fFragBuilder;
686 SkAssertResult(fsBuilder->enableFeature(
687 GrGLSLFragmentShaderBuilder::kPixelLocalStorage_GLSLFeature));
688 fsBuilder->declAppendf(GR_GL_PLS_PATH_DATA_DECL);
689 fsBuilder->codeAppend("float coverage;");
690 fsBuilder->codeAppendf("if (%s != 0.0) {", useEvenOdd);
691 fsBuilder->codeAppend("coverage = float(abs(pls.windings[0]) % 2) * 0.25;");
692 fsBuilder->codeAppend("coverage += float(abs(pls.windings[1]) % 2) * 0.25;");
693 fsBuilder->codeAppend("coverage += float(abs(pls.windings[2]) % 2) * 0.25;");
694 fsBuilder->codeAppend("coverage += float(abs(pls.windings[3]) % 2) * 0.25;");
695 fsBuilder->codeAppend("} else {");
696 fsBuilder->codeAppend("coverage = pls.windings[0] != 0 ? 0.25 : 0.0;");
697 fsBuilder->codeAppend("coverage += pls.windings[1] != 0 ? 0.25 : 0.0;");
698 fsBuilder->codeAppend("coverage += pls.windings[2] != 0 ? 0.25 : 0.0;");
699 fsBuilder->codeAppend("coverage += pls.windings[3] != 0 ? 0.25 : 0.0;");
700 fsBuilder->codeAppend("}");
701 if (!fe.colorIgnored()) {
702 this->setupUniformColor(fsBuilder, uniformHandler, args.fOutputColor,
703 &fColorUniform);
704 }
705 fsBuilder->codeAppendf("%s = vec4(coverage);", args.fOutputCoverage);
706 fsBuilder->codeAppendf("%s = vec4(1.0, 0.0, 1.0, 1.0);", args.fOutputColor);
707 }
708
GenKey(const GrGeometryProcessor & gp,const GrGLSLCaps &,GrProcessorKeyBuilder * b)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() ? 0x1 : 0x0;
715 b->add32(key);
716 }
717
setData(const GrGLSLProgramDataManager & pdman,const GrPrimitiveProcessor & gp)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
setTransformData(const GrPrimitiveProcessor & primProc,const GrGLSLProgramDataManager & pdman,int index,const SkTArray<const GrCoordTransform *,true> & transforms)730 void setTransformData(const GrPrimitiveProcessor& primProc,
731 const GrGLSLProgramDataManager& pdman,
732 int index,
733 const SkTArray<const GrCoordTransform*, true>& transforms) 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
getGLSLProcessorKey(const GrGLSLCaps & caps,GrProcessorKeyBuilder * b) const745 virtual void getGLSLProcessorKey(const GrGLSLCaps& caps,
746 GrProcessorKeyBuilder* b) const override {
747 GLSLProcessor::GenKey(*this, caps, b);
748 }
749
createGLSLInstance(const GrGLSLCaps &) const750 virtual GrGLSLPrimitiveProcessor* createGLSLInstance(const GrGLSLCaps&) const override {
751 return new GLSLProcessor(*this);
752 }
753
754 private:
PLSFinishEffect(GrColor color,bool useEvenOdd,const SkMatrix & localMatrix,bool usesLocalCoords)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_GrVertexAttribType,
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
onCanDrawPath(const CanDrawPathArgs & args) const777 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
Create(const Geometry & geometry)794 static GrDrawBatch* Create(const Geometry& geometry) {
795 return new PLSPathBatch(geometry);
796 }
797
name() const798 const char* name() const override { return "PLSBatch"; }
799
computePipelineOptimizations(GrInitInvariantOutput * color,GrInitInvariantOutput * coverage,GrBatchToXPOverrides * overrides) const800 void computePipelineOptimizations(GrInitInvariantOutput* color,
801 GrInitInvariantOutput* coverage,
802 GrBatchToXPOverrides* overrides) const override {
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
initBatchTracker(const GrXPOverridesForBatch & overrides)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
onPrepareDraws(Target * target) const824 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 based 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->makeVertexSpace(
880 triStride, triVertices.count(), &triVertexBuffer, &firstTriVertex));
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, firstTriVertex,
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->makeVertexSpace(
899 quadStride, quadVertices.count(), &quadVertexBuffer, &firstQuadVertex));
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, firstQuadVertex,
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->makeVertexSpace(
924 finishStride, kRectVertexCount, &rectVertexBuffer, &firstRectVertex));
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, firstRectVertex,
937 kRectVertexCount);
938 target->initDraw(finishProcessor, this->pipeline());
939 target->draw(grVertices);
940 }
941 }
942
geoData()943 SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; }
944
945 private:
PLSPathBatch(const Geometry & geometry)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
onCombineIfPossible(GrBatch * t,const GrCaps & caps)954 bool onCombineIfPossible(GrBatch* t, const GrCaps& caps) override {
955 return false;
956 }
957
color() const958 GrColor color() const { return fBatch.fColor; }
usesLocalCoords() const959 bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; }
canTweakAlphaForCoverage() const960 bool canTweakAlphaForCoverage() const { return fBatch.fCanTweakAlphaForCoverage; }
viewMatrix() const961 const SkMatrix& viewMatrix() const { return fGeoData[0].fViewMatrix; }
coverageIgnored() const962 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
SkDEBUGCODE(bool inPLSDraw=false;)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
DRAW_BATCH_TEST_DEFINE(PLSPathBatch)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
1012