Improve quad edges' smoothness in non-AA cases

Previously, non-AA quad edges only have an accuracy about 1/2 pixel
(while the AA quad edges have an accuracy about 1/8 pixel).  Now, we
increase non-AA quad edges' accuracy to 1/8 pixel as well.

The difference is very significant for rotating non-AA filled circles.
For example, run `./out/Debug/SampleApp --slide GM:fillcircle` with AA
turned off (by pressing b).

The benchmark added reveals that increasing quad accuracy from 1/2 to
1/8 doesn't affect the performance significantly. The following is the
1/2-accuracy performance versus 1/8-accuracy performance:

curr/maxrss     loops   min     median  mean    max     stddev  samples
config  bench
7/17  MB        19      2.43µs  2.57µs  2.81µs  10.5µs  22%     16119
8888    path_fill_big_nonaacircle
7/17  MB        17      1.38µs  1.42µs  1.52µs  13µs    20%     21409
8888    path_fill_small_nonaacircle

curr/maxrss     loops   min     median  mean    max     stddev  samples
config  bench
7/17  MB        71      2.52µs  2.59µs  2.79µs  7.67µs  19%     7557
8888    path_fill_big_nonaacircle
7/17  MB        64      1.45µs  1.49µs  1.51µs  2.39µs  5%      12704
8888    path_fill_small_nonaacircle


BUG=skia:

Change-Id: I3482098aeafcc6f2ec9aa3382977c0dc1b650964
Reviewed-on: https://skia-review.googlesource.com/6699
Reviewed-by: Mike Reed <reed@google.com>
Commit-Queue: Yuqian Li <liyuqian@google.com>
This commit is contained in:
Yuqian Li 2017-01-06 16:31:46 -05:00 committed by Skia Commit-Bot
parent 2e2cb9bc76
commit d4ed326d6f
2 changed files with 32 additions and 3 deletions

View File

@ -173,6 +173,23 @@ private:
typedef PathBench INHERITED; typedef PathBench INHERITED;
}; };
class NonAACirclePathBench: public CirclePathBench {
public:
NonAACirclePathBench(Flags flags) : INHERITED(flags) {}
void appendName(SkString* name) override {
name->append("nonaacircle");
}
void setupPaint(SkPaint* paint) override {
CirclePathBench::setupPaint(paint);
paint->setAntiAlias(false);
}
private:
typedef CirclePathBench INHERITED;
};
// Test max speedup of Analytic AA for concave paths // Test max speedup of Analytic AA for concave paths
class AAAConcavePathBench : public PathBench { class AAAConcavePathBench : public PathBench {
public: public:
@ -1090,6 +1107,9 @@ DEF_BENCH( return new CirclePathBench(FLAGS01); )
DEF_BENCH( return new CirclePathBench(FLAGS10); ) DEF_BENCH( return new CirclePathBench(FLAGS10); )
DEF_BENCH( return new CirclePathBench(FLAGS11); ) DEF_BENCH( return new CirclePathBench(FLAGS11); )
DEF_BENCH( return new NonAACirclePathBench(FLAGS00); )
DEF_BENCH( return new NonAACirclePathBench(FLAGS10); )
DEF_BENCH( return new AAAConcavePathBench(FLAGS00); ) DEF_BENCH( return new AAAConcavePathBench(FLAGS00); )
DEF_BENCH( return new AAAConcavePathBench(FLAGS10); ) DEF_BENCH( return new AAAConcavePathBench(FLAGS10); )
DEF_BENCH( return new AAAConvexPathBench(FLAGS00); ) DEF_BENCH( return new AAAConvexPathBench(FLAGS00); )

View File

@ -157,16 +157,22 @@ static inline SkFDot6 cheap_distance(SkFDot6 dx, SkFDot6 dy)
return dx; return dx;
} }
static inline int diff_to_shift(SkFDot6 dx, SkFDot6 dy) static inline int diff_to_shift(SkFDot6 dx, SkFDot6 dy, int shiftAA = 2)
{ {
// cheap calc of distance from center of p0-p2 to the center of the curve // cheap calc of distance from center of p0-p2 to the center of the curve
SkFDot6 dist = cheap_distance(dx, dy); SkFDot6 dist = cheap_distance(dx, dy);
// shift down dist (it is currently in dot6) // shift down dist (it is currently in dot6)
// down by 5 should give us 1/2 pixel accuracy (assuming our dist is accurate...) // down by 3 should give us 1/8 pixel accuracy (assuming our dist is accurate...)
// this is chosen by heuristic: make it as big as possible (to minimize segments) // this is chosen by heuristic: make it as big as possible (to minimize segments)
// ... but small enough so that our curves still look smooth // ... but small enough so that our curves still look smooth
// When shift > 0, we're using AA and everything is scaled up so we can
// lower the accuracy.
#ifdef SK_SUPPORT_LEGACY_QUAD_SHIFT
dist = (dist + (1 << 4)) >> 5; dist = (dist + (1 << 4)) >> 5;
#else
dist = (dist + (1 << 4)) >> (3 + shiftAA);
#endif
// each subdivision (shift value) cuts this dist (error) by 1/4 // each subdivision (shift value) cuts this dist (error) by 1/4
return (32 - SkCLZ(dist)) >> 1; return (32 - SkCLZ(dist)) >> 1;
@ -214,7 +220,10 @@ bool SkQuadraticEdge::setQuadraticWithoutUpdate(const SkPoint pts[3], int shift)
{ {
SkFDot6 dx = (SkLeftShift(x1, 1) - x0 - x2) >> 2; SkFDot6 dx = (SkLeftShift(x1, 1) - x0 - x2) >> 2;
SkFDot6 dy = (SkLeftShift(y1, 1) - y0 - y2) >> 2; SkFDot6 dy = (SkLeftShift(y1, 1) - y0 - y2) >> 2;
shift = diff_to_shift(dx, dy); // This is a little confusing:
// before this line, shift is the scale up factor for AA;
// after this line, shift is the fCurveShift.
shift = diff_to_shift(dx, dy, shift);
SkASSERT(shift >= 0); SkASSERT(shift >= 0);
} }
// need at least 1 subdivision for our bias trick // need at least 1 subdivision for our bias trick