[3/4] test: Check the dithering path in tolerance-test

Submitted by Basile Clement on Dec. 3, 2018, 2:55 p.m.

Details

Message ID 20181203145530.9649-3-basile-pixman@clement.pm
State New
Series "Series without cover letter"
Headers show

Commit Message

Basile Clement Dec. 3, 2018, 2:55 p.m.
From: Basile Clement <basile@clement.pm>

This adds support for testing dithered destinations in tolerance-test.
When dithering is enabled, the pixel checker allows for an additional
quantization error.
---
 test/tolerance-test.c |  22 +++++++-
 test/utils.c          | 122 ++++++++++++++++++++++++++++++++++++++----
 test/utils.h          |  12 +++++
 3 files changed, 143 insertions(+), 13 deletions(-)

Patch hide | download patch | download mbox

diff --git a/test/tolerance-test.c b/test/tolerance-test.c
index 320bb7f..c4869e8 100644
--- a/test/tolerance-test.c
+++ b/test/tolerance-test.c
@@ -76,6 +76,11 @@  static const pixman_op_t operators[] =
     PIXMAN_OP_EXCLUSION,
 };
 
+static const pixman_dither_t dithers[] =
+{
+    PIXMAN_DITHER_BAYER_8,
+};
+
 #define RANDOM_ELT(array)                                               \
     (array[prng_rand_n (ARRAY_LENGTH (array))])
 
@@ -176,7 +181,8 @@  verify (int test_no,
         pixman_image_t *orig_dest,
         int x, int y,
         int width, int height,
-	pixman_bool_t component_alpha)
+	pixman_bool_t component_alpha,
+	pixman_dither_t dither)
 {
     pixel_checker_t dest_checker, src_checker, mask_checker;
     int i, j;
@@ -185,6 +191,9 @@  verify (int test_no,
     pixel_checker_init (&dest_checker, dest->bits.format);
     pixel_checker_init (&mask_checker, mask->bits.format);
 
+    if (dest->bits.dither != PIXMAN_DITHER_NONE)
+	pixel_checker_allow_dither (&dest_checker);
+
     assert (dest->bits.format == orig_dest->bits.format);
 
     for (j = y; j < y + height; ++j)
@@ -220,6 +229,7 @@  verify (int test_no,
                 
                 printf ("   operator:         %s (%s alpha)\n", operator_name (op),
 			component_alpha? "component" : "unified");
+		printf ("   dither:           %s\n", dither_name (dither));
                 printf ("   dest_x, dest_y:   %d %d\n", x, y);
                 printf ("   width, height:    %d %d\n", width, height);
                 printf ("   source:           format: %-14s  size: %2d x %2d\n",
@@ -275,6 +285,7 @@  do_check (int i)
     pixman_image_t *dest_copy;
     pixman_bool_t result = TRUE;
     pixman_bool_t component_alpha;
+    pixman_dither_t dither = PIXMAN_DITHER_NONE;
 
     prng_srand (i);
     op = RANDOM_ELT (operators);
@@ -296,6 +307,12 @@  do_check (int i)
     if (y + height > dest->bits.height)
         height = dest->bits.height - y;
 
+    if (prng_rand_n (2))
+    {
+	dither = RANDOM_ELT (dithers);
+	pixman_image_set_dither (dest, dither);
+    }
+
     component_alpha = prng_rand_n (2);
 
     pixman_image_set_component_alpha (mask, component_alpha);
@@ -305,7 +322,8 @@  do_check (int i)
                               x, y, width, height);
 
     if (!verify (i, op, source, mask, dest, dest_copy,
-		 x, y, width, height, component_alpha))
+		 x, y, width, height, component_alpha,
+	         dither))
     {
 	result = FALSE;
     }
diff --git a/test/utils.c b/test/utils.c
index 4eeb068..ba9c112 100644
--- a/test/utils.c
+++ b/test/utils.c
@@ -1174,6 +1174,31 @@  static const operator_entry_t op_list[] =
 #undef ALIAS
 };
 
+typedef struct {
+    pixman_dither_t	 dither;
+    const char		*name;
+    pixman_bool_t	 is_alias;
+} dither_entry_t;
+
+static const dither_entry_t dither_list[] =
+{
+#define ENTRY(dither)							\
+    { PIXMAN_DITHER_##dither, "PIXMAN_DITHER_" #dither, FALSE }
+#define ALIAS(dither, nam)							\
+    { PIXMAN_OP_##dither, nam, TRUE }
+
+    /* dither_name () will return the first hit in this table,
+     * so keep the list properly ordered between entries and aliases.
+     * Aliases are not listed by list_dithers ().
+     */
+
+    ENTRY (BAYER_8),
+    ENTRY (NONE),
+
+#undef ENTRY
+#undef ALIAS
+};
+
 struct format_entry
 {
     pixman_format_code_t format;
@@ -1382,6 +1407,28 @@  list_operators (void)
     printf ("\n\n");
 }
 
+void
+list_dithers (void)
+{
+    int n_chars;
+    int i;
+
+    printf ("Dithers:\n    ");
+
+    n_chars = 0;
+    for (i = 0; i < ARRAY_LENGTH (dither_list); ++i)
+    {
+        const dither_entry_t *ent = &dither_list[i];
+
+        if (ent->is_alias)
+            continue;
+
+        emit (ent->name, &n_chars);
+    }
+
+    printf ("\n\n");
+}
+
 pixman_op_t
 operator_from_string (const char *s)
 {
@@ -1406,6 +1453,22 @@  operator_from_string (const char *s)
     return PIXMAN_OP_NONE;
 }
 
+pixman_dither_t
+dither_from_string (const char *s)
+{
+    int i;
+
+    for (i = 0; i < ARRAY_LENGTH (dither_list); ++i)
+    {
+        const dither_entry_t *ent = &dither_list[i];
+
+        if (strcasecmp (ent->name, s) == 0)
+            return ent->dither;
+    }
+
+    return PIXMAN_DITHER_NONE;
+}
+
 const char *
 operator_name (pixman_op_t op)
 {
@@ -1438,6 +1501,22 @@  format_name (pixman_format_code_t format)
     return "<unknown format>";
 };
 
+const char *
+dither_name (pixman_dither_t dither)
+{
+    int i;
+
+    for (i = 0; i < ARRAY_LENGTH (dither_list); ++i)
+    {
+	const dither_entry_t *ent = &dither_list[i];
+
+	if (ent->dither == dither)
+	    return ent->name;
+    }
+
+    return "<unknown dither>";
+}
+
 #define IS_ZERO(f)     (-DBL_MIN < (f) && (f) < DBL_MIN)
 
 typedef double (* blend_func_t) (double as, double s, double ad, double d);
@@ -1924,6 +2003,10 @@  round_color (pixman_format_code_t format, color_t *color)
 	color->a = round_channel (color->a, PIXMAN_FORMAT_A (format));
 }
 
+/* The acceptable deviation in units of [0.0, 1.0]
+ */
+#define DEVIATION (0.0128)
+
 /* Check whether @pixel is a valid quantization of the a, r, g, b
  * parameters. Some slack is permitted.
  */
@@ -1992,6 +2075,23 @@  pixel_checker_init (pixel_checker_t *checker, pixman_format_code_t format)
     checker->rw = PIXMAN_FORMAT_R (format);
     checker->gw = PIXMAN_FORMAT_G (format);
     checker->bw = PIXMAN_FORMAT_B (format);
+
+    checker->ad = DEVIATION;
+    checker->rd = DEVIATION;
+    checker->gd = DEVIATION;
+    checker->bd = DEVIATION;
+}
+
+/* When dithering is enabled, we allow one extra pixel of tolerance
+ * for the components which were higher resolution in the source.
+ */
+void
+pixel_checker_allow_dither (pixel_checker_t *checker)
+{
+    checker->ad += 1 / (double)((1 << checker->aw) - 1);
+    checker->rd += 1 / (double)((1 << checker->rw) - 1);
+    checker->gd += 1 / (double)((1 << checker->gw) - 1);
+    checker->bd += 1 / (double)((1 << checker->bw) - 1);
 }
 
 static void
@@ -2085,7 +2185,7 @@  convert (double v, uint32_t width, uint32_t mask, uint32_t shift, double def)
 }
 
 static void
-get_limits (const pixel_checker_t *checker, double limit,
+get_limits (const pixel_checker_t *checker, double sign,
 	    color_t *color,
 	    int *ao, int *ro, int *go, int *bo)
 {
@@ -2101,23 +2201,23 @@  get_limits (const pixel_checker_t *checker, double limit,
 	color = &tmp;
     }
     
-    *ao = convert (color->a + limit, checker->aw, checker->am, checker->as, 1.0);
-    *ro = convert (color->r + limit, checker->rw, checker->rm, checker->rs, 0.0);
-    *go = convert (color->g + limit, checker->gw, checker->gm, checker->gs, 0.0);
-    *bo = convert (color->b + limit, checker->bw, checker->bm, checker->bs, 0.0);
+    *ao = convert (color->a + sign * checker->ad,
+		   checker->aw, checker->am, checker->as, 1.0);
+    *ro = convert (color->r + sign * checker->rd,
+		   checker->rw, checker->rm, checker->rs, 0.0);
+    *go = convert (color->g + sign * checker->gd,
+		   checker->gw, checker->gm, checker->gs, 0.0);
+    *bo = convert (color->b + sign * checker->bd,
+		   checker->bw, checker->bm, checker->bs, 0.0);
 }
 
-/* The acceptable deviation in units of [0.0, 1.0]
- */
-#define DEVIATION (0.0128)
-
 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);
+    get_limits (checker, 1, color, am, rm, gm, bm);
 }
 
 void
@@ -2126,7 +2226,7 @@  pixel_checker_get_min (const pixel_checker_t *checker, color_t *color,
 {
     pixel_checker_require_uint32_format(checker);
 
-    get_limits (checker, - DEVIATION, color, am, rm, gm, bm);
+    get_limits (checker, - 1, color, am, rm, gm, bm);
 }
 
 pixman_bool_t
diff --git a/test/utils.h b/test/utils.h
index e5ac945..701417f 100644
--- a/test/utils.h
+++ b/test/utils.h
@@ -219,15 +219,23 @@  list_formats (void);
 void
 list_operators (void);
 
+void list_dithers (void);
+
 pixman_op_t
 operator_from_string (const char *s);
 
+pixman_dither_t
+dither_from_string (const char *s);
+
 const char *
 operator_name (pixman_op_t op);
 
 const char *
 format_name (pixman_format_code_t format);
 
+const char *
+dither_name (pixman_dither_t dither);
+
 typedef struct
 {
     double r, g, b, a;
@@ -250,11 +258,15 @@  typedef struct
     uint32_t am, rm, gm, bm;
     uint32_t as, rs, gs, bs;
     uint32_t aw, rw, gw, bw;
+    float ad, rd, gd, bd;
 } pixel_checker_t;
 
 void
 pixel_checker_init (pixel_checker_t *checker, pixman_format_code_t format);
 
+void
+pixel_checker_allow_dither (pixel_checker_t *checker);
+
 void
 pixel_checker_split_pixel (const pixel_checker_t *checker, uint32_t pixel,
 			   int *a, int *r, int *g, int *b);