Bug 996108 - Use even rounding for better results when converting from scalar to fdot6 r=upstream
authorJeff Muizelaar <jmuizelaar@mozilla.com>
Tue, 02 Sep 2014 12:15:27 -0400
changeset 203293 ce39df5dccdb5f0a1398761df6ca15e2ab65ef60
parent 203292 d45a41039ece71eaafb0e2cdbbf385b80369e884
child 203294 c8d299030e1d98f8a615cccecaf7348e75417628
push id27425
push userryanvm@gmail.com
push dateWed, 03 Sep 2014 20:38:59 +0000
treeherdermozilla-central@acbdce59da2f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersupstream
bugs996108
milestone35.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 996108 - Use even rounding for better results when converting from scalar to fdot6 r=upstream
gfx/skia/trunk/src/core/SkEdge.cpp
gfx/skia/trunk/src/core/SkEdge.h
gfx/skia/trunk/src/core/SkFDot6.h
--- a/gfx/skia/trunk/src/core/SkEdge.cpp
+++ b/gfx/skia/trunk/src/core/SkEdge.cpp
@@ -31,21 +31,28 @@ static inline SkFixed SkFDot6ToFixedDiv2
 
 /////////////////////////////////////////////////////////////////////////
 
 int SkEdge::setLine(const SkPoint& p0, const SkPoint& p1, const SkIRect* clip,
                     int shift) {
     SkFDot6 x0, y0, x1, y1;
 
     {
+#ifdef SK_RASTERIZE_EVEN_ROUNDING
+        x0 = SkScalarRoundToFDot6(p0.fX, shift);
+        y0 = SkScalarRoundToFDot6(p0.fY, shift);
+        x1 = SkScalarRoundToFDot6(p1.fX, shift);
+        y1 = SkScalarRoundToFDot6(p1.fY, shift);
+#else
         float scale = float(1 << (shift + 6));
         x0 = int(p0.fX * scale);
         y0 = int(p0.fY * scale);
         x1 = int(p1.fX * scale);
         y1 = int(p1.fY * scale);
+#endif
     }
 
     int winding = 1;
 
     if (y0 > y1) {
         SkTSwap(x0, x1);
         SkTSwap(y0, y1);
         winding = -1;
@@ -166,23 +173,32 @@ static inline int diff_to_shift(SkFDot6 
     return (32 - SkCLZ(dist)) >> 1;
 }
 
 int SkQuadraticEdge::setQuadratic(const SkPoint pts[3], int shift)
 {
     SkFDot6 x0, y0, x1, y1, x2, y2;
 
     {
+#ifdef SK_RASTERIZE_EVEN_ROUNDING
+        x0 = SkScalarRoundToFDot6(pts[0].fX, shift);
+        y0 = SkScalarRoundToFDot6(pts[0].fY, shift);
+        x1 = SkScalarRoundToFDot6(pts[1].fX, shift);
+        y1 = SkScalarRoundToFDot6(pts[1].fY, shift);
+        x2 = SkScalarRoundToFDot6(pts[2].fX, shift);
+        y2 = SkScalarRoundToFDot6(pts[2].fY, shift);
+#else
         float scale = float(1 << (shift + 6));
         x0 = int(pts[0].fX * scale);
         y0 = int(pts[0].fY * scale);
         x1 = int(pts[1].fX * scale);
         y1 = int(pts[1].fY * scale);
         x2 = int(pts[2].fX * scale);
         y2 = int(pts[2].fY * scale);
+#endif
     }
 
     int winding = 1;
     if (y0 > y2)
     {
         SkTSwap(x0, x2);
         SkTSwap(y0, y2);
         winding = -1;
@@ -316,25 +332,36 @@ static SkFDot6 cubic_delta_from_line(SkF
     return SkMax32(SkAbs32(oneThird), SkAbs32(twoThird));
 }
 
 int SkCubicEdge::setCubic(const SkPoint pts[4], const SkIRect* clip, int shift)
 {
     SkFDot6 x0, y0, x1, y1, x2, y2, x3, y3;
 
     {
+#ifdef SK_RASTERIZE_EVEN_ROUNDING
+        x0 = SkScalarRoundToFDot6(pts[0].fX, shift);
+        y0 = SkScalarRoundToFDot6(pts[0].fY, shift);
+        x1 = SkScalarRoundToFDot6(pts[1].fX, shift);
+        y1 = SkScalarRoundToFDot6(pts[1].fY, shift);
+        x2 = SkScalarRoundToFDot6(pts[2].fX, shift);
+        y2 = SkScalarRoundToFDot6(pts[2].fY, shift);
+        x3 = SkScalarRoundToFDot6(pts[3].fX, shift);
+        y3 = SkScalarRoundToFDot6(pts[3].fY, shift);
+#else
         float scale = float(1 << (shift + 6));
         x0 = int(pts[0].fX * scale);
         y0 = int(pts[0].fY * scale);
         x1 = int(pts[1].fX * scale);
         y1 = int(pts[1].fY * scale);
         x2 = int(pts[2].fX * scale);
         y2 = int(pts[2].fY * scale);
         x3 = int(pts[3].fX * scale);
         y3 = int(pts[3].fY * scale);
+#endif
     }
 
     int winding = 1;
     if (y0 > y3)
     {
         SkTSwap(x0, x3);
         SkTSwap(x1, x2);
         SkTSwap(y0, y3);
--- a/gfx/skia/trunk/src/core/SkEdge.h
+++ b/gfx/skia/trunk/src/core/SkEdge.h
@@ -84,21 +84,28 @@ struct SkCubicEdge : public SkEdge {
     int setCubic(const SkPoint pts[4], const SkIRect* clip, int shiftUp);
     int updateCubic();
 };
 
 int SkEdge::setLine(const SkPoint& p0, const SkPoint& p1, int shift) {
     SkFDot6 x0, y0, x1, y1;
 
     {
+#ifdef SK_RASTERIZE_EVEN_ROUNDING
+        x0 = SkScalarRoundToFDot6(p0.fX, shift);
+        y0 = SkScalarRoundToFDot6(p0.fY, shift);
+        x1 = SkScalarRoundToFDot6(p1.fX, shift);
+        y1 = SkScalarRoundToFDot6(p1.fY, shift);
+#else
         float scale = float(1 << (shift + 6));
         x0 = int(p0.fX * scale);
         y0 = int(p0.fY * scale);
         x1 = int(p1.fX * scale);
         y1 = int(p1.fY * scale);
+#endif
     }
 
     int winding = 1;
 
     if (y0 > y1) {
         SkTSwap(x0, x1);
         SkTSwap(y0, y1);
         winding = -1;
--- a/gfx/skia/trunk/src/core/SkFDot6.h
+++ b/gfx/skia/trunk/src/core/SkFDot6.h
@@ -10,16 +10,38 @@
 #ifndef SkFDot6_DEFINED
 #define SkFDot6_DEFINED
 
 #include "SkScalar.h"
 #include "SkMath.h"
 
 typedef int32_t SkFDot6;
 
+/* This uses the magic number approach suggested here:
+ * http://stereopsis.com/sree/fpu2006.html and used in
+ * _cairo_fixed_from_double. It does banker's rounding
+ * (i.e. round to nearest even)
+ */
+inline SkFDot6 SkScalarRoundToFDot6(SkScalar x, int shift = 0)
+{
+    union {
+        double  fDouble;
+        int32_t fBits[2];
+    } tmp;
+    int fractionalBits = 6 + shift;
+    double magic = (1LL << (52 - (fractionalBits))) * 1.5;
+
+    tmp.fDouble = SkScalarToDouble(x) + magic;
+#ifdef SK_CPU_BENDIAN
+    return tmp.fBits[1];
+#else
+    return tmp.fBits[0];
+#endif
+}
+
 #define SK_FDot6One         (64)
 #define SK_FDot6Half        (32)
 
 #ifdef SK_DEBUG
     inline SkFDot6 SkIntToFDot6(S16CPU x) {
         SkASSERT(SkToS16(x) == x);
         return x << 6;
     }