[cairo] MIPMAPPING cairo.

Jeff Muizelaar jeff at infidigm.net
Fri Oct 17 19:56:46 PDT 2008


Here's some initial, mostly superficial review:

On Tue, Oct 14, 2008 at 03:03:37PM -0400, Frédéric Plourde wrote:
> 
> diff --git a/pixman/pixman-compose.c b/pixman/pixman-compose.c
> index c583ea6..d3e74f1 100644
> --- a/pixman/pixman-compose.c
> +++ b/pixman/pixman-compose.c
> @@ -3,6 +3,7 @@
>   * Copyright ?? 2000 Keith Packard, member of The XFree86 Project, Inc.
>   *             2005 Lars Knoll & Zack Rusin, Trolltech
>   *             2008 Aaron Plattner, NVIDIA Corporation
> + *             2008 Frederic Plourde
>   *
>   * Permission to use, copy, modify, distribute, and sell this software and its
>   * documentation for any purpose is hereby granted without fee, provided that
> @@ -246,9 +247,10 @@ PIXMAN_COMPOSITE_RECT_GENERAL (const FbComposeData *data,
>      uint32_t *bits;
>      int32_t stride;
>      int xoff, yoff;
> +    pixman_fixed_t scaleX, scaleY;
>  
>      if (data->op == PIXMAN_OP_CLEAR)
> -        fetchSrc = NULL;
> +	fetchSrc = NULL;
>      else if (IS_SOURCE_IMAGE (data->src))
>      {
>  	fetchSrc = get_fetch_source_pict(wide);
> @@ -279,6 +281,40 @@ PIXMAN_COMPOSITE_RECT_GENERAL (const FbComposeData *data,
>  	else
>  	{
>  	    fetchSrc = get_fetch_transformed(wide);
> +
> +	    /* MIPMAPPING generation */
> +	    if ((bits->common.filter == PIXMAN_FILTER_BEST)      ||
> +		(bits->common.filter == PIXMAN_FILTER_NEAREST_MIPMAP_LINEAR) ||
> +		(bits->common.filter == PIXMAN_FILTER_LINEAR_MIPMAP_NEAREST) ||
> +		(bits->common.filter == PIXMAN_FILTER_LINEAR_MIPMAP_LINEAR) )
> +	    {
> +		bits->mipmap.has_mipmap  = TRUE;
> +
> +		/* check if we have a downscale */
> +		pixman_get_transformed_axis(data->src->common.transform->matrix, &scaleX, &scaleY);
> +		if ((scaleX > pixman_fixed_1) || (scaleY > pixman_fixed_1)) {
> +		    /* Build the mipmap pyramid if not generated yet */
> +		    if (!bits->mipmap.is_generated) {
> +			pixman_build_mipmap(bits);
> +			bits->mipmap.is_generated = TRUE;
> +		    }
> +
> +		    bits->mipmap.destWidth  = pixman_int_to_fixed(data->width);
> +		    bits->mipmap.destHeight = pixman_int_to_fixed(data->height);
> +
> +		    /* Find mipmap levels */
> +		    if (bits->common.filter == PIXMAN_FILTER_LINEAR_MIPMAP_NEAREST ||
> +			bits->common.filter == PIXMAN_FILTER_LINEAR_MIPMAP_LINEAR  ||
> +			bits->common.filter == PIXMAN_FILTER_BEST) {
> +			    pixman_get_mipmap_levels (bits, 1);
> +		    } else {
> +			pixman_get_mipmap_levels (bits, 2);
> +		    }
> +		} else {
> +		    /* fallback to regular bilinear filtering mode if upscaling */
> +		    bits->common.filter = PIXMAN_FILTER_BILINEAR;
> +		}
> +	    }
>  	}
>      }
>  
> diff --git a/pixman/pixman-image.c b/pixman/pixman-image.c
> index e80c479..f845c04 100644
> --- a/pixman/pixman-image.c
> +++ b/pixman/pixman-image.c
> @@ -1,6 +1,7 @@
>  /*
>   * Copyright ?? 2000 SuSE, Inc.
>   * Copyright ?? 2007 Red Hat, Inc.
> + * Copyright ?? 2008 Frederic Plourde
>   *
>   * Permission to use, copy, modify, distribute, and sell this software and its
>   * documentation for any purpose is hereby granted without fee, provided that
> @@ -145,9 +146,12 @@ pixman_image_unref (pixman_image_t *image)
>  		free (image->gradient.stops);
>  	}
>  
> +	if (image->type == BITS) {
> +	    if (image->bits.free_me)
> +		free (image->bits.free_me);
>  
> -	if (image->type == BITS && image->bits.free_me)
> -	    free (image->bits.free_me);
> +	    pixman_free_mipmap((bits_image_t*)image);
> +	}
>  
>  	free (image);
>  
> @@ -378,6 +382,9 @@ pixman_image_create_bits (pixman_format_code_t  format,
>  								  */
>      image->bits.indexed = NULL;
>  
> +    image->bits.mipmap.has_mipmap   = FALSE;
> +    image->bits.mipmap.is_generated = FALSE;
> +
>      pixman_region32_fini (&image->common.full_region);
>      pixman_region32_init_rect (&image->common.full_region, 0, 0,
>  			       image->bits.width, image->bits.height);
> diff --git a/pixman/pixman-mipmap.c b/pixman/pixman-mipmap.c
> new file mode 100644
> index 0000000..607c5b1
> --- /dev/null
> +++ b/pixman/pixman-mipmap.c
> @@ -0,0 +1,317 @@
> +/*
> +* Copyright ? 2008 Frederic Plourde
> +*
> +* Permission to use, copy, modify, distribute, and sell this software and its
> +* documentation for any purpose is hereby granted without fee, provided that
> +* the above copyright notice appear in all copies and that both that
> +* copyright notice and this permission notice appear in supporting
> +* documentation, and that the name of Keith Packard not be used in
> +* advertising or publicity pertaining to distribution of the software without
> +* specific, written prior permission.  Keith Packard makes no
> +* representations about the suitability of this software for any purpose.  It
> +* is provided "as is" without express or implied warranty.
> +*
> +* THE COPYRIGHT HOLDER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
> +* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
> +* FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
> +* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
> +* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
> +* AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
> +* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
> +* SOFTWARE.
> +*
> +* NOTE:
> +* This mipmaping code will only work fine with AFFINE transformations !
> +* In the non_affine case (projective transformations), I'll be more than
> +* happy to receive your input.
> +*
> +*/
> +
> +#ifdef HAVE_CONFIG_H
> +#include <config.h>
> +#endif
> +
> +#include "pixman-private.h"
> +
> +#define MIN(a,b) ((a) < (b) ? (a) : (b))
> +
> +/*
> +* this function assumes x is already a power of 2 (and x != 0)
> +*/
> +static inline int
> +whichPowerOf2 (int x)
> +{
> +    int c = 0;
> +
> +    x = x >> 1;
> +    while (x) {
> +	c++;
> +	x = x >> 1;
> +    }
> +    return c;
> +}
> +
> +/*
> +* Returns the next power of two > x.
> +* If x is already a power of two, x is returned
> +*/
> +static inline int
> +upperPowerOf2 (int x)
> +{
> +    int c = 1;
> +    int b = x;
> +
> +    if (!x) {
> +	return 1;
> +    } else if (x & (x-1)) {
> +	b = b >> 1;
> +	while (b) {
> +	    c++;
> +	    b = b >> 1;
> +	}
> +	return (1 << c);
> +    } else {
> +	return x;
> +    }
> +}
> +
> +/*
> +* Returns the nearest power of two
> +*/
> +static inline int
> +nearestPowerOf2 (int x)
> +{
> +    int c = 1;
> +    int b = x;
> +    int p1, p2;
> +
> +    if (!x) {
> +	return 1;
> +    } else if (x & (x-1)) {
> +	p1 = upperPowerOf2 (x);
> +	p2 = p1 >> 1;
> +	if ((x - p2) < (p1 - x))
> +	    return p2;
> +	else
> +	    return p1;
> +    } else {
> +	/* x already is a power of 2 */
> +	return x;
> +    }
> +}
> +
> +/*
> +* A routine to compute the nearest, or the two nearest mipmap levels.
> +* Note that even if asked for the 2 nearest levels, the routine may return
> +* only one level in certain conditions. For example, when the target width
> +* and height fall exactly on one level's size.
> +*/
> +void
> +pixman_get_mipmap_levels (bits_image_t * pict, int nbLevelsNeeded)
> +{
> +    mipmap_t *mm  = &pict->mipmap;	
> +    pixman_fixed_t srcWidth;
> +    pixman_fixed_t srcHeight;
> +    pixman_fixed_t majorScale, scaleWidth;
> +    pixman_fixed_t minorScale, scaleHeight;
> +    pixman_fixed_t  ind;
> +    int destWidth;
> +    int destHeight;
> +    int *nbL = &pict->mipmap.nbIndex;  /* a return pointer to the number of levels */
> +    int *l   = pict->mipmap.index;
> +    int p;
> +
> +    pixman_fixed_t x = pixman_double_to_fixed(14.2563);
> +    x = sqrt_fixed_16_16(x);
> +
> +    srcWidth  = pixman_int_to_fixed(pict->width);
> +    srcHeight = pixman_int_to_fixed(pict->height);
> +
> +    pixman_get_transformed_axis (pict->common.transform->matrix, &majorScale, &minorScale);
> +
> +    /* important checks for coherent axis retrieval */
> +    if (majorScale == minorScale) {
> +	/*
> +	* we can interchange majorScale and minorScale... it doesn't matter. 
> +	* so we make this arbitrary choice :
> +	*/
> +	scaleWidth  = majorScale;
> +	scaleHeight = minorScale;
> +    } else {
> +	/* 
> +	* here, we have to lean on additionnal info : destWidth and destHeight 
> +	* the problem is : if destination image is clipped, either destWidth,
> +	* destHeight (or both) will be clipped!... so we have to check each
> +	* separately.
> +	*/
> +	if (pict->mipmap.destWidth - div_fixed_16_16 (srcWidth , majorScale) <= pixman_fixed_1) {
> +	    scaleWidth  = majorScale;
> +	    scaleHeight = minorScale;
> +	} else if (pict->mipmap.destWidth - div_fixed_16_16 (srcWidth , minorScale) <= pixman_fixed_1) {
> + 	    scaleWidth  = minorScale;
> +	    scaleHeight = majorScale;
> +	} else if (pict->mipmap.destHeight - div_fixed_16_16 (srcHeight , majorScale) <= pixman_fixed_1) {
> +	    scaleWidth  = minorScale;
> +	    scaleHeight = majorScale;
> +	} else if (pict->mipmap.destHeight - div_fixed_16_16 (srcHeight , minorScale) <= pixman_fixed_1) {
> +	    scaleWidth  = majorScale;
> +	    scaleHeight = minorScale;
> +	} else {
> +	    /* we're in trouble... we don't know which of */
> +	    scaleWidth  = majorScale;
> +	    scaleHeight = minorScale;
> +	}
> +    }
> +
> +    destWidth  = pixman_fixed_to_int (div_fixed_16_16 (srcWidth , scaleWidth));
> +    destHeight = pixman_fixed_to_int (div_fixed_16_16 (srcHeight, scaleHeight));
> +
> +    if ((majorScale <= pixman_fixed_1) && (minorScale <= pixman_fixed_1)) {
> +	/* we're upscaling our image... use only one level : the base level */
> +	*nbL = 1;
> +	l[0] = 0;
> +    } else {
> +	/* 
> +	* we're downscaling x or y dimensions (or both) ... choose two
> +	* levels according to the average size index of the two dimensions
> +	*/
> +	if (destWidth > 1) {
> +	    p = upperPowerOf2(destWidth);
> +	    ind = (whichPowerOf2(pict->mipmap.base_width  / p) << 16) + ((((p - destWidth)  << 16) / (p >> 1)) & (0x0000FFFF));
> +	} else {
> +	    ind = (whichPowerOf2(pict->mipmap.base_width)) << 16;
> +	}
> +
> +	if (destHeight > 1) {
> +	    p = upperPowerOf2(destHeight);
> +	    ind += (whichPowerOf2(pict->mipmap.base_height / p) << 16) + ((((p - destHeight) << 16) / (p >> 1)) & (0x0000FFFF));
> +	} else {
> +	    ind += (whichPowerOf2(pict->mipmap.base_height)) << 16;
> +	}
> +	ind = ind >> 1;
> +	pict->mipmap.fracInd = pixman_fixed_frac(ind);
> +	l[0] = ind >> 16;
> +
> +	if (nbLevelsNeeded == 1) {
> +	    *nbL = 1;
> +	} else {
> +	    if (pixman_fixed_frac(ind) != 0) {
> +		*nbL = 2;
> +		l[1] = l[0] + 1;
> +	    } else {
> +		*nbL = 1;
> +	    }
> +	}
> +    }
> +}
> +
> +/*
> +* A routine for building a filtered mipmap pyramid from a source image.
> +* If source image dimensions are powers of 2, the mipmap levels are decimated
> +* from the original source image dimension until size 1 X 1. If not, an initial
> +* resizing phase is done to the nearest power of 2 dimensions before building
> +* the pyramid.
> +* Note : rectangular source image are decimated until size 1 X N.
> +*/
> +void
> +pixman_build_mipmap (bits_image_t * pict)
> +{
> +    int h,i,j,k;
> +    int baseWidth, baseHeight;
> +    int pictWidth, pictHeight;
> +    pixman_bool_t needResize = FALSE;
> +
> +    pictWidth = pict->width;
> +    pictHeight = pict->height;
> +
> +    /* find the max level */
> +    baseWidth  = nearestPowerOf2 (pictWidth);
> +    baseHeight = nearestPowerOf2 (pictHeight);
> +
> +    /* check if image size is power of 2 */
> +    if ((baseWidth != pictWidth) || (baseHeight != pictHeight)) {
> +	needResize = TRUE;
> +    }
> +    /* compute the mipmap maxLevel */
> +    pict->mipmap.max_level = whichPowerOf2 (MIN (baseWidth, baseHeight));
> +
> +    pict->mipmap.base_width = baseWidth;
> +    pict->mipmap.base_height = baseHeight;
> +
> +    /* mem allocation for all levels and mipmap_level init */
> +    pict->mipmap.levels = pixman_malloc_ab((pict->mipmap.max_level + 1), sizeof (mipmap_level_t));
> +
> +    for (i = 0; i <= pict->mipmap.max_level; i++) {
> +	/* build the prefiltered mipmap incrementally */
> +	if (i == 0) {
> +	    pict->mipmap.levels[i].width  = pict->mipmap.base_width;
> +	    pict->mipmap.levels[i].height = pict->mipmap.base_height;
> +
> +	    /* memory allocation for the current level bits */
> +	    pict->mipmap.levels[i].bits = (uint32_t *) pixman_malloc_abc (pict->mipmap.base_width, pict->mipmap.base_height, sizeof (uint32_t));
> +
> +	    /* initial resize if needed */
> +	    if (needResize) {
> +		int bufferWidth = pict->mipmap.base_width;
> +		uint32_t * buffer;
> +		pixman_vector_t v, unit;
> +		pixman_fixed_t unit1;
> +
> +		unit.vector[0] = pixman_int_to_fixed(pictWidth) / pict->mipmap.base_width;
> +		unit.vector[1] = 0;
> +		unit.vector[2] = 0;
> +
> +		unit1 = pixman_int_to_fixed(pictHeight) / pict->mipmap.base_height;
> +
> +		for (h = 0; h < pict->mipmap.base_height; h++) {
> +		    buffer = &pict->mipmap.levels[0].bits[h * bufferWidth];
> +
> +		    v.vector[0] = pixman_int_to_fixed(pictWidth)  / (2 * pict->mipmap.base_width);
> +		    v.vector[1] = (pixman_int_to_fixed(pictHeight) / (2 * pict->mipmap.base_height)) + (unit1 * h);
> +		    v.vector[2] = pixman_fixed_1;
> +
> +		    /* This allows filtering code to pretend that pixels are located at integer coordinates */
> +		    mipmapAdjust (&v, &unit, -(pixman_fixed_1 / 2));
> +		    fbFetchMipmapResize_Bilinear_General(pict, bufferWidth, buffer, NULL, 0, TRUE, v, unit);
> +		}
> +	    } else {
> +
> +		/* copy the source image in levels[0] */
> +		MEMCPY_WRAPPED(pict, pict->mipmap.levels[0].bits, pict->bits, pict->mipmap.base_width * pict->mipmap.base_height * sizeof (uint32_t));
> +	    }
> +	} else {
> +	    pict->mipmap.levels[i].width  = (pict->mipmap.levels[i-1].width  >> 1);
> +	    pict->mipmap.levels[i].height = (pict->mipmap.levels[i-1].height >> 1);
> +	    pict->mipmap.levels[i].bits = (uint32_t *) pixman_malloc_abc (pict->mipmap.levels[i].width, pict->mipmap.levels[i].height, sizeof (uint32_t));
> +	    for (k = 0; k < pict->mipmap.levels[i].height; k++) {
> +		for (j = 0; j < pict->mipmap.levels[i].width; j++) {	/* FIXME : do not use imbricated loops here to optimize */
> +		    uint32_t tl = pict->mipmap.levels[i-1].bits[((k*2) * pict->mipmap.levels[i-1].width) + (j*2)];
> +		    uint32_t tr = pict->mipmap.levels[i-1].bits[((k*2) * pict->mipmap.levels[i-1].width) + (j*2+1)];
> +		    uint32_t bl = pict->mipmap.levels[i-1].bits[((k*2+1) * pict->mipmap.levels[i-1].width) + (j*2)];
> +		    uint32_t br = pict->mipmap.levels[i-1].bits[((k*2+1) * pict->mipmap.levels[i-1].width) + (j*2+1)];
> +
> +		    uint32_t r = (FbGet8(tl,0) + FbGet8(tr,0) + FbGet8(bl,0) + FbGet8(br,0)) / 4;
> +		    r |= ((FbGet8(tl,8 ) + FbGet8(tr,8 ) + FbGet8(bl,8 ) + FbGet8(br,8 )) / 4) << 8;
> +		    r |= ((FbGet8(tl,16) + FbGet8(tr,16) + FbGet8(bl,16) + FbGet8(br,16)) / 4) << 16;
> +		    r |= ((FbGet8(tl,24) + FbGet8(tr,24) + FbGet8(bl,24) + FbGet8(br,24)) / 4) << 24;
> +
> +		    pict->mipmap.levels[i].bits[k*pict->mipmap.levels[i].width + j] = r;
> +		}
> +	    }
> +	}
> +    }
> +}
> +
> +/* frees all the allocated mipmap levels and the levels structure itself */
> +void
> +pixman_free_mipmap (bits_image_t *pict) {
> +    int i;
> +
> +    if (pict->mipmap.has_mipmap && pict->mipmap.is_generated) {
> +	for (i = 0; i <= pict->mipmap.max_level; i++) {
> +	    free (pict->mipmap.levels[i].bits);
> +	}
> +
> +	free (pict->mipmap.levels);
> +    }
> +}
> \ No newline at end of file
> diff --git a/pixman/pixman-private.h b/pixman/pixman-private.h
> index e26a0c3..5d4d6bb 100644
> --- a/pixman/pixman-private.h
> +++ b/pixman/pixman-private.h
> @@ -136,6 +136,8 @@ typedef struct vertical_gradient vertical_gradient_t;
>  typedef struct conical_gradient conical_gradient_t;
>  typedef struct radial_gradient radial_gradient_t;
>  typedef struct bits_image bits_image_t;
> +typedef struct mipmap_level mipmap_level_t;
> +typedef struct mipmap mipmap_t;
>  typedef struct circle circle_t;
>  typedef struct point point_t;
>  
> @@ -224,11 +226,19 @@ void pixmanFetchSourcePict64(source_image_t *, int x, int y, int width,
>  
>  void fbFetchTransformed(bits_image_t *, int x, int y, int width,
>                          uint32_t *buffer, uint32_t *mask, uint32_t maskBits);
> +
>  void fbStoreExternalAlpha(bits_image_t *, int x, int y, int width,
>                            uint32_t *buffer);
>  void fbFetchExternalAlpha(bits_image_t *, int x, int y, int width,
>                            uint32_t *buffer, uint32_t *mask, uint32_t maskBits);
>  
> +void fbFetchMipmapResize_Bilinear_General(bits_image_t * pict, int width,
> +				     uint32_t *buffer, uint32_t *mask,
> +				     uint32_t maskBits, pixman_bool_t affine,
> +				     pixman_vector_t v, pixman_vector_t unit);
> +
> +void mipmapAdjust(pixman_vector_t *v, pixman_vector_t *u, pixman_fixed_t adjustment);
> +
>  void fbFetchTransformed_accessors(bits_image_t *, int x, int y, int width,
>                                    uint32_t *buffer, uint32_t *mask,
>                                    uint32_t maskBits);
> @@ -254,6 +264,12 @@ void fbFetchExternalAlpha64_accessors(bits_image_t *, int x, int y, int width,
>                                        uint64_t *buffer, uint64_t *mask,
>                                        uint32_t maskBits);
>  
> +void pixman_get_mipmap_levels (bits_image_t *pict, int nbLevelsNeeded);
> +
> +void pixman_build_mipmap (bits_image_t *pict);
> +
> +void pixman_free_mipmap (bits_image_t *pict);
> +
>  /* end */
>  
>  typedef enum
> @@ -354,6 +370,28 @@ struct conical_gradient
>      pixman_fixed_t		angle;
>  };
>  
> +struct mipmap_level
> +{
> +    int				width;
> +    int				height;
> +    uint32_t *			bits;
> +};
> +
> +struct mipmap
> +{
> +    pixman_bool_t		has_mipmap;
> +    pixman_bool_t		is_generated;
> +    int				base_width;
> +    int				base_height;
> +    int				max_level;
> +    mipmap_level_t *		levels;
> +    int				nbIndex;
> +    int				index[2];
> +    pixman_fixed_t		fracInd;
> +    pixman_fixed_t		destWidth;
> +    pixman_fixed_t		destHeight;
> +};
> +
>  struct bits_image
>  {
>      image_common_t		common;
> @@ -362,6 +400,7 @@ struct bits_image
>      int				width;
>      int				height;
>      uint32_t *			bits;
> +    mipmap_t			mipmap;
>      uint32_t *			free_me;
>      int				rowstride; /* in number of uint32_t's */
>  };
> diff --git a/pixman/pixman-transformed.c b/pixman/pixman-transformed.c
> index fca1cdb..a8fa481 100644
> --- a/pixman/pixman-transformed.c
> +++ b/pixman/pixman-transformed.c
> @@ -3,6 +3,7 @@
>   * Copyright ?? 2000 Keith Packard, member of The XFree86 Project, Inc.
>   *             2005 Lars Knoll & Zack Rusin, Trolltech
>   *             2008 Aaron Plattner, NVIDIA Corporation
> + *             2008 Frederic Plourde
>   *
>   * Permission to use, copy, modify, distribute, and sell this software and its
>   * documentation for any purpose is hereby granted without fee, provided that
> @@ -29,6 +30,7 @@
>  #endif
>  
>  #include <stdlib.h>
> +#include <math.h>
>  
>  #include "pixman-private.h"
>  
> @@ -422,6 +424,1038 @@ fbFetchTransformed_Bilinear_General(bits_image_t * pict, int width, uint32_t *bu
>      }
>  }
>  
> +void
> +ACCESS(fbFetchMipmapResize_Bilinear_General)(bits_image_t * pict, int width,
> +				    uint32_t *buffer, uint32_t *mask,
> +				    uint32_t maskBits, pixman_bool_t affine,
> +				    pixman_vector_t v, pixman_vector_t unit)
> +{
> +    fbFetchTransformed_Bilinear_General(pict, width, buffer, mask, maskBits, affine, v, unit);
> +}
> +
> +static void
> +adjust (pixman_vector_t *v, pixman_vector_t *u, pixman_fixed_t adjustment)
> +{
> +    int delta_v = (adjustment * v->vector[2]) >> 16;
> +    int delta_u = (adjustment * u->vector[2]) >> 16;
> +
> +    v->vector[0] += delta_v;
> +    v->vector[1] += delta_v;
> +
> +    u->vector[0] += delta_u;
> +    u->vector[1] += delta_u;
> +}
> +
> +void
> +ACCESS(mipmapAdjust)(pixman_vector_t *v, pixman_vector_t *u, pixman_fixed_t adjustment)
> +{
> +    adjust(v, u, adjustment);
> +}

I don't see any reason for the ACCESS wrapper or the name change...

> +
> +static void
> +fbFetchTransformed_Nearest_Mipmap_Linear_Normal(bits_image_t * pict, int width, uint32_t *buffer,
> +				    uint32_t *mask, uint32_t maskBits, pixman_bool_t affine,
> +				    pixman_vector_t v, pixman_vector_t unit)
> +{
> +    bits_image_t fakePict;
> +    pixman_region32_t full_region_copy, src_clip_copy;
> +    pixman_bool_t src_clip;
> +    pixman_fixed_t mipmap_width_ratio;
> +    pixman_fixed_t mipmap_height_ratio;
> +    fetchPixelProc32 fetch;
> +    int i, m;
> +    int nbIndex = pict->mipmap.nbIndex;
> +    int *index  = pict->mipmap.index;
> +    pixman_fixed_t fracInd  = pict->mipmap.fracInd;
> +    pixman_fixed_t iFracInd = pixman_fixed_1 - pict->mipmap.fracInd;
> +

[snip]

There's a lot of code duplication here...

> +		if (nbIndex == 1) {
> +		    *(buffer + i) = rr[0];
> +		} else {
> +		    r =  ( pixman_fixed_to_int(iFracInd * FbGet8(rr[0],0) + fracInd * FbGet8(rr[1],0 )) );
> +		    r |= ( pixman_fixed_to_int(iFracInd * FbGet8(rr[0],0) + fracInd * FbGet8(rr[1],8 )) ) << 8;
> +		    r |= ( pixman_fixed_to_int(iFracInd * FbGet8(rr[0],0) + fracInd * FbGet8(rr[1],16)) ) << 16;
> +		    r |= ( pixman_fixed_to_int(iFracInd * FbGet8(rr[0],0) + fracInd * FbGet8(rr[1],24)) ) << 24;
> +
> +		    *(buffer + i) = r;
> +		}
> +	    }
> +	}
> +	v.vector[0] += unit.vector[0];
> +	v.vector[1] += unit.vector[1];
> +	v.vector[2] += unit.vector[2];
> +    }
> +}
> +
>  static void
>  fbFetchTransformed_Convolution(bits_image_t * pict, int width, uint32_t *buffer, uint32_t *mask, uint32_t maskBits, pixman_bool_t affine, pixman_vector_t v, pixman_vector_t unit)
>  {
> @@ -521,19 +1555,6 @@ fbFetchTransformed_Convolution(bits_image_t * pict, int width, uint32_t *buffer,
>      }
>  }
>  
> -static void
> -adjust (pixman_vector_t *v, pixman_vector_t *u, pixman_fixed_t adjustment)
> -{
> -    int delta_v = (adjustment * v->vector[2]) >> 16;
> -    int delta_u = (adjustment * u->vector[2]) >> 16;
> -    
> -    v->vector[0] += delta_v;
> -    v->vector[1] += delta_v;
> -    
> -    u->vector[0] += delta_u;
> -    u->vector[1] += delta_u;
> -}
> -
>  void
>  ACCESS(fbFetchTransformed)(bits_image_t * pict, int x, int y, int width,
>                             uint32_t *buffer, uint32_t *mask, uint32_t maskBits)
> @@ -543,9 +1564,11 @@ ACCESS(fbFetchTransformed)(bits_image_t * pict, int x, int y, int width,
>      pixman_vector_t v;
>      pixman_vector_t unit;
>      pixman_bool_t affine = TRUE;
> +	pixman_box32_t *box, boxCopy;
>  
> -    bits = pict->bits;
> +    bits   = pict->bits;
>      stride = pict->rowstride;
> +	box    = &pict->common.src_clip->extents;
>  
>      /* reference point is the center of the pixel */
>      v.vector[0] = pixman_int_to_fixed(x) + pixman_fixed_1 / 2;
> @@ -561,6 +1584,19 @@ ACCESS(fbFetchTransformed)(bits_image_t * pict, int x, int y, int width,
>          unit.vector[1] = pict->common.transform->matrix[1][0];
>          unit.vector[2] = pict->common.transform->matrix[2][0];
>          affine = v.vector[2] == pixman_fixed_1 && unit.vector[2] == 0;
> +		
> +	if (pict->common.filter == PIXMAN_FILTER_NEAREST_MIPMAP_LINEAR ||
> +	    pict->common.filter == PIXMAN_FILTER_LINEAR_MIPMAP_NEAREST ||
> +	    pict->common.filter == PIXMAN_FILTER_LINEAR_MIPMAP_LINEAR  ||
> +	    pict->common.filter == PIXMAN_FILTER_BEST)
> +	{
> +	    // adjust v and unit values to the current mipmap level
> +	    v.vector[0] = ((pixman_fixed_48_16_t)v.vector[0] * pict->mipmap.base_width ) / box->x2;
> +	    v.vector[1] = ((pixman_fixed_48_16_t)v.vector[1] * pict->mipmap.base_height) / box->y2;
> +
> +	    unit.vector[0] = ((pixman_fixed_48_16_t)unit.vector[0] * pict->mipmap.base_width ) / box->x2;
> +	    unit.vector[1] = ((pixman_fixed_48_16_t)unit.vector[1] * pict->mipmap.base_height) / box->y2;
> +	}
>      }
>      else
>      {
> @@ -569,11 +1605,11 @@ ACCESS(fbFetchTransformed)(bits_image_t * pict, int x, int y, int width,
>          unit.vector[2] = 0;
>      }
>  
> -    /* This allows filtering code to pretend that pixels are located at integer coordinates */
> -    adjust (&v, &unit, -(pixman_fixed_1 / 2));
> -
>      if (pict->common.filter == PIXMAN_FILTER_NEAREST || pict->common.filter == PIXMAN_FILTER_FAST)
>      {
> +	/* This allows filtering code to pretend that pixels are located at integer coordinates */
> +    adjust (&v, &unit, -(pixman_fixed_1 / 2));
> +
>  	/* Round down to closest integer, ensuring that 0.5 rounds to 0, not 1 */
>  	adjust (&v, &unit, pixman_fixed_1 / 2 - pixman_fixed_e);
>  	
> @@ -589,10 +1625,12 @@ ACCESS(fbFetchTransformed)(bits_image_t * pict, int x, int y, int width,
>          {
>              fbFetchTransformed_Nearest_General(pict, width, buffer, mask, maskBits, affine, v, unit);
>          }
> -    } else if (pict->common.filter == PIXMAN_FILTER_BILINEAR	||
> -	       pict->common.filter == PIXMAN_FILTER_GOOD	||
> -	       pict->common.filter == PIXMAN_FILTER_BEST)
> +    } 
> +	else if (pict->common.filter == PIXMAN_FILTER_BILINEAR || pict->common.filter == PIXMAN_FILTER_GOOD)
>      {
> +	/* This allows filtering code to pretend that pixels are located at integer coordinates */
> +	adjust (&v, &unit, -(pixman_fixed_1 / 2));
> +
>          if (pict->common.repeat == PIXMAN_REPEAT_NORMAL)
>          {
>              fbFetchTransformed_Bilinear_Normal(pict, width, buffer, mask, maskBits, affine, v, unit);
> @@ -606,6 +1644,55 @@ ACCESS(fbFetchTransformed)(bits_image_t * pict, int x, int y, int width,
>              fbFetchTransformed_Bilinear_General(pict, width, buffer, mask, maskBits, affine, v, unit);
>          }
>      }
> +    else if (pict->common.filter == PIXMAN_FILTER_NEAREST_MIPMAP_LINEAR)
> +    {
> +	/* We don't "adjust" the sampling coords to integer positions now ... */
> +	if (pict->common.repeat == PIXMAN_REPEAT_NORMAL)
> +	{
> +	    fbFetchTransformed_Nearest_Mipmap_Linear_Normal(pict, width, buffer, mask, maskBits, affine, v, unit);
> +	}
> +	else if (pict->common.repeat == PIXMAN_REPEAT_PAD)
> +        {
> +            fbFetchTransformed_Nearest_Mipmap_Linear_Pad(pict, width, buffer, mask, maskBits, affine, v, unit);
> +        }
> +        else
> +        {
> +            fbFetchTransformed_Nearest_Mipmap_Linear_General(pict, width, buffer, mask, maskBits, affine, v, unit);
> +        }
> +    }
> +    else if (pict->common.filter == PIXMAN_FILTER_LINEAR_MIPMAP_NEAREST ||
> +	     pict->common.filter == PIXMAN_FILTER_BEST)
> +    {
> +	/* We don't "adjust" the sampling coords to integer positions now ... */
> +	 if (pict->common.repeat == PIXMAN_REPEAT_NORMAL)
> +        {
> +            fbFetchTransformed_Linear_Mipmap_Nearest_Normal(pict, width, buffer, mask, maskBits, affine, v, unit);
> +        }
> +        else if (pict->common.repeat == PIXMAN_REPEAT_PAD)
> +        {
> +            fbFetchTransformed_Linear_Mipmap_Nearest_Pad(pict, width, buffer, mask, maskBits, affine, v, unit);
> +        }
> +        else
> +        {
> +            fbFetchTransformed_Linear_Mipmap_Nearest_General(pict, width, buffer, mask, maskBits, affine, v, unit);
> +        }
> +    }
> +    else if (pict->common.filter == PIXMAN_FILTER_LINEAR_MIPMAP_LINEAR)
> +    {
> +	/* We don't "adjust" the sampling coords to integer positions now ... */
> +	 if (pict->common.repeat == PIXMAN_REPEAT_NORMAL)
> +        {
> +            fbFetchTransformed_Linear_Mipmap_Linear_Normal(pict, width, buffer, mask, maskBits, affine, v, unit);
> +        }
> +        else if (pict->common.repeat == PIXMAN_REPEAT_PAD)
> +        {
> +            fbFetchTransformed_Linear_Mipmap_Linear_Pad(pict, width, buffer, mask, maskBits, affine, v, unit);
> +        }
> +        else
> +        {
> +            fbFetchTransformed_Linear_Mipmap_Linear_General(pict, width, buffer, mask, maskBits, affine, v, unit);
> +        }
> +    }
>      else if (pict->common.filter == PIXMAN_FILTER_CONVOLUTION)
>      {
>  	/* Round to closest integer, ensuring that 0.5 rounds to 0, not 1 */
> diff --git a/pixman/pixman-utils.c b/pixman/pixman-utils.c
> index adb3e20..1ea2a2d 100644
> --- a/pixman/pixman-utils.c
> +++ b/pixman/pixman-utils.c
> @@ -19,6 +19,8 @@
>   * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
>   *
>   * Author:  Keith Packard, SuSE, Inc.
> + * 
> + * Additionnal contributors : Frederic Plourde
>   */
>  
>  #ifdef HAVE_CONFIG_H
> @@ -26,6 +28,7 @@
>  #endif
>  
>  #include <stdlib.h>
> +#include <math.h>
>  
>  #include "pixman-private.h"
>  #include "pixman-mmx.h"
> @@ -611,3 +614,160 @@ pixman_format_supported_source (pixman_format_code_t format)
>  	return FALSE;
>      }
>  }
> +
> +/**
> + * mult_fixed_16_16:
> + * @a: first number to multiply in fixed-point 16.16 format
> + * @b: second number to multiply in fixed-point 16.16 format
> + * 
> + * This code is inspired by Ken Turkowski's fixed-point sqrt.
> + * http://www.worldserver.com/turk/computergraphics/FixedSqrt.pdf

Looks like an unintentional copy from sqrt_fixed_16_16.

> + *
> + * Author : Frederic Plourde 
> + **/
> +pixman_fixed_t
> +mult_fixed_16_16 (pixman_fixed_t a, pixman_fixed_t b)
> +{
> +    int64_t r = (int64_t)a * (int64_t)b;
> +    return ( pixman_fixed_t )( r >> 16 );
> +}
> +
> +/**
> + * div_fixed_16_16:
> + * @a: dividend in fixed-point 16.16 format
> + * @b: divisor  in fixed-point 16.16 format
> + * 
> + * This code is inspired by Ken Turkowski's fixed-point sqrt.
> + * http://www.worldserver.com/turk/computergraphics/FixedSqrt.pdf
> + *

Likewise

> + * Author : Frederic Plourde 
> + **/
> +pixman_fixed_t
> +div_fixed_16_16 (pixman_fixed_t a, pixman_fixed_t b)
> +{
> +    int64_t div;
> +
> +    int64_t a_64 = ((int64_t)a) << 32 ;
> +    int64_t b_64 = ((int64_t)b) << 16 ;
> +
> +    div = a_64 / b_64;
> +
> +    return (pixman_fixed_t)div;
> +}
> +


More information about the cairo mailing list