aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorGravatar Jim Van Verth <jvanverth@google.com>2017-02-10 15:24:39 -0500
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2017-02-10 21:26:33 +0000
commit6e83b13c226246041a33dc7bf0e92626581b5e79 (patch)
tree555310ae893c0e52c440e1163bb43dace38e4afa /src
parent368af4605db18f7197ed3289d2ebdc93bbb5879b (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. BUG=chromium:682918 Change-Id: I5a394098665d01e995a244fde278236f1471e6c9 Reviewed-on: https://skia-review.googlesource.com/8328 Reviewed-by: Brian Salomon <bsalomon@google.com> Commit-Queue: Jim Van Verth <jvanverth@google.com>
Diffstat (limited to 'src')
-rw-r--r--src/core/SkMathPriv.h24
-rw-r--r--src/gpu/ops/GrAADistanceFieldPathRenderer.cpp52
2 files changed, 56 insertions, 20 deletions
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 f817f86357..e1a04396eb 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,10 @@
#include "effects/GrDistanceFieldGeoProc.h"
#include "ops/GrMeshDrawOp.h"
-#include "SkPathOps.h"
#include "SkAutoMalloc.h"
#include "SkDistanceFieldGen.h"
-#include "GrDistanceFieldGenFromVector.h"
+#include "SkMathPriv.h"
+#include "SkPathOps.h"
#define ATLAS_TEXTURE_WIDTH 2048
#define ATLAS_TEXTURE_HEIGHT 2048
@@ -39,9 +40,12 @@ 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 int kMinMIP = 16;
+static const int kMinMIPLog = 4;
+static const int kMaxMIP = 162;
+
+static const int kMaxDim = 73;
+static const int kMaxSize = 2*kMaxMIP;
// Callback to clear out internal path cache when eviction occurs
void GrAADistanceFieldPathRenderer::HandleEviction(GrDrawOpAtlas::AtlasID id, void* pr) {
@@ -107,14 +111,14 @@ 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();
SkRect bounds = args.fShape->styledBounds();
SkScalar maxDim = SkMaxScalar(bounds.width(), bounds.height());
- return maxDim <= kMediumMIP && maxDim * maxScale <= 2.0f*kLargeMIP;
+ return maxDim <= kMaxDim && maxDim * maxScale <= kMaxSize;
}
////////////////////////////////////////////////////////////////////////////////
@@ -241,20 +245,28 @@ private:
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;
+ SkScalar mipScale = 1.0f;
+ // for small paths, scale up to a min size between kMinMIP and 2*kMinMIP
+ if (maxDim < kMinMIP) {
+ mipScale = SkIntToScalar(1 << (kMinMIPLog - SkPrevLog2(maxDim)));
+ // for larger paths, initial scale is half the original
+ // gives us a size between kMinMIP and kMaxDim/2 (or close to (kMinMIP, 2*kMinMIP])
+ } else if (maxDim > 2*kMinMIP) {
+ mipScale = 0.5f;
+ }
+ SkScalar smallMipSize = mipScale*maxDim;
+
+ SkScalar desiredDimension;
+ if (size <= smallMipSize) {
+ desiredDimension = smallMipSize;
+ } else if (size <= 2*smallMipSize) {
+ desiredDimension = 2*smallMipSize;
+ } else if (size <= 4*smallMipSize) {
+ desiredDimension = 4*smallMipSize;
} else {
- desiredDimension = kLargeMIP;
+ desiredDimension = kMaxMIP;
}
// check to see if path is cached