[Pixman] [PATCH v2] pixman: Add support for argb/xrgb float formats
Maarten Lankhorst
maarten.lankhorst at linux.intel.com
Mon Jun 11 11:34:50 UTC 2018
Pixman is already using the floating point formats internally, expose
this capability in case someone wants to support higher bit per
component formats.
This is useful for igt which depends on cairo to do the rendering.
It can use it to convert floats internally to planar Y'CbCr formats,
or to F16.
Changes since v1:
- Use RGBA 128 bits and RGB 96 bits memory layouts, to better match the opengl format.
Signed-off-by: Maarten Lankhorst <maarten.lankhorst at linux.intel.com>
---
pixman/pixman-access.c | 128 ++++++++++++++++++++++++++++++++++++++++-
pixman/pixman.h | 36 ++++++++----
test/alphamap.c | 73 ++++++++++++++++-------
test/utils.c | 76 ++++++++++++++++++++++++
test/utils.h | 2 +
5 files changed, 282 insertions(+), 33 deletions(-)
diff --git a/pixman/pixman-access.c b/pixman/pixman-access.c
index 4f0642d77785..10fa049becf4 100644
--- a/pixman/pixman-access.c
+++ b/pixman/pixman-access.c
@@ -642,6 +642,48 @@ fetch_scanline_a2r10g10b10_float (bits_image_t * image,
}
/* Expects a float buffer */
+#ifndef PIXMAN_FB_ACCESSORS
+static void
+fetch_scanline_rgb_float_float (bits_image_t *image,
+ int x,
+ int y,
+ int width,
+ uint32_t * b,
+ const uint32_t *mask)
+{
+ const float *bits = (float *)image->bits + y * image->rowstride;
+ const float *pixel = bits + x * 3;
+ argb_t *buffer = (argb_t *)b;
+
+ for (; width--; buffer++) {
+ buffer->r = *pixel++;
+ buffer->g = *pixel++;
+ buffer->b = *pixel++;
+ buffer->a = 1.f;
+ }
+}
+
+static void
+fetch_scanline_rgba_float_float (bits_image_t *image,
+ int x,
+ int y,
+ int width,
+ uint32_t * b,
+ const uint32_t *mask)
+{
+ const float *bits = (float *)image->bits + y * image->rowstride;
+ const float *pixel = bits + x * 4;
+ argb_t *buffer = (argb_t *)b;
+
+ for (; width--; buffer++) {
+ buffer->r = *pixel++;
+ buffer->g = *pixel++;
+ buffer->b = *pixel++;
+ buffer->a = *pixel++;
+ }
+}
+#endif
+
static void
fetch_scanline_x2r10g10b10_float (bits_image_t *image,
int x,
@@ -805,6 +847,40 @@ fetch_scanline_yv12 (bits_image_t *image,
/**************************** Pixel wise fetching *****************************/
+#ifndef PIXMAN_FB_ACCESSORS
+static argb_t
+fetch_pixel_rgb_float_float (bits_image_t *image,
+ int offset,
+ int line)
+{
+ float *bits = (float *)image->bits + line * image->rowstride;
+ argb_t argb;
+
+ argb.r = bits[offset * 3];
+ argb.g = bits[offset * 3 + 1];
+ argb.b = bits[offset * 3 + 2];
+ argb.a = 1.f;
+
+ return argb;
+}
+
+static argb_t
+fetch_pixel_rgba_float_float (bits_image_t *image,
+ int offset,
+ int line)
+{
+ float *bits = (float *)image->bits + line * image->rowstride;
+ argb_t argb;
+
+ argb.r = bits[offset * 4];
+ argb.g = bits[offset * 4 + 1];
+ argb.b = bits[offset * 4 + 2];
+ argb.a = bits[offset * 4 + 3];
+
+ return argb;
+}
+#endif
+
static argb_t
fetch_pixel_x2r10g10b10_float (bits_image_t *image,
int offset,
@@ -962,6 +1038,45 @@ fetch_pixel_yv12 (bits_image_t *image,
/*********************************** Store ************************************/
+#ifndef PIXMAN_FB_ACCESSORS
+static void
+store_scanline_rgba_float_float (bits_image_t * image,
+ int x,
+ int y,
+ int width,
+ const uint32_t *v)
+{
+ float *bits = (float *)image->bits + image->rowstride * y + 4 * x;
+ const argb_t *values = (argb_t *)v;
+
+ for (; width; width--, values++)
+ {
+ *bits++ = values->r;
+ *bits++ = values->g;
+ *bits++ = values->b;
+ *bits++ = values->a;
+ }
+}
+
+static void
+store_scanline_rgb_float_float (bits_image_t * image,
+ int x,
+ int y,
+ int width,
+ const uint32_t *v)
+{
+ float *bits = (float *)image->bits + image->rowstride * y + 3 * x;
+ const argb_t *values = (argb_t *)v;
+
+ for (; width; width--, values++)
+ {
+ *bits++ = values->r;
+ *bits++ = values->g;
+ *bits++ = values->b;
+ }
+}
+#endif
+
static void
store_scanline_a2r10g10b10_float (bits_image_t * image,
int x,
@@ -1351,7 +1466,18 @@ static const format_info_t accessors[] =
FORMAT_INFO (g1),
/* Wide formats */
-
+#ifndef PIXMAN_FB_ACCESSORS
+ { PIXMAN_rgba_float,
+ NULL, fetch_scanline_rgba_float_float,
+ fetch_pixel_generic_lossy_32, fetch_pixel_rgba_float_float,
+ NULL, store_scanline_rgba_float_float },
+
+ { PIXMAN_rgb_float,
+ NULL, fetch_scanline_rgb_float_float,
+ fetch_pixel_generic_lossy_32, fetch_pixel_rgb_float_float,
+ NULL, store_scanline_rgb_float_float },
+#endif
+
{ PIXMAN_a2r10g10b10,
NULL, fetch_scanline_a2r10g10b10_float,
fetch_pixel_generic_lossy_32, fetch_pixel_a2r10g10b10_float,
diff --git a/pixman/pixman.h b/pixman/pixman.h
index 509ba5e534a8..c376278c83e7 100644
--- a/pixman/pixman.h
+++ b/pixman/pixman.h
@@ -647,19 +647,28 @@ struct pixman_indexed
* sample implementation allows only packed RGB and GBR
* representations for data to simplify software rendering,
*/
-#define PIXMAN_FORMAT(bpp,type,a,r,g,b) (((bpp) << 24) | \
+#define PIXMAN_FORMAT_PACK_BPP(bpp) ((bpp) <= 64 || (bpp) == 96 ? (bpp) : \
+ (bpp) == 128 ? 65 : 0)
+#define PIXMAN_FORMAT_UNPACK_BPP(bpp) ((bpp) <= 64 || (bpp) == 96 ? (bpp) : \
+ (bpp) == 65 ? 128 : 0)
+#define PIXMAN_FORMAT_PACKC(val) ((val) <= 10 ? (val) : \
+ (val) == 32 ? 11 : 0)
+#define PIXMAN_FORMAT_UNPACKC(val) ((val) <= 10 ? (val) : \
+ (val) == 11 ? 32 : 0)
+
+#define PIXMAN_FORMAT(bpp,type,a,r,g,b) ((PIXMAN_FORMAT_PACK_BPP(bpp) << 24) | \
((type) << 16) | \
- ((a) << 12) | \
- ((r) << 8) | \
- ((g) << 4) | \
- ((b)))
+ (PIXMAN_FORMAT_PACKC(a) << 12) | \
+ (PIXMAN_FORMAT_PACKC(r) << 8) | \
+ (PIXMAN_FORMAT_PACKC(g) << 4) | \
+ (PIXMAN_FORMAT_PACKC(b)))
-#define PIXMAN_FORMAT_BPP(f) (((f) >> 24) )
+#define PIXMAN_FORMAT_BPP(f) PIXMAN_FORMAT_UNPACK_BPP((f) >> 24)
#define PIXMAN_FORMAT_TYPE(f) (((f) >> 16) & 0xff)
-#define PIXMAN_FORMAT_A(f) (((f) >> 12) & 0x0f)
-#define PIXMAN_FORMAT_R(f) (((f) >> 8) & 0x0f)
-#define PIXMAN_FORMAT_G(f) (((f) >> 4) & 0x0f)
-#define PIXMAN_FORMAT_B(f) (((f) ) & 0x0f)
+#define PIXMAN_FORMAT_A(f) PIXMAN_FORMAT_UNPACKC(((f) >> 12) & 0x0f)
+#define PIXMAN_FORMAT_R(f) PIXMAN_FORMAT_UNPACKC(((f) >> 8) & 0x0f)
+#define PIXMAN_FORMAT_G(f) PIXMAN_FORMAT_UNPACKC(((f) >> 4) & 0x0f)
+#define PIXMAN_FORMAT_B(f) PIXMAN_FORMAT_UNPACKC(((f) >> 0) & 0x0f)
#define PIXMAN_FORMAT_RGB(f) (((f) ) & 0xfff)
#define PIXMAN_FORMAT_VIS(f) (((f) ) & 0xffff)
#define PIXMAN_FORMAT_DEPTH(f) (PIXMAN_FORMAT_A(f) + \
@@ -685,8 +694,13 @@ struct pixman_indexed
PIXMAN_FORMAT_TYPE(f) == PIXMAN_TYPE_BGRA || \
PIXMAN_FORMAT_TYPE(f) == PIXMAN_TYPE_RGBA)
-/* 32bpp formats */
typedef enum {
+/* 128bpp formats */
+ PIXMAN_rgba_float = PIXMAN_FORMAT(128,PIXMAN_TYPE_ARGB,32,32,32,32),
+/* 96bpp formats */
+ PIXMAN_rgb_float = PIXMAN_FORMAT(96,PIXMAN_TYPE_ARGB,0,32,32,32),
+
+/* 32bpp formats */
PIXMAN_a8r8g8b8 = PIXMAN_FORMAT(32,PIXMAN_TYPE_ARGB,8,8,8,8),
PIXMAN_x8r8g8b8 = PIXMAN_FORMAT(32,PIXMAN_TYPE_ARGB,0,8,8,8),
PIXMAN_a8b8g8r8 = PIXMAN_FORMAT(32,PIXMAN_TYPE_ABGR,8,8,8,8),
diff --git a/test/alphamap.c b/test/alphamap.c
index 4d09076fbcf3..150d33eed5b5 100644
--- a/test/alphamap.c
+++ b/test/alphamap.c
@@ -10,7 +10,8 @@ static const pixman_format_code_t formats[] =
PIXMAN_a8r8g8b8,
PIXMAN_a2r10g10b10,
PIXMAN_a4r4g4b4,
- PIXMAN_a8
+ PIXMAN_a8,
+ PIXMAN_rgba_float,
};
static const pixman_format_code_t alpha_formats[] =
@@ -18,7 +19,8 @@ static const pixman_format_code_t alpha_formats[] =
PIXMAN_null,
PIXMAN_a8,
PIXMAN_a2r10g10b10,
- PIXMAN_a4r4g4b4
+ PIXMAN_a4r4g4b4,
+ PIXMAN_rgba_float,
};
static const int origins[] =
@@ -41,7 +43,10 @@ make_image (pixman_format_code_t format)
uint8_t bpp = PIXMAN_FORMAT_BPP (format) / 8;
pixman_image_t *image;
- bits = (uint32_t *)make_random_bytes (WIDTH * HEIGHT * bpp);
+ if (format != PIXMAN_rgba_float)
+ bits = (uint32_t *)make_random_bytes (WIDTH * HEIGHT * bpp);
+ else
+ bits = (uint32_t *)make_random_floats (WIDTH * HEIGHT * bpp);
image = pixman_image_create_bits (format, WIDTH, HEIGHT, bits, WIDTH * bpp);
@@ -51,11 +56,11 @@ make_image (pixman_format_code_t format)
return image;
}
-static uint8_t
+static float
get_alpha (pixman_image_t *image, int x, int y, int orig_x, int orig_y)
{
uint8_t *bits;
- uint8_t r;
+ uint32_t r;
if (image->common.alpha_map)
{
@@ -69,7 +74,7 @@ get_alpha (pixman_image_t *image, int x, int y, int orig_x, int orig_y)
}
else
{
- return 0;
+ return 0.f;
}
}
@@ -78,28 +83,32 @@ get_alpha (pixman_image_t *image, int x, int y, int orig_x, int orig_y)
if (image->bits.format == PIXMAN_a8)
{
r = bits[y * WIDTH + x];
+ return r / 255.f;
}
else if (image->bits.format == PIXMAN_a2r10g10b10)
{
r = ((uint32_t *)bits)[y * WIDTH + x] >> 30;
- r |= r << 2;
- r |= r << 4;
+ return r / 3.f;
}
else if (image->bits.format == PIXMAN_a8r8g8b8)
{
r = ((uint32_t *)bits)[y * WIDTH + x] >> 24;
+ return r / 255.f;
}
else if (image->bits.format == PIXMAN_a4r4g4b4)
{
r = ((uint16_t *)bits)[y * WIDTH + x] >> 12;
- r |= r << 4;
+ return r / 15.f;
+ }
+ else if (image->bits.format == PIXMAN_rgba_float)
+ {
+ return ((float *)bits)[y * WIDTH * 4 + x * 4 + 3];
}
else
{
assert (0);
+ return 0.f;
}
-
- return r;
}
static uint16_t
@@ -133,6 +142,11 @@ get_red (pixman_image_t *image, int x, int y, int orig_x, int orig_y)
r |= r << 4;
r |= r << 8;
}
+ else if (image->bits.format == PIXMAN_rgba_float)
+ {
+ double tmp = ((float *)bits)[y * WIDTH * 4 + x * 4];
+ return tmp * 65535.;
+ }
else
{
assert (0);
@@ -141,6 +155,23 @@ get_red (pixman_image_t *image, int x, int y, int orig_x, int orig_y)
return r;
}
+static float get_alpha_err(pixman_format_code_t sf, pixman_format_code_t saf,
+ pixman_format_code_t df, pixman_format_code_t daf)
+{
+ pixman_format_code_t s = saf != PIXMAN_null ? saf : sf;
+ pixman_format_code_t d = daf != PIXMAN_null ? daf : df;
+
+ /* There are cases where we go through the 8 bit compositing
+ * path even with 10bpc and higher formats.
+ */
+ if (PIXMAN_FORMAT_A(s) == PIXMAN_FORMAT_A(d))
+ return 1.f / 255.f;
+ else if (PIXMAN_FORMAT_A(s) > PIXMAN_FORMAT_A(d))
+ return 1.f / ((1 << PIXMAN_FORMAT_A(d)) - 1);
+ else
+ return 1.f / ((1 << PIXMAN_FORMAT_A(s)) - 1);
+}
+
static int
run_test (int s, int d, int sa, int da, int soff, int doff)
{
@@ -151,15 +182,11 @@ run_test (int s, int d, int sa, int da, int soff, int doff)
pixman_image_t *src, *dst, *orig_dst, *alpha, *orig_alpha;
pixman_transform_t t1;
int j, k;
- int n_alpha_bits, n_red_bits;
+ int 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 */
@@ -211,21 +238,25 @@ run_test (int s, int d, int sa, int da, int soff, int doff)
{
for (k = MAX (doff, 0); k < MIN (WIDTH, WIDTH + doff); ++k)
{
- uint8_t sa, da, oda, refa;
+ float sa, da, oda, refa;
uint16_t sr, dr, odr, refr;
+ float err;
+
+ err = get_alpha_err(sf, saf, df, daf);
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;
+ if (sa + oda > 1.f)
+ refa = 1.f;
else
refa = sa + oda;
- if (da >> (8 - n_alpha_bits) != refa >> (8 - n_alpha_bits))
+ if (da - err > refa ||
+ da + err < refa)
{
- printf ("\nWrong alpha value at (%d, %d). Should be 0x%x; got 0x%x. Source was 0x%x, original dest was 0x%x\n",
+ printf ("\nWrong alpha value at (%d, %d). Should be %g; got %g. Source was %g, original dest was %g\n",
k, j, refa, da, sa, oda);
printf ("src: %s, alpha: %s, origin %d %d\ndst: %s, alpha: %s, origin: %d %d\n\n",
diff --git a/test/utils.c b/test/utils.c
index f8e42a5d3f3d..4eeb068497ec 100644
--- a/test/utils.c
+++ b/test/utils.c
@@ -595,6 +595,21 @@ make_random_bytes (int n_bytes)
return bytes;
}
+float *
+make_random_floats (int n_bytes)
+{
+ uint8_t *bytes = fence_malloc (n_bytes);
+ float *vals = (float *)bytes;
+
+ if (!bytes)
+ return 0;
+
+ for (n_bytes /= 4; n_bytes; vals++, n_bytes--)
+ *vals = (float)rand() / (float)RAND_MAX;
+
+ return (float *)bytes;
+}
+
void
a8r8g8b8_to_rgba_np (uint32_t *dst, uint32_t *src, int n_pixels)
{
@@ -1180,6 +1195,11 @@ static const format_entry_t format_list[] =
* Aliases are not listed by list_formats ().
*/
+/* 128bpp formats */
+ ENTRY (rgba_float),
+/* 96bpp formats */
+ ENTRY (rgb_float),
+
/* 32bpp formats */
ENTRY (a8r8g8b8),
ALIAS (a8r8g8b8, "8888"),
@@ -1914,6 +1934,10 @@ pixel_checker_init (pixel_checker_t *checker, pixman_format_code_t format)
checker->format = format;
+ if (format == PIXMAN_rgba_float ||
+ format == PIXMAN_rgb_float)
+ return;
+
switch (PIXMAN_FORMAT_TYPE (format))
{
case PIXMAN_TYPE_A:
@@ -1970,10 +1994,19 @@ pixel_checker_init (pixel_checker_t *checker, pixman_format_code_t format)
checker->bw = PIXMAN_FORMAT_B (format);
}
+static void
+pixel_checker_require_uint32_format (const pixel_checker_t *checker)
+{
+ assert (checker->format != PIXMAN_rgba_float &&
+ checker->format != PIXMAN_rgb_float);
+}
+
void
pixel_checker_split_pixel (const pixel_checker_t *checker, uint32_t pixel,
int *a, int *r, int *g, int *b)
{
+ pixel_checker_require_uint32_format(checker);
+
*a = (pixel & checker->am) >> checker->as;
*r = (pixel & checker->rm) >> checker->rs;
*g = (pixel & checker->gm) >> checker->gs;
@@ -1987,6 +2020,8 @@ pixel_checker_get_masks (const pixel_checker_t *checker,
uint32_t *gm,
uint32_t *bm)
{
+ pixel_checker_require_uint32_format(checker);
+
if (am)
*am = checker->am;
if (rm)
@@ -2003,6 +2038,8 @@ pixel_checker_convert_pixel_to_color (const pixel_checker_t *checker,
{
int a, r, g, b;
+ pixel_checker_require_uint32_format(checker);
+
pixel_checker_split_pixel (checker, pixel, &a, &r, &g, &b);
if (checker->am == 0)
@@ -2078,6 +2115,8 @@ void
pixel_checker_get_max (const pixel_checker_t *checker, color_t *color,
int *am, int *rm, int *gm, int *bm)
{
+ pixel_checker_require_uint32_format(checker);
+
get_limits (checker, DEVIATION, color, am, rm, gm, bm);
}
@@ -2085,6 +2124,8 @@ void
pixel_checker_get_min (const pixel_checker_t *checker, color_t *color,
int *am, int *rm, int *gm, int *bm)
{
+ pixel_checker_require_uint32_format(checker);
+
get_limits (checker, - DEVIATION, color, am, rm, gm, bm);
}
@@ -2096,6 +2137,8 @@ pixel_checker_check (const pixel_checker_t *checker, uint32_t pixel,
int32_t ai, ri, gi, bi;
pixman_bool_t result;
+ pixel_checker_require_uint32_format(checker);
+
pixel_checker_get_min (checker, color, &a_lo, &r_lo, &g_lo, &b_lo);
pixel_checker_get_max (checker, color, &a_hi, &r_hi, &g_hi, &b_hi);
pixel_checker_split_pixel (checker, pixel, &ai, &ri, &gi, &bi);
@@ -2108,3 +2151,36 @@ pixel_checker_check (const pixel_checker_t *checker, uint32_t pixel,
return result;
}
+
+static void
+color_limits (const pixel_checker_t *checker,
+ double limit, const color_t *color, color_t *out)
+{
+ if (PIXMAN_FORMAT_A(checker->format))
+ out->a = color->a + limit;
+ else
+ out->a = 1.;
+
+ out->r = color->r + limit;
+ out->g = color->g + limit;
+ out->b = color->b + limit;
+}
+
+pixman_bool_t
+pixel_checker_check_color (const pixel_checker_t *checker,
+ const color_t *actual, const color_t *reference)
+{
+ color_t min, max;
+ pixman_bool_t result;
+
+ color_limits(checker, -DEVIATION, reference, &min);
+ color_limits(checker, DEVIATION, reference, &max);
+
+ result =
+ actual->a >= min.a && actual->a <= max.a &&
+ actual->r >= min.r && actual->r <= max.r &&
+ actual->g >= min.g && actual->g <= max.g &&
+ actual->b >= min.b && actual->b <= max.b;
+
+ return result;
+}
diff --git a/test/utils.h b/test/utils.h
index e299d1d066ed..e5ac945ab3f8 100644
--- a/test/utils.h
+++ b/test/utils.h
@@ -119,6 +119,8 @@ fence_get_page_size ();
/* Generate n_bytes random bytes in fence_malloced memory */
uint8_t *
make_random_bytes (int n_bytes);
+float *
+make_random_floats (int n_bytes);
/* Return current time in seconds */
double
--
2.17.1
More information about the Pixman
mailing list