diff options
author | Jim Van Verth <jvanverth@google.com> | 2017-02-15 15:46:52 -0500 |
---|---|---|
committer | Skia Commit-Bot <skia-commit-bot@chromium.org> | 2017-02-16 13:35:20 +0000 |
commit | f9e678d6964bc5a6c2b38edbc36d9f23cf96c37f (patch) | |
tree | 990878ccfa1b0102f48d7108b9bc0000dd95cee8 | |
parent | fa64774820cb42594d3f5bc2059953510f038636 (diff) |
Use SDF path miplevels based on the original path's size
Should produce sharper results than arbitrary fixed sizes.
Adds a new test to pathfill GM.
Was: https://skia-review.googlesource.com/c/8328/
BUG=chromium:682918, skia:6238
Change-Id: Ia62ea5ce6b4a5ac2b8b51d06d57dc951d6c340b8
Reviewed-on: https://skia-review.googlesource.com/8384
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Jim Van Verth <jvanverth@google.com>
-rw-r--r-- | gm/convexpaths.cpp | 44 | ||||
-rw-r--r-- | gm/pathfill.cpp | 55 | ||||
-rw-r--r-- | src/core/SkMathPriv.h | 24 | ||||
-rw-r--r-- | src/gpu/ops/GrAADistanceFieldPathRenderer.cpp | 53 |
4 files changed, 128 insertions, 48 deletions
diff --git a/gm/convexpaths.cpp b/gm/convexpaths.cpp index 50939f9183..766a6cee18 100644 --- a/gm/convexpaths.cpp +++ b/gm/convexpaths.cpp @@ -260,29 +260,29 @@ protected: virtual void onDraw(SkCanvas* canvas) { this->makePaths(); - SkPaint paint; - paint.setAntiAlias(true); - SkRandom rand; - canvas->translate(20 * SK_Scalar1, 20 * SK_Scalar1); - - // As we've added more paths this has gotten pretty big. Scale the whole thing down. - canvas->scale(2 * SK_Scalar1 / 3, 2 * SK_Scalar1 / 3); - - for (int i = 0; i < fPaths.count(); ++i) { - canvas->save(); - // position the path, and make it at off-integer coords. - canvas->translate(SK_Scalar1 * 200 * (i % 5) + SK_Scalar1 / 10, - SK_Scalar1 * 200 * (i / 5) + 9 * SK_Scalar1 / 10); - SkColor color = rand.nextU(); - color |= 0xff000000; - paint.setColor(color); -#if 0 // This hitting on 32bit Linux builds for some paths. Temporarily disabling while it is - // debugged. - SkASSERT(fPaths[i].isConvex()); + SkPaint paint; + paint.setAntiAlias(true); + SkRandom rand; + canvas->translate(20 * SK_Scalar1, 20 * SK_Scalar1); + + // As we've added more paths this has gotten pretty big. Scale the whole thing down. + canvas->scale(2 * SK_Scalar1 / 3, 2 * SK_Scalar1 / 3); + + for (int i = 0; i < fPaths.count(); ++i) { + canvas->save(); + // position the path, and make it at off-integer coords. + canvas->translate(SK_Scalar1 * 200 * (i % 5) + SK_Scalar1 / 10, + SK_Scalar1 * 200 * (i / 5) + 9 * SK_Scalar1 / 10); + SkColor color = rand.nextU(); + color |= 0xff000000; + paint.setColor(color); +#if 0 // This hitting on 32bit Linux builds for some paths. Temporarily disabling while it is + // debugged. + SkASSERT(fPaths[i].isConvex()); #endif - canvas->drawPath(fPaths[i], paint); - canvas->restore(); - } + canvas->drawPath(fPaths[i], paint); + canvas->restore(); + } } private: diff --git a/gm/pathfill.cpp b/gm/pathfill.cpp index de762a9548..a36ab1f459 100644 --- a/gm/pathfill.cpp +++ b/gm/pathfill.cpp @@ -140,7 +140,7 @@ static SkScalar make_line(SkPath* path) { return SkIntToScalar(40); } -static SkScalar make_info(SkPath* path) { +static void make_info(SkPath* path) { path->moveTo(24, 4); path->cubicTo(12.94999980926514f, 4, @@ -179,8 +179,49 @@ static SkScalar make_info(SkPath* path) { path->lineTo(26, 14); path->lineTo(26, 18); path->close(); +} - return SkIntToScalar(44); +static void make_accessibility(SkPath* path) { + path->moveTo(12, 2); + path->cubicTo(13.10000038146973f, + 2, + 14, + 2.900000095367432f, + 14, + 4); + path->cubicTo(14, + 5.099999904632568f, + 13.10000038146973f, + 6, + 12, + 6); + path->cubicTo(10.89999961853027f, + 6, + 10, + 5.099999904632568f, + 10, + 4); + path->cubicTo(10, + 2.900000095367432f, + 10.89999961853027f, + 2, + 12, + 2); + path->close(); + path->moveTo(21, 9); + path->lineTo(15, 9); + path->lineTo(15, 22); + path->lineTo(13, 22); + path->lineTo(13, 16); + path->lineTo(11, 16); + path->lineTo(11, 22); + path->lineTo(9, 22); + path->lineTo(9, 9); + path->lineTo(3, 9); + path->lineTo(3, 7); + path->lineTo(21, 7); + path->lineTo(21, 9); + path->close(); } constexpr MakePathProc gProcs[] = { @@ -202,13 +243,15 @@ class PathFillGM : public skiagm::GM { SkPath fPath[N]; SkScalar fDY[N]; SkPath fInfoPath; + SkPath fAccessibilityPath; protected: void onOnceBeforeDraw() override { for (size_t i = 0; i < N; i++) { fDY[i] = gProcs[i](&fPath[i]); } - (void) make_info(&fInfoPath); + make_info(&fInfoPath); + make_accessibility(&fAccessibilityPath); } @@ -229,9 +272,15 @@ protected: canvas->translate(SkIntToScalar(0), fDY[i]); } + canvas->save(); canvas->scale(0.300000011920929f, 0.300000011920929f); canvas->translate(50, 50); canvas->drawPath(fInfoPath, paint); + canvas->restore(); + + canvas->scale(2, 2); + canvas->translate(5, 15); + canvas->drawPath(fAccessibilityPath, paint); } private: diff --git a/src/core/SkMathPriv.h b/src/core/SkMathPriv.h index 14ebeb17b7..5ef0cb25e4 100644 --- a/src/core/SkMathPriv.h +++ b/src/core/SkMathPriv.h @@ -132,6 +132,16 @@ static inline int SkNextPow2(int value) { } /** +* Returns the largest power-of-2 that is <= the specified value. If value +* is already a power of 2, then it is returned unchanged. It is undefined +* if value is <= 0. +*/ +static inline int SkPrevPow2(int value) { + SkASSERT(value > 0); + return 1 << (32 - SkCLZ(value >> 1)); +} + +/** * Returns the log2 of the specified value, were that value to be rounded up * to the next power of 2. It is undefined to pass 0. Examples: * SkNextLog2(1) -> 0 @@ -145,6 +155,20 @@ static inline int SkNextLog2(uint32_t value) { return 32 - SkCLZ(value - 1); } +/** +* Returns the log2 of the specified value, were that value to be rounded down +* to the previous power of 2. It is undefined to pass 0. Examples: +* SkPrevLog2(1) -> 0 +* SkPrevLog2(2) -> 1 +* SkPrevLog2(3) -> 1 +* SkPrevLog2(4) -> 2 +* SkPrevLog2(5) -> 2 +*/ +static inline int SkPrevLog2(uint32_t value) { + SkASSERT(value != 0); + return 32 - SkCLZ(value >> 1); +} + /////////////////////////////////////////////////////////////////////////////// /** diff --git a/src/gpu/ops/GrAADistanceFieldPathRenderer.cpp b/src/gpu/ops/GrAADistanceFieldPathRenderer.cpp index a72f7dc40f..7131e18a46 100644 --- a/src/gpu/ops/GrAADistanceFieldPathRenderer.cpp +++ b/src/gpu/ops/GrAADistanceFieldPathRenderer.cpp @@ -10,6 +10,7 @@ #include "GrBuffer.h" #include "GrContext.h" +#include "GrDistanceFieldGenFromVector.h" #include "GrDrawOpTest.h" #include "GrOpFlushState.h" #include "GrPipelineBuilder.h" @@ -20,10 +21,9 @@ #include "effects/GrDistanceFieldGeoProc.h" #include "ops/GrMeshDrawOp.h" -#include "SkPathOps.h" #include "SkAutoMalloc.h" #include "SkDistanceFieldGen.h" -#include "GrDistanceFieldGenFromVector.h" +#include "SkPathOps.h" #define ATLAS_TEXTURE_WIDTH 2048 #define ATLAS_TEXTURE_HEIGHT 2048 @@ -39,9 +39,11 @@ static int g_NumFreedShapes = 0; #endif // mip levels -static const int kSmallMIP = 32; -static const int kMediumMIP = 73; -static const int kLargeMIP = 162; +static const SkScalar kMaxMIP = 162; + +static const SkScalar kMaxDim = 73; +static const SkScalar kMinSize = 8; +static const SkScalar kMaxSize = 2*kMaxMIP; // Callback to clear out internal path cache when eviction occurs void GrAADistanceFieldPathRenderer::HandleEviction(GrDrawOpAtlas::AtlasID id, void* pr) { @@ -107,14 +109,20 @@ bool GrAADistanceFieldPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) c return false; } - // Only support paths with bounds within kMediumMIP by kMediumMIP, - // scaled to have bounds within 2.0f*kLargeMIP by 2.0f*kLargeMIP. + // Only support paths with bounds within kMaxDim by kMaxDim, + // scaled to have bounds within kMaxSize by kMaxSize. // The goal is to accelerate rendering of lots of small paths that may be scaling. - SkScalar maxScale = args.fViewMatrix->getMaxScale(); + SkScalar scaleFactors[2]; + if (!args.fViewMatrix->getMinMaxScales(scaleFactors)) { + return false; + } SkRect bounds = args.fShape->styledBounds(); + SkScalar minDim = SkMinScalar(bounds.width(), bounds.height()); SkScalar maxDim = SkMaxScalar(bounds.width(), bounds.height()); + SkScalar minSize = minDim * scaleFactors[0]; + SkScalar maxSize = maxDim * scaleFactors[1]; - return maxDim <= kMediumMIP && maxDim * maxScale <= 2.0f*kLargeMIP; + return maxDim <= kMaxDim && kMinSize <= minSize && maxSize <= kMaxSize; } //////////////////////////////////////////////////////////////////////////////// @@ -240,23 +248,22 @@ private: SkScalar maxScale = this->viewMatrix().getMaxScale(); const SkRect& bounds = args.fShape.bounds(); SkScalar maxDim = SkMaxScalar(bounds.width(), bounds.height()); - SkScalar size = maxScale * maxDim; - SkScalar desiredDimension; - // For minimizing (or the common case of identity) transforms, we try to - // create the DF at the appropriately sized native src-space path resolution. + // We try to create the DF at a power of two scaled path resolution (1/2, 1, 2, 4, etc) // In the majority of cases this will yield a crisper rendering. - if (size <= maxDim && maxDim < kSmallMIP) { - desiredDimension = maxDim; - } else if (size <= kSmallMIP) { - desiredDimension = kSmallMIP; - } else if (size <= maxDim) { - desiredDimension = maxDim; - } else if (size <= kMediumMIP) { - desiredDimension = kMediumMIP; - } else { - desiredDimension = kLargeMIP; + SkScalar mipScale = 1.0f; + // Our mipscale is the maxScale clamped to the next highest power of 2 + if (maxScale < SK_ScalarHalf) { + SkScalar log = SkScalarFloorToScalar(SkScalarLog2(SkScalarInvert(maxScale))); + mipScale = SkScalarPow(2, -log); + } else if (maxScale > SK_Scalar1) { + SkScalar log = SkScalarCeilToScalar(SkScalarLog2(maxScale)); + mipScale = SkScalarPow(2, log); } + SkScalar mipSize = mipScale*maxDim; + SkASSERT(maxScale * maxDim <= mipSize); + SkScalar desiredDimension = SkTMin(mipSize, kMaxMIP); + // check to see if path is cached ShapeData::Key key(args.fShape, SkScalarCeilToInt(desiredDimension)); ShapeData* shapeData = fShapeCache->find(key); |