OLD | NEW |
1 | 1 |
2 /* | 2 /* |
3 * Copyright 2014 Google Inc. | 3 * Copyright 2014 Google Inc. |
4 * | 4 * |
5 * Use of this source code is governed by a BSD-style license that can be | 5 * Use of this source code is governed by a BSD-style license that can be |
6 * found in the LICENSE file. | 6 * found in the LICENSE file. |
7 */ | 7 */ |
8 | 8 |
9 #include "GrAADistanceFieldPathRenderer.h" | 9 #include "GrAADistanceFieldPathRenderer.h" |
10 | 10 |
(...skipping 20 matching lines...) Expand all Loading... |
31 #define NUM_PLOTS_X (ATLAS_TEXTURE_WIDTH / PLOT_WIDTH) | 31 #define NUM_PLOTS_X (ATLAS_TEXTURE_WIDTH / PLOT_WIDTH) |
32 #define NUM_PLOTS_Y (ATLAS_TEXTURE_HEIGHT / PLOT_HEIGHT) | 32 #define NUM_PLOTS_Y (ATLAS_TEXTURE_HEIGHT / PLOT_HEIGHT) |
33 | 33 |
34 #ifdef DF_PATH_TRACKING | 34 #ifdef DF_PATH_TRACKING |
35 static int g_NumCachedPaths = 0; | 35 static int g_NumCachedPaths = 0; |
36 static int g_NumFreedPaths = 0; | 36 static int g_NumFreedPaths = 0; |
37 #endif | 37 #endif |
38 | 38 |
39 // mip levels | 39 // mip levels |
40 static const int kSmallMIP = 32; | 40 static const int kSmallMIP = 32; |
41 static const int kMediumMIP = 73; | 41 static const int kMediumMIP = 72; |
42 static const int kLargeMIP = 162; | 42 static const int kLargeMIP = 162; |
43 | 43 |
44 // Callback to clear out internal path cache when eviction occurs | 44 // Callback to clear out internal path cache when eviction occurs |
45 void GrAADistanceFieldPathRenderer::HandleEviction(GrBatchAtlas::AtlasID id, voi
d* pr) { | 45 void GrAADistanceFieldPathRenderer::HandleEviction(GrBatchAtlas::AtlasID id, voi
d* pr) { |
46 GrAADistanceFieldPathRenderer* dfpr = (GrAADistanceFieldPathRenderer*)pr; | 46 GrAADistanceFieldPathRenderer* dfpr = (GrAADistanceFieldPathRenderer*)pr; |
47 // remove any paths that use this plot | 47 // remove any paths that use this plot |
48 PathDataList::Iter iter; | 48 PathDataList::Iter iter; |
49 iter.init(dfpr->fPathList, PathDataList::Iter::kHead_IterStart); | 49 iter.init(dfpr->fPathList, PathDataList::Iter::kHead_IterStart); |
50 PathData* pathData; | 50 PathData* pathData; |
51 while ((pathData = iter.get())) { | 51 while ((pathData = iter.get())) { |
(...skipping 25 matching lines...) Expand all Loading... |
77 | 77 |
78 #ifdef DF_PATH_TRACKING | 78 #ifdef DF_PATH_TRACKING |
79 SkDebugf("Cached paths: %d, freed paths: %d\n", g_NumCachedPaths, g_NumFreed
Paths); | 79 SkDebugf("Cached paths: %d, freed paths: %d\n", g_NumCachedPaths, g_NumFreed
Paths); |
80 #endif | 80 #endif |
81 } | 81 } |
82 | 82 |
83 //////////////////////////////////////////////////////////////////////////////// | 83 //////////////////////////////////////////////////////////////////////////////// |
84 bool GrAADistanceFieldPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) c
onst { | 84 bool GrAADistanceFieldPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) c
onst { |
85 | 85 |
86 // TODO: Support inverse fill | 86 // TODO: Support inverse fill |
| 87 // TODO: Support strokes |
87 if (!args.fShaderCaps->shaderDerivativeSupport() || !args.fAntiAlias || | 88 if (!args.fShaderCaps->shaderDerivativeSupport() || !args.fAntiAlias || |
88 SkStrokeRec::kHairline_Style == args.fStroke->getStyle() || | 89 args.fPath->isInverseFillType() || args.fPath->isVolatile() || |
89 args.fPath->isInverseFillType() || args.fPath->isVolatile()) { | 90 !args.fStroke->isFillStyle()) { |
90 return false; | 91 return false; |
91 } | 92 } |
92 | 93 |
93 // currently don't support perspective | 94 // currently don't support perspective |
94 if (args.fViewMatrix->hasPerspective()) { | 95 if (args.fViewMatrix->hasPerspective()) { |
95 return false; | 96 return false; |
96 } | 97 } |
97 | 98 |
98 // only support paths with bounds within kMediumMIP by kMediumMIP, | 99 // only support paths smaller than 64x64, scaled to less than 256x256 |
99 // scaled to have bounds within 2.0f*kLargeMIP by 2.0f*kLargeMIP | |
100 // the goal is to accelerate rendering of lots of small paths that may be sc
aling | 100 // the goal is to accelerate rendering of lots of small paths that may be sc
aling |
101 SkScalar maxScale = args.fViewMatrix->getMaxScale(); | 101 SkScalar maxScale = args.fViewMatrix->getMaxScale(); |
102 const SkRect& bounds = args.fPath->getBounds(); | 102 const SkRect& bounds = args.fPath->getBounds(); |
103 SkScalar maxDim = SkMaxScalar(bounds.width(), bounds.height()); | 103 SkScalar maxDim = SkMaxScalar(bounds.width(), bounds.height()); |
104 // Approximate stroked size by adding the maximum of the stroke width or 2x
the miter limit | 104 return maxDim < 64.f && maxDim * maxScale < 256.f; |
105 if (!args.fStroke->isFillStyle()) { | |
106 SkScalar extraWidth = args.fStroke->getWidth(); | |
107 if (SkPaint::kMiter_Join == args.fStroke->getJoin()) { | |
108 extraWidth = SkTMax(extraWidth, 2.0f*args.fStroke->getMiter()); | |
109 } | |
110 maxDim += extraWidth; | |
111 } | |
112 | |
113 return maxDim <= kMediumMIP && maxDim * maxScale <= 2.0f*kLargeMIP; | |
114 } | 105 } |
115 | 106 |
116 //////////////////////////////////////////////////////////////////////////////// | 107 //////////////////////////////////////////////////////////////////////////////// |
117 | 108 |
118 // padding around path bounds to allow for antialiased pixels | 109 // padding around path bounds to allow for antialiased pixels |
119 static const SkScalar kAntiAliasPad = 1.0f; | 110 static const SkScalar kAntiAliasPad = 1.0f; |
120 | 111 |
121 class AADistanceFieldPathBatch : public GrVertexBatch { | 112 class AADistanceFieldPathBatch : public GrVertexBatch { |
122 public: | 113 public: |
123 DEFINE_BATCH_CLASS_ID | 114 DEFINE_BATCH_CLASS_ID |
124 | 115 |
125 typedef GrAADistanceFieldPathRenderer::PathData PathData; | 116 typedef GrAADistanceFieldPathRenderer::PathData PathData; |
126 typedef SkTDynamicHash<PathData, PathData::Key> PathCache; | 117 typedef SkTDynamicHash<PathData, PathData::Key> PathCache; |
127 typedef GrAADistanceFieldPathRenderer::PathDataList PathDataList; | 118 typedef GrAADistanceFieldPathRenderer::PathDataList PathDataList; |
128 | 119 |
129 struct Geometry { | 120 struct Geometry { |
130 Geometry(const SkStrokeRec& stroke) : fStroke(stroke) {} | 121 Geometry(const SkStrokeRec& stroke) : fStroke(stroke) {} |
131 SkPath fPath; | 122 SkPath fPath; |
132 // The unique ID of the path involved in this draw. This may be differen
t than the ID | |
133 // in fPath since that path may have resulted from a SkStrokeRec::applyT
oPath call. | |
134 uint32_t fGenID; | |
135 SkStrokeRec fStroke; | 123 SkStrokeRec fStroke; |
136 bool fAntiAlias; | 124 bool fAntiAlias; |
137 PathData* fPathData; | 125 PathData* fPathData; |
138 }; | 126 }; |
139 | 127 |
140 static GrDrawBatch* Create(const Geometry& geometry, GrColor color, const Sk
Matrix& viewMatrix, | 128 static GrDrawBatch* Create(const Geometry& geometry, GrColor color, const Sk
Matrix& viewMatrix, |
141 GrBatchAtlas* atlas, PathCache* pathCache, PathDa
taList* pathList) { | 129 GrBatchAtlas* atlas, PathCache* pathCache, PathDa
taList* pathList) { |
142 return new AADistanceFieldPathBatch(geometry, color, viewMatrix, atlas,
pathCache, | 130 return new AADistanceFieldPathBatch(geometry, color, viewMatrix, atlas,
pathCache, |
143 pathList); | 131 pathList); |
144 } | 132 } |
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
230 uint32_t desiredDimension; | 218 uint32_t desiredDimension; |
231 if (size <= kSmallMIP) { | 219 if (size <= kSmallMIP) { |
232 desiredDimension = kSmallMIP; | 220 desiredDimension = kSmallMIP; |
233 } else if (size <= kMediumMIP) { | 221 } else if (size <= kMediumMIP) { |
234 desiredDimension = kMediumMIP; | 222 desiredDimension = kMediumMIP; |
235 } else { | 223 } else { |
236 desiredDimension = kLargeMIP; | 224 desiredDimension = kLargeMIP; |
237 } | 225 } |
238 | 226 |
239 // check to see if path is cached | 227 // check to see if path is cached |
240 PathData::Key key(args.fGenID, desiredDimension, args.fStroke); | 228 // TODO: handle stroked vs. filled version of same path |
| 229 PathData::Key key = { args.fPath.getGenerationID(), desiredDimension
}; |
241 args.fPathData = fPathCache->find(key); | 230 args.fPathData = fPathCache->find(key); |
242 if (nullptr == args.fPathData || !atlas->hasID(args.fPathData->fID))
{ | 231 if (nullptr == args.fPathData || !atlas->hasID(args.fPathData->fID))
{ |
243 // Remove the stale cache entry | 232 // Remove the stale cache entry |
244 if (args.fPathData) { | 233 if (args.fPathData) { |
245 fPathCache->remove(args.fPathData->fKey); | 234 fPathCache->remove(args.fPathData->fKey); |
246 fPathList->remove(args.fPathData); | 235 fPathList->remove(args.fPathData); |
247 delete args.fPathData; | 236 delete args.fPathData; |
248 } | 237 } |
249 SkScalar scale = desiredDimension/maxDim; | 238 SkScalar scale = desiredDimension/maxDim; |
250 args.fPathData = new PathData; | 239 args.fPathData = new PathData; |
251 if (!this->addPathToAtlas(target, | 240 if (!this->addPathToAtlas(target, |
252 dfProcessor, | 241 dfProcessor, |
253 this->pipeline(), | 242 this->pipeline(), |
254 &flushInfo, | 243 &flushInfo, |
255 atlas, | 244 atlas, |
256 args.fPathData, | 245 args.fPathData, |
257 args.fPath, | 246 args.fPath, |
258 args.fGenID, | |
259 args.fStroke, | 247 args.fStroke, |
260 args.fAntiAlias, | 248 args.fAntiAlias, |
261 desiredDimension, | 249 desiredDimension, |
262 scale)) { | 250 scale)) { |
263 SkDebugf("Can't rasterize path\n"); | 251 SkDebugf("Can't rasterize path\n"); |
264 return; | 252 return; |
265 } | 253 } |
266 } | 254 } |
267 | 255 |
268 atlas->setLastUseToken(args.fPathData->fID, target->currentToken()); | 256 atlas->setLastUseToken(args.fPathData->fID, target->currentToken()); |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
306 viewMatrix.mapRect(&fBounds); | 294 viewMatrix.mapRect(&fBounds); |
307 } | 295 } |
308 | 296 |
309 bool addPathToAtlas(GrVertexBatch::Target* target, | 297 bool addPathToAtlas(GrVertexBatch::Target* target, |
310 const GrGeometryProcessor* dfProcessor, | 298 const GrGeometryProcessor* dfProcessor, |
311 const GrPipeline* pipeline, | 299 const GrPipeline* pipeline, |
312 FlushInfo* flushInfo, | 300 FlushInfo* flushInfo, |
313 GrBatchAtlas* atlas, | 301 GrBatchAtlas* atlas, |
314 PathData* pathData, | 302 PathData* pathData, |
315 const SkPath& path, | 303 const SkPath& path, |
316 uint32_t genID, | 304 const SkStrokeRec& |
317 const SkStrokeRec& stroke, | 305 stroke, bool antiAlias, |
318 bool antiAlias, | |
319 uint32_t dimension, | 306 uint32_t dimension, |
320 SkScalar scale) { | 307 SkScalar scale) { |
321 const SkRect& bounds = path.getBounds(); | 308 const SkRect& bounds = path.getBounds(); |
322 | 309 |
323 // generate bounding rect for bitmap draw | 310 // generate bounding rect for bitmap draw |
324 SkRect scaledBounds = bounds; | 311 SkRect scaledBounds = bounds; |
325 // scale to mip level size | 312 // scale to mip level size |
326 scaledBounds.fLeft *= scale; | 313 scaledBounds.fLeft *= scale; |
327 scaledBounds.fTop *= scale; | 314 scaledBounds.fTop *= scale; |
328 scaledBounds.fRight *= scale; | 315 scaledBounds.fRight *= scale; |
(...skipping 10 matching lines...) Expand all Loading... |
339 // move origin to upper left corner | 326 // move origin to upper left corner |
340 devPathBounds.offsetTo(0,0); | 327 devPathBounds.offsetTo(0,0); |
341 | 328 |
342 // draw path to bitmap | 329 // draw path to bitmap |
343 SkMatrix drawMatrix; | 330 SkMatrix drawMatrix; |
344 drawMatrix.setTranslate(-bounds.left(), -bounds.top()); | 331 drawMatrix.setTranslate(-bounds.left(), -bounds.top()); |
345 drawMatrix.postScale(scale, scale); | 332 drawMatrix.postScale(scale, scale); |
346 drawMatrix.postTranslate(kAntiAliasPad, kAntiAliasPad); | 333 drawMatrix.postTranslate(kAntiAliasPad, kAntiAliasPad); |
347 | 334 |
348 // setup bitmap backing | 335 // setup bitmap backing |
349 SkASSERT(devPathBounds.fLeft == 0); | 336 // Now translate so the bound's UL corner is at the origin |
350 SkASSERT(devPathBounds.fTop == 0); | 337 drawMatrix.postTranslate(-devPathBounds.fLeft * SK_Scalar1, |
| 338 -devPathBounds.fTop * SK_Scalar1); |
| 339 SkIRect pathBounds = SkIRect::MakeWH(devPathBounds.width(), |
| 340 devPathBounds.height()); |
| 341 |
351 SkAutoPixmapStorage dst; | 342 SkAutoPixmapStorage dst; |
352 if (!dst.tryAlloc(SkImageInfo::MakeA8(devPathBounds.width(), | 343 if (!dst.tryAlloc(SkImageInfo::MakeA8(pathBounds.width(), |
353 devPathBounds.height()))) { | 344 pathBounds.height()))) { |
354 return false; | 345 return false; |
355 } | 346 } |
356 sk_bzero(dst.writable_addr(), dst.getSafeSize()); | 347 sk_bzero(dst.writable_addr(), dst.getSafeSize()); |
357 | 348 |
358 // rasterize path | 349 // rasterize path |
359 SkPaint paint; | 350 SkPaint paint; |
360 paint.setStyle(SkPaint::kFill_Style); | 351 if (stroke.isHairlineStyle()) { |
| 352 paint.setStyle(SkPaint::kStroke_Style); |
| 353 paint.setStrokeWidth(SK_Scalar1); |
| 354 } else { |
| 355 if (stroke.isFillStyle()) { |
| 356 paint.setStyle(SkPaint::kFill_Style); |
| 357 } else { |
| 358 paint.setStyle(SkPaint::kStroke_Style); |
| 359 paint.setStrokeJoin(stroke.getJoin()); |
| 360 paint.setStrokeCap(stroke.getCap()); |
| 361 paint.setStrokeWidth(stroke.getWidth()); |
| 362 } |
| 363 } |
361 paint.setAntiAlias(antiAlias); | 364 paint.setAntiAlias(antiAlias); |
362 | 365 |
363 SkDraw draw; | 366 SkDraw draw; |
364 sk_bzero(&draw, sizeof(draw)); | 367 sk_bzero(&draw, sizeof(draw)); |
365 | 368 |
366 SkRasterClip rasterClip; | 369 SkRasterClip rasterClip; |
367 rasterClip.setRect(devPathBounds); | 370 rasterClip.setRect(pathBounds); |
368 draw.fRC = &rasterClip; | 371 draw.fRC = &rasterClip; |
369 draw.fClip = &rasterClip.bwRgn(); | 372 draw.fClip = &rasterClip.bwRgn(); |
370 draw.fMatrix = &drawMatrix; | 373 draw.fMatrix = &drawMatrix; |
371 draw.fDst = dst; | 374 draw.fDst = dst; |
372 | 375 |
373 draw.drawPathCoverage(path, paint); | 376 draw.drawPathCoverage(path, paint); |
374 | 377 |
375 // generate signed distance field | 378 // generate signed distance field |
376 devPathBounds.outset(SK_DistanceFieldPad, SK_DistanceFieldPad); | 379 devPathBounds.outset(SK_DistanceFieldPad, SK_DistanceFieldPad); |
377 int width = devPathBounds.width(); | 380 int width = devPathBounds.width(); |
(...skipping 15 matching lines...) Expand all Loading... |
393 this->flush(target, flushInfo); | 396 this->flush(target, flushInfo); |
394 target->initDraw(dfProcessor, pipeline); | 397 target->initDraw(dfProcessor, pipeline); |
395 | 398 |
396 SkDEBUGCODE(success =) atlas->addToAtlas(&id, target, width, height, | 399 SkDEBUGCODE(success =) atlas->addToAtlas(&id, target, width, height, |
397 dfStorage.get(), &atlasLoca
tion); | 400 dfStorage.get(), &atlasLoca
tion); |
398 SkASSERT(success); | 401 SkASSERT(success); |
399 | 402 |
400 } | 403 } |
401 | 404 |
402 // add to cache | 405 // add to cache |
403 pathData->fKey = PathData::Key(genID, dimension, stroke); | 406 pathData->fKey.fGenID = path.getGenerationID(); |
| 407 pathData->fKey.fDimension = dimension; |
404 pathData->fScale = scale; | 408 pathData->fScale = scale; |
405 pathData->fID = id; | 409 pathData->fID = id; |
406 // change the scaled rect to match the size of the inset distance field | 410 // change the scaled rect to match the size of the inset distance field |
407 scaledBounds.fRight = scaledBounds.fLeft + | 411 scaledBounds.fRight = scaledBounds.fLeft + |
408 SkIntToScalar(devPathBounds.width() - 2*SK_DistanceFieldInset); | 412 SkIntToScalar(devPathBounds.width() - 2*SK_DistanceFieldInset); |
409 scaledBounds.fBottom = scaledBounds.fTop + | 413 scaledBounds.fBottom = scaledBounds.fTop + |
410 SkIntToScalar(devPathBounds.height() - 2*SK_DistanceFieldInset); | 414 SkIntToScalar(devPathBounds.height() - 2*SK_DistanceFieldInset); |
411 // shift the origin to the correct place relative to the distance field | 415 // shift the origin to the correct place relative to the distance field |
412 // need to also restore the fractional translation | 416 // need to also restore the fractional translation |
413 scaledBounds.offset(-SkIntToScalar(SK_DistanceFieldInset) - kAntiAliasPa
d + dx, | 417 scaledBounds.offset(-SkIntToScalar(SK_DistanceFieldInset) - kAntiAliasPa
d + dx, |
(...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
532 ATLAS_TEXTURE_WIDTH, ATLAS_
TEXTURE_HEIGHT, | 536 ATLAS_TEXTURE_WIDTH, ATLAS_
TEXTURE_HEIGHT, |
533 NUM_PLOTS_X, NUM_PLOTS_Y, | 537 NUM_PLOTS_X, NUM_PLOTS_Y, |
534 &GrAADistanceFieldPathRende
rer::HandleEviction, | 538 &GrAADistanceFieldPathRende
rer::HandleEviction, |
535 (void*)this); | 539 (void*)this); |
536 if (!fAtlas) { | 540 if (!fAtlas) { |
537 return false; | 541 return false; |
538 } | 542 } |
539 } | 543 } |
540 | 544 |
541 AADistanceFieldPathBatch::Geometry geometry(*args.fStroke); | 545 AADistanceFieldPathBatch::Geometry geometry(*args.fStroke); |
542 if (SkStrokeRec::kFill_Style == args.fStroke->getStyle()) { | 546 geometry.fPath = *args.fPath; |
543 geometry.fPath = *args.fPath; | |
544 } else { | |
545 args.fStroke->applyToPath(&geometry.fPath, *args.fPath); | |
546 } | |
547 geometry.fAntiAlias = args.fAntiAlias; | 547 geometry.fAntiAlias = args.fAntiAlias; |
548 // Note: this is the generation ID of the _original_ path. When a new path i
s | 548 |
549 // generated due to stroking it is important that the original path's id is
used | |
550 // for caching. | |
551 geometry.fGenID = args.fPath->getGenerationID(); | |
552 | |
553 SkAutoTUnref<GrDrawBatch> batch(AADistanceFieldPathBatch::Create(geometry, a
rgs.fColor, | 549 SkAutoTUnref<GrDrawBatch> batch(AADistanceFieldPathBatch::Create(geometry, a
rgs.fColor, |
554 *args.fView
Matrix, fAtlas, | 550 *args.fView
Matrix, fAtlas, |
555 &fPathCache
, &fPathList)); | 551 &fPathCache
, &fPathList)); |
556 args.fTarget->drawBatch(*args.fPipelineBuilder, batch); | 552 args.fTarget->drawBatch(*args.fPipelineBuilder, batch); |
557 | 553 |
558 return true; | 554 return true; |
559 } | 555 } |
560 | 556 |
561 ////////////////////////////////////////////////////////////////////////////////
/////////////////// | 557 ////////////////////////////////////////////////////////////////////////////////
/////////////////// |
562 | 558 |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
625 geometry.fPath = GrTest::TestPath(random); | 621 geometry.fPath = GrTest::TestPath(random); |
626 geometry.fAntiAlias = random->nextBool(); | 622 geometry.fAntiAlias = random->nextBool(); |
627 | 623 |
628 return AADistanceFieldPathBatch::Create(geometry, color, viewMatrix, | 624 return AADistanceFieldPathBatch::Create(geometry, color, viewMatrix, |
629 gTestStruct.fAtlas, | 625 gTestStruct.fAtlas, |
630 &gTestStruct.fPathCache, | 626 &gTestStruct.fPathCache, |
631 &gTestStruct.fPathList); | 627 &gTestStruct.fPathList); |
632 } | 628 } |
633 | 629 |
634 #endif | 630 #endif |
OLD | NEW |