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