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

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

Powered by Google App Engine
This is Rietveld 408576698