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

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

Powered by Google App Engine
This is Rietveld 408576698