mirror of
https://salsa.debian.org/xorg-team/lib/pixman
synced 2025-09-04 00:13:41 +00:00

When making the copy of the destination, do so separately for the image and the alpha map. This ensures that the alpha channel of the alpha map will be different from the alpha channel of the actual image. Previously, orig_dst would be copied onto dst along with its alpha map, which mean that the alpha map of orig_dst would become the new alpha channel of *both* dst and dst's alpha map. This meant that test didn't actually test that the alpha maps alpha channel was actually fetched.
333 lines
7.6 KiB
C
333 lines
7.6 KiB
C
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include "utils.h"
|
|
|
|
#define WIDTH 48
|
|
#define HEIGHT 48
|
|
|
|
static const pixman_format_code_t formats[] =
|
|
{
|
|
PIXMAN_a8r8g8b8,
|
|
PIXMAN_a2r10g10b10,
|
|
PIXMAN_a4r4g4b4,
|
|
PIXMAN_a8
|
|
};
|
|
|
|
static const pixman_format_code_t alpha_formats[] =
|
|
{
|
|
PIXMAN_null,
|
|
PIXMAN_a8,
|
|
PIXMAN_a2r10g10b10,
|
|
PIXMAN_a4r4g4b4
|
|
};
|
|
|
|
static const int origins[] =
|
|
{
|
|
0, 10, -100
|
|
};
|
|
|
|
static const char *
|
|
format_name (pixman_format_code_t format)
|
|
{
|
|
if (format == PIXMAN_a8)
|
|
return "a8";
|
|
else if (format == PIXMAN_a2r10g10b10)
|
|
return "a2r10g10b10";
|
|
else if (format == PIXMAN_a8r8g8b8)
|
|
return "a8r8g8b8";
|
|
else if (format == PIXMAN_a4r4g4b4)
|
|
return "a4r4g4b4";
|
|
else if (format == PIXMAN_null)
|
|
return "none";
|
|
else
|
|
assert (0);
|
|
|
|
return "<unknown - bug in alphamap.c>";
|
|
}
|
|
|
|
static void
|
|
on_destroy (pixman_image_t *image, void *data)
|
|
{
|
|
uint32_t *bits = pixman_image_get_data (image);
|
|
|
|
fence_free (bits);
|
|
}
|
|
|
|
static pixman_image_t *
|
|
make_image (pixman_format_code_t format)
|
|
{
|
|
uint32_t *bits;
|
|
uint8_t bpp = PIXMAN_FORMAT_BPP (format) / 8;
|
|
pixman_image_t *image;
|
|
|
|
bits = (uint32_t *)make_random_bytes (WIDTH * HEIGHT * bpp);
|
|
|
|
image = pixman_image_create_bits (format, WIDTH, HEIGHT, bits, WIDTH * bpp);
|
|
|
|
if (image && bits)
|
|
pixman_image_set_destroy_function (image, on_destroy, NULL);
|
|
|
|
return image;
|
|
}
|
|
|
|
static uint8_t
|
|
get_alpha (pixman_image_t *image, int x, int y, int orig_x, int orig_y)
|
|
{
|
|
uint8_t *bits;
|
|
uint8_t r;
|
|
|
|
if (image->common.alpha_map)
|
|
{
|
|
if (x - orig_x >= 0 && x - orig_x < WIDTH &&
|
|
y - orig_y >= 0 && y - orig_y < HEIGHT)
|
|
{
|
|
image = (pixman_image_t *)image->common.alpha_map;
|
|
|
|
x -= orig_x;
|
|
y -= orig_y;
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
bits = (uint8_t *)image->bits.bits;
|
|
|
|
if (image->bits.format == PIXMAN_a8)
|
|
{
|
|
r = bits[y * WIDTH + x];
|
|
}
|
|
else if (image->bits.format == PIXMAN_a2r10g10b10)
|
|
{
|
|
r = ((uint32_t *)bits)[y * WIDTH + x] >> 30;
|
|
r |= r << 2;
|
|
r |= r << 4;
|
|
}
|
|
else if (image->bits.format == PIXMAN_a8r8g8b8)
|
|
{
|
|
r = ((uint32_t *)bits)[y * WIDTH + x] >> 24;
|
|
}
|
|
else if (image->bits.format == PIXMAN_a4r4g4b4)
|
|
{
|
|
r = ((uint16_t *)bits)[y * WIDTH + x] >> 12;
|
|
r |= r << 4;
|
|
}
|
|
else
|
|
{
|
|
assert (0);
|
|
}
|
|
|
|
return r;
|
|
}
|
|
|
|
static uint16_t
|
|
get_red (pixman_image_t *image, int x, int y, int orig_x, int orig_y)
|
|
{
|
|
uint8_t *bits;
|
|
uint16_t r;
|
|
|
|
bits = (uint8_t *)image->bits.bits;
|
|
|
|
if (image->bits.format == PIXMAN_a8)
|
|
{
|
|
r = 0x00;
|
|
}
|
|
else if (image->bits.format == PIXMAN_a2r10g10b10)
|
|
{
|
|
r = ((uint32_t *)bits)[y * WIDTH + x] >> 14;
|
|
r &= 0xffc0;
|
|
r |= (r >> 10);
|
|
}
|
|
else if (image->bits.format == PIXMAN_a8r8g8b8)
|
|
{
|
|
r = ((uint32_t *)bits)[y * WIDTH + x] >> 16;
|
|
r &= 0xff;
|
|
r |= r << 8;
|
|
}
|
|
else if (image->bits.format == PIXMAN_a4r4g4b4)
|
|
{
|
|
r = ((uint16_t *)bits)[y * WIDTH + x] >> 8;
|
|
r &= 0xf;
|
|
r |= r << 4;
|
|
r |= r << 8;
|
|
}
|
|
else
|
|
{
|
|
assert (0);
|
|
}
|
|
|
|
return r;
|
|
}
|
|
|
|
static int
|
|
run_test (int s, int d, int sa, int da, int soff, int doff)
|
|
{
|
|
pixman_format_code_t sf = formats[s];
|
|
pixman_format_code_t df = formats[d];
|
|
pixman_format_code_t saf = alpha_formats[sa];
|
|
pixman_format_code_t daf = alpha_formats[da];
|
|
pixman_image_t *src, *dst, *orig_dst, *alpha, *orig_alpha;
|
|
pixman_transform_t t1;
|
|
int j, k;
|
|
int n_alpha_bits, n_red_bits;
|
|
|
|
soff = origins[soff];
|
|
doff = origins[doff];
|
|
|
|
n_alpha_bits = PIXMAN_FORMAT_A (df);
|
|
if (daf != PIXMAN_null)
|
|
n_alpha_bits = PIXMAN_FORMAT_A (daf);
|
|
|
|
n_red_bits = PIXMAN_FORMAT_R (df);
|
|
|
|
/* Source */
|
|
src = make_image (sf);
|
|
if (saf != PIXMAN_null)
|
|
{
|
|
alpha = make_image (saf);
|
|
pixman_image_set_alpha_map (src, alpha, soff, soff);
|
|
pixman_image_unref (alpha);
|
|
}
|
|
|
|
/* Destination */
|
|
orig_dst = make_image (df);
|
|
dst = make_image (df);
|
|
pixman_image_composite (PIXMAN_OP_SRC, orig_dst, NULL, dst,
|
|
0, 0, 0, 0, 0, 0, WIDTH, HEIGHT);
|
|
|
|
if (daf != PIXMAN_null)
|
|
{
|
|
orig_alpha = make_image (daf);
|
|
alpha = make_image (daf);
|
|
|
|
pixman_image_composite (PIXMAN_OP_SRC, orig_alpha, NULL, alpha,
|
|
0, 0, 0, 0, 0, 0, WIDTH, HEIGHT);
|
|
|
|
pixman_image_set_alpha_map (orig_dst, orig_alpha, doff, doff);
|
|
pixman_image_set_alpha_map (dst, alpha, doff, doff);
|
|
|
|
pixman_image_unref (orig_alpha);
|
|
pixman_image_unref (alpha);
|
|
}
|
|
|
|
/* Transformations, repeats and filters on destinations should be ignored,
|
|
* so just set some random ones.
|
|
*/
|
|
pixman_transform_init_identity (&t1);
|
|
pixman_transform_scale (&t1, NULL, pixman_int_to_fixed (100), pixman_int_to_fixed (11));
|
|
pixman_transform_rotate (&t1, NULL, pixman_double_to_fixed (0.5), pixman_double_to_fixed (0.11));
|
|
pixman_transform_translate (&t1, NULL, pixman_int_to_fixed (11), pixman_int_to_fixed (17));
|
|
|
|
pixman_image_set_transform (dst, &t1);
|
|
pixman_image_set_filter (dst, PIXMAN_FILTER_BILINEAR, NULL, 0);
|
|
pixman_image_set_repeat (dst, PIXMAN_REPEAT_REFLECT);
|
|
|
|
pixman_image_composite (PIXMAN_OP_ADD, src, NULL, dst,
|
|
0, 0, 0, 0, 0, 0, WIDTH, HEIGHT);
|
|
|
|
for (j = MAX (doff, 0); j < MIN (HEIGHT, HEIGHT + doff); ++j)
|
|
{
|
|
for (k = MAX (doff, 0); k < MIN (WIDTH, WIDTH + doff); ++k)
|
|
{
|
|
uint8_t sa, da, oda, refa;
|
|
uint16_t sr, dr, odr, refr;
|
|
|
|
sa = get_alpha (src, k, j, soff, soff);
|
|
da = get_alpha (dst, k, j, doff, doff);
|
|
oda = get_alpha (orig_dst, k, j, doff, doff);
|
|
|
|
if (sa + oda > 255)
|
|
refa = 255;
|
|
else
|
|
refa = sa + oda;
|
|
|
|
if (da >> (8 - n_alpha_bits) != refa >> (8 - n_alpha_bits))
|
|
{
|
|
printf ("\nWrong alpha value at (%d, %d). Should be 0x%x; got 0x%x. Source was 0x%x, original dest was 0x%x\n",
|
|
k, j, refa, da, sa, oda);
|
|
|
|
printf ("src: %s, alpha: %s, origin %d %d\ndst: %s, alpha: %s, origin: %d %d\n\n",
|
|
format_name (sf),
|
|
format_name (saf),
|
|
soff, soff,
|
|
format_name (df),
|
|
format_name (daf),
|
|
doff, doff);
|
|
return 1;
|
|
}
|
|
|
|
/* There are cases where we go through the 8 bit compositing
|
|
* path even with 10bpc formats. This results in incorrect
|
|
* results here, so only do the red check for narrow formats
|
|
*/
|
|
if (n_red_bits <= 8)
|
|
{
|
|
sr = get_red (src, k, j, soff, soff);
|
|
dr = get_red (dst, k, j, doff, doff);
|
|
odr = get_red (orig_dst, k, j, doff, doff);
|
|
|
|
if (sr + odr > 0xffff)
|
|
refr = 0xffff;
|
|
else
|
|
refr = sr + odr;
|
|
|
|
if (abs ((dr >> (16 - n_red_bits)) - (refr >> (16 - n_red_bits))) > 1)
|
|
{
|
|
printf ("%d red bits\n", n_red_bits);
|
|
printf ("\nWrong red value at (%d, %d). Should be 0x%x; got 0x%x. Source was 0x%x, original dest was 0x%x\n",
|
|
k, j, refr, dr, sr, odr);
|
|
|
|
printf ("src: %s, alpha: %s, origin %d %d\ndst: %s, alpha: %s, origin: %d %d\n\n",
|
|
format_name (sf),
|
|
format_name (saf),
|
|
soff, soff,
|
|
format_name (df),
|
|
format_name (daf),
|
|
doff, doff);
|
|
return 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
pixman_image_set_alpha_map (src, NULL, 0, 0);
|
|
pixman_image_set_alpha_map (dst, NULL, 0, 0);
|
|
pixman_image_set_alpha_map (orig_dst, NULL, 0, 0);
|
|
|
|
pixman_image_unref (src);
|
|
pixman_image_unref (dst);
|
|
pixman_image_unref (orig_dst);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
main (int argc, char **argv)
|
|
{
|
|
int i, j, a, b, x, y;
|
|
|
|
for (i = 0; i < ARRAY_LENGTH (formats); ++i)
|
|
{
|
|
for (j = 0; j < ARRAY_LENGTH (formats); ++j)
|
|
{
|
|
for (a = 0; a < ARRAY_LENGTH (alpha_formats); ++a)
|
|
{
|
|
for (b = 0; b < ARRAY_LENGTH (alpha_formats); ++b)
|
|
{
|
|
for (x = 0; x < ARRAY_LENGTH (origins); ++x)
|
|
{
|
|
for (y = 0; y < ARRAY_LENGTH (origins); ++y)
|
|
{
|
|
if (run_test (i, j, a, b, x, y) != 0)
|
|
return 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|