From fb0f3526ce46070bbf71f4c6bf745d6ef1f5e4c1 Mon Sep 17 00:00:00 2001 From: Jeff Muizelaar Date: Tue, 2 Sep 2014 12:15:27 -0400 Subject: [PATCH] Bug 996108 - Use even rounding for better results when converting from scalar to fdot6 r=upstream --- gfx/skia/trunk/src/core/SkEdge.cpp | 27 +++++++++++++++++++++++++++ gfx/skia/trunk/src/core/SkEdge.h | 7 +++++++ gfx/skia/trunk/src/core/SkFDot6.h | 22 ++++++++++++++++++++++ 3 files changed, 56 insertions(+) diff --git a/gfx/skia/trunk/src/core/SkEdge.cpp b/gfx/skia/trunk/src/core/SkEdge.cpp index 9ce255843f66..dd5ab5fbc62f 100644 --- a/gfx/skia/trunk/src/core/SkEdge.cpp +++ b/gfx/skia/trunk/src/core/SkEdge.cpp @@ -36,11 +36,18 @@ int SkEdge::setLine(const SkPoint& p0, const SkPoint& p1, const SkIRect* clip, 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; @@ -171,6 +178,14 @@ 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); @@ -178,6 +193,7 @@ int SkQuadraticEdge::setQuadratic(const SkPoint pts[3], int shift) y1 = int(pts[1].fY * scale); x2 = int(pts[2].fX * scale); y2 = int(pts[2].fY * scale); +#endif } int winding = 1; @@ -321,6 +337,16 @@ 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); @@ -330,6 +356,7 @@ int SkCubicEdge::setCubic(const SkPoint pts[4], const SkIRect* clip, int shift) y2 = int(pts[2].fY * scale); x3 = int(pts[3].fX * scale); y3 = int(pts[3].fY * scale); +#endif } int winding = 1; diff --git a/gfx/skia/trunk/src/core/SkEdge.h b/gfx/skia/trunk/src/core/SkEdge.h index 091223631fed..67a0ee787604 100644 --- a/gfx/skia/trunk/src/core/SkEdge.h +++ b/gfx/skia/trunk/src/core/SkEdge.h @@ -89,11 +89,18 @@ 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; diff --git a/gfx/skia/trunk/src/core/SkFDot6.h b/gfx/skia/trunk/src/core/SkFDot6.h index 5a0ec57f5954..3da753da4131 100644 --- a/gfx/skia/trunk/src/core/SkFDot6.h +++ b/gfx/skia/trunk/src/core/SkFDot6.h @@ -15,6 +15,28 @@ 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)