[gtk/wip/otte/float-textures: 3/7] testsuite: Overhaul memorytexture test




commit 0c32a579237b774867fb6a6362d8646a31bb2c17
Author: Benjamin Otte <otte redhat com>
Date:   Sat Sep 11 21:19:48 2021 +0200

    testsuite: Overhaul memorytexture test
    
    Instead of hardcoding pixel values, allow construction of textures by
    filling them with GdkRGBA values.

 testsuite/gdk/memorytexture.c | 449 ++++++++++++++++++++++++++++++------------
 1 file changed, 327 insertions(+), 122 deletions(-)
---
diff --git a/testsuite/gdk/memorytexture.c b/testsuite/gdk/memorytexture.c
index ea24c827e3..49f7159965 100644
--- a/testsuite/gdk/memorytexture.c
+++ b/testsuite/gdk/memorytexture.c
@@ -1,9 +1,6 @@
 #include <locale.h>
 #include <gdk/gdk.h>
 
-/* maximum bytes per pixel */
-#define MAX_BPP 4
-
 typedef enum {
   BLUE,
   GREEN,
@@ -13,7 +10,7 @@ typedef enum {
   N_COLORS
 } Color;
 
-const char * color_names[N_COLORS] = {
+static const char * color_names[N_COLORS] = {
   "blue",
   "green",
   "red",
@@ -21,37 +18,310 @@ const char * color_names[N_COLORS] = {
   "almost_opaque_rebeccapurple"
 };
 
-typedef struct _MemoryData {
-  gsize bytes_per_pixel;
-  guint opaque : 1;
-  guchar data[N_COLORS][MAX_BPP];
-} MemoryData;
+static const GdkRGBA colors[N_COLORS] = {
+  { 0.0, 0.0, 1.0, 1.0 },
+  { 0.0, 1.0, 0.0, 1.0 },
+  { 1.0, 0.0, 0.0, 1.0 },
+  { 0.0, 0.0, 0.0, 0.0 },
+  { 0.4, 0.2, 0.6, 2.f/3.f },
+};
+
+typedef struct _TextureBuilder TextureBuilder;
+typedef struct _TestData TestData;
+
+struct _TextureBuilder
+{
+  GdkMemoryFormat format;
+  int width;
+  int height;
+
+  guchar *pixels;
+  gsize stride;
+  gsize offset;
+};
 
-typedef struct _TestData {
+struct _TestData
+{
   GdkMemoryFormat format;
   Color color;
-} TestData;
-
-#define RGBA(a, b, c, d) { 0x ## a, 0x ## b, 0x ## c, 0x ## d }
-
-static MemoryData tests[GDK_MEMORY_N_FORMATS] = {
-  { 4, FALSE, { RGBA(FF,00,00,FF), RGBA(00,FF,00,FF), RGBA(00,00,FF,FF), RGBA(00,00,00,00), 
RGBA(66,22,44,AA) } },
-  { 4, FALSE, { RGBA(FF,00,00,FF), RGBA(FF,00,FF,00), RGBA(FF,FF,00,00), RGBA(00,00,00,00), 
RGBA(AA,44,22,66) } },
-  { 4, FALSE, { RGBA(00,00,FF,FF), RGBA(00,FF,00,FF), RGBA(FF,00,00,FF), RGBA(00,00,00,00), 
RGBA(44,22,66,AA) } },
-  { 4, FALSE, { RGBA(FF,00,00,FF), RGBA(00,FF,00,FF), RGBA(00,00,FF,FF), RGBA(00,00,00,00), 
RGBA(99,33,66,AA) } },
-  { 4, FALSE, { RGBA(FF,00,00,FF), RGBA(FF,00,FF,00), RGBA(FF,FF,00,00), RGBA(00,00,00,00), 
RGBA(AA,66,33,99) } },
-  { 4, FALSE, { RGBA(00,00,FF,FF), RGBA(00,FF,00,FF), RGBA(FF,00,00,FF), RGBA(00,00,00,00), 
RGBA(66,33,99,AA) } },
-  { 4, FALSE, { RGBA(FF,FF,00,00), RGBA(FF,00,FF,00), RGBA(FF,00,00,FF), RGBA(00,00,00,00), 
RGBA(AA,99,33,66) } },
-  { 3, TRUE,  { RGBA(00,00,FF,00), RGBA(00,FF,00,00), RGBA(FF,00,00,00), RGBA(00,00,00,00), 
RGBA(44,22,66,00) } },
-  { 3, TRUE,  { RGBA(FF,00,00,00), RGBA(00,FF,00,00), RGBA(00,00,FF,00), RGBA(00,00,00,00), 
RGBA(66,22,44,00) } },
 };
 
+static gsize
+gdk_memory_format_bytes_per_pixel (GdkMemoryFormat format)
+{
+  switch (format)
+    {
+    case GDK_MEMORY_R8G8B8:
+    case GDK_MEMORY_B8G8R8:
+      return 3;
+
+    case GDK_MEMORY_B8G8R8A8_PREMULTIPLIED:
+    case GDK_MEMORY_A8R8G8B8_PREMULTIPLIED:
+    case GDK_MEMORY_R8G8B8A8_PREMULTIPLIED:
+    case GDK_MEMORY_B8G8R8A8:
+    case GDK_MEMORY_A8R8G8B8:
+    case GDK_MEMORY_R8G8B8A8:
+    case GDK_MEMORY_A8B8G8R8:
+      return 4;
+
+    case GDK_MEMORY_R16G16B16:
+    case GDK_MEMORY_R16G16B16_FLOAT:
+      return 6;
+
+    case GDK_MEMORY_R16G16B16A16_PREMULTIPLIED:
+    case GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED:
+      return 8;
+
+    case GDK_MEMORY_R32G32B32_FLOAT:
+      return 12;
+
+    case GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED:
+      return 16;
+
+    case GDK_MEMORY_N_FORMATS:
+    default:
+      g_assert_not_reached ();
+      return 4;
+    }
+}
+
+static gboolean
+gdk_memory_format_has_alpha (GdkMemoryFormat format)
+{
+  switch (format)
+    {
+    case GDK_MEMORY_R8G8B8:
+    case GDK_MEMORY_B8G8R8:
+    case GDK_MEMORY_R16G16B16:
+    case GDK_MEMORY_R16G16B16_FLOAT:
+    case GDK_MEMORY_R32G32B32_FLOAT:
+      return FALSE;
+
+    case GDK_MEMORY_B8G8R8A8_PREMULTIPLIED:
+    case GDK_MEMORY_A8R8G8B8_PREMULTIPLIED:
+    case GDK_MEMORY_R8G8B8A8_PREMULTIPLIED:
+    case GDK_MEMORY_B8G8R8A8:
+    case GDK_MEMORY_A8R8G8B8:
+    case GDK_MEMORY_R8G8B8A8:
+    case GDK_MEMORY_A8B8G8R8:
+    case GDK_MEMORY_R16G16B16A16_PREMULTIPLIED:
+    case GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED:
+    case GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED:
+      return TRUE;
+
+    case GDK_MEMORY_N_FORMATS:
+    default:
+      g_assert_not_reached ();
+      return TRUE;
+    }
+}
+
+static void
+texture_builder_init (TextureBuilder  *builder,
+                      GdkMemoryFormat  format,
+                      int              width,
+                      int              height)
+{
+  gsize extra_stride;
+
+  builder->format = format;
+  builder->width = width;
+  builder->height = height;
+
+  extra_stride = g_test_rand_bit() ? g_test_rand_int_range (0, 16) : 0;
+  builder->offset = g_test_rand_bit() ? g_test_rand_int_range (0, 128) : 0;
+  builder->stride = width * gdk_memory_format_bytes_per_pixel (format) + extra_stride;
+  builder->pixels = g_malloc0 (builder->offset + builder->stride * height);
+}
+
+static GdkTexture *
+texture_builder_finish (TextureBuilder *builder)
+{
+  GBytes *bytes;
+  GdkTexture *texture;
+
+  bytes = g_bytes_new_with_free_func (builder->pixels + builder->offset,
+                                      builder->height * builder->stride,
+                                      g_free,
+                                      builder->pixels);
+  texture = gdk_memory_texture_new (builder->width,
+                                    builder->height,
+                                    builder->format,
+                                    bytes,
+                                    builder->stride);
+  g_bytes_unref (bytes);
+
+  return texture;
+}
+
+static inline void
+set_pixel_u8 (guchar          *data,
+              int              r,
+              int              g,
+              int              b,
+              int              a,
+              gboolean         premultiply,
+              const GdkRGBA   *color)
+{
+  if (a >= 0)
+    data[a] = CLAMP (color->alpha * 256.f, 0.f, 255.f);
+  if (premultiply)
+    {
+      data[r] = CLAMP (color->red * color->alpha * 256.f, 0.f, 255.f);
+      data[g] = CLAMP (color->green * color->alpha * 256.f, 0.f, 255.f);
+      data[b] = CLAMP (color->blue * color->alpha * 256.f, 0.f, 255.f);
+    }
+  else
+    {
+      data[r] = CLAMP (color->red * 256.f, 0.f, 255.f);
+      data[g] = CLAMP (color->green * 256.f, 0.f, 255.f);
+      data[b] = CLAMP (color->blue * 256.f, 0.f, 255.f);
+    }
+}
+
+static inline guint16
+float_to_half (const float x)
+{
+  const guint b = *(guint*)&x+0x00001000; // round-to-nearest-even
+  const guint e = (b&0x7F800000)>>23; // exponent
+  const guint m = b&0x007FFFFF; // mantissa
+  return (b&0x80000000)>>16 | (e>112)*((((e-112)<<10)&0x7C00)|m>>13) | 
((e<113)&(e>101))*((((0x007FF000+m)>>(125-e))+1)>>1) | (e>143)*0x7FFF; // sign : normalized : denormalized : 
saturate
+}
+
+static void
+texture_builder_set_pixel (TextureBuilder  *builder,
+                           int              x,
+                           int              y,
+                           const GdkRGBA   *color)
+{
+  guchar *data;
+
+  g_assert_cmpint (x, >=, 0);
+  g_assert_cmpint (x, <, builder->width);
+  g_assert_cmpint (y, >=, 0);
+  g_assert_cmpint (y, <, builder->height);
+
+  data = builder->pixels
+         + builder->offset
+         + y * builder->stride
+         + x * gdk_memory_format_bytes_per_pixel (builder->format);
+
+  switch (builder->format)
+  {
+    case GDK_MEMORY_B8G8R8A8_PREMULTIPLIED:
+      set_pixel_u8 (data, 2, 1, 0, 3, TRUE, color);
+      break;
+    case GDK_MEMORY_A8R8G8B8_PREMULTIPLIED:
+      set_pixel_u8 (data, 1, 2, 3, 0, TRUE, color);
+      break;
+    case GDK_MEMORY_R8G8B8A8_PREMULTIPLIED:
+      set_pixel_u8 (data, 0, 1, 2, 3, TRUE, color);
+      break;
+    case GDK_MEMORY_B8G8R8A8:
+      set_pixel_u8 (data, 2, 1, 0, 3, FALSE, color);
+      break;
+    case GDK_MEMORY_A8R8G8B8:
+      set_pixel_u8 (data, 1, 2, 3, 0, FALSE, color);
+      break;
+    case GDK_MEMORY_R8G8B8A8:
+      set_pixel_u8 (data, 0, 1, 2, 3, FALSE, color);
+      break;
+    case GDK_MEMORY_A8B8G8R8:
+      set_pixel_u8 (data, 3, 2, 1, 0, FALSE, color);
+      break;
+    case GDK_MEMORY_R8G8B8:
+      set_pixel_u8 (data, 0, 1, 2, -1, TRUE, color);
+      break;
+    case GDK_MEMORY_B8G8R8:
+      set_pixel_u8 (data, 2, 1, 0, -1, TRUE, color);
+      break;
+    case GDK_MEMORY_R16G16B16:
+      {
+        guint16 pixels[3] = {
+          CLAMP (color->red * color->alpha * 65536.f, 0, 65535.f),
+          CLAMP (color->green * color->alpha * 65536.f, 0, 65535.f),
+          CLAMP (color->blue * color->alpha * 65536.f, 0, 65535.f),
+        };
+        memcpy (data, pixels, 3 * sizeof (guint16));
+      }
+      break;
+    case GDK_MEMORY_R16G16B16A16_PREMULTIPLIED:
+      {
+        guint16 pixels[4] = {
+          CLAMP (color->red * color->alpha * 65536.f, 0, 65535.f),
+          CLAMP (color->green * color->alpha * 65536.f, 0, 65535.f),
+          CLAMP (color->blue * color->alpha * 65536.f, 0, 65535.f),
+          CLAMP (color->alpha * 65536.f, 0, 65535.f),
+        };
+        memcpy (data, pixels, 4 * sizeof (guint16));
+      }
+      break;
+    case GDK_MEMORY_R16G16B16_FLOAT:
+      {
+        guint16 pixels[3] = {
+          float_to_half (color->red * color->alpha),
+          float_to_half (color->green * color->alpha),
+          float_to_half (color->blue * color->alpha)
+        };
+        memcpy (data, pixels, 3 * sizeof (guint16));
+      }
+      break;
+    case GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED:
+      {
+        guint16 pixels[4] = {
+          float_to_half (color->red * color->alpha),
+          float_to_half (color->green * color->alpha),
+          float_to_half (color->blue * color->alpha),
+          float_to_half (color->alpha)
+        };
+        memcpy (data, pixels, 4 * sizeof (guint16));
+      }
+      break;
+    case GDK_MEMORY_R32G32B32_FLOAT:
+      {
+        float pixels[3] = {
+          color->red * color->alpha,
+          color->green * color->alpha,
+          color->blue * color->alpha
+        };
+        memcpy (data, pixels, 3 * sizeof (float));
+      }
+      break;
+    case GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED:
+      {
+        float pixels[4] = {
+          color->red * color->alpha,
+          color->green * color->alpha,
+          color->blue * color->alpha,
+          color->alpha
+        };
+        memcpy (data, pixels, 4 * sizeof (float));
+      }
+      break;
+    case GDK_MEMORY_N_FORMATS:
+    default:
+      g_assert_not_reached ();
+      break;
+  }
+}
+
+static void
+texture_builder_fill (TextureBuilder  *builder,
+                      const GdkRGBA   *color)
+{
+  int x, y;
+
+  for (y = 0; y < builder->height; y++)
+    for (x = 0; x < builder->width; x++)
+      texture_builder_set_pixel (builder, x, y, color);
+}
+
 static void
 compare_textures (GdkTexture *expected,
                   GdkTexture *test,
-                  gboolean    ignore_alpha)
+                  gboolean    has_alpha)
 {
-  guchar *expected_data, *test_data;
+  guint32 *expected_data, *test_data;
   int width, height;
   int x, y;
 
@@ -61,20 +331,20 @@ compare_textures (GdkTexture *expected,
   width = gdk_texture_get_width (expected);
   height = gdk_texture_get_height (expected);
 
-  expected_data = g_malloc (width * height * 4);
-  gdk_texture_download (expected, expected_data, width * 4);
+  expected_data = g_new (guint32, width * height);
+  gdk_texture_download (expected, (guchar *) expected_data, width * 4);
 
-  test_data = g_malloc (width * height * 4);
-  gdk_texture_download (test, test_data, width * 4);
+  test_data = g_new (guint32, width * height);
+  gdk_texture_download (test, (guchar *) test_data, width * 4);
 
   for (y = 0; y < height; y++)
     {
       for (x = 0; x < width; x++)
         {
-          if (ignore_alpha)
-            g_assert_cmphex (*(guint32 *) &expected_data[y * width + x * 4] & 0xFFFFFF, ==, *(guint32 *) 
&test_data[y * width + x * 4] & 0xFFFFFF);
+          if (has_alpha)
+            g_assert_cmphex (expected_data[y * width + x], ==, test_data[y * width + x]);
           else
-            g_assert_cmphex (*(guint32 *) &expected_data[y * width + x * 4], ==, *(guint32 *) &test_data[y * 
width + x * 4]);
+            g_assert_cmphex (expected_data[y * width + x] | 0xFF000000, ==, test_data[y * width + x]);
         }
     }
 
@@ -84,33 +354,16 @@ compare_textures (GdkTexture *expected,
 
 static GdkTexture *
 create_texture (GdkMemoryFormat  format,
-                Color            color,
                 int              width,
                 int              height,
-                gsize            stride)
+                const GdkRGBA   *color)
 {
-  GdkTexture *texture;
-  GBytes *bytes;
-  guchar *data;
-  int x, y;
+  TextureBuilder builder;
 
-  data = g_malloc (height * MAX (stride, tests[format].bytes_per_pixel));
-  for (y = 0; y < height; y++)
-    for (x = 0; x < width; x++)
-      {
-        memcpy (&data[y * stride + x * tests[format].bytes_per_pixel],
-                &tests[format].data[color],
-                tests[format].bytes_per_pixel);
-      }
+  texture_builder_init (&builder, format, width, height);
+  texture_builder_fill (&builder, color);
 
-  bytes = g_bytes_new_take (data, height * MAX (stride, tests[format].bytes_per_pixel));
-  texture = gdk_memory_texture_new (width, height,
-                                    format,
-                                    bytes,
-                                    stride);
-  g_bytes_unref (bytes);
-
-  return texture;
+  return texture_builder_finish (&builder);
 }
 
 static void
@@ -119,25 +372,10 @@ test_download_1x1 (gconstpointer data)
   const TestData *test_data = data;
   GdkTexture *expected, *test;
 
-  expected = create_texture (GDK_MEMORY_DEFAULT, test_data->color, 1, 1, 
tests[test_data->format].bytes_per_pixel);
-  test = create_texture (test_data->format, test_data->color, 1, 1, 
tests[test_data->format].bytes_per_pixel);
+  expected = create_texture (GDK_MEMORY_DEFAULT, 1, 1, &colors[test_data->color]);
+  test = create_texture (test_data->format, 1, 1, &colors[test_data->color]);
 
-  compare_textures (expected, test, tests[test_data->format].opaque);
-
-  g_object_unref (expected);
-  g_object_unref (test);
-}
-
-static void
-test_download_1x1_with_stride (gconstpointer data)
-{
-  const TestData *test_data = data;
-  GdkTexture *expected, *test;
-
-  expected = create_texture (GDK_MEMORY_DEFAULT, test_data->color, 1, 1, 4);
-  test = create_texture (test_data->format, test_data->color, 1, 1, 2 * MAX_BPP);
-
-  compare_textures (expected, test, tests[test_data->format].opaque);
+  compare_textures (expected, test, gdk_memory_format_has_alpha (test_data->format));
 
   g_object_unref (expected);
   g_object_unref (test);
@@ -149,39 +387,23 @@ test_download_4x4 (gconstpointer data)
   const TestData *test_data = data;
   GdkTexture *expected, *test;
 
-  expected = create_texture (GDK_MEMORY_DEFAULT, test_data->color, 4, 4, 16);
-  test = create_texture (test_data->format, test_data->color, 4, 4, 4 * 
tests[test_data->format].bytes_per_pixel);
+  expected = create_texture (GDK_MEMORY_DEFAULT, 4, 4, &colors[test_data->color]);
+  test = create_texture (test_data->format, 4, 4, &colors[test_data->color]);
 
-  compare_textures (expected, test, tests[test_data->format].opaque);
+  compare_textures (expected, test, gdk_memory_format_has_alpha (test_data->format));
 
   g_object_unref (expected);
   g_object_unref (test);
 }
 
 static void
-test_download_4x4_with_stride (gconstpointer data)
-{
-  const TestData *test_data = data;
-  GdkTexture *expected, *test;
-
-  expected = create_texture (GDK_MEMORY_DEFAULT, test_data->color, 4, 4, 16);
-  test = create_texture (test_data->format, test_data->color, 4, 4, 4 * MAX_BPP);
-
-  compare_textures (expected, test, tests[test_data->format].opaque);
-
-  g_object_unref (expected);
-  g_object_unref (test);
-}
-
-int
-main (int argc, char *argv[])
+add_test (const char    *name,
+          GTestDataFunc  func)
 {
   GdkMemoryFormat format;
   Color color;
   GEnumClass *enum_class;
 
-  (g_test_init) (&argc, &argv, NULL);
-
   enum_class = g_type_class_ref (GDK_TYPE_MEMORY_FORMAT);
 
   for (format = 0; format < GDK_MEMORY_N_FORMATS; format++)
@@ -189,42 +411,25 @@ main (int argc, char *argv[])
       for (color = 0; color < N_COLORS; color++)
         {
           TestData *test_data = g_new (TestData, 1);
-          char *test_name = g_strdup_printf ("/memorytexture/download_1x1/%s/%s",
+          char *test_name = g_strdup_printf ("%s/%s/%s",
+                                             name,
                                              g_enum_get_value (enum_class, format)->value_nick,
                                              color_names[color]);
           test_data->format = format;
           test_data->color = color;
           g_test_add_data_func_full (test_name, test_data, test_download_1x1, g_free);
           g_free (test_name);
-
-          test_data = g_new (TestData, 1);
-          test_name = g_strdup_printf ("/memorytexture/download_1x1_with_stride/%s/%s",
-                                       g_enum_get_value (enum_class, format)->value_nick,
-                                       color_names[color]);
-          test_data->format = format;
-          test_data->color = color;
-          g_test_add_data_func_full (test_name, test_data, test_download_1x1_with_stride, g_free);
-          g_free (test_name);
-
-          test_data = g_new (TestData, 1);
-          test_name = g_strdup_printf ("/memorytexture/download_4x4/%s/%s",
-                                       g_enum_get_value (enum_class, format)->value_nick,
-                                       color_names[color]);
-          test_data->format = format;
-          test_data->color = color;
-          g_test_add_data_func_full (test_name, test_data, test_download_4x4, g_free);
-          g_free (test_name);
-
-          test_data = g_new (TestData, 1);
-          test_name = g_strdup_printf ("/memorytexture/download_4x4_with_stride/%s/%s",
-                                       g_enum_get_value (enum_class, format)->value_nick,
-                                       color_names[color]);
-          test_data->format = format;
-          test_data->color = color;
-          g_test_add_data_func_full (test_name, test_data, test_download_4x4_with_stride, g_free);
-          g_free (test_name);
         }
     }
+}
+
+int
+main (int argc, char *argv[])
+{
+  (g_test_init) (&argc, &argv, NULL);
+
+  add_test ("/memorytexture/download_1x1", test_download_1x1);
+  add_test ("/memorytexture/download_4x4", test_download_4x4);
 
   return g_test_run ();
 }


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]