OLD | NEW |
---|---|
1 | 1 |
2 /* | 2 /* |
3 * Copyright 2014 Google Inc. | 3 * Copyright 2014 Google Inc. |
4 * Copyright 2016 ARM Ltd. | |
4 * | 5 * |
5 * Use of this source code is governed by a BSD-style license that can be | 6 * Use of this source code is governed by a BSD-style license that can be |
6 * found in the LICENSE file. | 7 * found in the LICENSE file. |
7 */ | 8 */ |
8 | 9 |
9 #include "GrAADistanceFieldPathRenderer.h" | 10 #include "GrAADistanceFieldPathRenderer.h" |
10 | 11 |
11 #include "GrBatchFlushState.h" | 12 #include "GrBatchFlushState.h" |
12 #include "GrBatchTest.h" | 13 #include "GrBatchTest.h" |
13 #include "GrContext.h" | 14 #include "GrContext.h" |
14 #include "GrPipelineBuilder.h" | 15 #include "GrPipelineBuilder.h" |
15 #include "GrResourceProvider.h" | 16 #include "GrResourceProvider.h" |
16 #include "GrSurfacePriv.h" | 17 #include "GrSurfacePriv.h" |
17 #include "GrSWMaskHelper.h" | 18 #include "GrSWMaskHelper.h" |
18 #include "GrTexturePriv.h" | 19 #include "GrTexturePriv.h" |
19 #include "GrVertexBuffer.h" | 20 #include "GrVertexBuffer.h" |
20 #include "batches/GrVertexBatch.h" | 21 #include "batches/GrVertexBatch.h" |
21 #include "effects/GrDistanceFieldGeoProc.h" | 22 #include "effects/GrDistanceFieldGeoProc.h" |
22 | 23 |
23 #include "SkDistanceFieldGen.h" | 24 #include "SkDistanceFieldGen.h" |
25 #include "GrDistanceFieldGenFromVector.h" | |
24 #include "SkRTConf.h" | 26 #include "SkRTConf.h" |
27 #include "SkPathOps.h" | |
25 | 28 |
26 #define ATLAS_TEXTURE_WIDTH 2048 | 29 #define ATLAS_TEXTURE_WIDTH 2048 |
27 #define ATLAS_TEXTURE_HEIGHT 2048 | 30 #define ATLAS_TEXTURE_HEIGHT 2048 |
28 #define PLOT_WIDTH 512 | 31 #define PLOT_WIDTH 512 |
29 #define PLOT_HEIGHT 256 | 32 #define PLOT_HEIGHT 256 |
30 | 33 |
31 #define NUM_PLOTS_X (ATLAS_TEXTURE_WIDTH / PLOT_WIDTH) | 34 #define NUM_PLOTS_X (ATLAS_TEXTURE_WIDTH / PLOT_WIDTH) |
32 #define NUM_PLOTS_Y (ATLAS_TEXTURE_HEIGHT / PLOT_HEIGHT) | 35 #define NUM_PLOTS_Y (ATLAS_TEXTURE_HEIGHT / PLOT_HEIGHT) |
33 | 36 |
34 #ifdef DF_PATH_TRACKING | 37 #ifdef DF_PATH_TRACKING |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
87 if (!args.fShaderCaps->shaderDerivativeSupport() || !args.fAntiAlias || | 90 if (!args.fShaderCaps->shaderDerivativeSupport() || !args.fAntiAlias || |
88 SkStrokeRec::kHairline_Style == args.fStroke->getStyle() || | 91 SkStrokeRec::kHairline_Style == args.fStroke->getStyle() || |
89 args.fPath->isInverseFillType() || args.fPath->isVolatile()) { | 92 args.fPath->isInverseFillType() || args.fPath->isVolatile()) { |
90 return false; | 93 return false; |
91 } | 94 } |
92 | 95 |
93 // currently don't support perspective | 96 // currently don't support perspective |
94 if (args.fViewMatrix->hasPerspective()) { | 97 if (args.fViewMatrix->hasPerspective()) { |
95 return false; | 98 return false; |
96 } | 99 } |
97 | 100 |
98 // only support paths with bounds within kMediumMIP by kMediumMIP, | 101 // only support paths with bounds within kMediumMIP by kMediumMIP, |
99 // scaled to have bounds within 2.0f*kLargeMIP by 2.0f*kLargeMIP | 102 // 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 | 103 // the goal is to accelerate rendering of lots of small paths that may be sc aling |
101 SkScalar maxScale = args.fViewMatrix->getMaxScale(); | 104 SkScalar maxScale = args.fViewMatrix->getMaxScale(); |
102 const SkRect& bounds = args.fPath->getBounds(); | 105 const SkRect& bounds = args.fPath->getBounds(); |
103 SkScalar maxDim = SkMaxScalar(bounds.width(), bounds.height()); | 106 SkScalar maxDim = SkMaxScalar(bounds.width(), bounds.height()); |
104 // Approximate stroked size by adding the maximum of the stroke width or 2x the miter limit | 107 // Approximate stroked size by adding the maximum of the stroke width or 2x the miter limit |
105 if (!args.fStroke->isFillStyle()) { | 108 if (!args.fStroke->isFillStyle()) { |
106 SkScalar extraWidth = args.fStroke->getWidth(); | 109 SkScalar extraWidth = args.fStroke->getWidth(); |
107 if (SkPaint::kMiter_Join == args.fStroke->getJoin()) { | 110 if (SkPaint::kMiter_Join == args.fStroke->getJoin()) { |
108 extraWidth = SkTMax(extraWidth, 2.0f*args.fStroke->getMiter()); | 111 extraWidth = SkTMax(extraWidth, 2.0f*args.fStroke->getMiter()); |
109 } | 112 } |
110 maxDim += extraWidth; | 113 maxDim += extraWidth; |
111 } | 114 } |
112 | 115 |
113 return maxDim <= kMediumMIP && maxDim * maxScale <= 2.0f*kLargeMIP; | 116 return maxDim <= kMediumMIP && maxDim * maxScale <= 2.0f*kLargeMIP; |
114 } | 117 } |
115 | 118 |
116 //////////////////////////////////////////////////////////////////////////////// | 119 //////////////////////////////////////////////////////////////////////////////// |
117 | 120 |
118 // padding around path bounds to allow for antialiased pixels | 121 // padding around path bounds to allow for antialiased pixels |
119 static const SkScalar kAntiAliasPad = 1.0f; | 122 static const SkScalar kAntiAliasPad = 1.0f; |
120 | 123 |
121 class AADistanceFieldPathBatch : public GrVertexBatch { | 124 class AADistanceFieldPathBatch : public GrVertexBatch { |
122 public: | 125 public: |
(...skipping 23 matching lines...) Expand all Loading... | |
146 bool fAntiAlias; | 149 bool fAntiAlias; |
147 }; | 150 }; |
148 | 151 |
149 static GrDrawBatch* Create(const Geometry& geometry, const SkMatrix& viewMat rix, | 152 static GrDrawBatch* Create(const Geometry& geometry, const SkMatrix& viewMat rix, |
150 GrBatchAtlas* atlas, PathCache* pathCache, PathDa taList* pathList) { | 153 GrBatchAtlas* atlas, PathCache* pathCache, PathDa taList* pathList) { |
151 return new AADistanceFieldPathBatch(geometry, viewMatrix, atlas, pathCac he, pathList); | 154 return new AADistanceFieldPathBatch(geometry, viewMatrix, atlas, pathCac he, pathList); |
152 } | 155 } |
153 | 156 |
154 const char* name() const override { return "AADistanceFieldPathBatch"; } | 157 const char* name() const override { return "AADistanceFieldPathBatch"; } |
155 | 158 |
156 void computePipelineOptimizations(GrInitInvariantOutput* color, | 159 void computePipelineOptimizations(GrInitInvariantOutput* color, |
157 GrInitInvariantOutput* coverage, | 160 GrInitInvariantOutput* coverage, |
158 GrBatchToXPOverrides* overrides) const ove rride { | 161 GrBatchToXPOverrides* overrides) const ove rride { |
159 color->setKnownFourComponents(fGeoData[0].fColor); | 162 color->setKnownFourComponents(fGeoData[0].fColor); |
160 coverage->setUnknownSingleComponent(); | 163 coverage->setUnknownSingleComponent(); |
161 overrides->fUsePLSDstRead = false; | 164 overrides->fUsePLSDstRead = false; |
162 } | 165 } |
163 | 166 |
164 private: | 167 private: |
165 void initBatchTracker(const GrXPOverridesForBatch& overrides) override { | 168 void initBatchTracker(const GrXPOverridesForBatch& overrides) override { |
166 // Handle any color overrides | 169 // Handle any color overrides |
(...skipping 184 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
351 devPathBounds.fRight = intPad + width; | 354 devPathBounds.fRight = intPad + width; |
352 devPathBounds.fBottom = intPad + height; | 355 devPathBounds.fBottom = intPad + height; |
353 devPathBounds.outset(intPad, intPad); | 356 devPathBounds.outset(intPad, intPad); |
354 | 357 |
355 // draw path to bitmap | 358 // draw path to bitmap |
356 SkMatrix drawMatrix; | 359 SkMatrix drawMatrix; |
357 drawMatrix.setTranslate(-bounds.left(), -bounds.top()); | 360 drawMatrix.setTranslate(-bounds.left(), -bounds.top()); |
358 drawMatrix.postScale(scale, scale); | 361 drawMatrix.postScale(scale, scale); |
359 drawMatrix.postTranslate(kAntiAliasPad, kAntiAliasPad); | 362 drawMatrix.postTranslate(kAntiAliasPad, kAntiAliasPad); |
360 | 363 |
361 // setup bitmap backing | |
362 SkASSERT(devPathBounds.fLeft == 0); | 364 SkASSERT(devPathBounds.fLeft == 0); |
363 SkASSERT(devPathBounds.fTop == 0); | 365 SkASSERT(devPathBounds.fTop == 0); |
364 SkAutoPixmapStorage dst; | |
365 if (!dst.tryAlloc(SkImageInfo::MakeA8(devPathBounds.width(), | |
366 devPathBounds.height()))) { | |
367 return false; | |
368 } | |
369 sk_bzero(dst.writable_addr(), dst.getSafeSize()); | |
370 | 366 |
371 // rasterize path | 367 // setup signed distance field storage |
372 SkPaint paint; | 368 SkIRect sdfPathBounds = devPathBounds.makeOutset(SK_DistanceFieldPad, SK _DistanceFieldPad); |
373 paint.setStyle(SkPaint::kFill_Style); | 369 width = sdfPathBounds.width(); |
374 paint.setAntiAlias(antiAlias); | 370 height = sdfPathBounds.height(); |
375 | |
376 SkDraw draw; | |
377 sk_bzero(&draw, sizeof(draw)); | |
378 | |
379 SkRasterClip rasterClip; | |
380 rasterClip.setRect(devPathBounds); | |
381 draw.fRC = &rasterClip; | |
382 draw.fClip = &rasterClip.bwRgn(); | |
383 draw.fMatrix = &drawMatrix; | |
384 draw.fDst = dst; | |
385 | |
386 draw.drawPathCoverage(path, paint); | |
387 | |
388 // generate signed distance field | |
389 devPathBounds.outset(SK_DistanceFieldPad, SK_DistanceFieldPad); | |
390 width = devPathBounds.width(); | |
391 height = devPathBounds.height(); | |
392 // TODO We should really generate this directly into the plot somehow | 371 // TODO We should really generate this directly into the plot somehow |
393 SkAutoSMalloc<1024> dfStorage(width * height * sizeof(unsigned char)); | 372 SkAutoSMalloc<1024> dfStorage(width * height * sizeof(unsigned char)); |
394 | 373 |
395 // Generate signed distance field | 374 bool success = false; |
396 SkGenerateDistanceFieldFromA8Image((unsigned char*)dfStorage.get(), | 375 SkPath simplifiedPath; |
397 (const unsigned char*)dst.addr(), | 376 |
398 dst.width(), dst.height(), dst.rowByt es()); | 377 Simplify(path, &simplifiedPath); |
bsalomon
2016/02/06 13:22:06
Should this go into GrGenerateDistanceFieldFromPat
Joel.Liang
2016/02/17 10:42:42
Done.
| |
378 | |
379 if (SkPath::kEvenOdd_FillType == simplifiedPath.getFillType()) { | |
bsalomon
2016/02/06 13:22:06
Can this be an assert rather than a branch?
Joel.Liang
2016/02/17 10:42:42
Done and moved the assertion into GrGenerateDistan
| |
380 // Generate signed distance field directly from SkPath | |
381 success = GrGenerateDistanceFieldFromPath((unsigned char*)dfStorage. get(), | |
382 simplifiedPath, drawMatrix, | |
383 width, height, width * sizeof(unsign ed char)); | |
384 } | |
385 if (!success) { | |
386 SkASSERT(false && | |
bsalomon
2016/02/06 13:22:06
This seems like a lot of code for a fallback we ne
Joel.Liang
2016/02/15 08:36:48
We will need this fallback if "get_direction" may
Joel.Liang
2016/02/17 10:42:42
I have removed the fallback code as now we can han
| |
387 "We should use GrGenerateDistanceFieldFromPath to generate SDF f or all paths."); | |
388 | |
389 // setup bitmap backing | |
390 SkAutoPixmapStorage dst; | |
391 if (!dst.tryAlloc(SkImageInfo::MakeA8(devPathBounds.width(), | |
392 devPathBounds.height()))) { | |
393 return false; | |
394 } | |
395 sk_bzero(dst.writable_addr(), dst.getSafeSize()); | |
396 | |
397 // rasterize path | |
398 SkPaint paint; | |
399 paint.setStyle(SkPaint::kFill_Style); | |
400 paint.setAntiAlias(antiAlias); | |
401 | |
402 SkDraw draw; | |
403 sk_bzero(&draw, sizeof(draw)); | |
404 | |
405 SkRasterClip rasterClip; | |
406 rasterClip.setRect(devPathBounds); | |
407 draw.fRC = &rasterClip; | |
408 draw.fClip = &rasterClip.bwRgn(); | |
409 draw.fMatrix = &drawMatrix; | |
410 draw.fDst = dst; | |
411 | |
412 draw.drawPathCoverage(simplifiedPath, paint); | |
413 | |
414 // Generate signed distance field | |
415 SkGenerateDistanceFieldFromA8Image((unsigned char*)dfStorage.get(), | |
416 (const unsigned char*)dst.addr(), | |
417 dst.width(), dst.height(), dst.ro wBytes()); | |
418 } | |
399 | 419 |
400 // add to atlas | 420 // add to atlas |
401 SkIPoint16 atlasLocation; | 421 SkIPoint16 atlasLocation; |
402 GrBatchAtlas::AtlasID id; | 422 GrBatchAtlas::AtlasID id; |
403 bool success = atlas->addToAtlas(&id, target, width, height, dfStorage.g et(), | 423 success = atlas->addToAtlas(&id, target, width, height, dfStorage.get(), |
404 &atlasLocation); | 424 &atlasLocation); |
405 if (!success) { | 425 if (!success) { |
406 this->flush(target, flushInfo); | 426 this->flush(target, flushInfo); |
407 target->initDraw(dfProcessor, pipeline); | 427 target->initDraw(dfProcessor, pipeline); |
408 | 428 |
409 SkDEBUGCODE(success =) atlas->addToAtlas(&id, target, width, height, | 429 SkDEBUGCODE(success =) atlas->addToAtlas(&id, target, width, height, |
410 dfStorage.get(), &atlasLoca tion); | 430 dfStorage.get(), &atlasLoca tion); |
411 SkASSERT(success); | 431 SkASSERT(success); |
412 | 432 |
413 } | 433 } |
(...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
561 geometry.fPath = *args.fPath; | 581 geometry.fPath = *args.fPath; |
562 } else { | 582 } else { |
563 args.fStroke->applyToPath(&geometry.fPath, *args.fPath); | 583 args.fStroke->applyToPath(&geometry.fPath, *args.fPath); |
564 } | 584 } |
565 geometry.fColor = args.fColor; | 585 geometry.fColor = args.fColor; |
566 geometry.fAntiAlias = args.fAntiAlias; | 586 geometry.fAntiAlias = args.fAntiAlias; |
567 // Note: this is the generation ID of the _original_ path. When a new path i s | 587 // Note: this is the generation ID of the _original_ path. When a new path i s |
568 // generated due to stroking it is important that the original path's id is used | 588 // generated due to stroking it is important that the original path's id is used |
569 // for caching. | 589 // for caching. |
570 geometry.fGenID = args.fPath->getGenerationID(); | 590 geometry.fGenID = args.fPath->getGenerationID(); |
571 | 591 |
572 SkAutoTUnref<GrDrawBatch> batch(AADistanceFieldPathBatch::Create(geometry, | 592 SkAutoTUnref<GrDrawBatch> batch(AADistanceFieldPathBatch::Create(geometry, |
573 *args.fView Matrix, fAtlas, | 593 *args.fView Matrix, fAtlas, |
574 &fPathCache , &fPathList)); | 594 &fPathCache , &fPathList)); |
575 args.fTarget->drawBatch(*args.fPipelineBuilder, batch); | 595 args.fTarget->drawBatch(*args.fPipelineBuilder, batch); |
576 | 596 |
577 return true; | 597 return true; |
578 } | 598 } |
579 | 599 |
580 //////////////////////////////////////////////////////////////////////////////// /////////////////// | 600 //////////////////////////////////////////////////////////////////////////////// /////////////////// |
581 | 601 |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
646 geometry.fAntiAlias = random->nextBool(); | 666 geometry.fAntiAlias = random->nextBool(); |
647 geometry.fGenID = random->nextU(); | 667 geometry.fGenID = random->nextU(); |
648 | 668 |
649 return AADistanceFieldPathBatch::Create(geometry, viewMatrix, | 669 return AADistanceFieldPathBatch::Create(geometry, viewMatrix, |
650 gTestStruct.fAtlas, | 670 gTestStruct.fAtlas, |
651 &gTestStruct.fPathCache, | 671 &gTestStruct.fPathCache, |
652 &gTestStruct.fPathList); | 672 &gTestStruct.fPathList); |
653 } | 673 } |
654 | 674 |
655 #endif | 675 #endif |
OLD | NEW |