blob: eaa0b8436aec3d89e55965493e67174fe94526b0 [file] [log] [blame]
senorblancod6ed19c2015-02-26 06:58:17 -08001/*
2 * Copyright 2015 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "GrTessellatingPathRenderer.h"
9
robertphillips976f5f02016-06-03 10:59:20 -070010#include "GrAuditTrail.h"
bsalomon75398562015-08-17 12:55:38 -070011#include "GrBatchFlushState.h"
joshualitt2fbd4062015-05-07 13:06:41 -070012#include "GrBatchTest.h"
robertphillips976f5f02016-06-03 10:59:20 -070013#include "GrClip.h"
senorblancod6ed19c2015-02-26 06:58:17 -080014#include "GrDefaultGeoProcFactory.h"
egdaniel0e1853c2016-03-17 11:35:45 -070015#include "GrMesh.h"
senorblancod6ed19c2015-02-26 06:58:17 -080016#include "GrPathUtils.h"
bsalomonbb243832016-07-22 07:10:19 -070017#include "GrPipelineBuilder.h"
senorblanco84cd6212015-08-04 10:01:58 -070018#include "GrResourceCache.h"
19#include "GrResourceProvider.h"
ethannicholase9709e82016-01-07 13:34:16 -080020#include "GrTessellator.h"
senorblancod6ed19c2015-02-26 06:58:17 -080021#include "SkGeometry.h"
22
bsalomon16b99132015-08-13 14:55:50 -070023#include "batches/GrVertexBatch.h"
joshualitt74417822015-08-07 11:42:16 -070024
senorblancod6ed19c2015-02-26 06:58:17 -080025#include <stdio.h>
26
27/*
senorblancof57372d2016-08-31 10:36:19 -070028 * This path renderer tessellates the path into triangles using GrTessellator, uploads the
29 * triangles to a vertex buffer, and renders them with a single draw call. It can do screenspace
30 * antialiasing with a one-pixel coverage ramp.
senorblancod6ed19c2015-02-26 06:58:17 -080031 */
senorblancod6ed19c2015-02-26 06:58:17 -080032namespace {
33
senorblanco84cd6212015-08-04 10:01:58 -070034struct TessInfo {
35 SkScalar fTolerance;
senorblanco06f989a2015-09-02 09:05:17 -070036 int fCount;
senorblanco84cd6212015-08-04 10:01:58 -070037};
38
ethannicholase9709e82016-01-07 13:34:16 -080039// When the SkPathRef genID changes, invalidate a corresponding GrResource described by key.
40class PathInvalidator : public SkPathRef::GenIDChangeListener {
41public:
42 explicit PathInvalidator(const GrUniqueKey& key) : fMsg(key) {}
43private:
44 GrUniqueKeyInvalidatedMessage fMsg;
45
46 void onChange() override {
47 SkMessageBus<GrUniqueKeyInvalidatedMessage>::Post(fMsg);
48 }
49};
50
cdalton397536c2016-03-25 12:15:03 -070051bool cache_match(GrBuffer* vertexBuffer, SkScalar tol, int* actualCount) {
senorblanco84cd6212015-08-04 10:01:58 -070052 if (!vertexBuffer) {
53 return false;
54 }
55 const SkData* data = vertexBuffer->getUniqueKey().getCustomData();
56 SkASSERT(data);
57 const TessInfo* info = static_cast<const TessInfo*>(data->data());
58 if (info->fTolerance == 0 || info->fTolerance < 3.0f * tol) {
senorblanco06f989a2015-09-02 09:05:17 -070059 *actualCount = info->fCount;
senorblanco84cd6212015-08-04 10:01:58 -070060 return true;
61 }
62 return false;
63}
64
senorblanco6599eff2016-03-10 08:38:45 -080065class StaticVertexAllocator : public GrTessellator::VertexAllocator {
66public:
senorblancof57372d2016-08-31 10:36:19 -070067 StaticVertexAllocator(size_t stride, GrResourceProvider* resourceProvider, bool canMapVB)
68 : VertexAllocator(stride)
69 , fResourceProvider(resourceProvider)
senorblanco6599eff2016-03-10 08:38:45 -080070 , fCanMapVB(canMapVB)
71 , fVertices(nullptr) {
72 }
senorblancof57372d2016-08-31 10:36:19 -070073 void* lock(int vertexCount) override {
74 size_t size = vertexCount * stride();
cdalton397536c2016-03-25 12:15:03 -070075 fVertexBuffer.reset(fResourceProvider->createBuffer(
cdaltone2e71c22016-04-07 18:13:29 -070076 size, kVertex_GrBufferType, kStatic_GrAccessPattern, 0));
senorblanco6599eff2016-03-10 08:38:45 -080077 if (!fVertexBuffer.get()) {
78 return nullptr;
79 }
80 if (fCanMapVB) {
senorblancof57372d2016-08-31 10:36:19 -070081 fVertices = fVertexBuffer->map();
senorblanco6599eff2016-03-10 08:38:45 -080082 } else {
senorblancof57372d2016-08-31 10:36:19 -070083 fVertices = sk_malloc_throw(vertexCount * stride());
senorblanco6599eff2016-03-10 08:38:45 -080084 }
85 return fVertices;
86 }
87 void unlock(int actualCount) override {
88 if (fCanMapVB) {
89 fVertexBuffer->unmap();
90 } else {
senorblancof57372d2016-08-31 10:36:19 -070091 fVertexBuffer->updateData(fVertices, actualCount * stride());
92 sk_free(fVertices);
senorblanco6599eff2016-03-10 08:38:45 -080093 }
94 fVertices = nullptr;
95 }
cdalton397536c2016-03-25 12:15:03 -070096 GrBuffer* vertexBuffer() { return fVertexBuffer.get(); }
senorblanco6599eff2016-03-10 08:38:45 -080097private:
Hal Canary144caf52016-11-07 17:57:18 -050098 sk_sp<GrBuffer> fVertexBuffer;
senorblanco6599eff2016-03-10 08:38:45 -080099 GrResourceProvider* fResourceProvider;
100 bool fCanMapVB;
senorblancof57372d2016-08-31 10:36:19 -0700101 void* fVertices;
102};
103
104class DynamicVertexAllocator : public GrTessellator::VertexAllocator {
105public:
106 DynamicVertexAllocator(size_t stride, GrVertexBatch::Target* target)
107 : VertexAllocator(stride)
108 , fTarget(target)
109 , fVertexBuffer(nullptr)
110 , fVertices(nullptr) {
111 }
112 void* lock(int vertexCount) override {
113 fVertexCount = vertexCount;
114 fVertices = fTarget->makeVertexSpace(stride(), vertexCount, &fVertexBuffer, &fFirstVertex);
115 return fVertices;
116 }
117 void unlock(int actualCount) override {
118 fTarget->putBackVertices(fVertexCount - actualCount, stride());
119 fVertices = nullptr;
120 }
121 const GrBuffer* vertexBuffer() const { return fVertexBuffer; }
122 int firstVertex() const { return fFirstVertex; }
123private:
124 GrVertexBatch::Target* fTarget;
125 const GrBuffer* fVertexBuffer;
126 int fVertexCount;
127 int fFirstVertex;
128 void* fVertices;
senorblanco6599eff2016-03-10 08:38:45 -0800129};
130
ethannicholase9709e82016-01-07 13:34:16 -0800131} // namespace
senorblancod6ed19c2015-02-26 06:58:17 -0800132
133GrTessellatingPathRenderer::GrTessellatingPathRenderer() {
134}
135
bsalomon0aff2fa2015-07-31 06:48:27 -0700136bool GrTessellatingPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
senorblancof57372d2016-08-31 10:36:19 -0700137 // This path renderer can draw fill styles, and can do screenspace antialiasing via a
138 // one-pixel coverage ramp. It can do convex and concave paths, but we'll leave the convex
139 // ones to simpler algorithms. We pass on paths that have styles, though they may come back
140 // around after applying the styling information to the geometry to create a filled path. In
141 // the non-AA case, We skip paths thta don't have a key since the real advantage of this path
142 // renderer comes from caching the tessellated geometry. In the AA case, we do not cache, so we
143 // accept paths without keys.
144 if (!args.fShape->style().isSimpleFill() || args.fShape->knownToBeConvex()) {
145 return false;
146 }
147 if (args.fAntiAlias) {
148#ifdef SK_DISABLE_SCREENSPACE_TESS_AA_PATH_RENDERER
149 return false;
150#else
151 SkPath path;
152 args.fShape->asPath(&path);
153 if (path.countVerbs() > 10) {
154 return false;
155 }
156#endif
157 } else if (!args.fShape->hasUnstyledKey()) {
158 return false;
159 }
160 return true;
senorblancod6ed19c2015-02-26 06:58:17 -0800161}
162
bsalomonabd30f52015-08-13 13:34:48 -0700163class TessellatingPathBatch : public GrVertexBatch {
senorblanco9ba39722015-03-05 07:13:42 -0800164public:
Brian Salomon25a88092016-12-01 09:36:50 -0500165 DEFINE_OP_CLASS_ID
senorblanco9ba39722015-03-05 07:13:42 -0800166
Brian Salomon9afd3712016-12-01 10:59:09 -0500167 static GrDrawOp* Create(const GrColor& color,
168 const GrShape& shape,
169 const SkMatrix& viewMatrix,
170 SkIRect devClipBounds,
171 bool antiAlias) {
senorblancof57372d2016-08-31 10:36:19 -0700172 return new TessellatingPathBatch(color, shape, viewMatrix, devClipBounds, antiAlias);
senorblanco9ba39722015-03-05 07:13:42 -0800173 }
174
mtklein36352bf2015-03-25 18:17:31 -0700175 const char* name() const override { return "TessellatingPathBatch"; }
senorblanco9ba39722015-03-05 07:13:42 -0800176
Brian Salomon7c3e7182016-12-01 09:35:30 -0500177 SkString dumpInfo() const override {
178 SkString string;
179 string.appendf("Color 0x%08x, aa: %d\n", fColor, fAntiAlias);
180 string.append(DumpPipelineInfo(*this->pipeline()));
181 string.append(INHERITED::dumpInfo());
182 return string;
183 }
184
halcanary9d524f22016-03-29 09:03:52 -0700185 void computePipelineOptimizations(GrInitInvariantOutput* color,
ethannicholasff210322015-11-24 12:10:10 -0800186 GrInitInvariantOutput* coverage,
187 GrBatchToXPOverrides* overrides) const override {
188 color->setKnownFourComponents(fColor);
189 coverage->setUnknownSingleComponent();
senorblanco9ba39722015-03-05 07:13:42 -0800190 }
191
bsalomone46f9fe2015-08-18 06:05:14 -0700192private:
ethannicholasff210322015-11-24 12:10:10 -0800193 void initBatchTracker(const GrXPOverridesForBatch& overrides) override {
senorblanco9ba39722015-03-05 07:13:42 -0800194 // Handle any color overrides
ethannicholasff210322015-11-24 12:10:10 -0800195 if (!overrides.readsColor()) {
senorblanco9ba39722015-03-05 07:13:42 -0800196 fColor = GrColor_ILLEGAL;
senorblanco9ba39722015-03-05 07:13:42 -0800197 }
ethannicholasff210322015-11-24 12:10:10 -0800198 overrides.getOverrideColorIfSet(&fColor);
199 fPipelineInfo = overrides;
senorblanco9ba39722015-03-05 07:13:42 -0800200 }
201
senorblancof57372d2016-08-31 10:36:19 -0700202 SkPath getPath() const {
203 SkASSERT(!fShape.style().applies());
bsalomonee432412016-06-27 07:18:18 -0700204 SkPath path;
205 fShape.asPath(&path);
senorblancof57372d2016-08-31 10:36:19 -0700206 return path;
207 }
208
209 void draw(Target* target, const GrGeometryProcessor* gp) const {
210 SkASSERT(!fAntiAlias);
211 GrResourceProvider* rp = target->resourceProvider();
212 bool inverseFill = fShape.inverseFilled();
senorblanco84cd6212015-08-04 10:01:58 -0700213 // construct a cache key from the path's genID and the view matrix
214 static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain();
215 GrUniqueKey key;
senorblancof57372d2016-08-31 10:36:19 -0700216 static constexpr int kClipBoundsCnt = sizeof(fDevClipBounds) / sizeof(uint32_t);
bsalomonee432412016-06-27 07:18:18 -0700217 int shapeKeyDataCnt = fShape.unstyledKeySize();
218 SkASSERT(shapeKeyDataCnt >= 0);
219 GrUniqueKey::Builder builder(&key, kDomain, shapeKeyDataCnt + kClipBoundsCnt);
220 fShape.writeUnstyledKey(&builder[0]);
221 // For inverse fills, the tessellation is dependent on clip bounds.
222 if (inverseFill) {
senorblancof57372d2016-08-31 10:36:19 -0700223 memcpy(&builder[shapeKeyDataCnt], &fDevClipBounds, sizeof(fDevClipBounds));
bsalomonee432412016-06-27 07:18:18 -0700224 } else {
senorblancof57372d2016-08-31 10:36:19 -0700225 memset(&builder[shapeKeyDataCnt], 0, sizeof(fDevClipBounds));
bsalomonee432412016-06-27 07:18:18 -0700226 }
227 builder.finish();
Hal Canary144caf52016-11-07 17:57:18 -0500228 sk_sp<GrBuffer> cachedVertexBuffer(rp->findAndRefTByUniqueKey<GrBuffer>(key));
bsalomonee432412016-06-27 07:18:18 -0700229 int actualCount;
senorblancof57372d2016-08-31 10:36:19 -0700230 SkScalar tol = GrPathUtils::kDefaultTolerance;
231 tol = GrPathUtils::scaleToleranceToSrc(tol, fViewMatrix, fShape.bounds());
bsalomonee432412016-06-27 07:18:18 -0700232 if (cache_match(cachedVertexBuffer.get(), tol, &actualCount)) {
233 this->drawVertices(target, gp, cachedVertexBuffer.get(), 0, actualCount);
234 return;
senorblanco84cd6212015-08-04 10:01:58 -0700235 }
236
senorblancof57372d2016-08-31 10:36:19 -0700237 SkRect clipBounds = SkRect::Make(fDevClipBounds);
238
239 SkMatrix vmi;
240 if (!fViewMatrix.invert(&vmi)) {
241 return;
242 }
243 vmi.mapRect(&clipBounds);
senorblanco6599eff2016-03-10 08:38:45 -0800244 bool isLinear;
245 bool canMapVB = GrCaps::kNone_MapFlags != target->caps().mapBufferFlags();
senorblancof57372d2016-08-31 10:36:19 -0700246 StaticVertexAllocator allocator(gp->getVertexStride(), rp, canMapVB);
247 int count = GrTessellator::PathToTriangles(getPath(), tol, clipBounds, &allocator,
248 false, GrColor(), false, &isLinear);
senorblanco6599eff2016-03-10 08:38:45 -0800249 if (count == 0) {
250 return;
251 }
senorblancoaf1e21e2016-03-16 10:25:58 -0700252 this->drawVertices(target, gp, allocator.vertexBuffer(), 0, count);
bsalomonee432412016-06-27 07:18:18 -0700253 TessInfo info;
254 info.fTolerance = isLinear ? 0 : tol;
255 info.fCount = count;
bungeman38d909e2016-08-02 14:40:46 -0700256 key.setCustomData(SkData::MakeWithCopy(&info, sizeof(info)));
bsalomonee432412016-06-27 07:18:18 -0700257 rp->assignUniqueKeyToResource(key, allocator.vertexBuffer());
senorblanco6599eff2016-03-10 08:38:45 -0800258 }
259
senorblancof57372d2016-08-31 10:36:19 -0700260 void drawAA(Target* target, const GrGeometryProcessor* gp) const {
261 SkASSERT(fAntiAlias);
262 SkPath path = getPath();
263 if (path.isEmpty()) {
264 return;
265 }
266 SkRect clipBounds = SkRect::Make(fDevClipBounds);
267 path.transform(fViewMatrix);
268 SkScalar tol = GrPathUtils::kDefaultTolerance;
269 bool isLinear;
270 DynamicVertexAllocator allocator(gp->getVertexStride(), target);
271 bool canTweakAlphaForCoverage = fPipelineInfo.canTweakAlphaForCoverage();
272 int count = GrTessellator::PathToTriangles(path, tol, clipBounds, &allocator,
273 true, fColor, canTweakAlphaForCoverage,
274 &isLinear);
275 if (count == 0) {
276 return;
277 }
278 drawVertices(target, gp, allocator.vertexBuffer(), allocator.firstVertex(), count);
279 }
280
senorblanco6599eff2016-03-10 08:38:45 -0800281 void onPrepareDraws(Target* target) const override {
bungeman06ca8ec2016-06-09 08:01:03 -0700282 sk_sp<GrGeometryProcessor> gp;
joshualittdf0c5572015-08-03 11:35:28 -0700283 {
284 using namespace GrDefaultGeoProcFactory;
285
286 Color color(fColor);
287 LocalCoords localCoords(fPipelineInfo.readsLocalCoords() ?
288 LocalCoords::kUsePosition_Type :
289 LocalCoords::kUnused_Type);
290 Coverage::Type coverageType;
senorblancof57372d2016-08-31 10:36:19 -0700291 if (fAntiAlias) {
292 color = Color(Color::kAttribute_Type);
293 if (fPipelineInfo.canTweakAlphaForCoverage()) {
294 coverageType = Coverage::kSolid_Type;
295 } else {
296 coverageType = Coverage::kAttribute_Type;
297 }
298 } else if (fPipelineInfo.readsCoverage()) {
joshualittdf0c5572015-08-03 11:35:28 -0700299 coverageType = Coverage::kSolid_Type;
300 } else {
301 coverageType = Coverage::kNone_Type;
302 }
303 Coverage coverage(coverageType);
senorblancof57372d2016-08-31 10:36:19 -0700304 if (fAntiAlias) {
305 gp = GrDefaultGeoProcFactory::MakeForDeviceSpace(color, coverage, localCoords,
306 fViewMatrix);
307 } else {
308 gp = GrDefaultGeoProcFactory::Make(color, coverage, localCoords, fViewMatrix);
309 }
joshualittdf0c5572015-08-03 11:35:28 -0700310 }
senorblancof57372d2016-08-31 10:36:19 -0700311 if (fAntiAlias) {
312 this->drawAA(target, gp.get());
313 } else {
314 this->draw(target, gp.get());
315 }
senorblanco6599eff2016-03-10 08:38:45 -0800316 }
senorblanco84cd6212015-08-04 10:01:58 -0700317
cdalton397536c2016-03-25 12:15:03 -0700318 void drawVertices(Target* target, const GrGeometryProcessor* gp, const GrBuffer* vb,
senorblanco6599eff2016-03-10 08:38:45 -0800319 int firstVertex, int count) const {
ethannicholase9709e82016-01-07 13:34:16 -0800320 GrPrimitiveType primitiveType = TESSELLATOR_WIREFRAME ? kLines_GrPrimitiveType
321 : kTriangles_GrPrimitiveType;
egdaniel0e1853c2016-03-17 11:35:45 -0700322 GrMesh mesh;
323 mesh.init(primitiveType, vb, firstVertex, count);
bsalomon342bfc22016-04-01 06:06:20 -0700324 target->draw(gp, mesh);
senorblanco9ba39722015-03-05 07:13:42 -0800325 }
326
Brian Salomon25a88092016-12-01 09:36:50 -0500327 bool onCombineIfPossible(GrOp*, const GrCaps&) override { return false; }
senorblanco9ba39722015-03-05 07:13:42 -0800328
senorblanco9ba39722015-03-05 07:13:42 -0800329 TessellatingPathBatch(const GrColor& color,
bsalomonee432412016-06-27 07:18:18 -0700330 const GrShape& shape,
senorblanco9ba39722015-03-05 07:13:42 -0800331 const SkMatrix& viewMatrix,
senorblancof57372d2016-08-31 10:36:19 -0700332 const SkIRect& devClipBounds,
333 bool antiAlias)
reed1b55a962015-09-17 20:16:13 -0700334 : INHERITED(ClassID())
335 , fColor(color)
bsalomonee432412016-06-27 07:18:18 -0700336 , fShape(shape)
senorblancof57372d2016-08-31 10:36:19 -0700337 , fViewMatrix(viewMatrix)
338 , fDevClipBounds(devClipBounds)
339 , fAntiAlias(antiAlias) {
340 SkRect devBounds;
341 viewMatrix.mapRect(&devBounds, shape.bounds());
342 if (shape.inverseFilled()) {
343 // Because the clip bounds are used to add a contour for inverse fills, they must also
344 // include the path bounds.
345 devBounds.join(SkRect::Make(fDevClipBounds));
346 }
347 this->setBounds(devBounds, HasAABloat::kNo, IsZeroArea::kNo);
senorblanco9ba39722015-03-05 07:13:42 -0800348 }
349
bsalomon91d844d2015-08-10 10:47:29 -0700350 GrColor fColor;
bsalomonee432412016-06-27 07:18:18 -0700351 GrShape fShape;
bsalomon91d844d2015-08-10 10:47:29 -0700352 SkMatrix fViewMatrix;
senorblancof57372d2016-08-31 10:36:19 -0700353 SkIRect fDevClipBounds;
354 bool fAntiAlias;
ethannicholasff210322015-11-24 12:10:10 -0800355 GrXPOverridesForBatch fPipelineInfo;
reed1b55a962015-09-17 20:16:13 -0700356
357 typedef GrVertexBatch INHERITED;
senorblanco9ba39722015-03-05 07:13:42 -0800358};
359
bsalomon0aff2fa2015-07-31 06:48:27 -0700360bool GrTessellatingPathRenderer::onDrawPath(const DrawPathArgs& args) {
Brian Osman11052242016-10-27 14:47:55 -0400361 GR_AUDIT_TRAIL_AUTO_FRAME(args.fRenderTargetContext->auditTrail(),
joshualittde83b412016-01-14 09:58:36 -0800362 "GrTessellatingPathRenderer::onDrawPath");
senorblancod6ed19c2015-02-26 06:58:17 -0800363 SkIRect clipBoundsI;
Robert Phillips93f16332016-11-23 19:37:13 -0500364 args.fClip->getConservativeBounds(args.fRenderTargetContext->worstCaseWidth(),
365 args.fRenderTargetContext->worstCaseHeight(),
robertphillips976f5f02016-06-03 10:59:20 -0700366 &clipBoundsI);
Brian Salomon9afd3712016-12-01 10:59:09 -0500367 sk_sp<GrDrawOp> batch(TessellatingPathBatch::Create(args.fPaint->getColor(),
368 *args.fShape,
369 *args.fViewMatrix,
370 clipBoundsI,
371 args.fAntiAlias));
robertphillips976f5f02016-06-03 10:59:20 -0700372
Brian Osman11052242016-10-27 14:47:55 -0400373 GrPipelineBuilder pipelineBuilder(*args.fPaint,
374 args.fRenderTargetContext->mustUseHWAA(*args.fPaint));
bsalomonbb243832016-07-22 07:10:19 -0700375 pipelineBuilder.setUserStencil(args.fUserStencilSettings);
376
Hal Canary144caf52016-11-07 17:57:18 -0500377 args.fRenderTargetContext->drawBatch(pipelineBuilder, *args.fClip, batch.get());
senorblancod6ed19c2015-02-26 06:58:17 -0800378
379 return true;
380}
joshualitt2fbd4062015-05-07 13:06:41 -0700381
382///////////////////////////////////////////////////////////////////////////////////////////////////
383
384#ifdef GR_TEST_UTILS
385
bsalomonabd30f52015-08-13 13:34:48 -0700386DRAW_BATCH_TEST_DEFINE(TesselatingPathBatch) {
joshualitt2fbd4062015-05-07 13:06:41 -0700387 GrColor color = GrRandomColor(random);
388 SkMatrix viewMatrix = GrTest::TestMatrixInvertible(random);
389 SkPath path = GrTest::TestPath(random);
bsalomond3030ac2016-09-01 07:20:29 -0700390 SkIRect devClipBounds = SkIRect::MakeLTRB(
senorblancof57372d2016-08-31 10:36:19 -0700391 random->nextU(), random->nextU(), random->nextU(), random->nextU());
bsalomond3030ac2016-09-01 07:20:29 -0700392 devClipBounds.sort();
senorblancof57372d2016-08-31 10:36:19 -0700393 bool antiAlias = random->nextBool();
bsalomon6663acf2016-05-10 09:14:17 -0700394 GrStyle style;
395 do {
396 GrTest::TestStyle(random, &style);
senorblancof57372d2016-08-31 10:36:19 -0700397 } while (!style.isSimpleFill());
bsalomonee432412016-06-27 07:18:18 -0700398 GrShape shape(path, style);
senorblancof57372d2016-08-31 10:36:19 -0700399 return TessellatingPathBatch::Create(color, shape, viewMatrix, devClipBounds, antiAlias);
joshualitt2fbd4062015-05-07 13:06:41 -0700400}
401
402#endif