From 0048a26a4477d3acb5dd0231756cfaae92d240a9 Mon Sep 17 00:00:00 2001 From: Vladimir Vukicevic Date: Mon, 18 Jun 2007 16:26:14 -0700 Subject: [PATCH] [fixpt] Make fixed point methods static inline and generic Move the fixed point methods to static inline versions in cairo-fixed-private.h, and don't hardcode fixed to be 16.16. --- src/cairo-fixed-private.h | 256 +++++++++++++++++++++++++++++++++++++ src/cairo-fixed.c | 100 +-------------- src/cairo-quartz-surface.c | 2 +- src/cairoint.h | 37 +----- 4 files changed, 259 insertions(+), 136 deletions(-) create mode 100644 src/cairo-fixed-private.h diff --git a/src/cairo-fixed-private.h b/src/cairo-fixed-private.h new file mode 100644 index 000000000..333a60b37 --- /dev/null +++ b/src/cairo-fixed-private.h @@ -0,0 +1,256 @@ +/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */ +/* Cairo - a vector graphics library with display and print output + * + * Copyright © 2007 Mozilla Corporation + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Mozilla Corporation + * + * Contributor(s): + * Vladimir Vukicevic + */ + +#ifndef CAIRO_FIXED_PRIVATE_H +#define CAIRO_FIXED_PRIVATE_H + +#include "cairo-wideint-private.h" + +/* + * Fixed-point configuration + */ + +typedef int32_t cairo_fixed_16_16_t; +typedef cairo_int64_t cairo_fixed_32_32_t; +typedef cairo_int64_t cairo_fixed_48_16_t; +typedef cairo_int128_t cairo_fixed_64_64_t; +typedef cairo_int128_t cairo_fixed_96_32_t; + +/* Eventually, we should allow changing this, but I think + * there are some assumptions in the tesselator about the + * size of a fixed type. + */ +#define CAIRO_FIXED_BITS 32 + +/* The number of fractional bits. Changing this involves + * making sure that you compute a double-to-fixed magic number. + * (see below). + */ +#define CAIRO_FIXED_FRAC_BITS 16 + +/* A signed type CAIRO_FIXED_BITS in size; the main fixed point type */ +typedef int32_t cairo_fixed_t; + +/* An unsigned type of the same size as cairo_fixed_t */ +typedef uint32_t cairo_fixed_unsigned_t; + +/* + * No configurable bits below this. + */ + + +#if (CAIRO_FIXED_BITS != 32) +# error CAIRO_FIXED_BITS must be 32, and the type must be a 32-bit type. +# error To remove this limitation, you will have to fix the tesselator. +#endif + +#define CAIRO_FIXED_ONE ((cairo_fixed_t)(1 << CAIRO_FIXED_FRAC_BITS)) +#define CAIRO_FIXED_ONE_DOUBLE ((double)(1 << CAIRO_FIXED_FRAC_BITS)) +#define CAIRO_FIXED_EPSILON ((cairo_fixed_t)(1)) + +#define CAIRO_FIXED_FRAC_MASK (((cairo_fixed_unsigned_t)(-1)) >> (CAIRO_FIXED_BITS - CAIRO_FIXED_FRAC_BITS)) +#define CAIRO_FIXED_WHOLE_MASK (~CAIRO_FIXED_FRAC_MASK) + +static inline cairo_fixed_t +_cairo_fixed_from_int (int i) +{ + return i << CAIRO_FIXED_FRAC_BITS; +} + +/* This is the "magic number" approach to converting a double into fixed + * point as described here: + * + * http://www.stereopsis.com/sree/fpu2006.html (an overview) + * http://www.d6.com/users/checker/pdfs/gdmfp.pdf (in detail) + * + * The basic idea is to add a large enough number to the double that the + * literal floating point is moved up to the extent that it forces the + * double's value to be shifted down to the bottom of the mantissa (to make + * room for the large number being added in). Since the mantissa is, at a + * given moment in time, a fixed point integer itself, one can convert a + * float to various fixed point representations by moving around the point + * of a floating point number through arithmetic operations. This behavior + * is reliable on most modern platforms as it is mandated by the IEEE-754 + * standard for floating point arithmetic. + * + * For our purposes, a "magic number" must be carefully selected that is + * both large enough to produce the desired point-shifting effect, and also + * has no lower bits in its representation that would interfere with our + * value at the bottom of the mantissa. The magic number is calculated as + * follows: + * + * (2 ^ (MANTISSA_SIZE - FRACTIONAL_SIZE)) * 1.5 + * + * where in our case: + * - MANTISSA_SIZE for 64-bit doubles is 52 + * - FRACTIONAL_SIZE for 16.16 fixed point is 16 + * + * Although this approach provides a very large speedup of this function + * on a wide-array of systems, it does come with two caveats: + * + * 1) It uses banker's rounding as opposed to arithmetic rounding. + * 2) It doesn't function properly if the FPU is in single-precision + * mode. + */ + +/* The 16.16 number must always be available */ +#define CAIRO_MAGIC_NUMBER_FIXED_16_16 (103079215104.0) + +#if CAIRO_FIXED_BITS == 32 + +# if CAIRO_FIXED_FRAC_BITS == 16 +# define CAIRO_MAGIC_NUMBER_FIXED CAIRO_MAGIC_NUMBER_FIXED_16_16 +# elif CAIRO_FIXED_FRAC_BITS == 8 +# define CAIRO_MAGIC_NUMBER_FIXED (26388279066624.0) +# elif CAIRO_FIXED_FRAC_BITS == 6 +# define CAIRO_MAGIC_NUMBER_FIXED (105553116266496.0) +# else +# error Please define a magic number for your fixed point type! +# error See cairo-fixed-private.h for details. +# endif + +/* For 32-bit fixed point numbers */ +static inline cairo_fixed_t +_cairo_fixed_from_double (double d) +{ + union { + double d; + int32_t i[2]; + } u; + + u.d = d + CAIRO_MAGIC_NUMBER_FIXED; +#ifdef FLOAT_WORDS_BIGENDIAN + return u.i[1]; +#else + return u.i[0]; +#endif +} + +#else +# error Please define a magic number for your fixed point type! +# error See cairo-fixed-private.h for details. +#endif + +static inline cairo_fixed_t +_cairo_fixed_from_26_6 (uint32_t i) +{ +#if CAIRO_FIXED_FRAC_BITS > 6 + return i << (CAIRO_FIXED_FRAC_BITS - 6); +#else + return i >> (6 - CAIRO_FIXED_FRAC_BITS); +#endif +} + +static inline double +_cairo_fixed_to_double (cairo_fixed_t f) +{ + return ((double) f) / CAIRO_FIXED_ONE_DOUBLE; +} + +static inline int +_cairo_fixed_is_integer (cairo_fixed_t f) +{ + return (f & CAIRO_FIXED_FRAC_MASK) == 0; +} + +static inline int +_cairo_fixed_integer_part (cairo_fixed_t f) +{ + return f >> CAIRO_FIXED_FRAC_BITS; +} + +static inline int +_cairo_fixed_integer_floor (cairo_fixed_t f) +{ + if (f >= 0) + return f >> CAIRO_FIXED_FRAC_BITS; + else + return -((-f - 1) >> CAIRO_FIXED_FRAC_BITS) - 1; +} + +static inline int +_cairo_fixed_integer_ceil (cairo_fixed_t f) +{ + if (f > 0) + return ((f - 1)>>CAIRO_FIXED_FRAC_BITS) + 1; + else + return - (-f >> CAIRO_FIXED_FRAC_BITS); +} + +/* A bunch of explicit 16.16 operators; we need these + * to interface with pixman and other backends that require + * 16.16 fixed point types. + */ +static inline cairo_fixed_16_16_t +_cairo_fixed_to_16_16 (cairo_fixed_t f) +{ +#if CAIRO_FIXED_FRAC_BITS > 16 + return f >> (CAIRO_FIXED_FRAC_BITS - 16); +#else + return f << (16 - CAIRO_FIXED_FRAC_BITS); +#endif +} + +static inline cairo_fixed_16_16_t +_cairo_fixed_16_16_from_double (double d) +{ + union { + double d; + int32_t i[2]; + } u; + + u.d = d + CAIRO_MAGIC_NUMBER_FIXED_16_16; +#ifdef FLOAT_WORDS_BIGENDIAN + return u.i[1]; +#else + return u.i[0]; +#endif +} + +#if CAIRO_FIXED_BITS == 32 + +static inline cairo_fixed_t +_cairo_fixed_mul (cairo_fixed_t a, cairo_fixed_t b) +{ + cairo_int64_t temp = _cairo_int32x32_64_mul (a, b); + return _cairo_int64_to_int32(_cairo_int64_rsl (temp, CAIRO_FIXED_FRAC_BITS)); +} + +#else +# error Please define multiplication and other operands for your fixed-point type size +#endif + +#endif /* CAIRO_FIXED_PRIVATE_H */ diff --git a/src/cairo-fixed.c b/src/cairo-fixed.c index fe6c2dc3e..2bb0dfe17 100644 --- a/src/cairo-fixed.c +++ b/src/cairo-fixed.c @@ -36,102 +36,4 @@ #include "cairoint.h" -cairo_fixed_t -_cairo_fixed_from_int (int i) -{ - return i << 16; -} - -/* This is the "magic number" approach to converting a double into fixed - * point as described here: - * - * http://www.stereopsis.com/sree/fpu2006.html (an overview) - * http://www.d6.com/users/checker/pdfs/gdmfp.pdf (in detail) - * - * The basic idea is to add a large enough number to the double that the - * literal floating point is moved up to the extent that it forces the - * double's value to be shifted down to the bottom of the mantissa (to make - * room for the large number being added in). Since the mantissa is, at a - * given moment in time, a fixed point integer itself, one can convert a - * float to various fixed point representations by moving around the point - * of a floating point number through arithmetic operations. This behavior - * is reliable on most modern platforms as it is mandated by the IEEE-754 - * standard for floating point arithmetic. - * - * For our purposes, a "magic number" must be carefully selected that is - * both large enough to produce the desired point-shifting effect, and also - * has no lower bits in its representation that would interfere with our - * value at the bottom of the mantissa. The magic number is calculated as - * follows: - * - * (2 ^ (MANTISSA_SIZE - FRACTIONAL_SIZE)) * 1.5 - * - * where in our case: - * - MANTISSA_SIZE for 64-bit doubles is 52 - * - FRACTIONAL_SIZE for 16.16 fixed point is 16 - * - * Although this approach provides a very large speedup of this function - * on a wide-array of systems, it does come with two caveats: - * - * 1) It uses banker's rounding as opposed to arithmetic rounding. - * 2) It doesn't function properly if the FPU is in single-precision - * mode. - */ -#define CAIRO_MAGIC_NUMBER_FIXED_16_16 (103079215104.0) -cairo_fixed_t -_cairo_fixed_from_double (double d) -{ - union { - double d; - int32_t i[2]; - } u; - - u.d = d + CAIRO_MAGIC_NUMBER_FIXED_16_16; -#ifdef FLOAT_WORDS_BIGENDIAN - return u.i[1]; -#else - return u.i[0]; -#endif -} - -cairo_fixed_t -_cairo_fixed_from_26_6 (uint32_t i) -{ - return i << 10; -} - -double -_cairo_fixed_to_double (cairo_fixed_t f) -{ - return ((double) f) / 65536.0; -} - -int -_cairo_fixed_is_integer (cairo_fixed_t f) -{ - return (f & 0xFFFF) == 0; -} - -int -_cairo_fixed_integer_part (cairo_fixed_t f) -{ - return f >> 16; -} - -int -_cairo_fixed_integer_floor (cairo_fixed_t f) -{ - if (f >= 0) - return f >> 16; - else - return -((-f - 1) >> 16) - 1; -} - -int -_cairo_fixed_integer_ceil (cairo_fixed_t f) -{ - if (f > 0) - return ((f - 1)>>16) + 1; - else - return - (-f >> 16); -} +#include "cairo-fixed-private.h" diff --git a/src/cairo-quartz-surface.c b/src/cairo-quartz-surface.c index 9911b4aab..c65b29940 100644 --- a/src/cairo-quartz-surface.c +++ b/src/cairo-quartz-surface.c @@ -282,7 +282,7 @@ static void ComputeGradientValue (void *info, const float *in, float *out) { float fdist = *in; /* 0.0 .. 1.0 */ - cairo_fixed_16_16_t fdist_fix = _cairo_fixed_from_double(*in); + cairo_fixed_t fdist_fix = _cairo_fixed_from_double(*in); cairo_gradient_pattern_t *grad = (cairo_gradient_pattern_t*) info; unsigned int i; diff --git a/src/cairoint.h b/src/cairoint.h index 4fd8a847a..96652976f 100644 --- a/src/cairoint.h +++ b/src/cairoint.h @@ -182,15 +182,7 @@ do { \ #include "cairo-mutex-private.h" #include "cairo-wideint-private.h" #include "cairo-malloc-private.h" - -typedef int32_t cairo_fixed_16_16_t; -typedef cairo_int64_t cairo_fixed_32_32_t; -typedef cairo_int64_t cairo_fixed_48_16_t; -typedef cairo_int128_t cairo_fixed_64_64_t; -typedef cairo_int128_t cairo_fixed_96_32_t; - -/* The common 16.16 format gets a shorter name */ -typedef cairo_fixed_16_16_t cairo_fixed_t; +#include "cairo-fixed-private.h" #define CAIRO_ALPHA_IS_OPAQUE(alpha) ((alpha) >= ((double)0xff00 / (double)0xffff)) #define CAIRO_ALPHA_SHORT_IS_OPAQUE(alpha) ((alpha) >= 0xff00) @@ -1114,33 +1106,6 @@ _cairo_restrict_value (double *value, double min, double max); cairo_private int _cairo_lround (double d); -/* cairo_fixed.c */ -cairo_private cairo_fixed_t -_cairo_fixed_from_int (int i); - -#define CAIRO_FIXED_ONE _cairo_fixed_from_int (1) - -cairo_private cairo_fixed_t -_cairo_fixed_from_double (double d); - -cairo_private cairo_fixed_t -_cairo_fixed_from_26_6 (uint32_t i); - -cairo_private double -_cairo_fixed_to_double (cairo_fixed_t f); - -cairo_private int -_cairo_fixed_is_integer (cairo_fixed_t f); - -cairo_private int -_cairo_fixed_integer_part (cairo_fixed_t f); - -cairo_private int -_cairo_fixed_integer_floor (cairo_fixed_t f); - -cairo_private int -_cairo_fixed_integer_ceil (cairo_fixed_t f); - /* cairo_gstate.c */ cairo_private cairo_status_t _cairo_gstate_init (cairo_gstate_t *gstate,