OLD | NEW |
---|---|
1 /* | 1 /* |
2 * Copyright 2014 Google Inc. | 2 * Copyright 2014 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 "GrAADistanceFieldPathRenderer.h" | 8 #include "GrAADistanceFieldPathRenderer.h" |
9 | 9 |
10 #include "GrBatchFlushState.h" | 10 #include "GrBatchFlushState.h" |
(...skipping 13 matching lines...) Expand all Loading... | |
24 | 24 |
25 #define ATLAS_TEXTURE_WIDTH 2048 | 25 #define ATLAS_TEXTURE_WIDTH 2048 |
26 #define ATLAS_TEXTURE_HEIGHT 2048 | 26 #define ATLAS_TEXTURE_HEIGHT 2048 |
27 #define PLOT_WIDTH 512 | 27 #define PLOT_WIDTH 512 |
28 #define PLOT_HEIGHT 256 | 28 #define PLOT_HEIGHT 256 |
29 | 29 |
30 #define NUM_PLOTS_X (ATLAS_TEXTURE_WIDTH / PLOT_WIDTH) | 30 #define NUM_PLOTS_X (ATLAS_TEXTURE_WIDTH / PLOT_WIDTH) |
31 #define NUM_PLOTS_Y (ATLAS_TEXTURE_HEIGHT / PLOT_HEIGHT) | 31 #define NUM_PLOTS_Y (ATLAS_TEXTURE_HEIGHT / PLOT_HEIGHT) |
32 | 32 |
33 #ifdef DF_PATH_TRACKING | 33 #ifdef DF_PATH_TRACKING |
34 static int g_NumCachedPaths = 0; | 34 static int g_NumCachedShapes = 0; |
35 static int g_NumFreedPaths = 0; | 35 static int g_NumFreedShapes = 0; |
36 #endif | 36 #endif |
37 | 37 |
38 // mip levels | 38 // mip levels |
39 static const int kSmallMIP = 32; | 39 static const int kSmallMIP = 32; |
40 static const int kMediumMIP = 73; | 40 static const int kMediumMIP = 73; |
41 static const int kLargeMIP = 162; | 41 static const int kLargeMIP = 162; |
42 | 42 |
43 // Callback to clear out internal path cache when eviction occurs | 43 // Callback to clear out internal path cache when eviction occurs |
44 void GrAADistanceFieldPathRenderer::HandleEviction(GrBatchAtlas::AtlasID id, voi d* pr) { | 44 void GrAADistanceFieldPathRenderer::HandleEviction(GrBatchAtlas::AtlasID id, voi d* pr) { |
45 GrAADistanceFieldPathRenderer* dfpr = (GrAADistanceFieldPathRenderer*)pr; | 45 GrAADistanceFieldPathRenderer* dfpr = (GrAADistanceFieldPathRenderer*)pr; |
46 // remove any paths that use this plot | 46 // remove any paths that use this plot |
47 PathDataList::Iter iter; | 47 ShapeDataList::Iter iter; |
48 iter.init(dfpr->fPathList, PathDataList::Iter::kHead_IterStart); | 48 iter.init(dfpr->fShapeList, ShapeDataList::Iter::kHead_IterStart); |
49 PathData* pathData; | 49 ShapeData* shapeData; |
50 while ((pathData = iter.get())) { | 50 while ((shapeData = iter.get())) { |
51 iter.next(); | 51 iter.next(); |
52 if (id == pathData->fID) { | 52 if (id == shapeData->fID) { |
53 dfpr->fPathCache.remove(pathData->fKey); | 53 dfpr->fShapeCache.remove(shapeData->fKey); |
54 dfpr->fPathList.remove(pathData); | 54 dfpr->fShapeList.remove(shapeData); |
55 delete pathData; | 55 delete shapeData; |
56 #ifdef DF_PATH_TRACKING | 56 #ifdef DF_PATH_TRACKING |
57 ++g_NumFreedPaths; | 57 ++g_NumFreedPaths; |
58 #endif | 58 #endif |
59 } | 59 } |
60 } | 60 } |
61 } | 61 } |
62 | 62 |
63 //////////////////////////////////////////////////////////////////////////////// | 63 //////////////////////////////////////////////////////////////////////////////// |
64 GrAADistanceFieldPathRenderer::GrAADistanceFieldPathRenderer() : fAtlas(nullptr) {} | 64 GrAADistanceFieldPathRenderer::GrAADistanceFieldPathRenderer() : fAtlas(nullptr) {} |
65 | 65 |
66 GrAADistanceFieldPathRenderer::~GrAADistanceFieldPathRenderer() { | 66 GrAADistanceFieldPathRenderer::~GrAADistanceFieldPathRenderer() { |
67 PathDataList::Iter iter; | 67 ShapeDataList::Iter iter; |
68 iter.init(fPathList, PathDataList::Iter::kHead_IterStart); | 68 iter.init(fShapeList, ShapeDataList::Iter::kHead_IterStart); |
69 PathData* pathData; | 69 ShapeData* shapeData; |
70 while ((pathData = iter.get())) { | 70 while ((shapeData = iter.get())) { |
71 iter.next(); | 71 iter.next(); |
72 fPathList.remove(pathData); | 72 fShapeList.remove(shapeData); |
73 delete pathData; | 73 delete shapeData; |
74 } | 74 } |
75 delete fAtlas; | 75 delete fAtlas; |
76 | 76 |
77 #ifdef DF_PATH_TRACKING | 77 #ifdef DF_PATH_TRACKING |
78 SkDebugf("Cached paths: %d, freed paths: %d\n", g_NumCachedPaths, g_NumFreed Paths); | 78 SkDebugf("Cached shapes: %d, freed shapes: %d\n", g_NumCachedShapes, g_NumFr eedShapes); |
79 #endif | 79 #endif |
80 } | 80 } |
81 | 81 |
82 //////////////////////////////////////////////////////////////////////////////// | 82 //////////////////////////////////////////////////////////////////////////////// |
83 bool GrAADistanceFieldPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) c onst { | 83 bool GrAADistanceFieldPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) c onst { |
84 // We don't currently apply the dash or factor it into the DF key. (skbug.co m/5082) | 84 if (!args.fShaderCaps->shaderDerivativeSupport()) { |
85 if (args.fShape->style().pathEffect()) { | |
86 return false; | 85 return false; |
87 } | 86 } |
87 // If the shape has no key then we won't get any reuse. | |
88 if (!args.fShape->hasUnstyledKey()) { | |
89 return false; | |
90 } | |
91 if (args.fShape->style().applies()) { | |
92 // This may come back around after the style has been applied. | |
93 return false; | |
94 } | |
95 // This does non-inverse antialiased fills. | |
88 // TODO: Support inverse fill | 96 // TODO: Support inverse fill |
89 if (!args.fShaderCaps->shaderDerivativeSupport() || !args.fAntiAlias || | 97 if (!args.fAntiAlias || !args.fShape->style().isSimpleFill() ||args.fShape-> inverseFilled()) { |
egdaniel
2016/06/27 13:16:58
space after ||
bsalomon
2016/06/27 13:37:52
Done.
| |
90 args.fShape->style().isSimpleHairline() || args.fShape->mayBeInverseFill edAfterStyling() || | |
91 !args.fShape->hasUnstyledKey()) { | |
92 return false; | 98 return false; |
93 } | 99 } |
94 | 100 |
95 // currently don't support perspective | 101 // currently don't support perspective |
96 if (args.fViewMatrix->hasPerspective()) { | 102 if (args.fViewMatrix->hasPerspective()) { |
97 return false; | 103 return false; |
98 } | 104 } |
99 | 105 |
100 // only support paths with bounds within kMediumMIP by kMediumMIP, | 106 // only support paths with bounds within kMediumMIP by kMediumMIP, |
101 // scaled to have bounds within 2.0f*kLargeMIP by 2.0f*kLargeMIP | 107 // scaled to have bounds within 2.0f*kLargeMIP by 2.0f*kLargeMIP |
102 // the goal is to accelerate rendering of lots of small paths that may be sc aling | 108 // the goal is to accelerate rendering of lots of small paths that may be sc aling |
103 SkScalar maxScale = args.fViewMatrix->getMaxScale(); | 109 SkScalar maxScale = args.fViewMatrix->getMaxScale(); |
104 SkRect bounds; | 110 SkRect bounds; |
105 args.fShape->styledBounds(&bounds); | 111 args.fShape->styledBounds(&bounds); |
106 SkScalar maxDim = SkMaxScalar(bounds.width(), bounds.height()); | 112 SkScalar maxDim = SkMaxScalar(bounds.width(), bounds.height()); |
107 | 113 |
108 return maxDim <= kMediumMIP && maxDim * maxScale <= 2.0f*kLargeMIP; | 114 return maxDim <= kMediumMIP && maxDim * maxScale <= 2.0f*kLargeMIP; |
109 } | 115 } |
110 | 116 |
111 //////////////////////////////////////////////////////////////////////////////// | 117 //////////////////////////////////////////////////////////////////////////////// |
112 | 118 |
113 // padding around path bounds to allow for antialiased pixels | 119 // padding around path bounds to allow for antialiased pixels |
114 static const SkScalar kAntiAliasPad = 1.0f; | 120 static const SkScalar kAntiAliasPad = 1.0f; |
115 | 121 |
116 class AADistanceFieldPathBatch : public GrVertexBatch { | 122 class AADistanceFieldPathBatch : public GrVertexBatch { |
117 public: | 123 public: |
118 DEFINE_BATCH_CLASS_ID | 124 DEFINE_BATCH_CLASS_ID |
119 | 125 |
120 typedef GrAADistanceFieldPathRenderer::PathData PathData; | 126 typedef GrAADistanceFieldPathRenderer::ShapeData ShapeData; |
121 typedef SkTDynamicHash<PathData, PathData::Key> PathCache; | 127 typedef SkTDynamicHash<ShapeData, ShapeData::Key> ShapeCache; |
122 typedef GrAADistanceFieldPathRenderer::PathDataList PathDataList; | 128 typedef GrAADistanceFieldPathRenderer::ShapeDataList ShapeDataList; |
123 | 129 |
124 struct Geometry { | 130 struct Geometry { |
125 Geometry(const SkStrokeRec& stroke) : fStroke(stroke) { | 131 GrShape fShape; |
126 if (!stroke.needToApply()) { | |
127 // purify unused values to ensure binary equality | |
128 fStroke.setStrokeParams(SkPaint::kDefault_Cap, SkPaint::kDefault _Join, | |
129 SkIntToScalar(4)); | |
130 if (fStroke.getWidth() < 0) { | |
131 fStroke.setStrokeStyle(-1.0f); | |
132 } | |
133 } | |
134 } | |
135 SkPath fPath; | |
136 // The unique ID of the path involved in this draw. This may be differen t than the ID | |
137 // in fPath since that path may have resulted from a SkStrokeRec::applyT oPath call. | |
138 uint32_t fGenID; | |
139 SkStrokeRec fStroke; | |
140 GrColor fColor; | 132 GrColor fColor; |
141 bool fAntiAlias; | 133 bool fAntiAlias; |
142 }; | 134 }; |
143 | 135 |
144 static GrDrawBatch* Create(const Geometry& geometry, const SkMatrix& viewMat rix, | 136 static GrDrawBatch* Create(const Geometry& geometry, const SkMatrix& viewMat rix, |
145 GrBatchAtlas* atlas, PathCache* pathCache, PathDa taList* pathList, | 137 GrBatchAtlas* atlas, ShapeCache* shapeCache, |
146 bool gammaCorrect) { | 138 ShapeDataList* shapeList, bool gammaCorrect) { |
147 return new AADistanceFieldPathBatch(geometry, viewMatrix, atlas, pathCac he, pathList, | 139 return new AADistanceFieldPathBatch(geometry, viewMatrix, atlas, shapeCa che, shapeList, |
148 gammaCorrect); | 140 gammaCorrect); |
149 } | 141 } |
150 | 142 |
151 const char* name() const override { return "AADistanceFieldPathBatch"; } | 143 const char* name() const override { return "AADistanceFieldPathBatch"; } |
152 | 144 |
153 void computePipelineOptimizations(GrInitInvariantOutput* color, | 145 void computePipelineOptimizations(GrInitInvariantOutput* color, |
154 GrInitInvariantOutput* coverage, | 146 GrInitInvariantOutput* coverage, |
155 GrBatchToXPOverrides* overrides) const ove rride { | 147 GrBatchToXPOverrides* overrides) const ove rride { |
156 color->setKnownFourComponents(fGeoData[0].fColor); | 148 color->setKnownFourComponents(fGeoData[0].fColor); |
157 coverage->setUnknownSingleComponent(); | 149 coverage->setUnknownSingleComponent(); |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
222 SkDebugf("Could not allocate vertices\n"); | 214 SkDebugf("Could not allocate vertices\n"); |
223 return; | 215 return; |
224 } | 216 } |
225 | 217 |
226 flushInfo.fInstancesToFlush = 0; | 218 flushInfo.fInstancesToFlush = 0; |
227 for (int i = 0; i < instanceCount; i++) { | 219 for (int i = 0; i < instanceCount; i++) { |
228 const Geometry& args = fGeoData[i]; | 220 const Geometry& args = fGeoData[i]; |
229 | 221 |
230 // get mip level | 222 // get mip level |
231 SkScalar maxScale = this->viewMatrix().getMaxScale(); | 223 SkScalar maxScale = this->viewMatrix().getMaxScale(); |
232 const SkRect& bounds = args.fPath.getBounds(); | 224 const SkRect& bounds = args.fShape.bounds(); |
233 SkScalar maxDim = SkMaxScalar(bounds.width(), bounds.height()); | 225 SkScalar maxDim = SkMaxScalar(bounds.width(), bounds.height()); |
234 SkScalar size = maxScale * maxDim; | 226 SkScalar size = maxScale * maxDim; |
235 uint32_t desiredDimension; | 227 uint32_t desiredDimension; |
236 if (size <= kSmallMIP) { | 228 if (size <= kSmallMIP) { |
237 desiredDimension = kSmallMIP; | 229 desiredDimension = kSmallMIP; |
238 } else if (size <= kMediumMIP) { | 230 } else if (size <= kMediumMIP) { |
239 desiredDimension = kMediumMIP; | 231 desiredDimension = kMediumMIP; |
240 } else { | 232 } else { |
241 desiredDimension = kLargeMIP; | 233 desiredDimension = kLargeMIP; |
242 } | 234 } |
243 | 235 |
244 // check to see if path is cached | 236 // check to see if path is cached |
245 PathData::Key key(args.fGenID, desiredDimension, args.fStroke); | 237 ShapeData::Key key(args.fShape, desiredDimension); |
246 PathData* pathData = fPathCache->find(key); | 238 ShapeData* shapeData = fShapeCache->find(key); |
247 if (nullptr == pathData || !atlas->hasID(pathData->fID)) { | 239 if (nullptr == shapeData || !atlas->hasID(shapeData->fID)) { |
248 // Remove the stale cache entry | 240 // Remove the stale cache entry |
249 if (pathData) { | 241 if (shapeData) { |
250 fPathCache->remove(pathData->fKey); | 242 fShapeCache->remove(shapeData->fKey); |
251 fPathList->remove(pathData); | 243 fShapeList->remove(shapeData); |
252 delete pathData; | 244 delete shapeData; |
253 } | 245 } |
254 SkScalar scale = desiredDimension/maxDim; | 246 SkScalar scale = desiredDimension/maxDim; |
255 pathData = new PathData; | 247 shapeData = new ShapeData; |
256 if (!this->addPathToAtlas(target, | 248 if (!this->addPathToAtlas(target, |
257 &flushInfo, | 249 &flushInfo, |
258 atlas, | 250 atlas, |
259 pathData, | 251 shapeData, |
260 args.fPath, | 252 args.fShape, |
261 args.fGenID, | |
262 args.fStroke, | |
263 args.fAntiAlias, | 253 args.fAntiAlias, |
264 desiredDimension, | 254 desiredDimension, |
265 scale)) { | 255 scale)) { |
266 SkDebugf("Can't rasterize path\n"); | 256 SkDebugf("Can't rasterize path\n"); |
267 return; | 257 return; |
268 } | 258 } |
269 } | 259 } |
270 | 260 |
271 atlas->setLastUseToken(pathData->fID, target->nextDrawToken()); | 261 atlas->setLastUseToken(shapeData->fID, target->nextDrawToken()); |
272 | 262 |
273 // Now set vertices | 263 // Now set vertices |
274 intptr_t offset = reinterpret_cast<intptr_t>(vertices); | 264 intptr_t offset = reinterpret_cast<intptr_t>(vertices); |
275 offset += i * kVerticesPerQuad * vertexStride; | 265 offset += i * kVerticesPerQuad * vertexStride; |
276 this->writePathVertices(target, | 266 this->writePathVertices(target, |
277 atlas, | 267 atlas, |
278 offset, | 268 offset, |
279 args.fColor, | 269 args.fColor, |
280 vertexStride, | 270 vertexStride, |
281 this->viewMatrix(), | 271 this->viewMatrix(), |
282 args.fPath, | 272 args.fShape, |
283 pathData); | 273 shapeData); |
284 flushInfo.fInstancesToFlush++; | 274 flushInfo.fInstancesToFlush++; |
285 } | 275 } |
286 | 276 |
287 this->flush(target, &flushInfo); | 277 this->flush(target, &flushInfo); |
288 } | 278 } |
289 | 279 |
290 SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; } | |
291 | |
292 AADistanceFieldPathBatch(const Geometry& geometry, | 280 AADistanceFieldPathBatch(const Geometry& geometry, |
293 const SkMatrix& viewMatrix, | 281 const SkMatrix& viewMatrix, |
294 GrBatchAtlas* atlas, | 282 GrBatchAtlas* atlas, |
295 PathCache* pathCache, PathDataList* pathList, | 283 ShapeCache* shapeCache, ShapeDataList* shapeList, |
296 bool gammaCorrect) | 284 bool gammaCorrect) |
297 : INHERITED(ClassID()) { | 285 : INHERITED(ClassID()) { |
286 SkASSERT(geometry.fShape.hasUnstyledKey()); | |
298 fBatch.fViewMatrix = viewMatrix; | 287 fBatch.fViewMatrix = viewMatrix; |
299 fGeoData.push_back(geometry); | 288 fGeoData.push_back(geometry); |
289 SkASSERT(fGeoData[0].fShape.hasUnstyledKey()); | |
300 | 290 |
301 fAtlas = atlas; | 291 fAtlas = atlas; |
302 fPathCache = pathCache; | 292 fShapeCache = shapeCache; |
303 fPathList = pathList; | 293 fShapeList = shapeList; |
304 fGammaCorrect = gammaCorrect; | 294 fGammaCorrect = gammaCorrect; |
305 | 295 |
306 // Compute bounds | 296 // Compute bounds |
307 fBounds = geometry.fPath.getBounds(); | 297 fBounds = geometry.fShape.bounds(); |
308 viewMatrix.mapRect(&fBounds); | 298 viewMatrix.mapRect(&fBounds); |
309 } | 299 } |
310 | 300 |
311 bool addPathToAtlas(GrVertexBatch::Target* target, | 301 bool addPathToAtlas(GrVertexBatch::Target* target, |
312 FlushInfo* flushInfo, | 302 FlushInfo* flushInfo, |
313 GrBatchAtlas* atlas, | 303 GrBatchAtlas* atlas, |
314 PathData* pathData, | 304 ShapeData* shapeData, |
315 const SkPath& path, | 305 const GrShape& shape, |
316 uint32_t genID, | |
317 const SkStrokeRec& stroke, | |
318 bool antiAlias, | 306 bool antiAlias, |
319 uint32_t dimension, | 307 uint32_t dimension, |
320 SkScalar scale) const { | 308 SkScalar scale) const { |
321 const SkRect& bounds = path.getBounds(); | 309 const SkRect& bounds = shape.bounds(); |
322 | 310 |
323 // generate bounding rect for bitmap draw | 311 // generate bounding rect for bitmap draw |
324 SkRect scaledBounds = bounds; | 312 SkRect scaledBounds = bounds; |
325 // scale to mip level size | 313 // scale to mip level size |
326 scaledBounds.fLeft *= scale; | 314 scaledBounds.fLeft *= scale; |
327 scaledBounds.fTop *= scale; | 315 scaledBounds.fTop *= scale; |
328 scaledBounds.fRight *= scale; | 316 scaledBounds.fRight *= scale; |
329 scaledBounds.fBottom *= scale; | 317 scaledBounds.fBottom *= scale; |
330 // move the origin to an integer boundary (gives better results) | 318 // move the origin to an integer boundary (gives better results) |
331 SkScalar dx = SkScalarFraction(scaledBounds.fLeft); | 319 SkScalar dx = SkScalarFraction(scaledBounds.fLeft); |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
368 | 356 |
369 SkDraw draw; | 357 SkDraw draw; |
370 sk_bzero(&draw, sizeof(draw)); | 358 sk_bzero(&draw, sizeof(draw)); |
371 | 359 |
372 SkRasterClip rasterClip; | 360 SkRasterClip rasterClip; |
373 rasterClip.setRect(devPathBounds); | 361 rasterClip.setRect(devPathBounds); |
374 draw.fRC = &rasterClip; | 362 draw.fRC = &rasterClip; |
375 draw.fMatrix = &drawMatrix; | 363 draw.fMatrix = &drawMatrix; |
376 draw.fDst = dst; | 364 draw.fDst = dst; |
377 | 365 |
366 SkPath path; | |
367 shape.asPath(&path); | |
378 draw.drawPathCoverage(path, paint); | 368 draw.drawPathCoverage(path, paint); |
379 | 369 |
380 // generate signed distance field | 370 // generate signed distance field |
381 devPathBounds.outset(SK_DistanceFieldPad, SK_DistanceFieldPad); | 371 devPathBounds.outset(SK_DistanceFieldPad, SK_DistanceFieldPad); |
382 width = devPathBounds.width(); | 372 width = devPathBounds.width(); |
383 height = devPathBounds.height(); | 373 height = devPathBounds.height(); |
384 // TODO We should really generate this directly into the plot somehow | 374 // TODO We should really generate this directly into the plot somehow |
385 SkAutoSMalloc<1024> dfStorage(width * height * sizeof(unsigned char)); | 375 SkAutoSMalloc<1024> dfStorage(width * height * sizeof(unsigned char)); |
386 | 376 |
387 // Generate signed distance field | 377 // Generate signed distance field |
388 SkGenerateDistanceFieldFromA8Image((unsigned char*)dfStorage.get(), | 378 SkGenerateDistanceFieldFromA8Image((unsigned char*)dfStorage.get(), |
389 (const unsigned char*)dst.addr(), | 379 (const unsigned char*)dst.addr(), |
390 dst.width(), dst.height(), dst.rowByt es()); | 380 dst.width(), dst.height(), dst.rowByt es()); |
391 | 381 |
392 // add to atlas | 382 // add to atlas |
393 SkIPoint16 atlasLocation; | 383 SkIPoint16 atlasLocation; |
394 GrBatchAtlas::AtlasID id; | 384 GrBatchAtlas::AtlasID id; |
395 bool success = atlas->addToAtlas(&id, target, width, height, dfStorage.g et(), | 385 bool success = atlas->addToAtlas(&id, target, width, height, dfStorage.g et(), |
396 &atlasLocation); | 386 &atlasLocation); |
397 if (!success) { | 387 if (!success) { |
398 this->flush(target, flushInfo); | 388 this->flush(target, flushInfo); |
399 | 389 |
400 SkDEBUGCODE(success =) atlas->addToAtlas(&id, target, width, height, | 390 SkDEBUGCODE(success =) atlas->addToAtlas(&id, target, width, height, |
401 dfStorage.get(), &atlasLoca tion); | 391 dfStorage.get(), &atlasLoca tion); |
402 SkASSERT(success); | 392 SkASSERT(success); |
403 | 393 |
404 } | 394 } |
405 | 395 |
406 // add to cache | 396 // add to cache |
407 pathData->fKey = PathData::Key(genID, dimension, stroke); | 397 shapeData->fKey.set(shape, dimension); |
408 pathData->fScale = scale; | 398 shapeData->fScale = scale; |
409 pathData->fID = id; | 399 shapeData->fID = id; |
410 // change the scaled rect to match the size of the inset distance field | 400 // change the scaled rect to match the size of the inset distance field |
411 scaledBounds.fRight = scaledBounds.fLeft + | 401 scaledBounds.fRight = scaledBounds.fLeft + |
412 SkIntToScalar(devPathBounds.width() - 2*SK_DistanceFieldInset); | 402 SkIntToScalar(devPathBounds.width() - 2*SK_DistanceFieldInset); |
413 scaledBounds.fBottom = scaledBounds.fTop + | 403 scaledBounds.fBottom = scaledBounds.fTop + |
414 SkIntToScalar(devPathBounds.height() - 2*SK_DistanceFieldInset); | 404 SkIntToScalar(devPathBounds.height() - 2*SK_DistanceFieldInset); |
415 // shift the origin to the correct place relative to the distance field | 405 // shift the origin to the correct place relative to the distance field |
416 // need to also restore the fractional translation | 406 // need to also restore the fractional translation |
417 scaledBounds.offset(-SkIntToScalar(SK_DistanceFieldInset) - kAntiAliasPa d + dx, | 407 scaledBounds.offset(-SkIntToScalar(SK_DistanceFieldInset) - kAntiAliasPa d + dx, |
418 -SkIntToScalar(SK_DistanceFieldInset) - kAntiAliasPa d + dy); | 408 -SkIntToScalar(SK_DistanceFieldInset) - kAntiAliasPa d + dy); |
419 pathData->fBounds = scaledBounds; | 409 shapeData->fBounds = scaledBounds; |
420 // origin we render from is inset from distance field edge | 410 // origin we render from is inset from distance field edge |
421 atlasLocation.fX += SK_DistanceFieldInset; | 411 atlasLocation.fX += SK_DistanceFieldInset; |
422 atlasLocation.fY += SK_DistanceFieldInset; | 412 atlasLocation.fY += SK_DistanceFieldInset; |
423 pathData->fAtlasLocation = atlasLocation; | 413 shapeData->fAtlasLocation = atlasLocation; |
424 | 414 |
425 fPathCache->add(pathData); | 415 fShapeCache->add(shapeData); |
426 fPathList->addToTail(pathData); | 416 fShapeList->addToTail(shapeData); |
427 #ifdef DF_PATH_TRACKING | 417 #ifdef DF_PATH_TRACKING |
428 ++g_NumCachedPaths; | 418 ++g_NumCachedPaths; |
429 #endif | 419 #endif |
430 return true; | 420 return true; |
431 } | 421 } |
432 | 422 |
433 void writePathVertices(GrDrawBatch::Target* target, | 423 void writePathVertices(GrDrawBatch::Target* target, |
434 GrBatchAtlas* atlas, | 424 GrBatchAtlas* atlas, |
435 intptr_t offset, | 425 intptr_t offset, |
436 GrColor color, | 426 GrColor color, |
437 size_t vertexStride, | 427 size_t vertexStride, |
438 const SkMatrix& viewMatrix, | 428 const SkMatrix& viewMatrix, |
439 const SkPath& path, | 429 const GrShape& shape, |
440 const PathData* pathData) const { | 430 const ShapeData* shapeData) const { |
441 GrTexture* texture = atlas->getTexture(); | 431 GrTexture* texture = atlas->getTexture(); |
442 | 432 |
443 SkScalar dx = pathData->fBounds.fLeft; | 433 SkScalar dx = shapeData->fBounds.fLeft; |
444 SkScalar dy = pathData->fBounds.fTop; | 434 SkScalar dy = shapeData->fBounds.fTop; |
445 SkScalar width = pathData->fBounds.width(); | 435 SkScalar width = shapeData->fBounds.width(); |
446 SkScalar height = pathData->fBounds.height(); | 436 SkScalar height = shapeData->fBounds.height(); |
447 | 437 |
448 SkScalar invScale = 1.0f / pathData->fScale; | 438 SkScalar invScale = 1.0f / shapeData->fScale; |
449 dx *= invScale; | 439 dx *= invScale; |
450 dy *= invScale; | 440 dy *= invScale; |
451 width *= invScale; | 441 width *= invScale; |
452 height *= invScale; | 442 height *= invScale; |
453 | 443 |
454 SkPoint* positions = reinterpret_cast<SkPoint*>(offset); | 444 SkPoint* positions = reinterpret_cast<SkPoint*>(offset); |
455 | 445 |
456 // vertex positions | 446 // vertex positions |
457 // TODO make the vertex attributes a struct | 447 // TODO make the vertex attributes a struct |
458 SkRect r = SkRect::MakeXYWH(dx, dy, width, height); | 448 SkRect r = SkRect::MakeXYWH(dx, dy, width, height); |
459 positions->setRectFan(r.left(), r.top(), r.right(), r.bottom(), vertexSt ride); | 449 positions->setRectFan(r.left(), r.top(), r.right(), r.bottom(), vertexSt ride); |
460 | 450 |
461 // colors | 451 // colors |
462 for (int i = 0; i < kVerticesPerQuad; i++) { | 452 for (int i = 0; i < kVerticesPerQuad; i++) { |
463 GrColor* colorPtr = (GrColor*)(offset + sizeof(SkPoint) + i * vertex Stride); | 453 GrColor* colorPtr = (GrColor*)(offset + sizeof(SkPoint) + i * vertex Stride); |
464 *colorPtr = color; | 454 *colorPtr = color; |
465 } | 455 } |
466 | 456 |
467 const SkScalar tx = SkIntToScalar(pathData->fAtlasLocation.fX); | 457 const SkScalar tx = SkIntToScalar(shapeData->fAtlasLocation.fX); |
468 const SkScalar ty = SkIntToScalar(pathData->fAtlasLocation.fY); | 458 const SkScalar ty = SkIntToScalar(shapeData->fAtlasLocation.fY); |
469 | 459 |
470 // vertex texture coords | 460 // vertex texture coords |
471 SkPoint* textureCoords = (SkPoint*)(offset + sizeof(SkPoint) + sizeof(Gr Color)); | 461 SkPoint* textureCoords = (SkPoint*)(offset + sizeof(SkPoint) + sizeof(Gr Color)); |
472 textureCoords->setRectFan(tx / texture->width(), | 462 textureCoords->setRectFan(tx / texture->width(), |
473 ty / texture->height(), | 463 ty / texture->height(), |
474 (tx + pathData->fBounds.width()) / texture->wi dth(), | 464 (tx + shapeData->fBounds.width()) / texture->w idth(), |
475 (ty + pathData->fBounds.height()) / texture-> height(), | 465 (ty + shapeData->fBounds.height()) / texture- >height(), |
476 vertexStride); | 466 vertexStride); |
477 } | 467 } |
478 | 468 |
479 void flush(GrVertexBatch::Target* target, FlushInfo* flushInfo) const { | 469 void flush(GrVertexBatch::Target* target, FlushInfo* flushInfo) const { |
480 GrMesh mesh; | 470 GrMesh mesh; |
481 int maxInstancesPerDraw = | 471 int maxInstancesPerDraw = |
482 static_cast<int>(flushInfo->fIndexBuffer->gpuMemorySize() / sizeof(u int16_t) / 6); | 472 static_cast<int>(flushInfo->fIndexBuffer->gpuMemorySize() / sizeof(u int16_t) / 6); |
483 mesh.initInstanced(kTriangles_GrPrimitiveType, flushInfo->fVertexBuffer, | 473 mesh.initInstanced(kTriangles_GrPrimitiveType, flushInfo->fVertexBuffer, |
484 flushInfo->fIndexBuffer, flushInfo->fVertexOffset, kVerticesPerQuad, | 474 flushInfo->fIndexBuffer, flushInfo->fVertexOffset, kVerticesPerQuad, |
485 kIndicesPerQuad, flushInfo->fInstancesToFlush, maxInstancesPerDraw); | 475 kIndicesPerQuad, flushInfo->fInstancesToFlush, maxInstancesPerDraw); |
(...skipping 11 matching lines...) Expand all Loading... | |
497 if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pi peline(), | 487 if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pi peline(), |
498 that->bounds(), caps)) { | 488 that->bounds(), caps)) { |
499 return false; | 489 return false; |
500 } | 490 } |
501 | 491 |
502 // TODO We can position on the cpu | 492 // TODO We can position on the cpu |
503 if (!this->viewMatrix().cheapEqualTo(that->viewMatrix())) { | 493 if (!this->viewMatrix().cheapEqualTo(that->viewMatrix())) { |
504 return false; | 494 return false; |
505 } | 495 } |
506 | 496 |
507 fGeoData.push_back_n(that->geoData()->count(), that->geoData()->begin()) ; | 497 fGeoData.push_back_n(that->fGeoData.count(), that->fGeoData.begin()); |
508 this->joinBounds(that->bounds()); | 498 this->joinBounds(that->bounds()); |
509 return true; | 499 return true; |
510 } | 500 } |
511 | 501 |
512 struct BatchTracker { | 502 struct BatchTracker { |
513 SkMatrix fViewMatrix; | 503 SkMatrix fViewMatrix; |
514 bool fUsesLocalCoords; | 504 bool fUsesLocalCoords; |
515 bool fColorIgnored; | 505 bool fColorIgnored; |
516 bool fCoverageIgnored; | 506 bool fCoverageIgnored; |
517 }; | 507 }; |
518 | 508 |
519 BatchTracker fBatch; | 509 BatchTracker fBatch; |
520 SkSTArray<1, Geometry, true> fGeoData; | 510 SkSTArray<1, Geometry> fGeoData; |
521 GrBatchAtlas* fAtlas; | 511 GrBatchAtlas* fAtlas; |
522 PathCache* fPathCache; | 512 ShapeCache* fShapeCache; |
523 PathDataList* fPathList; | 513 ShapeDataList* fShapeList; |
524 bool fGammaCorrect; | 514 bool fGammaCorrect; |
525 | 515 |
526 typedef GrVertexBatch INHERITED; | 516 typedef GrVertexBatch INHERITED; |
527 }; | 517 }; |
528 | 518 |
529 bool GrAADistanceFieldPathRenderer::onDrawPath(const DrawPathArgs& args) { | 519 bool GrAADistanceFieldPathRenderer::onDrawPath(const DrawPathArgs& args) { |
530 GR_AUDIT_TRAIL_AUTO_FRAME(args.fDrawContext->auditTrail(), | 520 GR_AUDIT_TRAIL_AUTO_FRAME(args.fDrawContext->auditTrail(), |
531 "GrAADistanceFieldPathRenderer::onDrawPath"); | 521 "GrAADistanceFieldPathRenderer::onDrawPath"); |
532 SkASSERT(!args.fDrawContext->isUnifiedMultisampled()); | 522 SkASSERT(!args.fDrawContext->isUnifiedMultisampled()); |
533 | 523 |
534 // we've already bailed on inverse filled paths, so this is safe | 524 // we've already bailed on inverse filled paths, so this is safe |
535 SkASSERT(!args.fShape->isEmpty()); | 525 SkASSERT(!args.fShape->isEmpty()); |
536 | 526 SkASSERT(args.fShape->hasUnstyledKey()); |
537 if (!fAtlas) { | 527 if (!fAtlas) { |
538 fAtlas = args.fResourceProvider->createAtlas(kAlpha_8_GrPixelConfig, | 528 fAtlas = args.fResourceProvider->createAtlas(kAlpha_8_GrPixelConfig, |
539 ATLAS_TEXTURE_WIDTH, ATLAS_ TEXTURE_HEIGHT, | 529 ATLAS_TEXTURE_WIDTH, ATLAS_ TEXTURE_HEIGHT, |
540 NUM_PLOTS_X, NUM_PLOTS_Y, | 530 NUM_PLOTS_X, NUM_PLOTS_Y, |
541 &GrAADistanceFieldPathRende rer::HandleEviction, | 531 &GrAADistanceFieldPathRende rer::HandleEviction, |
542 (void*)this); | 532 (void*)this); |
543 if (!fAtlas) { | 533 if (!fAtlas) { |
544 return false; | 534 return false; |
545 } | 535 } |
546 } | 536 } |
547 | 537 |
548 const GrStyle& style = args.fShape->style(); | 538 AADistanceFieldPathBatch::Geometry geometry; |
549 // It's ok to ignore style's path effect because canDrawPath filtered out pa th effects. | 539 geometry.fShape = *args.fShape; |
550 AADistanceFieldPathBatch::Geometry geometry(style.strokeRec()); | |
551 args.fShape->asPath(&geometry.fPath); | |
552 // Note: this is the generation ID of the _original_ path. When a new path i s | |
553 // generated due to stroking it is important that the original path's id is used | |
554 // for caching. | |
555 geometry.fGenID = geometry.fPath.getGenerationID(); | |
556 if (!style.isSimpleFill()) { | |
557 style.strokeRec().applyToPath(&geometry.fPath, geometry.fPath); | |
558 } | |
559 geometry.fColor = args.fColor; | 540 geometry.fColor = args.fColor; |
560 geometry.fAntiAlias = args.fAntiAlias; | 541 geometry.fAntiAlias = args.fAntiAlias; |
561 | 542 |
562 SkAutoTUnref<GrDrawBatch> batch(AADistanceFieldPathBatch::Create(geometry, | 543 SkAutoTUnref<GrDrawBatch> batch(AADistanceFieldPathBatch::Create(geometry, |
563 *args.fView Matrix, fAtlas, | 544 *args.fView Matrix, fAtlas, |
564 &fPathCache , &fPathList, | 545 &fShapeCach e, &fShapeList, |
565 args.fGamma Correct)); | 546 args.fGamma Correct)); |
566 | 547 |
567 GrPipelineBuilder pipelineBuilder(*args.fPaint); | 548 GrPipelineBuilder pipelineBuilder(*args.fPaint); |
568 pipelineBuilder.setUserStencil(args.fUserStencilSettings); | 549 pipelineBuilder.setUserStencil(args.fUserStencilSettings); |
569 | 550 |
570 args.fDrawContext->drawBatch(pipelineBuilder, *args.fClip, batch); | 551 args.fDrawContext->drawBatch(pipelineBuilder, *args.fClip, batch); |
571 | 552 |
572 return true; | 553 return true; |
573 } | 554 } |
574 | 555 |
575 //////////////////////////////////////////////////////////////////////////////// /////////////////// | 556 //////////////////////////////////////////////////////////////////////////////// /////////////////// |
576 | 557 |
577 #ifdef GR_TEST_UTILS | 558 #ifdef GR_TEST_UTILS |
578 | 559 |
579 struct PathTestStruct { | 560 struct PathTestStruct { |
580 typedef GrAADistanceFieldPathRenderer::PathCache PathCache; | 561 typedef GrAADistanceFieldPathRenderer::ShapeCache ShapeCache; |
581 typedef GrAADistanceFieldPathRenderer::PathData PathData; | 562 typedef GrAADistanceFieldPathRenderer::ShapeData ShapeData; |
582 typedef GrAADistanceFieldPathRenderer::PathDataList PathDataList; | 563 typedef GrAADistanceFieldPathRenderer::ShapeDataList ShapeDataList; |
583 PathTestStruct() : fContextID(SK_InvalidGenID), fAtlas(nullptr) {} | 564 PathTestStruct() : fContextID(SK_InvalidGenID), fAtlas(nullptr) {} |
584 ~PathTestStruct() { this->reset(); } | 565 ~PathTestStruct() { this->reset(); } |
585 | 566 |
586 void reset() { | 567 void reset() { |
587 PathDataList::Iter iter; | 568 ShapeDataList::Iter iter; |
588 iter.init(fPathList, PathDataList::Iter::kHead_IterStart); | 569 iter.init(fShapeList, ShapeDataList::Iter::kHead_IterStart); |
589 PathData* pathData; | 570 ShapeData* shapeData; |
590 while ((pathData = iter.get())) { | 571 while ((shapeData = iter.get())) { |
591 iter.next(); | 572 iter.next(); |
592 fPathList.remove(pathData); | 573 fShapeList.remove(shapeData); |
593 delete pathData; | 574 delete shapeData; |
594 } | 575 } |
595 delete fAtlas; | 576 delete fAtlas; |
596 fPathCache.reset(); | 577 fShapeCache.reset(); |
597 } | 578 } |
598 | 579 |
599 static void HandleEviction(GrBatchAtlas::AtlasID id, void* pr) { | 580 static void HandleEviction(GrBatchAtlas::AtlasID id, void* pr) { |
600 PathTestStruct* dfpr = (PathTestStruct*)pr; | 581 PathTestStruct* dfpr = (PathTestStruct*)pr; |
601 // remove any paths that use this plot | 582 // remove any paths that use this plot |
602 PathDataList::Iter iter; | 583 ShapeDataList::Iter iter; |
603 iter.init(dfpr->fPathList, PathDataList::Iter::kHead_IterStart); | 584 iter.init(dfpr->fShapeList, ShapeDataList::Iter::kHead_IterStart); |
604 PathData* pathData; | 585 ShapeData* shapeData; |
605 while ((pathData = iter.get())) { | 586 while ((shapeData = iter.get())) { |
606 iter.next(); | 587 iter.next(); |
607 if (id == pathData->fID) { | 588 if (id == shapeData->fID) { |
608 dfpr->fPathCache.remove(pathData->fKey); | 589 dfpr->fShapeCache.remove(shapeData->fKey); |
609 dfpr->fPathList.remove(pathData); | 590 dfpr->fShapeList.remove(shapeData); |
610 delete pathData; | 591 delete shapeData; |
611 } | 592 } |
612 } | 593 } |
613 } | 594 } |
614 | 595 |
615 uint32_t fContextID; | 596 uint32_t fContextID; |
616 GrBatchAtlas* fAtlas; | 597 GrBatchAtlas* fAtlas; |
617 PathCache fPathCache; | 598 ShapeCache fShapeCache; |
618 PathDataList fPathList; | 599 ShapeDataList fShapeList; |
619 }; | 600 }; |
620 | 601 |
621 DRAW_BATCH_TEST_DEFINE(AADistanceFieldPathBatch) { | 602 DRAW_BATCH_TEST_DEFINE(AADistanceFieldPathBatch) { |
622 static PathTestStruct gTestStruct; | 603 static PathTestStruct gTestStruct; |
623 | 604 |
624 if (context->uniqueID() != gTestStruct.fContextID) { | 605 if (context->uniqueID() != gTestStruct.fContextID) { |
625 gTestStruct.fContextID = context->uniqueID(); | 606 gTestStruct.fContextID = context->uniqueID(); |
626 gTestStruct.reset(); | 607 gTestStruct.reset(); |
627 gTestStruct.fAtlas = | 608 gTestStruct.fAtlas = |
628 context->resourceProvider()->createAtlas(kAlpha_8_GrPixelConfig, | 609 context->resourceProvider()->createAtlas(kAlpha_8_GrPixelConfig, |
629 ATLAS_TEXTURE_WIDTH, ATLAS_ TEXTURE_HEIGHT, | 610 ATLAS_TEXTURE_WIDTH, ATLAS_ TEXTURE_HEIGHT, |
630 NUM_PLOTS_X, NUM_PLOTS_Y, | 611 NUM_PLOTS_X, NUM_PLOTS_Y, |
631 &PathTestStruct::HandleEvic tion, | 612 &PathTestStruct::HandleEvic tion, |
632 (void*)&gTestStruct); | 613 (void*)&gTestStruct); |
633 } | 614 } |
634 | 615 |
635 SkMatrix viewMatrix = GrTest::TestMatrix(random); | 616 SkMatrix viewMatrix = GrTest::TestMatrix(random); |
636 GrColor color = GrRandomColor(random); | 617 GrColor color = GrRandomColor(random); |
637 bool gammaCorrect = random->nextBool(); | 618 bool gammaCorrect = random->nextBool(); |
638 | 619 |
639 AADistanceFieldPathBatch::Geometry geometry(GrTest::TestStrokeRec(random)); | 620 AADistanceFieldPathBatch::Geometry geometry; |
621 SkStrokeRec strokeRec = GrTest::TestStrokeRec(random); | |
622 GrShape shape(GrTest::TestPath(random), GrStyle(strokeRec, nullptr)); | |
623 geometry.fShape = shape; | |
640 geometry.fColor = color; | 624 geometry.fColor = color; |
641 geometry.fPath = GrTest::TestPath(random); | |
642 geometry.fAntiAlias = random->nextBool(); | 625 geometry.fAntiAlias = random->nextBool(); |
643 geometry.fGenID = random->nextU(); | |
644 | 626 |
645 return AADistanceFieldPathBatch::Create(geometry, viewMatrix, | 627 return AADistanceFieldPathBatch::Create(geometry, viewMatrix, |
646 gTestStruct.fAtlas, | 628 gTestStruct.fAtlas, |
647 &gTestStruct.fPathCache, | 629 &gTestStruct.fShapeCache, |
648 &gTestStruct.fPathList, | 630 &gTestStruct.fShapeList, |
649 gammaCorrect); | 631 gammaCorrect); |
650 } | 632 } |
651 | 633 |
652 #endif | 634 #endif |
OLD | NEW |