Support multiple scales for dfpaths.
authorjvanverth <jvanverth@google.com>
Thu, 30 Oct 2014 12:57:21 +0000 (05:57 -0700)
committerCommit bot <commit-bot@chromium.org>
Thu, 30 Oct 2014 12:57:21 +0000 (05:57 -0700)
Adds miplevel as part of dfpath key, and scale factor so we know
how much to adjust to fit desired scale.

BUG=skia:2935

Review URL: https://codereview.chromium.org/687283002

expectations/gm/ignored-tests.txt
src/gpu/GrAADistanceFieldPathRenderer.cpp
src/gpu/GrAADistanceFieldPathRenderer.h

index 63d6a84..9b49b1a 100644 (file)
@@ -47,3 +47,12 @@ dropshadowimagefilter
 # senorblanco https://codereview.chromium.org/637283009/
 # quality improvements to imagemagnifier GM
 imagemagnifier
+
+# jvanverth https://codereview.chromium.org/687283002
+# multiple scaled versions for dfpaths
+nested_aa
+path-reverse
+pathfill
+pathopsinverse
+polygons
+rects
index 95675e4..fdd0f68 100755 (executable)
@@ -20,7 +20,7 @@
 #include "SkRTConf.h"
 
 #define ATLAS_TEXTURE_WIDTH 1024
-#define ATLAS_TEXTURE_HEIGHT 1024
+#define ATLAS_TEXTURE_HEIGHT 2048
 #define PLOT_WIDTH  256
 #define PLOT_HEIGHT 256
 
@@ -35,6 +35,11 @@ static int g_NumCachedPaths = 0;
 static int g_NumFreedPaths = 0;
 #endif
 
+// mip levels
+static const int kSmallMIP = 32;
+static const int kMediumMIP = 64;
+static const int kLargeMIP = 128;
+
 ////////////////////////////////////////////////////////////////////////////////
 GrAADistanceFieldPathRenderer::GrAADistanceFieldPathRenderer(GrContext* context)
     : fContext(context)
@@ -72,16 +77,19 @@ bool GrAADistanceFieldPathRenderer::canDrawPath(const SkPath& path,
         return false;
     }
 
-    // currently don't support perspective or scaling more than 3x
+    // currently don't support perspective
     const GrDrawState& drawState = target->getDrawState();
     const SkMatrix& vm = drawState.getViewMatrix();
-    if (vm.hasPerspective() || vm.getMaxScale() > 3.0f) {
+    if (vm.hasPerspective()) {
         return false;
     }
     
-    // only support paths smaller than 64 x 64
+    // only support paths smaller than 64x64, scaled to less than 256x256
+    // the goal is to accelerate rendering of lots of small paths that may be scaling
+    SkScalar maxScale = vm.getMaxScale();
     const SkRect& bounds = path.getBounds();
-    return bounds.width() < 64.f && bounds.height() < 64.f;
+    SkScalar maxDim = SkMaxScalar(bounds.width(), bounds.height());
+    return maxDim < 64.f && maxDim*maxScale < 256.f;
 }
 
 
@@ -112,11 +120,29 @@ bool GrAADistanceFieldPathRenderer::onDrawPath(const SkPath& path,
 
     SkASSERT(fContext);
 
+    // get mip level
+    const GrDrawState& drawState = target->getDrawState();
+    const SkMatrix& vm = drawState.getViewMatrix();
+    SkScalar maxScale = vm.getMaxScale();
+    const SkRect& bounds = path.getBounds();
+    SkScalar maxDim = SkMaxScalar(bounds.width(), bounds.height());
+    SkScalar size = maxScale*maxDim;
+    uint32_t desiredDimension;
+    if (size <= kSmallMIP) {
+        desiredDimension = kSmallMIP;
+    } else if (size <= kMediumMIP) {
+        desiredDimension = kMediumMIP;
+    } else {
+        desiredDimension = kLargeMIP;
+    }
+
     // check to see if path is cached
     // TODO: handle stroked vs. filled version of same path
-    PathData* pathData = fPathCache.find(path.getGenerationID());
+    PathData::Key key = { path.getGenerationID(), desiredDimension };
+    PathData* pathData = fPathCache.find(key);
     if (NULL == pathData) {
-        pathData = this->addPathToAtlas(path, stroke, antiAlias);
+        SkScalar scale = desiredDimension/maxDim;
+        pathData = this->addPathToAtlas(path, stroke, antiAlias, desiredDimension, scale);
         if (NULL == pathData) {
             return false;
         }
@@ -126,15 +152,15 @@ bool GrAADistanceFieldPathRenderer::onDrawPath(const SkPath& path,
     return this->internalDrawPath(path, pathData, target);
 }
 
-// factor used to scale the path prior to building distance field
-const SkScalar kScaleFactor = 2.0f;
 // padding around path bounds to allow for antialiased pixels
 const SkScalar kAntiAliasPad = 1.0f;
 
 GrAADistanceFieldPathRenderer::PathData* GrAADistanceFieldPathRenderer::addPathToAtlas(
                                                                         const SkPath& path,
                                                                         const SkStrokeRec& stroke,
-                                                                        bool antiAlias) {
+                                                                        bool antiAlias,
+                                                                        uint32_t dimension,
+                                                                        SkScalar scale) {
 
     // generate distance field and add to atlas
     if (NULL == fAtlas) {
@@ -151,11 +177,11 @@ GrAADistanceFieldPathRenderer::PathData* GrAADistanceFieldPathRenderer::addPathT
     
     // generate bounding rect for bitmap draw
     SkRect scaledBounds = bounds;
-    // scale up to improve maxification range
-    scaledBounds.fLeft *= kScaleFactor;
-    scaledBounds.fTop *= kScaleFactor;
-    scaledBounds.fRight *= kScaleFactor;
-    scaledBounds.fBottom *= kScaleFactor;
+    // scale to mip level size
+    scaledBounds.fLeft *= scale;
+    scaledBounds.fTop *= scale;
+    scaledBounds.fRight *= scale;
+    scaledBounds.fBottom *= scale;
     // move the origin to an integer boundary (gives better results)
     SkScalar dx = SkScalarFraction(scaledBounds.fLeft);
     SkScalar dy = SkScalarFraction(scaledBounds.fTop);
@@ -171,7 +197,7 @@ GrAADistanceFieldPathRenderer::PathData* GrAADistanceFieldPathRenderer::addPathT
     // draw path to bitmap
     SkMatrix drawMatrix;
     drawMatrix.setTranslate(-bounds.left(), -bounds.top());
-    drawMatrix.postScale(kScaleFactor, kScaleFactor);
+    drawMatrix.postScale(scale, scale);
     drawMatrix.postTranslate(kAntiAliasPad, kAntiAliasPad);
     GrSWMaskHelper helper(fContext);
     
@@ -226,7 +252,9 @@ GrAADistanceFieldPathRenderer::PathData* GrAADistanceFieldPathRenderer::addPathT
 HAS_ATLAS:
     // add to cache
     PathData* pathData = SkNEW(PathData);
-    pathData->fGenID = path.getGenerationID();
+    pathData->fKey.fGenID = path.getGenerationID();
+    pathData->fKey.fDimension = dimension;
+    pathData->fScale = scale;
     pathData->fPlot = plot;
     // change the scaled rect to match the size of the inset distance field
     scaledBounds.fRight = scaledBounds.fLeft +
@@ -267,7 +295,7 @@ bool GrAADistanceFieldPathRenderer::freeUnusedPlot() {
     while ((pathData = iter.get())) {
         iter.next();
         if (plot == pathData->fPlot) {
-            fPathCache.remove(pathData->fGenID);
+            fPathCache.remove(pathData->fKey);
             fPathList.remove(pathData);
             SkDELETE(pathData);
 #ifdef DF_PATH_TRACKING
@@ -305,7 +333,7 @@ bool GrAADistanceFieldPathRenderer::internalDrawPath(const SkPath& path,
     SkScalar width = pathData->fBounds.width();
     SkScalar height = pathData->fBounds.height();
     
-    SkScalar invScale = 1.0f/kScaleFactor;
+    SkScalar invScale = 1.0f/pathData->fScale;
     dx *= invScale;
     dy *= invScale;
     width *= invScale;
index 40430bb..10f0eba 100755 (executable)
@@ -41,18 +41,27 @@ protected:
 
 private:
     struct PathData {
-        uint32_t   fGenID;
+        struct Key {
+            uint32_t   fGenID;
+            // rendered size for stored path (32x32 max, 64x64 max, 128x128 max)
+            uint32_t   fDimension;
+            bool operator==(const Key& other) const {
+                return other.fGenID == fGenID && other.fDimension == fDimension;
+            }
+        };
+        Key        fKey;
+        SkScalar   fScale;
         GrPlot*    fPlot;
         SkRect     fBounds;
         SkIPoint16 fAtlasLocation;
         SK_DECLARE_INTERNAL_LLIST_INTERFACE(PathData);
         
-        static inline const uint32_t& GetKey(const PathData& data) {
-            return data.fGenID;
+        static inline const Key& GetKey(const PathData& data) {
+            return data.fKey;
         }
         
-        static inline uint32_t Hash(uint32_t key) {
-            return SkChecksum::Murmur3(&key, sizeof(key));
+        static inline uint32_t Hash(Key key) {
+            return SkChecksum::Murmur3(reinterpret_cast<const uint32_t*>(&key), sizeof(key));
         }
     };
     typedef SkTInternalLList<PathData> PathDataList;
@@ -63,11 +72,12 @@ private:
     // current set of flags used to create the cached geometry processor
     uint32_t                           fEffectFlags;
     GrAtlas::ClientPlotUsage           fPlotUsage;
-    SkTDynamicHash<PathData, uint32_t> fPathCache;
+    SkTDynamicHash<PathData, PathData::Key> fPathCache;
     PathDataList                       fPathList;
     
     bool internalDrawPath(const SkPath& path, const PathData* pathData, GrDrawTarget* target);
-    PathData* addPathToAtlas(const SkPath& path, const SkStrokeRec& stroke, bool antiAlias);
+    PathData* addPathToAtlas(const SkPath& path, const SkStrokeRec& stroke, bool antiAlias,
+                             uint32_t dimension, SkScalar scale);
     bool freeUnusedPlot();
     
     typedef GrPathRenderer INHERITED;