blob: 835ce2c46340eabcd4c9183c69e310f479a6020b [file] [log] [blame]
ethannicholas22793252016-01-30 09:59:10 -08001/*
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
Brian Salomondad29232016-12-01 16:40:24 -050010#include "GrCaps.h"
11#include "GrContext.h"
12#include "GrDefaultGeoProcFactory.h"
Brian Salomon5ec9def2016-12-20 15:34:05 -050013#include "GrDrawOpTest.h"
Brian Salomondad29232016-12-01 16:40:24 -050014#include "GrInvariantOutput.h"
Brian Salomon742e31d2016-12-07 17:06:19 -050015#include "GrOpFlushState.h"
Brian Salomondad29232016-12-01 16:40:24 -050016#include "GrPLSGeometryProcessor.h"
17#include "GrPathUtils.h"
18#include "GrPipelineBuilder.h"
19#include "GrProcessor.h"
20#include "GrStyle.h"
21#include "GrTessellator.h"
ethannicholas22793252016-01-30 09:59:10 -080022#include "SkChunkAlloc.h"
23#include "SkGeometry.h"
24#include "SkPathPriv.h"
25#include "SkString.h"
26#include "SkTSort.h"
27#include "SkTraceEvent.h"
ethannicholas22793252016-01-30 09:59:10 -080028#include "gl/builders/GrGLProgramBuilder.h"
Brian Salomondad29232016-12-01 16:40:24 -050029#include "glsl/GrGLSLGeometryProcessor.h"
ethannicholas22793252016-01-30 09:59:10 -080030#include "glsl/GrGLSLPLSPathRendering.h"
Brian Salomon89527432016-12-16 09:52:16 -050031#include "ops/GrMeshDrawOp.h"
ethannicholas22793252016-01-30 09:59:10 -080032
33GrPLSPathRenderer::GrPLSPathRenderer() {
34}
35
36struct PLSVertex {
37 SkPoint fPos;
38 // for triangles, these are the three triangle vertices
halcanary9d524f22016-03-29 09:03:52 -070039 // for quads, vert1 is the texture UV coords, and vert2 and vert3 are the line segment
ethannicholas22793252016-01-30 09:59:10 -080040 // comprising the flat edge of the quad
41 SkPoint fVert1;
42 SkPoint fVert2;
43 SkPoint fVert3;
44 int fWinding;
45};
46typedef SkTArray<PLSVertex, true> PLSVertices;
47
48typedef SkTArray<SkPoint, true> FinishVertices;
49
50static const float kCubicTolerance = 0.5f;
51static const float kConicTolerance = 0.5f;
52
53static const float kBloatSize = 1.0f;
54
55static const float kBloatLimit = 640000.0f;
56
57#define kQuadNumVertices 5
58static void add_quad(SkPoint pts[3], PLSVertices& vertices) {
halcanary9d524f22016-03-29 09:03:52 -070059 SkPoint normal = SkPoint::Make(pts[0].fY - pts[2].fY,
ethannicholas22793252016-01-30 09:59:10 -080060 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. */
93static 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. */
108static 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
halcanary9d524f22016-03-29 09:03:52 -0700135static bool get_geometry(const SkPath& path, const SkMatrix& m, PLSVertices& triVertices,
ethannicholas22793252016-01-30 09:59:10 -0800136 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;
ethannicholas22793252016-01-30 09:59:10 -0800148 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;
bsalomon18fab302016-02-16 08:00:05 -0800177 GrPathUtils::convertCubicToQuads(pts, kCubicTolerance, &quads);
ethannicholas22793252016-01-30 09:59:10 -0800178 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
259class PLSAATriangleEffect : public GrPLSGeometryProcessor {
260public:
261
262 static GrPLSGeometryProcessor* Create(const SkMatrix& localMatrix,
263 bool usesLocalCoords) {
264 return new PLSAATriangleEffect(localMatrix, usesLocalCoords);
265 }
266
267 virtual ~PLSAATriangleEffect() {}
268
269 const char* name() const override { return "PLSAATriangle"; }
270
271 const Attribute* inPosition() const { return fInPosition; }
272 const Attribute* inVertex1() const { return fInVertex1; }
273 const Attribute* inVertex2() const { return fInVertex2; }
274 const Attribute* inVertex3() const { return fInVertex3; }
275 const Attribute* inWindings() const { return fInWindings; }
276 const SkMatrix& localMatrix() const { return fLocalMatrix; }
277 bool usesLocalCoords() const { return fUsesLocalCoords; }
278
279 class GLSLProcessor : public GrGLSLGeometryProcessor {
280 public:
281 GLSLProcessor(const GrGeometryProcessor&) {}
282
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);
halcanary9d524f22016-03-29 09:03:52 -0700295 vsBuilder->codeAppendf("%s = vec2(%s.x, %s.y);",
ethannicholas22793252016-01-30 09:59:10 -0800296 v1.vsOut(),
halcanary9d524f22016-03-29 09:03:52 -0700297 te.inVertex1()->fName,
ethannicholas22793252016-01-30 09:59:10 -0800298 te.inVertex1()->fName);
299
300 GrGLSLVertToFrag v2(kVec2f_GrSLType);
301 varyingHandler->addVarying("Vertex2", &v2, kHigh_GrSLPrecision);
halcanary9d524f22016-03-29 09:03:52 -0700302 vsBuilder->codeAppendf("%s = vec2(%s.x, %s.y);",
ethannicholas22793252016-01-30 09:59:10 -0800303 v2.vsOut(),
halcanary9d524f22016-03-29 09:03:52 -0700304 te.inVertex2()->fName,
ethannicholas22793252016-01-30 09:59:10 -0800305 te.inVertex2()->fName);
306
307 GrGLSLVertToFrag v3(kVec2f_GrSLType);
308 varyingHandler->addVarying("Vertex3", &v3, kHigh_GrSLPrecision);
halcanary9d524f22016-03-29 09:03:52 -0700309 vsBuilder->codeAppendf("%s = vec2(%s.x, %s.y);",
ethannicholas22793252016-01-30 09:59:10 -0800310 v3.vsOut(),
halcanary9d524f22016-03-29 09:03:52 -0700311 te.inVertex3()->fName,
ethannicholas22793252016-01-30 09:59:10 -0800312 te.inVertex3()->fName);
313
314 GrGLSLVertToFrag delta1(kVec2f_GrSLType);
315 varyingHandler->addVarying("delta1", &delta1, kHigh_GrSLPrecision);
halcanary9d524f22016-03-29 09:03:52 -0700316 vsBuilder->codeAppendf("%s = vec2(%s.x - %s.x, %s.y - %s.y) * 0.5;",
ethannicholas22793252016-01-30 09:59:10 -0800317 delta1.vsOut(), v1.vsOut(), v2.vsOut(), v2.vsOut(), v1.vsOut());
318
319 GrGLSLVertToFrag delta2(kVec2f_GrSLType);
320 varyingHandler->addVarying("delta2", &delta2, kHigh_GrSLPrecision);
halcanary9d524f22016-03-29 09:03:52 -0700321 vsBuilder->codeAppendf("%s = vec2(%s.x - %s.x, %s.y - %s.y) * 0.5;",
ethannicholas22793252016-01-30 09:59:10 -0800322 delta2.vsOut(), v2.vsOut(), v3.vsOut(), v3.vsOut(), v2.vsOut());
323
324 GrGLSLVertToFrag delta3(kVec2f_GrSLType);
325 varyingHandler->addVarying("delta3", &delta3, kHigh_GrSLPrecision);
halcanary9d524f22016-03-29 09:03:52 -0700326 vsBuilder->codeAppendf("%s = vec2(%s.x - %s.x, %s.y - %s.y) * 0.5;",
ethannicholas22793252016-01-30 09:59:10 -0800327 delta3.vsOut(), v3.vsOut(), v1.vsOut(), v1.vsOut(), v3.vsOut());
328
329 GrGLSLVertToFrag windings(kInt_GrSLType);
cdaltonc08f1962016-02-12 12:14:06 -0800330 varyingHandler->addFlatVarying("windings", &windings, kLow_GrSLPrecision);
halcanary9d524f22016-03-29 09:03:52 -0700331 vsBuilder->codeAppendf("%s = %s;",
ethannicholas22793252016-01-30 09:59:10 -0800332 windings.vsOut(), te.inWindings()->fName);
333
334 // emit transforms
halcanary9d524f22016-03-29 09:03:52 -0700335 this->emitTransforms(vsBuilder, varyingHandler, uniformHandler, gpArgs->fPositionVar,
bsalomona624bf32016-09-20 09:12:47 -0700336 te.inPosition()->fName, te.localMatrix(),
337 args.fFPCoordTransformHandler);
ethannicholas22793252016-01-30 09:59:10 -0800338
cdalton85285412016-02-18 12:37:07 -0800339 GrGLSLPPFragmentBuilder* fsBuilder = args.fFragBuilder;
ethannicholas22793252016-01-30 09:59:10 -0800340 SkAssertResult(fsBuilder->enableFeature(
341 GrGLSLFragmentShaderBuilder::kPixelLocalStorage_GLSLFeature));
ethannicholas22793252016-01-30 09:59:10 -0800342 fsBuilder->declAppendf(GR_GL_PLS_PATH_DATA_DECL);
halcanary9d524f22016-03-29 09:03:52 -0700343 // Compute four subsamples, each shifted a quarter pixel along x and y from
344 // gl_FragCoord. The oriented box positioning of the subsamples is of course not
ethannicholas22793252016-01-30 09:59:10 -0800345 // optimal, but it greatly simplifies the math and this simplification is necessary for
346 // performance reasons.
Ethan Nicholascae3a4c2017-02-02 10:43:58 -0500347 fsBuilder->codeAppendf("highp vec2 firstSample = %s.xy - vec2(0.25);",
348 fsBuilder->fragmentPosition());
ethannicholas22793252016-01-30 09:59:10 -0800349 fsBuilder->codeAppendf("highp vec2 delta1 = %s;", delta1.fsIn());
350 fsBuilder->codeAppendf("highp vec2 delta2 = %s;", delta2.fsIn());
351 fsBuilder->codeAppendf("highp vec2 delta3 = %s;", delta3.fsIn());
352 // Check whether first sample is inside the triangle by computing three dot products. If
353 // all are < 0, we're inside. The first vector in each case is half of what it is
354 // "supposed" to be, because we re-use them later as adjustment factors for which half
355 // is the correct value, so we multiply the dots by two to compensate.
halcanary9d524f22016-03-29 09:03:52 -0700356 fsBuilder->codeAppendf("highp float d1 = dot(delta1, (firstSample - %s).yx) * 2.0;",
ethannicholas22793252016-01-30 09:59:10 -0800357 v1.fsIn());
halcanary9d524f22016-03-29 09:03:52 -0700358 fsBuilder->codeAppendf("highp float d2 = dot(delta2, (firstSample - %s).yx) * 2.0;",
ethannicholas22793252016-01-30 09:59:10 -0800359 v2.fsIn());
halcanary9d524f22016-03-29 09:03:52 -0700360 fsBuilder->codeAppendf("highp float d3 = dot(delta3, (firstSample - %s).yx) * 2.0;",
ethannicholas22793252016-01-30 09:59:10 -0800361 v3.fsIn());
362 fsBuilder->codeAppend("highp float dmax = max(d1, max(d2, d3));");
363 fsBuilder->codeAppendf("pls.windings[0] += (dmax <= 0.0) ? %s : 0;", windings.fsIn());
364 // for subsequent samples, we don't recalculate the entire dot product -- just adjust it
365 // to the value it would have if we did recompute it.
366 fsBuilder->codeAppend("d1 += delta1.x;");
367 fsBuilder->codeAppend("d2 += delta2.x;");
368 fsBuilder->codeAppend("d3 += delta3.x;");
369 fsBuilder->codeAppend("dmax = max(d1, max(d2, d3));");
370 fsBuilder->codeAppendf("pls.windings[1] += (dmax <= 0.0) ? %s : 0;", windings.fsIn());
371 fsBuilder->codeAppend("d1 += delta1.y;");
372 fsBuilder->codeAppend("d2 += delta2.y;");
373 fsBuilder->codeAppend("d3 += delta3.y;");
374 fsBuilder->codeAppend("dmax = max(d1, max(d2, d3));");
375 fsBuilder->codeAppendf("pls.windings[2] += (dmax <= 0.0) ? %s : 0;", windings.fsIn());
376 fsBuilder->codeAppend("d1 -= delta1.x;");
377 fsBuilder->codeAppend("d2 -= delta2.x;");
378 fsBuilder->codeAppend("d3 -= delta3.x;");
379 fsBuilder->codeAppend("dmax = max(d1, max(d2, d3));");
380 fsBuilder->codeAppendf("pls.windings[3] += (dmax <= 0.0) ? %s : 0;", windings.fsIn());
381 }
382
383 static inline void GenKey(const GrGeometryProcessor& gp,
Brian Salomon94efbf52016-11-29 13:43:05 -0500384 const GrShaderCaps&,
ethannicholas22793252016-01-30 09:59:10 -0800385 GrProcessorKeyBuilder* b) {
386 const PLSAATriangleEffect& te = gp.cast<PLSAATriangleEffect>();
387 uint32_t key = 0;
388 key |= te.localMatrix().hasPerspective() ? 0x1 : 0x0;
389 b->add32(key);
390 }
391
bsalomona624bf32016-09-20 09:12:47 -0700392 void setData(const GrGLSLProgramDataManager& pdman, const GrPrimitiveProcessor& gp,
393 FPCoordTransformIter&& transformIter) override {
394 this->setTransformDataHelper(gp.cast<PLSAATriangleEffect>().fLocalMatrix, pdman,
395 &transformIter);
ethannicholas22793252016-01-30 09:59:10 -0800396 }
397
398 private:
399 typedef GrGLSLGeometryProcessor INHERITED;
400 };
401
Brian Salomon94efbf52016-11-29 13:43:05 -0500402 virtual void getGLSLProcessorKey(const GrShaderCaps& caps,
ethannicholas22793252016-01-30 09:59:10 -0800403 GrProcessorKeyBuilder* b) const override {
404 GLSLProcessor::GenKey(*this, caps, b);
405 }
406
Brian Salomon94efbf52016-11-29 13:43:05 -0500407 virtual GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const override {
ethannicholas22793252016-01-30 09:59:10 -0800408 return new GLSLProcessor(*this);
409 }
410
411private:
412 PLSAATriangleEffect(const SkMatrix& localMatrix, bool usesLocalCoords)
413 : fLocalMatrix(localMatrix)
414 , fUsesLocalCoords(usesLocalCoords) {
415 this->initClassID<PLSAATriangleEffect>();
bsalomon6cb807b2016-08-17 11:33:39 -0700416 fInPosition = &this->addVertexAttrib("inPosition", kVec2f_GrVertexAttribType,
417 kHigh_GrSLPrecision);
418 fInVertex1 = &this->addVertexAttrib("inVertex1", kVec2f_GrVertexAttribType,
419 kHigh_GrSLPrecision);
420 fInVertex2 = &this->addVertexAttrib("inVertex2", kVec2f_GrVertexAttribType,
421 kHigh_GrSLPrecision);
422 fInVertex3 = &this->addVertexAttrib("inVertex3", kVec2f_GrVertexAttribType,
423 kHigh_GrSLPrecision);
424 fInWindings = &this->addVertexAttrib("inWindings", kInt_GrVertexAttribType,
425 kLow_GrSLPrecision);
Ethan Nicholascae3a4c2017-02-02 10:43:58 -0500426 this->setWillReadFragmentPosition();
ethannicholas22793252016-01-30 09:59:10 -0800427 }
428
429 const Attribute* fInPosition;
430 const Attribute* fInVertex1;
431 const Attribute* fInVertex2;
432 const Attribute* fInVertex3;
433 const Attribute* fInWindings;
434 SkMatrix fLocalMatrix;
435 bool fUsesLocalCoords;
halcanary9d524f22016-03-29 09:03:52 -0700436
ethannicholas22793252016-01-30 09:59:10 -0800437 GR_DECLARE_GEOMETRY_PROCESSOR_TEST;
438
439 typedef GrGeometryProcessor INHERITED;
440};
441
442///////////////////////////////////////////////////////////////////////////////
443
444/*
445 * Quadratic specified by 0=u^2-v canonical coords. u and v are the first
446 * two components of the vertex attribute. Coverage is based on signed
447 * distance with negative being inside, positive outside. The edge is specified in
448 * window space (y-down). If either the third or fourth component of the interpolated
449 * vertex coord is > 0 then the pixel is considered outside the edge. This is used to
450 * attempt to trim to a portion of the infinite quad.
451 * Requires shader derivative instruction support.
452 */
453
454class PLSQuadEdgeEffect : public GrPLSGeometryProcessor {
455public:
456
457 static GrPLSGeometryProcessor* Create(const SkMatrix& localMatrix,
458 bool usesLocalCoords) {
459 return new PLSQuadEdgeEffect(localMatrix, usesLocalCoords);
460 }
461
462 virtual ~PLSQuadEdgeEffect() {}
463
464 const char* name() const override { return "PLSQuadEdge"; }
465
466 const Attribute* inPosition() const { return fInPosition; }
467 const Attribute* inUV() const { return fInUV; }
468 const Attribute* inEndpoint1() const { return fInEndpoint1; }
469 const Attribute* inEndpoint2() const { return fInEndpoint2; }
470 const Attribute* inWindings() const { return fInWindings; }
471 const SkMatrix& localMatrix() const { return fLocalMatrix; }
472 bool usesLocalCoords() const { return fUsesLocalCoords; }
473
474 class GLSLProcessor : public GrGLSLGeometryProcessor {
475 public:
476 GLSLProcessor(const GrGeometryProcessor&) {}
477
478 void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override {
479 const PLSQuadEdgeEffect& qe = args.fGP.cast<PLSQuadEdgeEffect>();
480 GrGLSLVertexBuilder* vsBuilder = args.fVertBuilder;
481 GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler;
482 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
483
484 // emit attributes
485 varyingHandler->emitAttributes(qe);
486
487 GrGLSLVertToFrag uv(kVec2f_GrSLType);
488 varyingHandler->addVarying("uv", &uv, kHigh_GrSLPrecision);
489 vsBuilder->codeAppendf("%s = %s;", uv.vsOut(), qe.inUV()->fName);
490
491 GrGLSLVertToFrag ep1(kVec2f_GrSLType);
492 varyingHandler->addVarying("endpoint1", &ep1, kHigh_GrSLPrecision);
halcanary9d524f22016-03-29 09:03:52 -0700493 vsBuilder->codeAppendf("%s = vec2(%s.x, %s.y);", ep1.vsOut(),
ethannicholas22793252016-01-30 09:59:10 -0800494 qe.inEndpoint1()->fName, qe.inEndpoint1()->fName);
495
496 GrGLSLVertToFrag ep2(kVec2f_GrSLType);
497 varyingHandler->addVarying("endpoint2", &ep2, kHigh_GrSLPrecision);
halcanary9d524f22016-03-29 09:03:52 -0700498 vsBuilder->codeAppendf("%s = vec2(%s.x, %s.y);", ep2.vsOut(),
ethannicholas22793252016-01-30 09:59:10 -0800499 qe.inEndpoint2()->fName, qe.inEndpoint2()->fName);
500
501 GrGLSLVertToFrag delta(kVec2f_GrSLType);
502 varyingHandler->addVarying("delta", &delta, kHigh_GrSLPrecision);
halcanary9d524f22016-03-29 09:03:52 -0700503 vsBuilder->codeAppendf("%s = vec2(%s.x - %s.x, %s.y - %s.y) * 0.5;",
504 delta.vsOut(), ep1.vsOut(), ep2.vsOut(), ep2.vsOut(),
ethannicholas22793252016-01-30 09:59:10 -0800505 ep1.vsOut());
506
507 GrGLSLVertToFrag windings(kInt_GrSLType);
cdaltonc08f1962016-02-12 12:14:06 -0800508 varyingHandler->addFlatVarying("windings", &windings, kLow_GrSLPrecision);
halcanary9d524f22016-03-29 09:03:52 -0700509 vsBuilder->codeAppendf("%s = %s;",
ethannicholas22793252016-01-30 09:59:10 -0800510 windings.vsOut(), qe.inWindings()->fName);
511
512 // Setup position
513 this->setupPosition(vsBuilder, gpArgs, qe.inPosition()->fName);
514
515 // emit transforms
halcanary9d524f22016-03-29 09:03:52 -0700516 this->emitTransforms(vsBuilder, varyingHandler, uniformHandler, gpArgs->fPositionVar,
bsalomona624bf32016-09-20 09:12:47 -0700517 qe.inPosition()->fName, qe.localMatrix(),
518 args.fFPCoordTransformHandler);
ethannicholas22793252016-01-30 09:59:10 -0800519
cdalton85285412016-02-18 12:37:07 -0800520 GrGLSLPPFragmentBuilder* fsBuilder = args.fFragBuilder;
ethannicholas22793252016-01-30 09:59:10 -0800521 SkAssertResult(fsBuilder->enableFeature(
522 GrGLSLFragmentShaderBuilder::kPixelLocalStorage_GLSLFeature));
ethannicholas22793252016-01-30 09:59:10 -0800523 static const int QUAD_ARGS = 2;
Brian Salomon99938a82016-11-21 13:41:08 -0500524 GrShaderVar inQuadArgs[QUAD_ARGS] = {
525 GrShaderVar("dot", kFloat_GrSLType, 0, kHigh_GrSLPrecision),
526 GrShaderVar("uv", kVec2f_GrSLType, 0, kHigh_GrSLPrecision)
ethannicholas22793252016-01-30 09:59:10 -0800527 };
528 SkString inQuadName;
529
530 const char* inQuadCode = "if (uv.x * uv.x <= uv.y) {"
531 "return dot >= 0.0;"
532 "} else {"
533 "return false;"
534 "}";
halcanary9d524f22016-03-29 09:03:52 -0700535 fsBuilder->emitFunction(kBool_GrSLType, "in_quad", QUAD_ARGS, inQuadArgs, inQuadCode,
ethannicholas22793252016-01-30 09:59:10 -0800536 &inQuadName);
537 fsBuilder->declAppendf(GR_GL_PLS_PATH_DATA_DECL);
538 // keep the derivative instructions outside the conditional
539 fsBuilder->codeAppendf("highp vec2 uvdX = dFdx(%s);", uv.fsIn());
540 fsBuilder->codeAppendf("highp vec2 uvdY = dFdy(%s);", uv.fsIn());
541 fsBuilder->codeAppend("highp vec2 uvIncX = uvdX * 0.45 + uvdY * -0.1;");
542 fsBuilder->codeAppend("highp vec2 uvIncY = uvdX * 0.1 + uvdY * 0.55;");
halcanary9d524f22016-03-29 09:03:52 -0700543 fsBuilder->codeAppendf("highp vec2 uv = %s.xy - uvdX * 0.35 - uvdY * 0.25;",
ethannicholas22793252016-01-30 09:59:10 -0800544 uv.fsIn());
Ethan Nicholascae3a4c2017-02-02 10:43:58 -0500545 fsBuilder->codeAppendf("highp vec2 firstSample = %s.xy - vec2(0.25);",
546 fsBuilder->fragmentPosition());
halcanary9d524f22016-03-29 09:03:52 -0700547 fsBuilder->codeAppendf("highp float d = dot(%s, (firstSample - %s).yx) * 2.0;",
ethannicholas22793252016-01-30 09:59:10 -0800548 delta.fsIn(), ep1.fsIn());
halcanary9d524f22016-03-29 09:03:52 -0700549 fsBuilder->codeAppendf("pls.windings[0] += %s(d, uv) ? %s : 0;", inQuadName.c_str(),
ethannicholas22793252016-01-30 09:59:10 -0800550 windings.fsIn());
551 fsBuilder->codeAppend("uv += uvIncX;");
552 fsBuilder->codeAppendf("d += %s.x;", delta.fsIn());
halcanary9d524f22016-03-29 09:03:52 -0700553 fsBuilder->codeAppendf("pls.windings[1] += %s(d, uv) ? %s : 0;", inQuadName.c_str(),
ethannicholas22793252016-01-30 09:59:10 -0800554 windings.fsIn());
555 fsBuilder->codeAppend("uv += uvIncY;");
556 fsBuilder->codeAppendf("d += %s.y;", delta.fsIn());
halcanary9d524f22016-03-29 09:03:52 -0700557 fsBuilder->codeAppendf("pls.windings[2] += %s(d, uv) ? %s : 0;", inQuadName.c_str(),
ethannicholas22793252016-01-30 09:59:10 -0800558 windings.fsIn());
559 fsBuilder->codeAppend("uv -= uvIncX;");
560 fsBuilder->codeAppendf("d -= %s.x;", delta.fsIn());
halcanary9d524f22016-03-29 09:03:52 -0700561 fsBuilder->codeAppendf("pls.windings[3] += %s(d, uv) ? %s : 0;", inQuadName.c_str(),
ethannicholas22793252016-01-30 09:59:10 -0800562 windings.fsIn());
563 }
564
565 static inline void GenKey(const GrGeometryProcessor& gp,
Brian Salomon94efbf52016-11-29 13:43:05 -0500566 const GrShaderCaps&,
ethannicholas22793252016-01-30 09:59:10 -0800567 GrProcessorKeyBuilder* b) {
568 const PLSQuadEdgeEffect& qee = gp.cast<PLSQuadEdgeEffect>();
569 uint32_t key = 0;
570 key |= qee.usesLocalCoords() && qee.localMatrix().hasPerspective() ? 0x1 : 0x0;
571 b->add32(key);
572 }
573
bsalomona624bf32016-09-20 09:12:47 -0700574 void setData(const GrGLSLProgramDataManager& pdman, const GrPrimitiveProcessor& gp,
575 FPCoordTransformIter&& transformIter) override {
576 this->setTransformDataHelper(gp.cast<PLSQuadEdgeEffect>().fLocalMatrix, pdman,
577 &transformIter);
ethannicholas22793252016-01-30 09:59:10 -0800578 }
579
580 private:
581 typedef GrGLSLGeometryProcessor INHERITED;
582 };
583
Brian Salomon94efbf52016-11-29 13:43:05 -0500584 virtual void getGLSLProcessorKey(const GrShaderCaps& caps,
ethannicholas22793252016-01-30 09:59:10 -0800585 GrProcessorKeyBuilder* b) const override {
586 GLSLProcessor::GenKey(*this, caps, b);
587 }
588
Brian Salomon94efbf52016-11-29 13:43:05 -0500589 virtual GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const override {
ethannicholas22793252016-01-30 09:59:10 -0800590 return new GLSLProcessor(*this);
591 }
592
593private:
594 PLSQuadEdgeEffect(const SkMatrix& localMatrix, bool usesLocalCoords)
595 : fLocalMatrix(localMatrix)
596 , fUsesLocalCoords(usesLocalCoords) {
597 this->initClassID<PLSQuadEdgeEffect>();
bsalomon6cb807b2016-08-17 11:33:39 -0700598 fInPosition = &this->addVertexAttrib("inPosition", kVec2f_GrVertexAttribType,
599 kHigh_GrSLPrecision);
600 fInUV = &this->addVertexAttrib("inUV", kVec2f_GrVertexAttribType, kHigh_GrSLPrecision);
601 fInEndpoint1 = &this->addVertexAttrib("inEndpoint1", kVec2f_GrVertexAttribType,
602 kHigh_GrSLPrecision);
603 fInEndpoint2 = &this->addVertexAttrib("inEndpoint2", kVec2f_GrVertexAttribType,
604 kHigh_GrSLPrecision);
605 fInWindings = &this->addVertexAttrib("inWindings", kInt_GrVertexAttribType,
606 kLow_GrSLPrecision);
Ethan Nicholascae3a4c2017-02-02 10:43:58 -0500607 this->setWillReadFragmentPosition();
ethannicholas22793252016-01-30 09:59:10 -0800608 }
609
610 const Attribute* fInPosition;
611 const Attribute* fInUV;
612 const Attribute* fInEndpoint1;
613 const Attribute* fInEndpoint2;
614 const Attribute* fInWindings;
615 SkMatrix fLocalMatrix;
616 bool fUsesLocalCoords;
halcanary9d524f22016-03-29 09:03:52 -0700617
ethannicholas22793252016-01-30 09:59:10 -0800618 GR_DECLARE_GEOMETRY_PROCESSOR_TEST;
619
620 typedef GrGeometryProcessor INHERITED;
621};
622
623class PLSFinishEffect : public GrGeometryProcessor {
624public:
625
626 static GrGeometryProcessor* Create(GrColor color, bool useEvenOdd, const SkMatrix& localMatrix,
627 bool usesLocalCoords) {
628 return new PLSFinishEffect(color, useEvenOdd, localMatrix, usesLocalCoords);
629 }
630
631 virtual ~PLSFinishEffect() {}
632
633 const char* name() const override { return "PLSFinish"; }
634
635 const Attribute* inPosition() const { return fInPosition; }
636 GrColor color() const { return fColor; }
ethannicholas22793252016-01-30 09:59:10 -0800637 const SkMatrix& localMatrix() const { return fLocalMatrix; }
638 bool usesLocalCoords() const { return fUsesLocalCoords; }
halcanary9d524f22016-03-29 09:03:52 -0700639
640 GrPixelLocalStorageState getPixelLocalStorageState() const override {
ethannicholas22793252016-01-30 09:59:10 -0800641 return GrPixelLocalStorageState::kFinish_GrPixelLocalStorageState;
642 }
643
644 const char* getDestColorOverride() const override {
halcanary9d524f22016-03-29 09:03:52 -0700645 return GR_GL_PLS_DSTCOLOR_NAME;
ethannicholas22793252016-01-30 09:59:10 -0800646 }
647
648 class GLSLProcessor : public GrGLSLGeometryProcessor {
649 public:
650 GLSLProcessor(const GrGeometryProcessor&) {}
651
652 void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override {
653 const PLSFinishEffect& fe = args.fGP.cast<PLSFinishEffect>();
654 GrGLSLVertexBuilder* vsBuilder = args.fVertBuilder;
655 GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler;
656 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
657
cdalton5e58cee2016-02-11 12:49:47 -0800658 fUseEvenOdd = uniformHandler->addUniform(kFragment_GrShaderFlag,
halcanary9d524f22016-03-29 09:03:52 -0700659 kFloat_GrSLType, kLow_GrSLPrecision,
ethannicholas22793252016-01-30 09:59:10 -0800660 "useEvenOdd");
661 const char* useEvenOdd = uniformHandler->getUniformCStr(fUseEvenOdd);
662
663 varyingHandler->emitAttributes(fe);
664 this->setupPosition(vsBuilder, gpArgs, fe.inPosition()->fName);
halcanary9d524f22016-03-29 09:03:52 -0700665 this->emitTransforms(vsBuilder, varyingHandler, uniformHandler, gpArgs->fPositionVar,
bsalomona624bf32016-09-20 09:12:47 -0700666 fe.inPosition()->fName, fe.localMatrix(),
667 args.fFPCoordTransformHandler);
ethannicholas22793252016-01-30 09:59:10 -0800668
cdalton85285412016-02-18 12:37:07 -0800669 GrGLSLPPFragmentBuilder* fsBuilder = args.fFragBuilder;
ethannicholas22793252016-01-30 09:59:10 -0800670 SkAssertResult(fsBuilder->enableFeature(
671 GrGLSLFragmentShaderBuilder::kPixelLocalStorage_GLSLFeature));
672 fsBuilder->declAppendf(GR_GL_PLS_PATH_DATA_DECL);
673 fsBuilder->codeAppend("float coverage;");
674 fsBuilder->codeAppendf("if (%s != 0.0) {", useEvenOdd);
675 fsBuilder->codeAppend("coverage = float(abs(pls.windings[0]) % 2) * 0.25;");
676 fsBuilder->codeAppend("coverage += float(abs(pls.windings[1]) % 2) * 0.25;");
677 fsBuilder->codeAppend("coverage += float(abs(pls.windings[2]) % 2) * 0.25;");
678 fsBuilder->codeAppend("coverage += float(abs(pls.windings[3]) % 2) * 0.25;");
679 fsBuilder->codeAppend("} else {");
680 fsBuilder->codeAppend("coverage = pls.windings[0] != 0 ? 0.25 : 0.0;");
681 fsBuilder->codeAppend("coverage += pls.windings[1] != 0 ? 0.25 : 0.0;");
682 fsBuilder->codeAppend("coverage += pls.windings[2] != 0 ? 0.25 : 0.0;");
683 fsBuilder->codeAppend("coverage += pls.windings[3] != 0 ? 0.25 : 0.0;");
684 fsBuilder->codeAppend("}");
Brian Salomonbfd51832017-01-04 13:22:08 -0500685 this->setupUniformColor(fsBuilder, uniformHandler, args.fOutputColor,
686 &fColorUniform);
ethannicholas22793252016-01-30 09:59:10 -0800687 fsBuilder->codeAppendf("%s = vec4(coverage);", args.fOutputCoverage);
688 fsBuilder->codeAppendf("%s = vec4(1.0, 0.0, 1.0, 1.0);", args.fOutputColor);
689 }
690
691 static inline void GenKey(const GrGeometryProcessor& gp,
Brian Salomon94efbf52016-11-29 13:43:05 -0500692 const GrShaderCaps&,
ethannicholas22793252016-01-30 09:59:10 -0800693 GrProcessorKeyBuilder* b) {
694 const PLSFinishEffect& fe = gp.cast<PLSFinishEffect>();
695 uint32_t key = 0;
696 key |= fe.usesLocalCoords() && fe.localMatrix().hasPerspective() ? 0x1 : 0x0;
697 b->add32(key);
698 }
699
bsalomona624bf32016-09-20 09:12:47 -0700700 void setData(const GrGLSLProgramDataManager& pdman, const GrPrimitiveProcessor& gp,
701 FPCoordTransformIter&& transformIter) override {
ethannicholas22793252016-01-30 09:59:10 -0800702 const PLSFinishEffect& fe = gp.cast<PLSFinishEffect>();
703 pdman.set1f(fUseEvenOdd, fe.fUseEvenOdd);
Brian Salomonbfd51832017-01-04 13:22:08 -0500704 if (fe.color() != fColor) {
ethannicholas22793252016-01-30 09:59:10 -0800705 GrGLfloat c[4];
706 GrColorToRGBAFloat(fe.color(), c);
707 pdman.set4fv(fColorUniform, 1, c);
708 fColor = fe.color();
709 }
bsalomona624bf32016-09-20 09:12:47 -0700710 this->setTransformDataHelper(fe.fLocalMatrix, pdman, &transformIter);
ethannicholas22793252016-01-30 09:59:10 -0800711 }
712
713 private:
714 GrColor fColor;
715 UniformHandle fColorUniform;
716 UniformHandle fUseEvenOdd;
717
718 typedef GrGLSLGeometryProcessor INHERITED;
719 };
720
Brian Salomon94efbf52016-11-29 13:43:05 -0500721 virtual void getGLSLProcessorKey(const GrShaderCaps& caps,
ethannicholas22793252016-01-30 09:59:10 -0800722 GrProcessorKeyBuilder* b) const override {
723 GLSLProcessor::GenKey(*this, caps, b);
724 }
725
Brian Salomon94efbf52016-11-29 13:43:05 -0500726 virtual GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const override {
ethannicholas22793252016-01-30 09:59:10 -0800727 return new GLSLProcessor(*this);
728 }
729
730private:
halcanary9d524f22016-03-29 09:03:52 -0700731 PLSFinishEffect(GrColor color, bool useEvenOdd, const SkMatrix& localMatrix,
ethannicholas22793252016-01-30 09:59:10 -0800732 bool usesLocalCoords)
733 : fColor(color)
734 , fUseEvenOdd(useEvenOdd)
735 , fLocalMatrix(localMatrix)
736 , fUsesLocalCoords(usesLocalCoords) {
737 this->initClassID<PLSFinishEffect>();
bsalomon6cb807b2016-08-17 11:33:39 -0700738 fInPosition = &this->addVertexAttrib("inPosition", kVec2f_GrVertexAttribType,
739 kHigh_GrSLPrecision);
ethannicholas22793252016-01-30 09:59:10 -0800740 }
741
742 const Attribute* fInPosition;
743 GrColor fColor;
744 bool fUseEvenOdd;
745 SkMatrix fLocalMatrix;
746 bool fUsesLocalCoords;
747
748 typedef GrGeometryProcessor INHERITED;
749};
750
751///////////////////////////////////////////////////////////////////////////////
752
753bool GrPLSPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
754 // We have support for even-odd rendering, but are having some troublesome
755 // seams. Disable in the presence of even-odd for now.
bsalomon8acedde2016-06-24 10:42:16 -0700756 SkPath path;
757 args.fShape->asPath(&path);
Brian Salomon0e8fc8b2016-12-09 15:10:07 -0500758 return args.fShaderCaps->shaderDerivativeSupport() && GrAAType::kCoverage == args.fAAType &&
bsalomon8acedde2016-06-24 10:42:16 -0700759 args.fShape->style().isSimpleFill() && !path.isInverseFillType() &&
760 path.getFillType() == SkPath::FillType::kWinding_FillType;
ethannicholas22793252016-01-30 09:59:10 -0800761}
762
Brian Salomona6aa5902016-12-16 09:32:00 -0500763class PLSPathOp final : public GrMeshDrawOp {
ethannicholas22793252016-01-30 09:59:10 -0800764public:
Brian Salomon25a88092016-12-01 09:36:50 -0500765 DEFINE_OP_CLASS_ID
Brian Salomonf8334782017-01-03 09:42:58 -0500766 static std::unique_ptr<GrDrawOp> Make(GrColor color, const SkPath& path,
767 const SkMatrix& viewMatrix) {
768 return std::unique_ptr<GrDrawOp>(new PLSPathOp(color, path, viewMatrix));
ethannicholas22793252016-01-30 09:59:10 -0800769 }
770
Brian Salomona6aa5902016-12-16 09:32:00 -0500771 const char* name() const override { return "PLSPathOp"; }
ethannicholas22793252016-01-30 09:59:10 -0800772
Brian Salomon7c3e7182016-12-01 09:35:30 -0500773 SkString dumpInfo() const override {
774 SkString string;
775 string.printf("Color 0x%08x, UsesLocalCoords: %d\n", fColor, fUsesLocalCoords);
776 string.append(DumpPipelineInfo(*this->pipeline()));
777 string.append(INHERITED::dumpInfo());
778 return string;
779 }
780
Brian Salomon92aee3d2016-12-21 09:20:25 -0500781private:
782 PLSPathOp(GrColor color, const SkPath& path, const SkMatrix& viewMatrix)
783 : INHERITED(ClassID()), fColor(color), fPath(path), fViewMatrix(viewMatrix) {
784 // compute bounds
785 this->setTransformedBounds(path.getBounds(), fViewMatrix, HasAABloat::kYes,
786 IsZeroArea::kNo);
ethannicholas22793252016-01-30 09:59:10 -0800787 }
788
Brian Salomon92aee3d2016-12-21 09:20:25 -0500789 void getPipelineAnalysisInput(GrPipelineAnalysisDrawOpInput* input) const override {
790 input->pipelineColorInput()->setKnownFourComponents(fColor);
791 input->pipelineCoverageInput()->setUnknownSingleComponent();
792 input->setUsesPLSDstRead();
793 }
794
795 void applyPipelineOptimizations(const GrPipelineOptimizations& optimizations) override {
Brian Salomon92aee3d2016-12-21 09:20:25 -0500796 optimizations.getOverrideColorIfSet(&fColor);
ethannicholas22793252016-01-30 09:59:10 -0800797
Brian Salomon92aee3d2016-12-21 09:20:25 -0500798 fUsesLocalCoords = optimizations.readsLocalCoords();
ethannicholas22793252016-01-30 09:59:10 -0800799 }
800
801 void onPrepareDraws(Target* target) const override {
ethannicholas22793252016-01-30 09:59:10 -0800802
803 SkMatrix invert;
bsalomon065c8cf2016-06-30 20:45:38 -0700804 if (fUsesLocalCoords && !fViewMatrix.invert(&invert)) {
ethannicholas22793252016-01-30 09:59:10 -0800805 SkDebugf("Could not invert viewmatrix\n");
806 return;
807 }
808
809 // Setup GrGeometryProcessors
Hal Canary144caf52016-11-07 17:57:18 -0500810 sk_sp<GrPLSGeometryProcessor> triangleProcessor(
bsalomon065c8cf2016-06-30 20:45:38 -0700811 PLSAATriangleEffect::Create(invert, fUsesLocalCoords));
Hal Canary144caf52016-11-07 17:57:18 -0500812 sk_sp<GrPLSGeometryProcessor> quadProcessor(
bsalomon065c8cf2016-06-30 20:45:38 -0700813 PLSQuadEdgeEffect::Create(invert, fUsesLocalCoords));
ethannicholas22793252016-01-30 09:59:10 -0800814
815 GrResourceProvider* rp = target->resourceProvider();
bsalomon065c8cf2016-06-30 20:45:38 -0700816 SkRect bounds;
817 this->bounds().roundOut(&bounds);
818 triangleProcessor->setBounds(bounds);
819 quadProcessor->setBounds(bounds);
ethannicholas22793252016-01-30 09:59:10 -0800820
bsalomon065c8cf2016-06-30 20:45:38 -0700821 // We use the fact that SkPath::transform path does subdivision based on
822 // perspective. Otherwise, we apply the view matrix when copying to the
823 // segment representation.
824 const SkMatrix* viewMatrix = &fViewMatrix;
ethannicholas22793252016-01-30 09:59:10 -0800825
bsalomon065c8cf2016-06-30 20:45:38 -0700826 // We avoid initializing the path unless we have to
827 const SkPath* pathPtr = &fPath;
828 SkTLazy<SkPath> tmpPath;
829 if (viewMatrix->hasPerspective()) {
830 SkPath* tmpPathPtr = tmpPath.init(*pathPtr);
831 tmpPathPtr->setIsVolatile(true);
832 tmpPathPtr->transform(*viewMatrix);
833 viewMatrix = &SkMatrix::I();
834 pathPtr = tmpPathPtr;
835 }
ethannicholas22793252016-01-30 09:59:10 -0800836
bsalomon065c8cf2016-06-30 20:45:38 -0700837 GrMesh mesh;
ethannicholas22793252016-01-30 09:59:10 -0800838
bsalomon065c8cf2016-06-30 20:45:38 -0700839 PLSVertices triVertices;
840 PLSVertices quadVertices;
841 if (!get_geometry(*pathPtr, *viewMatrix, triVertices, quadVertices, rp, bounds)) {
842 return;
843 }
ethannicholas22793252016-01-30 09:59:10 -0800844
bsalomon065c8cf2016-06-30 20:45:38 -0700845 if (triVertices.count()) {
846 const GrBuffer* triVertexBuffer;
847 int firstTriVertex;
848 size_t triStride = triangleProcessor->getVertexStride();
849 PLSVertex* triVerts = reinterpret_cast<PLSVertex*>(target->makeVertexSpace(
850 triStride, triVertices.count(), &triVertexBuffer, &firstTriVertex));
851 if (!triVerts) {
ethannicholas22793252016-01-30 09:59:10 -0800852 SkDebugf("Could not allocate vertices\n");
853 return;
854 }
bsalomon065c8cf2016-06-30 20:45:38 -0700855 for (int i = 0; i < triVertices.count(); ++i) {
856 triVerts[i] = triVertices[i];
857 }
858 mesh.init(kTriangles_GrPrimitiveType, triVertexBuffer, firstTriVertex,
859 triVertices.count());
Hal Canary144caf52016-11-07 17:57:18 -0500860 target->draw(triangleProcessor.get(), mesh);
ethannicholas22793252016-01-30 09:59:10 -0800861 }
ethannicholas22793252016-01-30 09:59:10 -0800862
bsalomon065c8cf2016-06-30 20:45:38 -0700863 if (quadVertices.count()) {
864 const GrBuffer* quadVertexBuffer;
865 int firstQuadVertex;
866 size_t quadStride = quadProcessor->getVertexStride();
867 PLSVertex* quadVerts = reinterpret_cast<PLSVertex*>(target->makeVertexSpace(
868 quadStride, quadVertices.count(), &quadVertexBuffer, &firstQuadVertex));
869 if (!quadVerts) {
870 SkDebugf("Could not allocate vertices\n");
871 return;
872 }
873 for (int i = 0; i < quadVertices.count(); ++i) {
874 quadVerts[i] = quadVertices[i];
875 }
876 mesh.init(kTriangles_GrPrimitiveType, quadVertexBuffer, firstQuadVertex,
877 quadVertices.count());
Hal Canary144caf52016-11-07 17:57:18 -0500878 target->draw(quadProcessor.get(), mesh);
bsalomon065c8cf2016-06-30 20:45:38 -0700879 }
880
Hal Canary144caf52016-11-07 17:57:18 -0500881 sk_sp<GrGeometryProcessor> finishProcessor(
bsalomon065c8cf2016-06-30 20:45:38 -0700882 PLSFinishEffect::Create(fColor,
883 pathPtr->getFillType() ==
884 SkPath::FillType::kEvenOdd_FillType,
885 invert,
886 fUsesLocalCoords));
887 const GrBuffer* rectVertexBuffer;
888 size_t finishStride = finishProcessor->getVertexStride();
889 int firstRectVertex;
890 static const int kRectVertexCount = 6;
891 SkPoint* rectVerts = reinterpret_cast<SkPoint*>(target->makeVertexSpace(
892 finishStride, kRectVertexCount, &rectVertexBuffer, &firstRectVertex));
893 if (!rectVerts) {
894 SkDebugf("Could not allocate vertices\n");
895 return;
896 }
897 rectVerts[0] = { bounds.fLeft, bounds.fTop };
898 rectVerts[1] = { bounds.fLeft, bounds.fBottom };
899 rectVerts[2] = { bounds.fRight, bounds.fBottom };
900 rectVerts[3] = { bounds.fLeft, bounds.fTop };
901 rectVerts[4] = { bounds.fRight, bounds.fTop };
902 rectVerts[5] = { bounds.fRight, bounds.fBottom };
903
904 mesh.init(kTriangles_GrPrimitiveType, rectVertexBuffer, firstRectVertex,
905 kRectVertexCount);
Hal Canary144caf52016-11-07 17:57:18 -0500906 target->draw(finishProcessor.get(), mesh);
bsalomon065c8cf2016-06-30 20:45:38 -0700907 }
ethannicholas22793252016-01-30 09:59:10 -0800908
Brian Salomon25a88092016-12-01 09:36:50 -0500909 bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
ethannicholas22793252016-01-30 09:59:10 -0800910 return false;
911 }
912
bsalomon065c8cf2016-06-30 20:45:38 -0700913 bool fUsesLocalCoords;
ethannicholas22793252016-01-30 09:59:10 -0800914
bsalomon065c8cf2016-06-30 20:45:38 -0700915 GrColor fColor;
916 SkPath fPath;
917 SkMatrix fViewMatrix;
Brian Salomondad29232016-12-01 16:40:24 -0500918 typedef GrMeshDrawOp INHERITED;
ethannicholas22793252016-01-30 09:59:10 -0800919};
920
921SkDEBUGCODE(bool inPLSDraw = false;)
922bool GrPLSPathRenderer::onDrawPath(const DrawPathArgs& args) {
caryclarkd6562002016-07-27 12:02:07 -0700923 SkASSERT(!args.fShape->isEmpty());
ethannicholas22793252016-01-30 09:59:10 -0800924 SkASSERT(!inPLSDraw);
925 SkDEBUGCODE(inPLSDraw = true;)
bsalomon065c8cf2016-06-30 20:45:38 -0700926 SkPath path;
927 args.fShape->asPath(&path);
ethannicholas22793252016-01-30 09:59:10 -0800928
Brian Salomon82f44312017-01-11 13:42:54 -0500929 std::unique_ptr<GrDrawOp> op = PLSPathOp::Make(args.fPaint.getColor(), path, *args.fViewMatrix);
930 GrPipelineBuilder pipelineBuilder(std::move(args.fPaint), args.fAAType);
bsalomonbb243832016-07-22 07:10:19 -0700931 pipelineBuilder.setUserStencil(args.fUserStencilSettings);
932
Brian Salomon24f19782016-12-13 15:10:11 -0500933 args.fRenderTargetContext->addDrawOp(pipelineBuilder, *args.fClip, std::move(op));
ethannicholas22793252016-01-30 09:59:10 -0800934 SkDEBUGCODE(inPLSDraw = false;)
935 return true;
936
937}
938
939///////////////////////////////////////////////////////////////////////////////////////////////////
940
Hal Canary6f6961e2017-01-31 13:50:44 -0500941#if GR_TEST_UTILS
ethannicholas22793252016-01-30 09:59:10 -0800942
Brian Salomon5ec9def2016-12-20 15:34:05 -0500943DRAW_OP_TEST_DEFINE(PLSPathOp) {
bsalomon065c8cf2016-06-30 20:45:38 -0700944 GrColor color = GrRandomColor(random);
945 SkMatrix vm = GrTest::TestMatrixInvertible(random);
946 SkPath path = GrTest::TestPathConvex(random);
ethannicholas22793252016-01-30 09:59:10 -0800947
Brian Salomon5ec9def2016-12-20 15:34:05 -0500948 return PLSPathOp::Make(color, path, vm);
ethannicholas22793252016-01-30 09:59:10 -0800949}
950
951#endif