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 66 matching lines...) Expand 10 before | Expand all | Expand 10 after 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 | |
88 if (!args.fShaderCaps->shaderDerivativeSupport() || !args.fAntiAlias || | 87 if (!args.fShaderCaps->shaderDerivativeSupport() || !args.fAntiAlias || |
89 args.fPath->isInverseFillType() || args.fPath->isVolatile() || | 88 SkStrokeRec::kHairline_Style == args.fStroke->getStyle() || |
90 !args.fStroke->isFillStyle()) { | 89 args.fPath->isInverseFillType() || args.fPath->isVolatile()) { |
91 return false; | 90 return false; |
92 } | 91 } |
93 | 92 |
94 // currently don't support perspective | 93 // currently don't support perspective |
95 if (args.fViewMatrix->hasPerspective()) { | 94 if (args.fViewMatrix->hasPerspective()) { |
96 return false; | 95 return false; |
97 } | 96 } |
98 | 97 |
99 // only support paths smaller than 64x64, scaled to less than 256x256 | 98 // only support paths smaller than kMediumMIP by kMediumMIP, |
99 // scaled to less than 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()); |
robertphillips
2015/11/19 19:03:28
// Outset by half the stroke width when stroking
?
jvanverth1
2015/11/19 20:33:23
Done.
| |
104 return maxDim < 64.f && maxDim * maxScale < 256.f; | 104 if (SkStrokeRec::kStroke_Style == args.fStroke->getStyle() || |
105 SkStrokeRec::kStrokeAndFill_Style == args.fStroke->getStyle()) { | |
106 maxDim += args.fStroke->getWidth()*0.5f; | |
107 } | |
108 | |
109 return maxDim < kMediumMIP && maxDim * maxScale < 2.0f*kLargeMIP; | |
105 } | 110 } |
106 | 111 |
107 //////////////////////////////////////////////////////////////////////////////// | 112 //////////////////////////////////////////////////////////////////////////////// |
108 | 113 |
109 // padding around path bounds to allow for antialiased pixels | 114 // padding around path bounds to allow for antialiased pixels |
110 static const SkScalar kAntiAliasPad = 1.0f; | 115 static const SkScalar kAntiAliasPad = 1.0f; |
111 | 116 |
112 class AADistanceFieldPathBatch : public GrVertexBatch { | 117 class AADistanceFieldPathBatch : public GrVertexBatch { |
113 public: | 118 public: |
114 DEFINE_BATCH_CLASS_ID | 119 DEFINE_BATCH_CLASS_ID |
115 | 120 |
116 typedef GrAADistanceFieldPathRenderer::PathData PathData; | 121 typedef GrAADistanceFieldPathRenderer::PathData PathData; |
117 typedef SkTDynamicHash<PathData, PathData::Key> PathCache; | 122 typedef SkTDynamicHash<PathData, PathData::Key> PathCache; |
118 typedef GrAADistanceFieldPathRenderer::PathDataList PathDataList; | 123 typedef GrAADistanceFieldPathRenderer::PathDataList PathDataList; |
119 | 124 |
120 struct Geometry { | 125 struct Geometry { |
121 Geometry(const SkStrokeRec& stroke) : fStroke(stroke) {} | 126 Geometry(const SkStrokeRec& stroke) : fStroke(stroke) {} |
122 SkPath fPath; | 127 SkPath fPath; |
robertphillips
2015/11/19 19:03:28
// The unique ID of the path involved in this draw
jvanverth1
2015/11/19 20:33:23
Done.
| |
128 uint32_t fGenID; | |
123 SkStrokeRec fStroke; | 129 SkStrokeRec fStroke; |
124 bool fAntiAlias; | 130 bool fAntiAlias; |
125 PathData* fPathData; | 131 PathData* fPathData; |
126 }; | 132 }; |
127 | 133 |
128 static GrDrawBatch* Create(const Geometry& geometry, GrColor color, const Sk Matrix& viewMatrix, | 134 static GrDrawBatch* Create(const Geometry& geometry, GrColor color, const Sk Matrix& viewMatrix, |
129 GrBatchAtlas* atlas, PathCache* pathCache, PathDa taList* pathList) { | 135 GrBatchAtlas* atlas, PathCache* pathCache, PathDa taList* pathList) { |
130 return new AADistanceFieldPathBatch(geometry, color, viewMatrix, atlas, pathCache, | 136 return new AADistanceFieldPathBatch(geometry, color, viewMatrix, atlas, pathCache, |
131 pathList); | 137 pathList); |
132 } | 138 } |
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
218 uint32_t desiredDimension; | 224 uint32_t desiredDimension; |
219 if (size <= kSmallMIP) { | 225 if (size <= kSmallMIP) { |
220 desiredDimension = kSmallMIP; | 226 desiredDimension = kSmallMIP; |
221 } else if (size <= kMediumMIP) { | 227 } else if (size <= kMediumMIP) { |
222 desiredDimension = kMediumMIP; | 228 desiredDimension = kMediumMIP; |
223 } else { | 229 } else { |
224 desiredDimension = kLargeMIP; | 230 desiredDimension = kLargeMIP; |
225 } | 231 } |
226 | 232 |
227 // check to see if path is cached | 233 // check to see if path is cached |
228 // TODO: handle stroked vs. filled version of same path | 234 PathData::Key key(args.fGenID, desiredDimension, args.fStroke); |
229 PathData::Key key = { args.fPath.getGenerationID(), desiredDimension }; | |
230 args.fPathData = fPathCache->find(key); | 235 args.fPathData = fPathCache->find(key); |
231 if (nullptr == args.fPathData || !atlas->hasID(args.fPathData->fID)) { | 236 if (nullptr == args.fPathData || !atlas->hasID(args.fPathData->fID)) { |
232 // Remove the stale cache entry | 237 // Remove the stale cache entry |
233 if (args.fPathData) { | 238 if (args.fPathData) { |
234 fPathCache->remove(args.fPathData->fKey); | 239 fPathCache->remove(args.fPathData->fKey); |
235 fPathList->remove(args.fPathData); | 240 fPathList->remove(args.fPathData); |
236 delete args.fPathData; | 241 delete args.fPathData; |
237 } | 242 } |
238 SkScalar scale = desiredDimension/maxDim; | 243 SkScalar scale = desiredDimension/maxDim; |
239 args.fPathData = new PathData; | 244 args.fPathData = new PathData; |
240 if (!this->addPathToAtlas(target, | 245 if (!this->addPathToAtlas(target, |
241 dfProcessor, | 246 dfProcessor, |
242 this->pipeline(), | 247 this->pipeline(), |
243 &flushInfo, | 248 &flushInfo, |
244 atlas, | 249 atlas, |
245 args.fPathData, | 250 args.fPathData, |
246 args.fPath, | 251 args.fPath, |
252 args.fGenID, | |
247 args.fStroke, | 253 args.fStroke, |
248 args.fAntiAlias, | 254 args.fAntiAlias, |
249 desiredDimension, | 255 desiredDimension, |
250 scale)) { | 256 scale)) { |
251 SkDebugf("Can't rasterize path\n"); | 257 SkDebugf("Can't rasterize path\n"); |
252 return; | 258 return; |
253 } | 259 } |
254 } | 260 } |
255 | 261 |
256 atlas->setLastUseToken(args.fPathData->fID, target->currentToken()); | 262 atlas->setLastUseToken(args.fPathData->fID, target->currentToken()); |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
294 viewMatrix.mapRect(&fBounds); | 300 viewMatrix.mapRect(&fBounds); |
295 } | 301 } |
296 | 302 |
297 bool addPathToAtlas(GrVertexBatch::Target* target, | 303 bool addPathToAtlas(GrVertexBatch::Target* target, |
298 const GrGeometryProcessor* dfProcessor, | 304 const GrGeometryProcessor* dfProcessor, |
299 const GrPipeline* pipeline, | 305 const GrPipeline* pipeline, |
300 FlushInfo* flushInfo, | 306 FlushInfo* flushInfo, |
301 GrBatchAtlas* atlas, | 307 GrBatchAtlas* atlas, |
302 PathData* pathData, | 308 PathData* pathData, |
303 const SkPath& path, | 309 const SkPath& path, |
304 const SkStrokeRec& | 310 uint32_t genID, |
305 stroke, bool antiAlias, | 311 const SkStrokeRec& stroke, |
312 bool antiAlias, | |
306 uint32_t dimension, | 313 uint32_t dimension, |
307 SkScalar scale) { | 314 SkScalar scale) { |
308 const SkRect& bounds = path.getBounds(); | 315 const SkRect& bounds = path.getBounds(); |
309 | 316 |
310 // generate bounding rect for bitmap draw | 317 // generate bounding rect for bitmap draw |
311 SkRect scaledBounds = bounds; | 318 SkRect scaledBounds = bounds; |
312 // scale to mip level size | 319 // scale to mip level size |
313 scaledBounds.fLeft *= scale; | 320 scaledBounds.fLeft *= scale; |
314 scaledBounds.fTop *= scale; | 321 scaledBounds.fTop *= scale; |
315 scaledBounds.fRight *= scale; | 322 scaledBounds.fRight *= scale; |
(...skipping 10 matching lines...) Expand all Loading... | |
326 // move origin to upper left corner | 333 // move origin to upper left corner |
327 devPathBounds.offsetTo(0,0); | 334 devPathBounds.offsetTo(0,0); |
328 | 335 |
329 // draw path to bitmap | 336 // draw path to bitmap |
330 SkMatrix drawMatrix; | 337 SkMatrix drawMatrix; |
331 drawMatrix.setTranslate(-bounds.left(), -bounds.top()); | 338 drawMatrix.setTranslate(-bounds.left(), -bounds.top()); |
332 drawMatrix.postScale(scale, scale); | 339 drawMatrix.postScale(scale, scale); |
333 drawMatrix.postTranslate(kAntiAliasPad, kAntiAliasPad); | 340 drawMatrix.postTranslate(kAntiAliasPad, kAntiAliasPad); |
334 | 341 |
335 // setup bitmap backing | 342 // setup bitmap backing |
336 // Now translate so the bound's UL corner is at the origin | 343 SkASSERT(devPathBounds.fLeft == 0); |
337 drawMatrix.postTranslate(-devPathBounds.fLeft * SK_Scalar1, | 344 SkASSERT(devPathBounds.fTop == 0); |
338 -devPathBounds.fTop * SK_Scalar1); | |
339 SkIRect pathBounds = SkIRect::MakeWH(devPathBounds.width(), | |
340 devPathBounds.height()); | |
341 | |
342 SkAutoPixmapStorage dst; | 345 SkAutoPixmapStorage dst; |
343 if (!dst.tryAlloc(SkImageInfo::MakeA8(pathBounds.width(), | 346 if (!dst.tryAlloc(SkImageInfo::MakeA8(devPathBounds.width(), |
344 pathBounds.height()))) { | 347 devPathBounds.height()))) { |
345 return false; | 348 return false; |
346 } | 349 } |
347 sk_bzero(dst.writable_addr(), dst.getSafeSize()); | 350 sk_bzero(dst.writable_addr(), dst.getSafeSize()); |
348 | 351 |
349 // rasterize path | 352 // rasterize path |
350 SkPaint paint; | 353 SkPaint paint; |
351 if (stroke.isHairlineStyle()) { | 354 paint.setStyle(SkPaint::kFill_Style); |
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 } | |
364 paint.setAntiAlias(antiAlias); | 355 paint.setAntiAlias(antiAlias); |
365 | 356 |
366 SkDraw draw; | 357 SkDraw draw; |
367 sk_bzero(&draw, sizeof(draw)); | 358 sk_bzero(&draw, sizeof(draw)); |
368 | 359 |
369 SkRasterClip rasterClip; | 360 SkRasterClip rasterClip; |
370 rasterClip.setRect(pathBounds); | 361 rasterClip.setRect(devPathBounds); |
371 draw.fRC = &rasterClip; | 362 draw.fRC = &rasterClip; |
372 draw.fClip = &rasterClip.bwRgn(); | 363 draw.fClip = &rasterClip.bwRgn(); |
373 draw.fMatrix = &drawMatrix; | 364 draw.fMatrix = &drawMatrix; |
374 draw.fDst = dst; | 365 draw.fDst = dst; |
375 | 366 |
376 draw.drawPathCoverage(path, paint); | 367 draw.drawPathCoverage(path, paint); |
377 | 368 |
378 // generate signed distance field | 369 // generate signed distance field |
379 devPathBounds.outset(SK_DistanceFieldPad, SK_DistanceFieldPad); | 370 devPathBounds.outset(SK_DistanceFieldPad, SK_DistanceFieldPad); |
380 int width = devPathBounds.width(); | 371 int width = devPathBounds.width(); |
(...skipping 15 matching lines...) Expand all Loading... | |
396 this->flush(target, flushInfo); | 387 this->flush(target, flushInfo); |
397 target->initDraw(dfProcessor, pipeline); | 388 target->initDraw(dfProcessor, pipeline); |
398 | 389 |
399 SkDEBUGCODE(success =) atlas->addToAtlas(&id, target, width, height, | 390 SkDEBUGCODE(success =) atlas->addToAtlas(&id, target, width, height, |
400 dfStorage.get(), &atlasLoca tion); | 391 dfStorage.get(), &atlasLoca tion); |
401 SkASSERT(success); | 392 SkASSERT(success); |
402 | 393 |
403 } | 394 } |
404 | 395 |
405 // add to cache | 396 // add to cache |
406 pathData->fKey.fGenID = path.getGenerationID(); | 397 pathData->fKey = PathData::Key(genID, dimension, stroke); |
407 pathData->fKey.fDimension = dimension; | |
408 pathData->fScale = scale; | 398 pathData->fScale = scale; |
409 pathData->fID = id; | 399 pathData->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, |
(...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
536 ATLAS_TEXTURE_WIDTH, ATLAS_ TEXTURE_HEIGHT, | 526 ATLAS_TEXTURE_WIDTH, ATLAS_ TEXTURE_HEIGHT, |
537 NUM_PLOTS_X, NUM_PLOTS_Y, | 527 NUM_PLOTS_X, NUM_PLOTS_Y, |
538 &GrAADistanceFieldPathRende rer::HandleEviction, | 528 &GrAADistanceFieldPathRende rer::HandleEviction, |
539 (void*)this); | 529 (void*)this); |
540 if (!fAtlas) { | 530 if (!fAtlas) { |
541 return false; | 531 return false; |
542 } | 532 } |
543 } | 533 } |
544 | 534 |
545 AADistanceFieldPathBatch::Geometry geometry(*args.fStroke); | 535 AADistanceFieldPathBatch::Geometry geometry(*args.fStroke); |
546 geometry.fPath = *args.fPath; | 536 if (SkStrokeRec::kFill_Style == args.fStroke->getStyle()) { |
537 geometry.fPath = *args.fPath; | |
538 } else { | |
robertphillips
2015/11/19 19:03:28
Do we need 'newPath'? Can't we pass "&geometry.fPa
jvanverth1
2015/11/19 20:33:23
Done.
| |
539 SkPath newPath; | |
540 args.fStroke->applyToPath(&newPath, *args.fPath); | |
541 geometry.fPath = newPath; | |
542 } | |
547 geometry.fAntiAlias = args.fAntiAlias; | 543 geometry.fAntiAlias = args.fAntiAlias; |
robertphillips
2015/11/19 19:03:28
// Note: this is the generation ID of the _origina
jvanverth1
2015/11/19 20:33:23
Done.
| |
548 | 544 geometry.fGenID = args.fPath->getGenerationID(); |
545 | |
549 SkAutoTUnref<GrDrawBatch> batch(AADistanceFieldPathBatch::Create(geometry, a rgs.fColor, | 546 SkAutoTUnref<GrDrawBatch> batch(AADistanceFieldPathBatch::Create(geometry, a rgs.fColor, |
550 *args.fView Matrix, fAtlas, | 547 *args.fView Matrix, fAtlas, |
551 &fPathCache , &fPathList)); | 548 &fPathCache , &fPathList)); |
552 args.fTarget->drawBatch(*args.fPipelineBuilder, batch); | 549 args.fTarget->drawBatch(*args.fPipelineBuilder, batch); |
553 | 550 |
554 return true; | 551 return true; |
555 } | 552 } |
556 | 553 |
557 //////////////////////////////////////////////////////////////////////////////// /////////////////// | 554 //////////////////////////////////////////////////////////////////////////////// /////////////////// |
558 | 555 |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
621 geometry.fPath = GrTest::TestPath(random); | 618 geometry.fPath = GrTest::TestPath(random); |
622 geometry.fAntiAlias = random->nextBool(); | 619 geometry.fAntiAlias = random->nextBool(); |
623 | 620 |
624 return AADistanceFieldPathBatch::Create(geometry, color, viewMatrix, | 621 return AADistanceFieldPathBatch::Create(geometry, color, viewMatrix, |
625 gTestStruct.fAtlas, | 622 gTestStruct.fAtlas, |
626 &gTestStruct.fPathCache, | 623 &gTestStruct.fPathCache, |
627 &gTestStruct.fPathList); | 624 &gTestStruct.fPathList); |
628 } | 625 } |
629 | 626 |
630 #endif | 627 #endif |
OLD | NEW |