Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(191)

Side by Side Diff: src/gpu/batches/GrPLSPathRenderer.cpp

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

Powered by Google App Engine
This is Rietveld 408576698