[gtk/wip/otte/float-textures: 24/30] memorytexture: Add support for HDR formats




commit 59acd058ec21663465a2f7ff944bd2751ac7b1cc
Author: Benjamin Otte <otte redhat com>
Date:   Sat Sep 11 21:18:56 2021 +0200

    memorytexture: Add support for HDR formats
    
    Also sanitize the input bytes so the strides match alignment
    requirements of the data types.

 gdk/gdkmemorytexture.c | 295 ++++++++++++++++++++++++++++++++++++++++++++++++-
 gdk/gdkmemorytexture.h |  21 ++++
 2 files changed, 312 insertions(+), 4 deletions(-)
---
diff --git a/gdk/gdkmemorytexture.c b/gdk/gdkmemorytexture.c
index 6d0c861eec..631357bcc8 100644
--- a/gdk/gdkmemorytexture.c
+++ b/gdk/gdkmemorytexture.c
@@ -20,6 +20,7 @@
 #include "config.h"
 
 #include "gdkmemorytextureprivate.h"
+#include "gsk/ngl/fp16private.h"
 
 /**
  * GdkMemoryTexture:
@@ -49,6 +50,10 @@ 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:
@@ -58,14 +63,59 @@ gdk_memory_format_bytes_per_pixel (GdkMemoryFormat format)
     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 gsize
+gdk_memory_format_alignment (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 G_ALIGNOF (guchar);
+
+    case GDK_MEMORY_R16G16B16:
+    case GDK_MEMORY_R16G16B16_FLOAT:
+      return G_ALIGNOF (guint16);
+
+    case GDK_MEMORY_R16G16B16A16_PREMULTIPLIED:
+    case GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED:
+      return G_ALIGNOF (guint16);
+
+    case GDK_MEMORY_R32G32B32_FLOAT:
+    case GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED:
+      return G_ALIGNOF (float);
 
     case GDK_MEMORY_N_FORMATS:
     default:
       g_assert_not_reached ();
-      return 4;
+      return G_ALIGNOF (double);
     }
 }
 
@@ -133,6 +183,41 @@ gdk_memory_texture_init (GdkMemoryTexture *self)
 {
 }
 
+static GBytes *
+gdk_memory_sanitize (GBytes          *bytes,
+                     int              width,
+                     int              height,
+                     GdkMemoryFormat  format,
+                     gsize            stride,
+                     gsize           *out_stride)
+{
+  gsize align, size, copy_stride, bpp;
+  const guchar *data;
+  guchar *copy;
+  int y;
+
+  data = g_bytes_get_data (bytes, &size);
+  align = gdk_memory_format_alignment (format);
+
+  if (GPOINTER_TO_SIZE (data) % align == 0 &&
+      stride % align == 0)
+    {
+      *out_stride = stride;
+      return g_bytes_ref (bytes);
+    }
+
+  bpp = gdk_memory_format_bytes_per_pixel (format);
+  copy_stride = bpp * width;
+  /* align to multiples of 4, just to be sure */
+  copy_stride = (copy_stride + 3) & ~3;
+  copy = g_malloc (copy_stride * height);
+  for (y = 0; y < height; y++)
+    memcpy (copy + y * copy_stride, data + y * stride, bpp * width);
+
+  *out_stride = copy_stride;
+  return g_bytes_new_take (copy, copy_stride * height);
+}
+
 /**
  * gdk_memory_texture_new:
  * @width: the width of the texture
@@ -157,13 +242,20 @@ gdk_memory_texture_new (int              width,
 {
   GdkMemoryTexture *self;
 
+  g_return_val_if_fail (width > 0, NULL);
+  g_return_val_if_fail (height > 0, NULL);
+  g_return_val_if_fail (bytes != NULL, NULL);
+  g_return_val_if_fail (stride >= width * gdk_memory_format_bytes_per_pixel (format), NULL);
+
+  bytes = gdk_memory_sanitize (bytes, width, height, format, stride, &stride);
+
   self = g_object_new (GDK_TYPE_MEMORY_TEXTURE,
                        "width", width,
                        "height", height,
                        NULL);
 
   self->format = format;
-  self->bytes = g_bytes_ref (bytes);
+  self->bytes = bytes;
   self->stride = stride;
 
   return GDK_TEXTURE (self);
@@ -304,6 +396,109 @@ SWIZZLE_PREMULTIPLY (3,0,1,2, 0,1,2,3)
 SWIZZLE_PREMULTIPLY (3,0,1,2, 3,0,1,2)
 SWIZZLE_PREMULTIPLY (3,0,1,2, 0,3,2,1)
 
+#define CONVERT_FUNC(name,suffix,R,G,B,A,step) \
+static void \
+convert_ ## name ## _to_ ## suffix (guchar       *dest_data, \
+                                    gsize         dest_stride, \
+                                    const guchar *src_data, \
+                                    gsize         src_stride, \
+                                    gsize         width, \
+                                    gsize         height) \
+{ \
+  gsize x, y; \
+\
+  for (y = 0; y < height; y++) \
+    { \
+      for (x = 0; x < width; x++) \
+        { \
+          guchar conv[4]; \
+          convert_pixel_ ## name (conv, src_data + step * x); \
+          dest_data[4 * x + R] = conv[0]; \
+          dest_data[4 * x + G] = conv[1]; \
+          dest_data[4 * x + B] = conv[2]; \
+          dest_data[4 * x + A] = conv[3]; \
+        } \
+\
+      dest_data += dest_stride; \
+      src_data += src_stride; \
+    } \
+}
+
+#define CONVERT_FUNCS(name,step) \
+CONVERT_FUNC(name, download_le, 2, 1, 0, 3, step) \
+CONVERT_FUNC(name, download_be, 1, 2, 3, 0, step) \
+CONVERT_FUNC(name, gles_rgba, 0, 1, 2, 3, step) \
+
+static inline void
+convert_pixel_rgb16 (guchar *dest_data, const guchar *src_data)
+{
+  const guint16 *src = (const guint16 *) src_data;
+  dest_data[0] = (guchar)(src[0] >> 8);
+  dest_data[1] = (guchar)(src[1] >> 8);
+  dest_data[2] = (guchar)(src[2] >> 8);
+  dest_data[3] = 0xFF;
+}
+CONVERT_FUNCS(rgb16, 3 * sizeof (guint16))
+
+static inline void
+convert_pixel_rgba16 (guchar *dest_data, const guchar *src_data)
+{
+  const guint16 *src = (const guint16 *) src_data;
+  dest_data[0] = (guchar)(src[0] >> 8);
+  dest_data[1] = (guchar)(src[1] >> 8);
+  dest_data[2] = (guchar)(src[2] >> 8);
+  dest_data[3] = (guchar)(src[3] >> 8);
+}
+CONVERT_FUNCS(rgba16, 4 * sizeof (guint16))
+
+static inline void
+convert_pixel_rgb16f (guchar *dest_data, const guchar *src_data)
+{
+  float src[4];
+  guint16 tmp[4];
+  memcpy(tmp, src_data, sizeof(guint16) * 3);
+  half_to_float4(tmp, src);
+  dest_data[0] = CLAMP (src[0] * 256.f, 0.f, 255.f);
+  dest_data[1] = CLAMP (src[1] * 256.f, 0.f, 255.f);
+  dest_data[2] = CLAMP (src[2] * 256.f, 0.f, 255.f);
+  dest_data[3] = 0xFF;
+}
+CONVERT_FUNCS(rgb16f, 3 * sizeof (guint16))
+
+static inline void
+convert_pixel_rgba16f (guchar *dest_data, const guchar *src_data)
+{
+  float src[4];
+  half_to_float4((const guint16 *) src_data, src);
+  dest_data[0] = CLAMP (src[0] * 256.f, 0.f, 255.f);
+  dest_data[1] = CLAMP (src[1] * 256.f, 0.f, 255.f);
+  dest_data[2] = CLAMP (src[2] * 256.f, 0.f, 255.f);
+  dest_data[3] = CLAMP (src[3] * 256.f, 0.f, 255.f);
+}
+CONVERT_FUNCS(rgba16f, 4 * sizeof (guint16))
+
+static inline void
+convert_pixel_rgb32f (guchar *dest_data, const guchar *src_data)
+{
+  float *src = (float *) src_data;
+  dest_data[0] = CLAMP (src[0] * 256.f, 0.f, 255.f);
+  dest_data[1] = CLAMP (src[1] * 256.f, 0.f, 255.f);
+  dest_data[2] = CLAMP (src[2] * 256.f, 0.f, 255.f);
+  dest_data[3] = 0xFF;
+}
+CONVERT_FUNCS(rgb32f, 3 * sizeof (float))
+
+static inline void
+convert_pixel_rgba32f (guchar *dest_data, const guchar *src_data)
+{
+  float *src = (float *) src_data;
+  dest_data[0] = CLAMP (src[0] * 256.f, 0.f, 255.f);
+  dest_data[1] = CLAMP (src[1] * 256.f, 0.f, 255.f);
+  dest_data[2] = CLAMP (src[2] * 256.f, 0.f, 255.f);
+  dest_data[3] = CLAMP (src[3] * 256.f, 0.f, 255.f);
+}
+CONVERT_FUNCS(rgba32f, 4 * sizeof (float))
+
 typedef void (* ConversionFunc) (guchar       *dest_data,
                                  gsize         dest_stride,
                                  const guchar *src_data,
@@ -321,7 +516,13 @@ static ConversionFunc converters[GDK_MEMORY_N_FORMATS][GDK_MEMORY_N_CONVERSIONS]
   { convert_swizzle_premultiply_3210_3012, convert_swizzle_premultiply_0123_3012, 
convert_swizzle_premultiply_3012_3012 },
   { convert_swizzle_premultiply_3210_0321, convert_swizzle_premultiply_0123_0321, 
convert_swizzle_premultiply_3012_0321 },
   { convert_swizzle_opaque_3210, convert_swizzle_opaque_0123, convert_swizzle_opaque_3012 },
-  { convert_swizzle_opaque_3012, convert_swizzle_opaque_0321, convert_swizzle_opaque_3210 }
+  { convert_swizzle_opaque_3012, convert_swizzle_opaque_0321, convert_swizzle_opaque_3210 },
+  { convert_rgb16_to_download_le, convert_rgb16_to_download_be, convert_rgb16_to_gles_rgba },
+  { convert_rgba16_to_download_le, convert_rgba16_to_download_be, convert_rgba16_to_gles_rgba },
+  { convert_rgb16f_to_download_le, convert_rgb16f_to_download_be, convert_rgb16f_to_gles_rgba },
+  { convert_rgba16f_to_download_le, convert_rgba16f_to_download_be, convert_rgba16f_to_gles_rgba },
+  { convert_rgb32f_to_download_le, convert_rgb32f_to_download_be, convert_rgb32f_to_gles_rgba },
+  { convert_rgba32f_to_download_le, convert_rgba32f_to_download_be, convert_rgba32f_to_gles_rgba }
 };
 
 void
@@ -372,6 +573,74 @@ gdk_memory_convert (guchar              *dest_data,
     } \
 }G_STMT_END
 
+#define CONVERT_FLOAT_PIXEL(func,step) G_STMT_START{\
+  for (y = 0; y < height; y++) \
+    { \
+      for (x = 0; x < width; x++) \
+        { \
+          func (dest_data + 4 * x, src_data + step * x); \
+        } \
+\
+      dest_data += dest_stride; \
+      src_data += src_stride; \
+    } \
+}G_STMT_END
+
+static inline void
+convert_rgb16_to_float (float *dest, const guchar *src_data)
+{
+  const guint16 *src = (const guint16 *) src_data;
+  dest[0] = src[0] / 65535.f;
+  dest[1] = src[1] / 65535.f;
+  dest[2] = src[2] / 65535.f;
+  dest[3] = 1.0;
+}
+
+static inline void
+convert_rgba16_to_float (float *dest, const guchar *src_data)
+{
+  const guint16 *src = (const guint16 *) src_data;
+  dest[0] = src[0] / 65535.f;
+  dest[1] = src[1] / 65535.f;
+  dest[2] = src[2] / 65535.f;
+  dest[3] = 1.0;
+}
+
+static inline void
+convert_rgb16f_to_float (float *dest, const guchar *src_data)
+{
+  guint16 tmp[4];
+  memcpy(tmp, src_data, sizeof(guint16) * 3);
+  tmp[3] = FP16_ONE;
+  half_to_float4 (tmp, dest);
+}
+
+static inline void
+convert_rgba16f_to_float (float *dest, const guchar *src_data)
+{
+  half_to_float4 ((const guint16 *) src_data, dest);
+}
+
+static inline void
+convert_rgb32f_to_float (float *dest, const guchar *src_data)
+{
+  const float *src = (const float *) src_data;
+  dest[0] = src[0];
+  dest[1] = src[1];
+  dest[2] = src[2];
+  dest[3] = 1.0;
+}
+
+static inline void
+convert_rgba32f_to_float (float *dest, const guchar *src_data)
+{
+  const float *src = (const float *) src_data;
+  dest[0] = src[0];
+  dest[1] = src[1];
+  dest[2] = src[2];
+  dest[3] = src[3];
+}
+
 void
 gdk_memory_convert_to_float (float           *dest_data,
                              gsize            dest_stride,
@@ -412,6 +681,24 @@ gdk_memory_convert_to_float (float           *dest_data,
     case GDK_MEMORY_B8G8R8:
       CONVERT_FLOAT (2, 1, 0, -1, FALSE);
       break;
+    case GDK_MEMORY_R16G16B16:
+      CONVERT_FLOAT_PIXEL (convert_rgb16_to_float, 3 * sizeof (guint16));
+      break;
+    case GDK_MEMORY_R16G16B16A16_PREMULTIPLIED:
+      CONVERT_FLOAT_PIXEL (convert_rgba16_to_float, 4 * sizeof (guint16));
+      break;
+    case GDK_MEMORY_R16G16B16_FLOAT:
+      CONVERT_FLOAT_PIXEL (convert_rgb16f_to_float, 3 * sizeof (guint16));
+      break;
+    case GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED:
+      CONVERT_FLOAT_PIXEL (convert_rgba16f_to_float, 4 * sizeof (guint16));
+      break;
+    case GDK_MEMORY_R32G32B32_FLOAT:
+      CONVERT_FLOAT_PIXEL (convert_rgb32f_to_float, 3 * sizeof (float));
+      break;
+    case GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED:
+      CONVERT_FLOAT_PIXEL (convert_rgba32f_to_float, 4 * sizeof (float));
+      break;
 
     case GDK_MEMORY_N_FORMATS:
     default:
diff --git a/gdk/gdkmemorytexture.h b/gdk/gdkmemorytexture.h
index b9f1f21282..26e7e500f9 100644
--- a/gdk/gdkmemorytexture.h
+++ b/gdk/gdkmemorytexture.h
@@ -42,6 +42,21 @@ G_BEGIN_DECLS
  * @GDK_MEMORY_A8B8G8R8: 4 bytes; for alpha, blue, green, red.
  * @GDK_MEMORY_R8G8B8: 3 bytes; for red, green, blue. The data is opaque.
  * @GDK_MEMORY_B8G8R8: 3 bytes; for blue, green, red. The data is opaque.
+ * @GDK_MEMORY_R16G16B16: 3 guint16 values; for red, green, blue. Since 4.6
+ * @GDK_MEMORY_R16G16B16A16_PREMULTIPLIED: 4 guint16 values; for red, green,
+ *   blue, alpha. The color values are premultiplied with the alpha value.
+ *   Since 4.6
+ * @GDK_MEMORY_R16G16B16_FLOAT: 3 half-float values; for red, green, blue.
+ *   The data is opaque. Since 4.6
+ * @GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED: 4 half-float values; for
+ *   red, green, blue and alpha. The color values are premultiplied with
+ *   the alpha value. Since 4.6
+ * @GDK_MEMORY_B32G32R32_FLOAT: 3 float values; for blue, green, red.
+ *   The data is opaque. Since 4.6
+ * @GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED: 4 float values; for
+ *   red, green, blue and alpha. The color values are premultiplied with
+ *   the alpha value. Since 4.6
+ *
  * @GDK_MEMORY_N_FORMATS: The number of formats. This value will change as
  *   more formats get added, so do not rely on its concrete integer.
  *
@@ -67,6 +82,12 @@ typedef enum {
   GDK_MEMORY_A8B8G8R8,
   GDK_MEMORY_R8G8B8,
   GDK_MEMORY_B8G8R8,
+  GDK_MEMORY_R16G16B16,
+  GDK_MEMORY_R16G16B16A16_PREMULTIPLIED,
+  GDK_MEMORY_R16G16B16_FLOAT,
+  GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED,
+  GDK_MEMORY_R32G32B32_FLOAT,
+  GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED,
 
   GDK_MEMORY_N_FORMATS
 } GdkMemoryFormat;


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