From 9a9d20e2744bd88bf75f64bbc6d61fbae84f1c8a Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Mon, 6 Sep 2021 08:27:42 -0400 Subject: [PATCH] Support 16-bit floating point textures Add R16G16B16_FLOAT and R16B16B16A16_FLOAT_PREMULTIPLIED formats, which are using half floats. The intention is to use these for HDR content. Not done here: Update memory texture tests to include floating point textures. --- gdk/gdkglcontext.c | 14 +++++++ gdk/gdkgltexture.c | 7 ++++ gdk/gdkmemorytexture.c | 77 ++++++++++++++++++++++++++++++++++- gdk/gdkmemorytexture.h | 7 ++++ testsuite/gdk/memorytexture.c | 4 ++ 5 files changed, 108 insertions(+), 1 deletion(-) diff --git a/gdk/gdkglcontext.c b/gdk/gdkglcontext.c index 0754f40703..7c535f2ce8 100644 --- a/gdk/gdkglcontext.c +++ b/gdk/gdkglcontext.c @@ -292,6 +292,20 @@ gdk_gl_context_upload_texture (GdkGLContext *context, gl_type = GL_UNSIGNED_SHORT; bpp = 8; } + else if (data_format == GDK_MEMORY_R16G16B16_FLOAT) + { + gl_internalformat = GL_RGB16F; + gl_format = GL_RGB; + gl_type = GL_HALF_FLOAT; + bpp = 6; + } + else if (data_format == GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED) + { + gl_internalformat = GL_RGBA16F; + gl_format = GL_RGBA; + gl_type = GL_HALF_FLOAT; + bpp = 8; + } else /* Fall-back, convert to cairo-surface-format */ { copy = g_malloc (width * height * 4); diff --git a/gdk/gdkgltexture.c b/gdk/gdkgltexture.c index f0d3e40ac6..45226fa50c 100644 --- a/gdk/gdkgltexture.c +++ b/gdk/gdkgltexture.c @@ -120,6 +120,9 @@ type_from_internal_format (int internal_format) case GL_RGB16: case GL_RGBA16: return GL_UNSIGNED_SHORT; + case GL_RGB16F: + case GL_RGBA16F: + return GL_HALF_FLOAT; default: g_assert_not_reached (); } @@ -134,6 +137,10 @@ internal_format_for_format (GdkMemoryFormat format) return GL_RGB16; case GDK_MEMORY_R16G16B16A16_PREMULTIPLIED: return GL_RGBA16; + case GDK_MEMORY_R16G16B16_FLOAT: + return GL_RGB16F; + case GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED: + return GL_RGB16F; default: g_assert_not_reached (); } diff --git a/gdk/gdkmemorytexture.c b/gdk/gdkmemorytexture.c index d6460ffc71..c0c20cb06c 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: @@ -66,8 +67,12 @@ gdk_memory_format_bytes_per_pixel (GdkMemoryFormat format) return 6; case GDK_MEMORY_R16G16B16A16_PREMULTIPLIED: + case GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED: return 8; + case GDK_MEMORY_R16G16B16_FLOAT: + return 6; + case GDK_MEMORY_N_FORMATS: default: g_assert_not_reached (); @@ -364,6 +369,74 @@ SWIZZLE_16TO8(0,1,2,3) SWIZZLE_16TO8(2,1,0,3) SWIZZLE_16TO8(1,2,3,0) +#define SWIZZLE_FP16_OPAQUE(A,R,G,B) \ +static void \ +convert_fp16_swizzle_opaque_ ## A ## R ## G ## B (guchar *dest_data, \ + gsize dest_stride, \ + const guchar *src_data, \ + gsize src_stride, \ + gsize width, \ + gsize height) \ +{ \ + gsize x, y; \ + float *c; \ +\ +c = g_malloc (width * sizeof (float)); \ + for (y = 0; y < height; y++) \ + { \ + guint16 *src = (guint16 *)src_data; \ + half_to_float (src, c, width); \ + for (x = 0; x < width; x++) \ + { \ + dest_data[4 * x + A] = 255; \ + dest_data[4 * x + R] = (guchar)(255 * c[3 * x + 0]); \ + dest_data[4 * x + G] = (guchar)(255 * c[3 * x + 1]); \ + dest_data[4 * x + B] = (guchar)(255 * c[3 * x + 2]); \ + } \ + dest_data += dest_stride; \ + src_data += src_stride; \ + } \ + g_free (c); \ +} + +SWIZZLE_FP16_OPAQUE(3,2,1,0) +SWIZZLE_FP16_OPAQUE(0,1,2,3) +SWIZZLE_FP16_OPAQUE(3,0,1,2) + +#define SWIZZLE_FP16(A,R,G,B) \ +static void \ +convert_fp16_swizzle_ ## A ## R ## G ## B (guchar *dest_data, \ + gsize dest_stride, \ + const guchar *src_data, \ + gsize src_stride, \ + gsize width, \ + gsize height) \ +{ \ + gsize x, y; \ + float *c; \ +\ + c = g_malloc (width * sizeof (float)); \ + for (y = 0; y < height; y++) \ + { \ + guint16 *src = (guint16 *)src_data; \ + half_to_float (src, c, width); \ + for (x = 0; x < width; x++) \ + { \ + dest_data[4 * x + A] = (guchar)(255 * c[4 * x + 0]); \ + dest_data[4 * x + R] = (guchar)(255 * c[4 * x + 1]); \ + dest_data[4 * x + G] = (guchar)(255 * c[4 * x + 2]); \ + dest_data[4 * x + B] = (guchar)(255 * c[4 * x + 3]); \ + } \ + dest_data += dest_stride; \ + src_data += src_stride; \ + } \ + g_free (c); \ +} + +SWIZZLE_FP16(3,2,1,0) +SWIZZLE_FP16(0,1,2,3) +SWIZZLE_FP16(3,0,1,2) + typedef void (* ConversionFunc) (guchar *dest_data, gsize dest_stride, const guchar *src_data, @@ -383,7 +456,9 @@ static ConversionFunc converters[GDK_MEMORY_N_FORMATS][3] = { 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_16to8_swizzle_opaque_2103, convert_16to8_swizzle_opaque_1230, convert_16to8_swizzle_opaque_0123 }, - { convert_16to8_swizzle_2103, convert_16to8_swizzle_1230, convert_16to8_swizzle_0123 } + { convert_16to8_swizzle_2103, convert_16to8_swizzle_1230, convert_16to8_swizzle_0123 }, + { convert_fp16_swizzle_opaque_3210, convert_fp16_swizzle_opaque_0123, convert_fp16_swizzle_opaque_3012 }, + { convert_fp16_swizzle_3210, convert_fp16_swizzle_0123, convert_fp16_swizzle_3012 } }; void diff --git a/gdk/gdkmemorytexture.h b/gdk/gdkmemorytexture.h index cac6fa52f7..5bab062d6f 100644 --- a/gdk/gdkmemorytexture.h +++ b/gdk/gdkmemorytexture.h @@ -46,6 +46,11 @@ G_BEGIN_DECLS * @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_N_FORMATS: The number of formats. This value will change as * more formats get added, so do not rely on its concrete integer. * @@ -75,6 +80,8 @@ typedef enum { GDK_MEMORY_B8G8R8, GDK_MEMORY_R16G16B16, GDK_MEMORY_R16G16B16A16_PREMULTIPLIED, + GDK_MEMORY_R16G16B16_FLOAT, + GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED, GDK_MEMORY_N_FORMATS } GdkMemoryFormat; diff --git a/testsuite/gdk/memorytexture.c b/testsuite/gdk/memorytexture.c index 00bb489b63..8645a96fec 100644 --- a/testsuite/gdk/memorytexture.c +++ b/testsuite/gdk/memorytexture.c @@ -189,6 +189,10 @@ main (int argc, char *argv[]) for (format = 0; format < GDK_MEMORY_N_FORMATS; format++) { + if (format == GDK_MEMORY_R16G16B16_FLOAT || + format == GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED) + continue; + for (color = 0; color < N_COLORS; color++) { TestData *test_data = g_new (TestData, 1);