From 27fbdcbecb6e497cd9dfdde0e67fc77d05f8917e Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Fri, 21 Jul 2023 03:02:33 +0200 Subject: [PATCH] gdk: Add A16_FLOAT and A32_FLOAT formats We need them for mask-only textures. For tiffs, we convert the formats to RGBA (the idea that tiff can save everything needs to be buried I guess) as tiffs can't do alpha-only. --- gdk/gdkenums.h | 2 + gdk/gdkmemoryformat.c | 82 +++++++++++++++++++++++++++++++++++ gdk/loaders/gdkpng.c | 2 + gdk/loaders/gdktiff.c | 2 + gsk/gskrendernodeparser.c | 2 + gsk/vulkan/gskvulkanimage.c | 22 ++++++++++ testsuite/gdk/memorytexture.c | 25 +++++++++++ 7 files changed, 137 insertions(+) diff --git a/gdk/gdkenums.h b/gdk/gdkenums.h index f2f7251b66..c03cf9f7c7 100644 --- a/gdk/gdkenums.h +++ b/gdk/gdkenums.h @@ -364,6 +364,8 @@ typedef enum { GDK_MEMORY_G16 GDK_AVAILABLE_ENUMERATOR_IN_4_12, GDK_MEMORY_A8 GDK_AVAILABLE_ENUMERATOR_IN_4_12, GDK_MEMORY_A16 GDK_AVAILABLE_ENUMERATOR_IN_4_12, + GDK_MEMORY_A16_FLOAT GDK_AVAILABLE_ENUMERATOR_IN_4_12, + GDK_MEMORY_A32_FLOAT GDK_AVAILABLE_ENUMERATOR_IN_4_12, GDK_MEMORY_N_FORMATS } GdkMemoryFormat; diff --git a/gdk/gdkmemoryformat.c b/gdk/gdkmemoryformat.c index c4cb2b7d22..9c85ae2575 100644 --- a/gdk/gdkmemoryformat.c +++ b/gdk/gdkmemoryformat.c @@ -156,6 +156,37 @@ r16g16b16a16_float_from_float (guchar *dest, float_to_half (src, (guint16 *) dest, 4 * n); } +static void +a16_float_to_float (float *dest, + const guchar *src_data, + gsize n) +{ + const guint16 *src = (const guint16 *) src_data; + for (gsize i = 0; i < n; i++) + { + half_to_float (src, dest, 1); + dest[1] = dest[0]; + dest[2] = dest[0]; + dest[3] = dest[0]; + src++; + dest += 4; + } +} + +static void +a16_float_from_float (guchar *dest_data, + const float *src, + gsize n) +{ + guint16 *dest = (guint16 *) dest_data; + for (gsize i = 0; i < n; i++) + { + float_to_half (&src[3], dest, 1); + dest ++; + src += 4; + } +} + static void r32g32b32_float_to_float (float *dest, const guchar *src_data, @@ -205,6 +236,37 @@ r32g32b32a32_float_from_float (guchar *dest, memcpy (dest, src, sizeof (float) * n * 4); } +static void +a32_float_to_float (float *dest, + const guchar *src_data, + gsize n) +{ + const float *src = (const float *) src_data; + for (gsize i = 0; i < n; i++) + { + dest[0] = src[0]; + dest[1] = src[0]; + dest[2] = src[0]; + dest[3] = src[0]; + src++; + dest += 4; + } +} + +static void +a32_float_from_float (guchar *dest_data, + const float *src, + gsize n) +{ + float *dest = (float *) dest_data; + for (gsize i = 0; i < n; i++) + { + dest[0] = src[3]; + dest ++; + src += 4; + } +} + #define PREMULTIPLY_FUNC(name, R1, G1, B1, A1, R2, G2, B2, A2) \ static void \ name (guchar *dest, \ @@ -544,6 +606,26 @@ static const GdkMemoryFormatDescription memory_formats[GDK_MEMORY_N_FORMATS] = { { GL_R16, GL_RED, GL_UNSIGNED_SHORT, { GL_ONE, GL_ONE, GL_ONE, GL_RED } }, a16_to_float, a16_from_float, + }, + [GDK_MEMORY_A16_FLOAT] = { + GDK_MEMORY_ALPHA_PREMULTIPLIED, + 2, + G_ALIGNOF (guint16), + GDK_MEMORY_FLOAT16, + { 0, 0, 3, 0 }, + { GL_R16F, GL_RED, GL_HALF_FLOAT, { GL_RED, GL_RED, GL_RED, GL_RED } }, + a16_float_to_float, + a16_float_from_float, + }, + [GDK_MEMORY_A32_FLOAT] = { + GDK_MEMORY_ALPHA_PREMULTIPLIED, + 4, + G_ALIGNOF (float), + GDK_MEMORY_FLOAT32, + { 0, 0, 3, 0 }, + { GL_R32F, GL_RED, GL_FLOAT, { GL_RED, GL_RED, GL_RED, GL_RED } }, + a32_float_to_float, + a32_float_from_float, } }; diff --git a/gdk/loaders/gdkpng.c b/gdk/loaders/gdkpng.c index 2f6d55d1f9..ebaa103b67 100644 --- a/gdk/loaders/gdkpng.c +++ b/gdk/loaders/gdkpng.c @@ -387,6 +387,8 @@ gdk_save_png (GdkTexture *texture) case GDK_MEMORY_G16A16_PREMULTIPLIED: case GDK_MEMORY_G16A16: case GDK_MEMORY_A16: + case GDK_MEMORY_A16_FLOAT: + case GDK_MEMORY_A32_FLOAT: format = GDK_MEMORY_G16A16; png_format = PNG_COLOR_TYPE_GRAY_ALPHA; depth = 16; diff --git a/gdk/loaders/gdktiff.c b/gdk/loaders/gdktiff.c index 674211898a..59d33f11e7 100644 --- a/gdk/loaders/gdktiff.c +++ b/gdk/loaders/gdktiff.c @@ -259,6 +259,8 @@ static const FormatData format_data[] = { [GDK_MEMORY_G16] = { GDK_MEMORY_G16, 16, 1, SAMPLEFORMAT_UINT, 0, PHOTOMETRIC_MINISBLACK }, [GDK_MEMORY_A8] = { GDK_MEMORY_G8A8, 8, 2, SAMPLEFORMAT_UINT, EXTRASAMPLE_UNASSALPHA, PHOTOMETRIC_MINISBLACK }, [GDK_MEMORY_A16] = { GDK_MEMORY_G16A16, 16, 2, SAMPLEFORMAT_UINT, EXTRASAMPLE_UNASSALPHA, PHOTOMETRIC_MINISBLACK }, + [GDK_MEMORY_A16_FLOAT] = { GDK_MEMORY_R16G16B16A16_FLOAT, 16, 4, SAMPLEFORMAT_IEEEFP, EXTRASAMPLE_ASSOCALPHA, PHOTOMETRIC_RGB }, + [GDK_MEMORY_A32_FLOAT] = { GDK_MEMORY_R32G32B32A32_FLOAT, 32, 4, SAMPLEFORMAT_IEEEFP, EXTRASAMPLE_ASSOCALPHA, PHOTOMETRIC_RGB }, }; /* if this fails, somebody forgot to add formats above */ diff --git a/gsk/gskrendernodeparser.c b/gsk/gskrendernodeparser.c index 923cddf3db..7a1b7a9bb1 100644 --- a/gsk/gskrendernodeparser.c +++ b/gsk/gskrendernodeparser.c @@ -2931,9 +2931,11 @@ append_texture_param (Printer *p, case GDK_MEMORY_R16G16B16_FLOAT: case GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED: case GDK_MEMORY_R16G16B16A16_FLOAT: + case GDK_MEMORY_A16_FLOAT: case GDK_MEMORY_R32G32B32_FLOAT: case GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED: case GDK_MEMORY_R32G32B32A32_FLOAT: + case GDK_MEMORY_A32_FLOAT: bytes = gdk_texture_save_to_tiff_bytes (texture); g_string_append (p->str, "url(\"data:image/tiff;base64,"); break; diff --git a/gsk/vulkan/gskvulkanimage.c b/gsk/vulkan/gskvulkanimage.c index 459551b214..1b92caec67 100644 --- a/gsk/vulkan/gskvulkanimage.c +++ b/gsk/vulkan/gskvulkanimage.c @@ -289,6 +289,24 @@ gsk_memory_format_get_vk_format_infos (GdkMemoryFormat format) return info; } + case GDK_MEMORY_A16_FLOAT: + { + static const GskMemoryFormatInfo info[] = { + { VK_FORMAT_R16_SFLOAT, SWIZZLE (R, R, R, R), 0 }, + { VK_FORMAT_UNDEFINED } + }; + return info; + } + + case GDK_MEMORY_A32_FLOAT: + { + static const GskMemoryFormatInfo info[] = { + { VK_FORMAT_R32_SFLOAT, SWIZZLE (R, R, R, R), 0 }, + { VK_FORMAT_UNDEFINED } + }; + return info; + } + case GDK_MEMORY_N_FORMATS: default: g_assert_not_reached (); @@ -355,6 +373,10 @@ gsk_memory_format_get_fallback (GdkMemoryFormat format) return GDK_MEMORY_R8G8B8A8_PREMULTIPLIED; case GDK_MEMORY_A16: return GDK_MEMORY_R16G16B16A16_PREMULTIPLIED; + case GDK_MEMORY_A16_FLOAT: + return GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED; + case GDK_MEMORY_A32_FLOAT: + return GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED; case GDK_MEMORY_N_FORMATS: default: diff --git a/testsuite/gdk/memorytexture.c b/testsuite/gdk/memorytexture.c index 00e9a36c69..c963be8c5b 100644 --- a/testsuite/gdk/memorytexture.c +++ b/testsuite/gdk/memorytexture.c @@ -92,6 +92,7 @@ gdk_memory_format_bytes_per_pixel (GdkMemoryFormat format) case GDK_MEMORY_G8A8: case GDK_MEMORY_G16: case GDK_MEMORY_A16: + case GDK_MEMORY_A16_FLOAT: return 2; case GDK_MEMORY_R8G8B8: @@ -107,6 +108,7 @@ gdk_memory_format_bytes_per_pixel (GdkMemoryFormat format) case GDK_MEMORY_A8B8G8R8: case GDK_MEMORY_G16A16_PREMULTIPLIED: case GDK_MEMORY_G16A16: + case GDK_MEMORY_A32_FLOAT: return 4; case GDK_MEMORY_R16G16B16: @@ -165,11 +167,13 @@ gdk_memory_format_get_channel_type (GdkMemoryFormat format) case GDK_MEMORY_R16G16B16_FLOAT: case GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED: case GDK_MEMORY_R16G16B16A16_FLOAT: + case GDK_MEMORY_A16_FLOAT: return CHANNEL_FLOAT_16; case GDK_MEMORY_R32G32B32_FLOAT: case GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED: case GDK_MEMORY_R32G32B32A32_FLOAT: + case GDK_MEMORY_A32_FLOAT: return CHANNEL_FLOAT_32; case GDK_MEMORY_N_FORMATS: @@ -215,6 +219,8 @@ gdk_memory_format_n_colors (GdkMemoryFormat format) case GDK_MEMORY_A8: case GDK_MEMORY_A16: + case GDK_MEMORY_A16_FLOAT: + case GDK_MEMORY_A32_FLOAT: return 0; case GDK_MEMORY_N_FORMATS: @@ -257,6 +263,8 @@ gdk_memory_format_has_alpha (GdkMemoryFormat format) case GDK_MEMORY_G16A16: case GDK_MEMORY_A8: case GDK_MEMORY_A16: + case GDK_MEMORY_A16_FLOAT: + case GDK_MEMORY_A32_FLOAT: return TRUE; case GDK_MEMORY_N_FORMATS: @@ -279,6 +287,8 @@ gdk_memory_format_is_premultiplied (GdkMemoryFormat format) case GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED: case GDK_MEMORY_G8A8_PREMULTIPLIED: case GDK_MEMORY_G16A16_PREMULTIPLIED: + case GDK_MEMORY_A16_FLOAT: + case GDK_MEMORY_A32_FLOAT: return TRUE; case GDK_MEMORY_R8G8B8: @@ -341,6 +351,8 @@ gdk_memory_format_is_deep (GdkMemoryFormat format) case GDK_MEMORY_G16: case GDK_MEMORY_G16A16: case GDK_MEMORY_A16: + case GDK_MEMORY_A16_FLOAT: + case GDK_MEMORY_A32_FLOAT: return TRUE; case GDK_MEMORY_N_FORMATS: @@ -395,6 +407,7 @@ gdk_memory_format_pixel_equal (GdkMemoryFormat format, case GDK_MEMORY_R16G16B16_FLOAT: case GDK_MEMORY_R16G16B16A16_FLOAT: case GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED: + case GDK_MEMORY_A16_FLOAT: { guint i; for (i = 0; i < gdk_memory_format_bytes_per_pixel (format) / sizeof (guint16); i++) @@ -410,6 +423,7 @@ gdk_memory_format_pixel_equal (GdkMemoryFormat format, case GDK_MEMORY_R32G32B32_FLOAT: case GDK_MEMORY_R32G32B32A32_FLOAT: case GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED: + case GDK_MEMORY_A32_FLOAT: { const float *f1 = (const float *) pixel1; const float *f2 = (const float *) pixel2; @@ -733,6 +747,17 @@ texture_builder_set_pixel (TextureBuilder *builder, memcpy (data, &pixel, sizeof (guint16)); } break; + case GDK_MEMORY_A16_FLOAT: + { + guint16 pixel = float_to_half (color->alpha); + memcpy (data, &pixel, sizeof (guint16)); + } + break; + case GDK_MEMORY_A32_FLOAT: + { + memcpy (data, &color->alpha, sizeof (float)); + } + break; case GDK_MEMORY_N_FORMATS: default: g_assert_not_reached ();