From 33ab199838791c9b3b7a29a342014ea4716fdd27 Mon Sep 17 00:00:00 2001 From: Jasper van de Gronde Date: Sat, 2 Apr 2011 17:31:36 +0200 Subject: Faster rounding for Gaussian blur (bzr r10144) --- src/display/nr-filter-gaussian.cpp | 43 ++++++++++++++++++++++++++++++++------ 1 file changed, 37 insertions(+), 6 deletions(-) diff --git a/src/display/nr-filter-gaussian.cpp b/src/display/nr-filter-gaussian.cpp index 3f7bea35d..9b83c8647 100644 --- a/src/display/nr-filter-gaussian.cpp +++ b/src/display/nr-filter-gaussian.cpp @@ -78,15 +78,46 @@ template static inline T clip(T const& v, T const& a, T const& b) { } template -static inline Tt round_cast(Ts const& v) { +static inline Tt round_cast(Ts v) { static Ts const rndoffset(.5); return static_cast(v+rndoffset); } +template<> +inline unsigned char round_cast(double v) { + // This (fast) rounding method is based on: + // http://stereopsis.com/sree/fpu2006.html +#if G_BYTE_ORDER==G_LITTLE_ENDIAN + double const dmr = 6755399441055744.0; + v = v + dmr; + return ((unsigned char*)&v)[0]; +#elif G_BYTE_ORDER==G_BIG_ENDIAN + double const dmr = 6755399441055744.0; + v = v + dmr; + return ((unsigned char*)&v)[7]; +#else + static double const rndoffset(.5); + return static_cast(v+rndoffset); +#endif +} + +template +static inline Tt clip_round_cast(Ts const v) { + Ts const minval = std::numeric_limits::min(); + Ts const maxval = std::numeric_limits::max(); + Tt const minval_rounded = std::numeric_limits::min(); + Ts const maxval_rounded = std::numeric_limits::max(); + if ( v < minval ) return minval_rounded; + if ( v > maxval ) return maxval_rounded; + return round_cast(v); +} + template -static inline Tt clip_round_cast(Ts const& v, Tt const minval=std::numeric_limits::min(), Tt const maxval=std::numeric_limits::max()) { - if ( v < minval ) return minval; - if ( v > maxval ) return maxval; +static inline Tt clip_round_cast_varmax(Ts const v, Ts const maxval, Tt const maxval_rounded) { + Ts const minval = std::numeric_limits::min(); + Tt const minval_rounded = std::numeric_limits::min(); + if ( v < minval ) return minval_rounded; + if ( v > maxval ) return maxval_rounded; return round_cast(v); } @@ -320,7 +351,7 @@ filter2D_IIR(PT *const dest, int const dstr1, int const dstr2, dstimg -= dstr1; if ( PREMULTIPLIED_ALPHA ) { dstimg[PC-1] = clip_round_cast(v[0][PC-1]); - for(unsigned int c=0; c(v[0][c], std::numeric_limits::min(), dstimg[PC-1]); + for(unsigned int c=0; c(v[0][c], v[0][PC-1], dstimg[PC-1]); } else { for(unsigned int c=0; c(v[0][c]); } @@ -335,7 +366,7 @@ filter2D_IIR(PT *const dest, int const dstr1, int const dstr2, dstimg -= dstr1; if ( PREMULTIPLIED_ALPHA ) { dstimg[PC-1] = clip_round_cast(v[0][PC-1]); - for(unsigned int c=0; c(v[0][c], std::numeric_limits::min(), dstimg[PC-1]); + for(unsigned int c=0; c(v[0][c], v[0][PC-1], dstimg[PC-1]); } else { for(unsigned int c=0; c(v[0][c]); } -- cgit v1.2.3