Chromium Code Reviews| 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" |
| 25 | 27 |
| 26 #define ATLAS_TEXTURE_WIDTH 2048 | 28 #define ATLAS_TEXTURE_WIDTH 2048 |
| 27 #define ATLAS_TEXTURE_HEIGHT 2048 | 29 #define ATLAS_TEXTURE_HEIGHT 2048 |
| 28 #define PLOT_WIDTH 512 | 30 #define PLOT_WIDTH 512 |
| 29 #define PLOT_HEIGHT 256 | 31 #define PLOT_HEIGHT 256 |
| 30 | 32 |
| 31 #define NUM_PLOTS_X (ATLAS_TEXTURE_WIDTH / PLOT_WIDTH) | 33 #define NUM_PLOTS_X (ATLAS_TEXTURE_WIDTH / PLOT_WIDTH) |
| 32 #define NUM_PLOTS_Y (ATLAS_TEXTURE_HEIGHT / PLOT_HEIGHT) | 34 #define NUM_PLOTS_Y (ATLAS_TEXTURE_HEIGHT / PLOT_HEIGHT) |
| 33 | 35 |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 87 if (!args.fShaderCaps->shaderDerivativeSupport() || !args.fAntiAlias || | 89 if (!args.fShaderCaps->shaderDerivativeSupport() || !args.fAntiAlias || |
| 88 SkStrokeRec::kHairline_Style == args.fStroke->getStyle() || | 90 SkStrokeRec::kHairline_Style == args.fStroke->getStyle() || |
| 89 args.fPath->isInverseFillType() || args.fPath->isVolatile()) { | 91 args.fPath->isInverseFillType() || args.fPath->isVolatile()) { |
| 90 return false; | 92 return false; |
| 91 } | 93 } |
| 92 | 94 |
| 93 // currently don't support perspective | 95 // currently don't support perspective |
| 94 if (args.fViewMatrix->hasPerspective()) { | 96 if (args.fViewMatrix->hasPerspective()) { |
| 95 return false; | 97 return false; |
| 96 } | 98 } |
| 97 | 99 |
| 98 // only support paths with bounds within kMediumMIP by kMediumMIP, | 100 // only support paths with bounds within kMediumMIP by kMediumMIP, |
| 99 // scaled to have bounds within 2.0f*kLargeMIP by 2.0f*kLargeMIP | 101 // 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 | 102 // the goal is to accelerate rendering of lots of small paths that may be sc aling |
| 101 SkScalar maxScale = args.fViewMatrix->getMaxScale(); | 103 SkScalar maxScale = args.fViewMatrix->getMaxScale(); |
| 102 const SkRect& bounds = args.fPath->getBounds(); | 104 const SkRect& bounds = args.fPath->getBounds(); |
| 103 SkScalar maxDim = SkMaxScalar(bounds.width(), bounds.height()); | 105 SkScalar maxDim = SkMaxScalar(bounds.width(), bounds.height()); |
| 104 // Approximate stroked size by adding the maximum of the stroke width or 2x the miter limit | 106 // Approximate stroked size by adding the maximum of the stroke width or 2x the miter limit |
| 105 if (!args.fStroke->isFillStyle()) { | 107 if (!args.fStroke->isFillStyle()) { |
| 106 SkScalar extraWidth = args.fStroke->getWidth(); | 108 SkScalar extraWidth = args.fStroke->getWidth(); |
| 107 if (SkPaint::kMiter_Join == args.fStroke->getJoin()) { | 109 if (SkPaint::kMiter_Join == args.fStroke->getJoin()) { |
| 108 extraWidth = SkTMax(extraWidth, 2.0f*args.fStroke->getMiter()); | 110 extraWidth = SkTMax(extraWidth, 2.0f*args.fStroke->getMiter()); |
| 109 } | 111 } |
| 110 maxDim += extraWidth; | 112 maxDim += extraWidth; |
| 111 } | 113 } |
| 112 | 114 |
| 113 return maxDim <= kMediumMIP && maxDim * maxScale <= 2.0f*kLargeMIP; | 115 return maxDim <= kMediumMIP && maxDim * maxScale <= 2.0f*kLargeMIP; |
| 114 } | 116 } |
| 115 | 117 |
| 116 //////////////////////////////////////////////////////////////////////////////// | 118 //////////////////////////////////////////////////////////////////////////////// |
| 117 | 119 |
| 118 // padding around path bounds to allow for antialiased pixels | 120 // padding around path bounds to allow for antialiased pixels |
| 119 static const SkScalar kAntiAliasPad = 1.0f; | 121 static const SkScalar kAntiAliasPad = 1.0f; |
| 120 | 122 |
| 121 class AADistanceFieldPathBatch : public GrVertexBatch { | 123 class AADistanceFieldPathBatch : public GrVertexBatch { |
| 122 public: | 124 public: |
| (...skipping 23 matching lines...) Expand all Loading... | |
| 146 bool fAntiAlias; | 148 bool fAntiAlias; |
| 147 }; | 149 }; |
| 148 | 150 |
| 149 static GrDrawBatch* Create(const Geometry& geometry, const SkMatrix& viewMat rix, | 151 static GrDrawBatch* Create(const Geometry& geometry, const SkMatrix& viewMat rix, |
| 150 GrBatchAtlas* atlas, PathCache* pathCache, PathDa taList* pathList) { | 152 GrBatchAtlas* atlas, PathCache* pathCache, PathDa taList* pathList) { |
| 151 return new AADistanceFieldPathBatch(geometry, viewMatrix, atlas, pathCac he, pathList); | 153 return new AADistanceFieldPathBatch(geometry, viewMatrix, atlas, pathCac he, pathList); |
| 152 } | 154 } |
| 153 | 155 |
| 154 const char* name() const override { return "AADistanceFieldPathBatch"; } | 156 const char* name() const override { return "AADistanceFieldPathBatch"; } |
| 155 | 157 |
| 156 void computePipelineOptimizations(GrInitInvariantOutput* color, | 158 void computePipelineOptimizations(GrInitInvariantOutput* color, |
| 157 GrInitInvariantOutput* coverage, | 159 GrInitInvariantOutput* coverage, |
| 158 GrBatchToXPOverrides* overrides) const ove rride { | 160 GrBatchToXPOverrides* overrides) const ove rride { |
| 159 color->setKnownFourComponents(fGeoData[0].fColor); | 161 color->setKnownFourComponents(fGeoData[0].fColor); |
| 160 coverage->setUnknownSingleComponent(); | 162 coverage->setUnknownSingleComponent(); |
| 161 overrides->fUsePLSDstRead = false; | 163 overrides->fUsePLSDstRead = false; |
| 162 } | 164 } |
| 163 | 165 |
| 164 private: | 166 private: |
| 165 void initBatchTracker(const GrXPOverridesForBatch& overrides) override { | 167 void initBatchTracker(const GrXPOverridesForBatch& overrides) override { |
| 166 // Handle any color overrides | 168 // Handle any color overrides |
| (...skipping 184 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 351 devPathBounds.fRight = intPad + width; | 353 devPathBounds.fRight = intPad + width; |
| 352 devPathBounds.fBottom = intPad + height; | 354 devPathBounds.fBottom = intPad + height; |
| 353 devPathBounds.outset(intPad, intPad); | 355 devPathBounds.outset(intPad, intPad); |
| 354 | 356 |
| 355 // draw path to bitmap | 357 // draw path to bitmap |
| 356 SkMatrix drawMatrix; | 358 SkMatrix drawMatrix; |
| 357 drawMatrix.setTranslate(-bounds.left(), -bounds.top()); | 359 drawMatrix.setTranslate(-bounds.left(), -bounds.top()); |
| 358 drawMatrix.postScale(scale, scale); | 360 drawMatrix.postScale(scale, scale); |
| 359 drawMatrix.postTranslate(kAntiAliasPad, kAntiAliasPad); | 361 drawMatrix.postTranslate(kAntiAliasPad, kAntiAliasPad); |
| 360 | 362 |
| 361 // setup bitmap backing | |
| 362 SkASSERT(devPathBounds.fLeft == 0); | 363 SkASSERT(devPathBounds.fLeft == 0); |
| 363 SkASSERT(devPathBounds.fTop == 0); | 364 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 | 365 |
| 371 // rasterize path | 366 // setup signed distance field storage |
| 372 SkPaint paint; | 367 SkIRect sdfPathBounds = devPathBounds.makeOutset(SK_DistanceFieldPad, SK _DistanceFieldPad); |
| 373 paint.setStyle(SkPaint::kFill_Style); | 368 width = sdfPathBounds.width(); |
| 374 paint.setAntiAlias(antiAlias); | 369 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 | 370 // TODO We should really generate this directly into the plot somehow |
| 393 SkAutoSMalloc<1024> dfStorage(width * height * sizeof(unsigned char)); | 371 SkAutoSMalloc<1024> dfStorage(width * height * sizeof(unsigned char)); |
| 394 | 372 |
| 395 // Generate signed distance field | 373 bool success = false; |
| 396 SkGenerateDistanceFieldFromA8Image((unsigned char*)dfStorage.get(), | 374 if (SkPath::kEvenOdd_FillType == path.getFillType()) { |
| 397 (const unsigned char*)dst.addr(), | 375 // Generate signed distance field directly from SkPath |
| 398 dst.width(), dst.height(), dst.rowByt es()); | 376 // TODO: Support non-zero fill type (SkPath::kWinding_FillType) |
|
bsalomon
2016/02/02 18:03:48
Have you tried using using Simplify from SkPathOps
Joel.Liang
2016/02/04 12:12:05
Wow, now we can pass all test cases in DM by using
| |
| 377 success = GrGenerateDistanceFieldFromPath((unsigned char*)dfStorage. get(), | |
| 378 path, drawMatrix, | |
| 379 width, height, width * sizeof(unsign ed char)); | |
| 380 } | |
| 381 if (!success) { | |
| 382 // setup bitmap backing | |
| 383 SkAutoPixmapStorage dst; | |
| 384 if (!dst.tryAlloc(SkImageInfo::MakeA8(devPathBounds.width(), | |
| 385 devPathBounds.height()))) { | |
| 386 return false; | |
| 387 } | |
| 388 sk_bzero(dst.writable_addr(), dst.getSafeSize()); | |
| 389 | |
| 390 // rasterize path | |
| 391 SkPaint paint; | |
| 392 paint.setStyle(SkPaint::kFill_Style); | |
| 393 paint.setAntiAlias(antiAlias); | |
| 394 | |
| 395 SkDraw draw; | |
| 396 sk_bzero(&draw, sizeof(draw)); | |
| 397 | |
| 398 SkRasterClip rasterClip; | |
| 399 rasterClip.setRect(devPathBounds); | |
| 400 draw.fRC = &rasterClip; | |
| 401 draw.fClip = &rasterClip.bwRgn(); | |
| 402 draw.fMatrix = &drawMatrix; | |
| 403 draw.fDst = dst; | |
| 404 | |
| 405 draw.drawPathCoverage(path, paint); | |
| 406 | |
| 407 // Generate signed distance field | |
| 408 SkGenerateDistanceFieldFromA8Image((unsigned char*)dfStorage.get(), | |
| 409 (const unsigned char*)dst.addr(), | |
| 410 dst.width(), dst.height(), dst.ro wBytes()); | |
| 411 } | |
| 399 | 412 |
| 400 // add to atlas | 413 // add to atlas |
| 401 SkIPoint16 atlasLocation; | 414 SkIPoint16 atlasLocation; |
| 402 GrBatchAtlas::AtlasID id; | 415 GrBatchAtlas::AtlasID id; |
| 403 bool success = atlas->addToAtlas(&id, target, width, height, dfStorage.g et(), | 416 success = atlas->addToAtlas(&id, target, width, height, dfStorage.get(), |
| 404 &atlasLocation); | 417 &atlasLocation); |
| 405 if (!success) { | 418 if (!success) { |
| 406 this->flush(target, flushInfo); | 419 this->flush(target, flushInfo); |
| 407 target->initDraw(dfProcessor, pipeline); | 420 target->initDraw(dfProcessor, pipeline); |
| 408 | 421 |
| 409 SkDEBUGCODE(success =) atlas->addToAtlas(&id, target, width, height, | 422 SkDEBUGCODE(success =) atlas->addToAtlas(&id, target, width, height, |
| 410 dfStorage.get(), &atlasLoca tion); | 423 dfStorage.get(), &atlasLoca tion); |
| 411 SkASSERT(success); | 424 SkASSERT(success); |
| 412 | 425 |
| 413 } | 426 } |
| (...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 561 geometry.fPath = *args.fPath; | 574 geometry.fPath = *args.fPath; |
| 562 } else { | 575 } else { |
| 563 args.fStroke->applyToPath(&geometry.fPath, *args.fPath); | 576 args.fStroke->applyToPath(&geometry.fPath, *args.fPath); |
| 564 } | 577 } |
| 565 geometry.fColor = args.fColor; | 578 geometry.fColor = args.fColor; |
| 566 geometry.fAntiAlias = args.fAntiAlias; | 579 geometry.fAntiAlias = args.fAntiAlias; |
| 567 // Note: this is the generation ID of the _original_ path. When a new path i s | 580 // 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 | 581 // generated due to stroking it is important that the original path's id is used |
| 569 // for caching. | 582 // for caching. |
| 570 geometry.fGenID = args.fPath->getGenerationID(); | 583 geometry.fGenID = args.fPath->getGenerationID(); |
| 571 | 584 |
| 572 SkAutoTUnref<GrDrawBatch> batch(AADistanceFieldPathBatch::Create(geometry, | 585 SkAutoTUnref<GrDrawBatch> batch(AADistanceFieldPathBatch::Create(geometry, |
| 573 *args.fView Matrix, fAtlas, | 586 *args.fView Matrix, fAtlas, |
| 574 &fPathCache , &fPathList)); | 587 &fPathCache , &fPathList)); |
| 575 args.fTarget->drawBatch(*args.fPipelineBuilder, batch); | 588 args.fTarget->drawBatch(*args.fPipelineBuilder, batch); |
| 576 | 589 |
| 577 return true; | 590 return true; |
| 578 } | 591 } |
| 579 | 592 |
| 580 //////////////////////////////////////////////////////////////////////////////// /////////////////// | 593 //////////////////////////////////////////////////////////////////////////////// /////////////////// |
| 581 | 594 |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 646 geometry.fAntiAlias = random->nextBool(); | 659 geometry.fAntiAlias = random->nextBool(); |
| 647 geometry.fGenID = random->nextU(); | 660 geometry.fGenID = random->nextU(); |
| 648 | 661 |
| 649 return AADistanceFieldPathBatch::Create(geometry, viewMatrix, | 662 return AADistanceFieldPathBatch::Create(geometry, viewMatrix, |
| 650 gTestStruct.fAtlas, | 663 gTestStruct.fAtlas, |
| 651 &gTestStruct.fPathCache, | 664 &gTestStruct.fPathCache, |
| 652 &gTestStruct.fPathList); | 665 &gTestStruct.fPathList); |
| 653 } | 666 } |
| 654 | 667 |
| 655 #endif | 668 #endif |
| OLD | NEW |