OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2015 Google Inc. | 2 * Copyright 2015 Google Inc. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
8 #include "GrTessellatingPathRenderer.h" | 8 #include "GrTessellatingPathRenderer.h" |
9 | 9 |
10 #include "GrAuditTrail.h" | 10 #include "GrAuditTrail.h" |
11 #include "GrBatchFlushState.h" | 11 #include "GrBatchFlushState.h" |
12 #include "GrBatchTest.h" | 12 #include "GrBatchTest.h" |
13 #include "GrClip.h" | 13 #include "GrClip.h" |
14 #include "GrDefaultGeoProcFactory.h" | 14 #include "GrDefaultGeoProcFactory.h" |
15 #include "GrDrawTarget.h" | |
16 #include "GrMesh.h" | 15 #include "GrMesh.h" |
17 #include "GrPathUtils.h" | 16 #include "GrPathUtils.h" |
18 #include "GrPipelineBuilder.h" | 17 #include "GrPipelineBuilder.h" |
19 #include "GrResourceCache.h" | 18 #include "GrResourceCache.h" |
20 #include "GrResourceProvider.h" | 19 #include "GrResourceProvider.h" |
21 #include "GrTessellator.h" | 20 #include "GrTessellator.h" |
22 #include "SkGeometry.h" | 21 #include "SkGeometry.h" |
23 | 22 |
24 #include "batches/GrVertexBatch.h" | 23 #include "batches/GrVertexBatch.h" |
25 | 24 |
26 #include <stdio.h> | 25 #include <stdio.h> |
27 | 26 |
28 #define SK_DISABLE_SCREENSPACE_TESS_AA_PATH_RENDERER | |
29 | |
30 /* | 27 /* |
31 * This path renderer tessellates the path into triangles using GrTessellator, u
ploads the | 28 * This path renderer tessellates the path into triangles using GrTessellator, u
ploads the triangles |
32 * triangles to a vertex buffer, and renders them with a single draw call. It ca
n do screenspace | 29 * to a vertex buffer, and renders them with a single draw call. It does not cur
rently do |
33 * antialiasing with a one-pixel coverage ramp. | 30 * antialiasing, so it must be used in conjunction with multisampling. |
34 */ | 31 */ |
35 namespace { | 32 namespace { |
36 | 33 |
37 struct TessInfo { | 34 struct TessInfo { |
38 SkScalar fTolerance; | 35 SkScalar fTolerance; |
39 int fCount; | 36 int fCount; |
40 }; | 37 }; |
41 | 38 |
42 // When the SkPathRef genID changes, invalidate a corresponding GrResource descr
ibed by key. | 39 // When the SkPathRef genID changes, invalidate a corresponding GrResource descr
ibed by key. |
43 class PathInvalidator : public SkPathRef::GenIDChangeListener { | 40 class PathInvalidator : public SkPathRef::GenIDChangeListener { |
(...skipping 16 matching lines...) Expand all Loading... |
60 const TessInfo* info = static_cast<const TessInfo*>(data->data()); | 57 const TessInfo* info = static_cast<const TessInfo*>(data->data()); |
61 if (info->fTolerance == 0 || info->fTolerance < 3.0f * tol) { | 58 if (info->fTolerance == 0 || info->fTolerance < 3.0f * tol) { |
62 *actualCount = info->fCount; | 59 *actualCount = info->fCount; |
63 return true; | 60 return true; |
64 } | 61 } |
65 return false; | 62 return false; |
66 } | 63 } |
67 | 64 |
68 class StaticVertexAllocator : public GrTessellator::VertexAllocator { | 65 class StaticVertexAllocator : public GrTessellator::VertexAllocator { |
69 public: | 66 public: |
70 StaticVertexAllocator(size_t stride, GrResourceProvider* resourceProvider, b
ool canMapVB) | 67 StaticVertexAllocator(GrResourceProvider* resourceProvider, bool canMapVB) |
71 : VertexAllocator(stride) | 68 : fResourceProvider(resourceProvider) |
72 , fResourceProvider(resourceProvider) | |
73 , fCanMapVB(canMapVB) | 69 , fCanMapVB(canMapVB) |
74 , fVertices(nullptr) { | 70 , fVertices(nullptr) { |
75 } | 71 } |
76 void* lock(int vertexCount) override { | 72 SkPoint* lock(int vertexCount) override { |
77 size_t size = vertexCount * stride(); | 73 size_t size = vertexCount * sizeof(SkPoint); |
78 fVertexBuffer.reset(fResourceProvider->createBuffer( | 74 fVertexBuffer.reset(fResourceProvider->createBuffer( |
79 size, kVertex_GrBufferType, kStatic_GrAccessPattern, 0)); | 75 size, kVertex_GrBufferType, kStatic_GrAccessPattern, 0)); |
80 if (!fVertexBuffer.get()) { | 76 if (!fVertexBuffer.get()) { |
81 return nullptr; | 77 return nullptr; |
82 } | 78 } |
83 if (fCanMapVB) { | 79 if (fCanMapVB) { |
84 fVertices = fVertexBuffer->map(); | 80 fVertices = static_cast<SkPoint*>(fVertexBuffer->map()); |
85 } else { | 81 } else { |
86 fVertices = sk_malloc_throw(vertexCount * stride()); | 82 fVertices = new SkPoint[vertexCount]; |
87 } | 83 } |
88 return fVertices; | 84 return fVertices; |
89 } | 85 } |
90 void unlock(int actualCount) override { | 86 void unlock(int actualCount) override { |
91 if (fCanMapVB) { | 87 if (fCanMapVB) { |
92 fVertexBuffer->unmap(); | 88 fVertexBuffer->unmap(); |
93 } else { | 89 } else { |
94 fVertexBuffer->updateData(fVertices, actualCount * stride()); | 90 fVertexBuffer->updateData(fVertices, actualCount * sizeof(SkPoint)); |
95 sk_free(fVertices); | 91 delete[] fVertices; |
96 } | 92 } |
97 fVertices = nullptr; | 93 fVertices = nullptr; |
98 } | 94 } |
99 GrBuffer* vertexBuffer() { return fVertexBuffer.get(); } | 95 GrBuffer* vertexBuffer() { return fVertexBuffer.get(); } |
100 private: | 96 private: |
101 SkAutoTUnref<GrBuffer> fVertexBuffer; | 97 SkAutoTUnref<GrBuffer> fVertexBuffer; |
102 GrResourceProvider* fResourceProvider; | 98 GrResourceProvider* fResourceProvider; |
103 bool fCanMapVB; | 99 bool fCanMapVB; |
104 void* fVertices; | 100 SkPoint* fVertices; |
105 }; | |
106 | |
107 class DynamicVertexAllocator : public GrTessellator::VertexAllocator { | |
108 public: | |
109 DynamicVertexAllocator(size_t stride, GrVertexBatch::Target* target) | |
110 : VertexAllocator(stride) | |
111 , fTarget(target) | |
112 , fVertexBuffer(nullptr) | |
113 , fVertices(nullptr) { | |
114 } | |
115 void* lock(int vertexCount) override { | |
116 fVertexCount = vertexCount; | |
117 fVertices = fTarget->makeVertexSpace(stride(), vertexCount, &fVertexBuff
er, &fFirstVertex); | |
118 return fVertices; | |
119 } | |
120 void unlock(int actualCount) override { | |
121 fTarget->putBackVertices(fVertexCount - actualCount, stride()); | |
122 fVertices = nullptr; | |
123 } | |
124 const GrBuffer* vertexBuffer() const { return fVertexBuffer; } | |
125 int firstVertex() const { return fFirstVertex; } | |
126 private: | |
127 GrVertexBatch::Target* fTarget; | |
128 const GrBuffer* fVertexBuffer; | |
129 int fVertexCount; | |
130 int fFirstVertex; | |
131 void* fVertices; | |
132 }; | 101 }; |
133 | 102 |
134 } // namespace | 103 } // namespace |
135 | 104 |
136 GrTessellatingPathRenderer::GrTessellatingPathRenderer() { | 105 GrTessellatingPathRenderer::GrTessellatingPathRenderer() { |
137 } | 106 } |
138 | 107 |
139 bool GrTessellatingPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) cons
t { | 108 bool GrTessellatingPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) cons
t { |
140 // This path renderer can draw fill styles, and can do screenspace antialias
ing via a | 109 // This path renderer can draw fill styles but does not do antialiasing. It
can do convex and |
141 // one-pixel coverage ramp. It can do convex and concave paths, but we'll le
ave the convex | 110 // concave paths, but we'll leave the convex ones to simpler algorithms. We
pass on paths that |
142 // ones to simpler algorithms. We pass on paths that have styles, though the
y may come back | 111 // have styles, though they may come back around after applying the styling
information to the |
143 // around after applying the styling information to the geometry to create a
filled path. In | 112 // geometry to create a filled path. We also skip paths that don't have a ke
y since the real |
144 // the non-AA case, We skip paths thta don't have a key since the real advan
tage of this path | 113 // advantage of this path renderer comes from caching the tessellated geomet
ry. |
145 // renderer comes from caching the tessellated geometry. In the AA case, we
do not cache, so we | 114 return !args.fShape->style().applies() && args.fShape->style().isSimpleFill(
) && |
146 // accept paths without keys. | 115 !args.fAntiAlias && args.fShape->hasUnstyledKey() && !args.fShape->kn
ownToBeConvex(); |
147 if (!args.fShape->style().isSimpleFill() || args.fShape->knownToBeConvex())
{ | |
148 return false; | |
149 } | |
150 if (args.fAntiAlias) { | |
151 #ifdef SK_DISABLE_SCREENSPACE_TESS_AA_PATH_RENDERER | |
152 return false; | |
153 #else | |
154 SkPath path; | |
155 args.fShape->asPath(&path); | |
156 if (path.countVerbs() > 10) { | |
157 return false; | |
158 } | |
159 #endif | |
160 } else if (!args.fShape->hasUnstyledKey()) { | |
161 return false; | |
162 } | |
163 return true; | |
164 } | 116 } |
165 | 117 |
166 class TessellatingPathBatch : public GrVertexBatch { | 118 class TessellatingPathBatch : public GrVertexBatch { |
167 public: | 119 public: |
168 DEFINE_BATCH_CLASS_ID | 120 DEFINE_BATCH_CLASS_ID |
169 | 121 |
170 static GrDrawBatch* Create(const GrColor& color, | 122 static GrDrawBatch* Create(const GrColor& color, |
171 const GrShape& shape, | 123 const GrShape& shape, |
172 const SkMatrix& viewMatrix, | 124 const SkMatrix& viewMatrix, |
173 SkIRect devClipBounds, | 125 SkRect clipBounds) { |
174 bool antiAlias) { | 126 return new TessellatingPathBatch(color, shape, viewMatrix, clipBounds); |
175 return new TessellatingPathBatch(color, shape, viewMatrix, devClipBounds
, antiAlias); | |
176 } | 127 } |
177 | 128 |
178 const char* name() const override { return "TessellatingPathBatch"; } | 129 const char* name() const override { return "TessellatingPathBatch"; } |
179 | 130 |
180 void computePipelineOptimizations(GrInitInvariantOutput* color, | 131 void computePipelineOptimizations(GrInitInvariantOutput* color, |
181 GrInitInvariantOutput* coverage, | 132 GrInitInvariantOutput* coverage, |
182 GrBatchToXPOverrides* overrides) const ove
rride { | 133 GrBatchToXPOverrides* overrides) const ove
rride { |
183 color->setKnownFourComponents(fColor); | 134 color->setKnownFourComponents(fColor); |
184 coverage->setUnknownSingleComponent(); | 135 coverage->setUnknownSingleComponent(); |
185 } | 136 } |
186 | 137 |
187 private: | 138 private: |
188 void initBatchTracker(const GrXPOverridesForBatch& overrides) override { | 139 void initBatchTracker(const GrXPOverridesForBatch& overrides) override { |
189 // Handle any color overrides | 140 // Handle any color overrides |
190 if (!overrides.readsColor()) { | 141 if (!overrides.readsColor()) { |
191 fColor = GrColor_ILLEGAL; | 142 fColor = GrColor_ILLEGAL; |
192 } | 143 } |
193 overrides.getOverrideColorIfSet(&fColor); | 144 overrides.getOverrideColorIfSet(&fColor); |
194 fPipelineInfo = overrides; | 145 fPipelineInfo = overrides; |
195 } | 146 } |
196 | 147 |
197 SkPath getPath() const { | 148 void draw(Target* target, const GrGeometryProcessor* gp) const { |
198 SkASSERT(!fShape.style().applies()); | 149 GrResourceProvider* rp = target->resourceProvider(); |
| 150 SkScalar screenSpaceTol = GrPathUtils::kDefaultTolerance; |
| 151 SkScalar tol = GrPathUtils::scaleToleranceToSrc(screenSpaceTol, fViewMat
rix, |
| 152 fShape.bounds()); |
| 153 |
199 SkPath path; | 154 SkPath path; |
200 fShape.asPath(&path); | 155 fShape.asPath(&path); |
201 return path; | 156 bool inverseFill = path.isInverseFillType(); |
202 } | |
203 | |
204 void draw(Target* target, const GrGeometryProcessor* gp) const { | |
205 SkASSERT(!fAntiAlias); | |
206 GrResourceProvider* rp = target->resourceProvider(); | |
207 bool inverseFill = fShape.inverseFilled(); | |
208 // construct a cache key from the path's genID and the view matrix | 157 // construct a cache key from the path's genID and the view matrix |
209 static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain()
; | 158 static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain()
; |
210 GrUniqueKey key; | 159 GrUniqueKey key; |
211 static constexpr int kClipBoundsCnt = sizeof(fDevClipBounds) / sizeof(ui
nt32_t); | 160 static constexpr int kClipBoundsCnt = sizeof(fClipBounds) / sizeof(uint3
2_t); |
212 int shapeKeyDataCnt = fShape.unstyledKeySize(); | 161 int shapeKeyDataCnt = fShape.unstyledKeySize(); |
213 SkASSERT(shapeKeyDataCnt >= 0); | 162 SkASSERT(shapeKeyDataCnt >= 0); |
214 GrUniqueKey::Builder builder(&key, kDomain, shapeKeyDataCnt + kClipBound
sCnt); | 163 GrUniqueKey::Builder builder(&key, kDomain, shapeKeyDataCnt + kClipBound
sCnt); |
215 fShape.writeUnstyledKey(&builder[0]); | 164 fShape.writeUnstyledKey(&builder[0]); |
216 // For inverse fills, the tessellation is dependent on clip bounds. | 165 // For inverse fills, the tessellation is dependent on clip bounds. |
217 if (inverseFill) { | 166 if (inverseFill) { |
218 memcpy(&builder[shapeKeyDataCnt], &fDevClipBounds, sizeof(fDevClipBo
unds)); | 167 memcpy(&builder[shapeKeyDataCnt], &fClipBounds, sizeof(fClipBounds))
; |
219 } else { | 168 } else { |
220 memset(&builder[shapeKeyDataCnt], 0, sizeof(fDevClipBounds)); | 169 memset(&builder[shapeKeyDataCnt], 0, sizeof(fClipBounds)); |
221 } | 170 } |
222 builder.finish(); | 171 builder.finish(); |
223 SkAutoTUnref<GrBuffer> cachedVertexBuffer(rp->findAndRefTByUniqueKey<GrB
uffer>(key)); | 172 SkAutoTUnref<GrBuffer> cachedVertexBuffer(rp->findAndRefTByUniqueKey<GrB
uffer>(key)); |
224 int actualCount; | 173 int actualCount; |
225 SkScalar tol = GrPathUtils::kDefaultTolerance; | |
226 tol = GrPathUtils::scaleToleranceToSrc(tol, fViewMatrix, fShape.bounds()
); | |
227 if (cache_match(cachedVertexBuffer.get(), tol, &actualCount)) { | 174 if (cache_match(cachedVertexBuffer.get(), tol, &actualCount)) { |
228 this->drawVertices(target, gp, cachedVertexBuffer.get(), 0, actualCo
unt); | 175 this->drawVertices(target, gp, cachedVertexBuffer.get(), 0, actualCo
unt); |
229 return; | 176 return; |
230 } | 177 } |
231 | 178 |
232 SkRect clipBounds = SkRect::Make(fDevClipBounds); | |
233 | |
234 SkMatrix vmi; | |
235 if (!fViewMatrix.invert(&vmi)) { | |
236 return; | |
237 } | |
238 vmi.mapRect(&clipBounds); | |
239 bool isLinear; | 179 bool isLinear; |
240 bool canMapVB = GrCaps::kNone_MapFlags != target->caps().mapBufferFlags(
); | 180 bool canMapVB = GrCaps::kNone_MapFlags != target->caps().mapBufferFlags(
); |
241 StaticVertexAllocator allocator(gp->getVertexStride(), rp, canMapVB); | 181 StaticVertexAllocator allocator(rp, canMapVB); |
242 int count = GrTessellator::PathToTriangles(getPath(), tol, clipBounds, &
allocator, | 182 int count = GrTessellator::PathToTriangles(path, tol, fClipBounds, &allo
cator, &isLinear); |
243 false, GrColor(), false, &isL
inear); | |
244 if (count == 0) { | 183 if (count == 0) { |
245 return; | 184 return; |
246 } | 185 } |
247 this->drawVertices(target, gp, allocator.vertexBuffer(), 0, count); | 186 this->drawVertices(target, gp, allocator.vertexBuffer(), 0, count); |
248 TessInfo info; | 187 TessInfo info; |
249 info.fTolerance = isLinear ? 0 : tol; | 188 info.fTolerance = isLinear ? 0 : tol; |
250 info.fCount = count; | 189 info.fCount = count; |
251 key.setCustomData(SkData::MakeWithCopy(&info, sizeof(info))); | 190 key.setCustomData(SkData::MakeWithCopy(&info, sizeof(info))); |
252 rp->assignUniqueKeyToResource(key, allocator.vertexBuffer()); | 191 rp->assignUniqueKeyToResource(key, allocator.vertexBuffer()); |
253 } | 192 } |
254 | 193 |
255 void drawAA(Target* target, const GrGeometryProcessor* gp) const { | |
256 SkASSERT(fAntiAlias); | |
257 SkPath path = getPath(); | |
258 if (path.isEmpty()) { | |
259 return; | |
260 } | |
261 SkRect clipBounds = SkRect::Make(fDevClipBounds); | |
262 path.transform(fViewMatrix); | |
263 SkScalar tol = GrPathUtils::kDefaultTolerance; | |
264 bool isLinear; | |
265 DynamicVertexAllocator allocator(gp->getVertexStride(), target); | |
266 bool canTweakAlphaForCoverage = fPipelineInfo.canTweakAlphaForCoverage()
; | |
267 int count = GrTessellator::PathToTriangles(path, tol, clipBounds, &alloc
ator, | |
268 true, fColor, canTweakAlphaFo
rCoverage, | |
269 &isLinear); | |
270 if (count == 0) { | |
271 return; | |
272 } | |
273 drawVertices(target, gp, allocator.vertexBuffer(), allocator.firstVertex
(), count); | |
274 } | |
275 | |
276 void onPrepareDraws(Target* target) const override { | 194 void onPrepareDraws(Target* target) const override { |
277 sk_sp<GrGeometryProcessor> gp; | 195 sk_sp<GrGeometryProcessor> gp; |
278 { | 196 { |
279 using namespace GrDefaultGeoProcFactory; | 197 using namespace GrDefaultGeoProcFactory; |
280 | 198 |
281 Color color(fColor); | 199 Color color(fColor); |
282 LocalCoords localCoords(fPipelineInfo.readsLocalCoords() ? | 200 LocalCoords localCoords(fPipelineInfo.readsLocalCoords() ? |
283 LocalCoords::kUsePosition_Type : | 201 LocalCoords::kUsePosition_Type : |
284 LocalCoords::kUnused_Type); | 202 LocalCoords::kUnused_Type); |
285 Coverage::Type coverageType; | 203 Coverage::Type coverageType; |
286 if (fAntiAlias) { | 204 if (fPipelineInfo.readsCoverage()) { |
287 color = Color(Color::kAttribute_Type); | |
288 if (fPipelineInfo.canTweakAlphaForCoverage()) { | |
289 coverageType = Coverage::kSolid_Type; | |
290 } else { | |
291 coverageType = Coverage::kAttribute_Type; | |
292 } | |
293 } else if (fPipelineInfo.readsCoverage()) { | |
294 coverageType = Coverage::kSolid_Type; | 205 coverageType = Coverage::kSolid_Type; |
295 } else { | 206 } else { |
296 coverageType = Coverage::kNone_Type; | 207 coverageType = Coverage::kNone_Type; |
297 } | 208 } |
298 Coverage coverage(coverageType); | 209 Coverage coverage(coverageType); |
299 if (fAntiAlias) { | 210 gp = GrDefaultGeoProcFactory::Make(color, coverage, localCoords, fVi
ewMatrix); |
300 gp = GrDefaultGeoProcFactory::MakeForDeviceSpace(color, coverage
, localCoords, | |
301 fViewMatrix); | |
302 } else { | |
303 gp = GrDefaultGeoProcFactory::Make(color, coverage, localCoords,
fViewMatrix); | |
304 } | |
305 } | 211 } |
306 if (fAntiAlias) { | 212 this->draw(target, gp.get()); |
307 this->drawAA(target, gp.get()); | |
308 } else { | |
309 this->draw(target, gp.get()); | |
310 } | |
311 } | 213 } |
312 | 214 |
313 void drawVertices(Target* target, const GrGeometryProcessor* gp, const GrBuf
fer* vb, | 215 void drawVertices(Target* target, const GrGeometryProcessor* gp, const GrBuf
fer* vb, |
314 int firstVertex, int count) const { | 216 int firstVertex, int count) const { |
| 217 SkASSERT(gp->getVertexStride() == sizeof(SkPoint)); |
| 218 |
315 GrPrimitiveType primitiveType = TESSELLATOR_WIREFRAME ? kLines_GrPrimiti
veType | 219 GrPrimitiveType primitiveType = TESSELLATOR_WIREFRAME ? kLines_GrPrimiti
veType |
316 : kTriangles_GrPri
mitiveType; | 220 : kTriangles_GrPri
mitiveType; |
317 GrMesh mesh; | 221 GrMesh mesh; |
318 mesh.init(primitiveType, vb, firstVertex, count); | 222 mesh.init(primitiveType, vb, firstVertex, count); |
319 target->draw(gp, mesh); | 223 target->draw(gp, mesh); |
320 } | 224 } |
321 | 225 |
322 bool onCombineIfPossible(GrBatch*, const GrCaps&) override { return false; } | 226 bool onCombineIfPossible(GrBatch*, const GrCaps&) override { return false; } |
323 | 227 |
324 TessellatingPathBatch(const GrColor& color, | 228 TessellatingPathBatch(const GrColor& color, |
325 const GrShape& shape, | 229 const GrShape& shape, |
326 const SkMatrix& viewMatrix, | 230 const SkMatrix& viewMatrix, |
327 const SkIRect& devClipBounds, | 231 const SkRect& clipBounds) |
328 bool antiAlias) | |
329 : INHERITED(ClassID()) | 232 : INHERITED(ClassID()) |
330 , fColor(color) | 233 , fColor(color) |
331 , fShape(shape) | 234 , fShape(shape) |
332 , fViewMatrix(viewMatrix) | 235 , fViewMatrix(viewMatrix) { |
333 , fDevClipBounds(devClipBounds) | 236 const SkRect& pathBounds = shape.bounds(); |
334 , fAntiAlias(antiAlias) { | 237 fClipBounds = clipBounds; |
335 SkRect devBounds; | 238 // Because the clip bounds are used to add a contour for inverse fills,
they must also |
336 viewMatrix.mapRect(&devBounds, shape.bounds()); | 239 // include the path bounds. |
337 if (shape.inverseFilled()) { | 240 fClipBounds.join(pathBounds); |
338 // Because the clip bounds are used to add a contour for inverse fil
ls, they must also | 241 const SkRect& srcBounds = shape.inverseFilled() ? fClipBounds : pathBoun
ds; |
339 // include the path bounds. | 242 this->setTransformedBounds(srcBounds, viewMatrix, HasAABloat::kNo, IsZer
oArea::kNo); |
340 devBounds.join(SkRect::Make(fDevClipBounds)); | |
341 } | |
342 this->setBounds(devBounds, HasAABloat::kNo, IsZeroArea::kNo); | |
343 } | 243 } |
344 | 244 |
345 GrColor fColor; | 245 GrColor fColor; |
346 GrShape fShape; | 246 GrShape fShape; |
347 SkMatrix fViewMatrix; | 247 SkMatrix fViewMatrix; |
348 SkIRect fDevClipBounds; | 248 SkRect fClipBounds; // in source space |
349 bool fAntiAlias; | |
350 GrXPOverridesForBatch fPipelineInfo; | 249 GrXPOverridesForBatch fPipelineInfo; |
351 | 250 |
352 typedef GrVertexBatch INHERITED; | 251 typedef GrVertexBatch INHERITED; |
353 }; | 252 }; |
354 | 253 |
355 bool GrTessellatingPathRenderer::onDrawPath(const DrawPathArgs& args) { | 254 bool GrTessellatingPathRenderer::onDrawPath(const DrawPathArgs& args) { |
356 GR_AUDIT_TRAIL_AUTO_FRAME(args.fDrawContext->auditTrail(), | 255 GR_AUDIT_TRAIL_AUTO_FRAME(args.fDrawContext->auditTrail(), |
357 "GrTessellatingPathRenderer::onDrawPath"); | 256 "GrTessellatingPathRenderer::onDrawPath"); |
| 257 SkASSERT(!args.fAntiAlias); |
| 258 |
358 SkIRect clipBoundsI; | 259 SkIRect clipBoundsI; |
359 args.fClip->getConservativeBounds(args.fDrawContext->width(), args.fDrawCont
ext->height(), | 260 args.fClip->getConservativeBounds(args.fDrawContext->width(), args.fDrawCont
ext->height(), |
360 &clipBoundsI); | 261 &clipBoundsI); |
| 262 SkRect clipBounds = SkRect::Make(clipBoundsI); |
| 263 SkMatrix vmi; |
| 264 if (!args.fViewMatrix->invert(&vmi)) { |
| 265 return false; |
| 266 } |
| 267 vmi.mapRect(&clipBounds); |
| 268 SkPath path; |
| 269 args.fShape->asPath(&path); |
361 SkAutoTUnref<GrDrawBatch> batch(TessellatingPathBatch::Create(args.fPaint->g
etColor(), | 270 SkAutoTUnref<GrDrawBatch> batch(TessellatingPathBatch::Create(args.fPaint->g
etColor(), |
362 *args.fShape, | 271 *args.fShape, |
363 *args.fViewMat
rix, | 272 *args.fViewMat
rix, clipBounds)); |
364 clipBoundsI, | |
365 args.fAntiAlia
s)); | |
366 | 273 |
367 GrPipelineBuilder pipelineBuilder(*args.fPaint, args.fDrawContext->mustUseHW
AA(*args.fPaint)); | 274 GrPipelineBuilder pipelineBuilder(*args.fPaint, args.fDrawContext->mustUseHW
AA(*args.fPaint)); |
368 pipelineBuilder.setUserStencil(args.fUserStencilSettings); | 275 pipelineBuilder.setUserStencil(args.fUserStencilSettings); |
369 | 276 |
370 args.fDrawContext->drawBatch(pipelineBuilder, *args.fClip, batch); | 277 args.fDrawContext->drawBatch(pipelineBuilder, *args.fClip, batch); |
371 | 278 |
372 return true; | 279 return true; |
373 } | 280 } |
374 | 281 |
375 ////////////////////////////////////////////////////////////////////////////////
/////////////////// | 282 ////////////////////////////////////////////////////////////////////////////////
/////////////////// |
376 | 283 |
377 #ifdef GR_TEST_UTILS | 284 #ifdef GR_TEST_UTILS |
378 | 285 |
379 DRAW_BATCH_TEST_DEFINE(TesselatingPathBatch) { | 286 DRAW_BATCH_TEST_DEFINE(TesselatingPathBatch) { |
380 GrColor color = GrRandomColor(random); | 287 GrColor color = GrRandomColor(random); |
381 SkMatrix viewMatrix = GrTest::TestMatrixInvertible(random); | 288 SkMatrix viewMatrix = GrTest::TestMatrixInvertible(random); |
382 SkPath path = GrTest::TestPath(random); | 289 SkPath path = GrTest::TestPath(random); |
383 SkIRect devClipBounds = SkIRect::MakeXYWH( | 290 SkRect clipBounds = GrTest::TestRect(random); |
384 random->nextU(), random->nextU(), random->nextU(), random->nextU()); | 291 SkMatrix vmi; |
385 bool antiAlias = random->nextBool(); | 292 bool result = viewMatrix.invert(&vmi); |
| 293 if (!result) { |
| 294 SkFAIL("Cannot invert matrix\n"); |
| 295 } |
| 296 vmi.mapRect(&clipBounds); |
386 GrStyle style; | 297 GrStyle style; |
387 do { | 298 do { |
388 GrTest::TestStyle(random, &style); | 299 GrTest::TestStyle(random, &style); |
389 } while (style.strokeRec().isHairlineStyle()); | 300 } while (style.strokeRec().isHairlineStyle()); |
390 GrShape shape(path, style); | 301 GrShape shape(path, style); |
391 return TessellatingPathBatch::Create(color, shape, viewMatrix, devClipBounds
, antiAlias); | 302 return TessellatingPathBatch::Create(color, shape, viewMatrix, clipBounds); |
392 } | 303 } |
393 | 304 |
394 #endif | 305 #endif |
OLD | NEW |