[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