From e3c85be53f68cb313f0e21864f7744b5fa48031b Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Mon, 11 Dec 2023 04:23:16 +0100 Subject: [PATCH] memoryformat: Add gdk_memory_format_get_fallbacks() Track fallback formats to use in the memoryformat directly instead of using in the GL uploading code. First of all, this allows sharing the code and ensuring all our renderers use the same fallback mechanism. But also, this allows tracking fallbacks per-format which is useful because the fallback formats aren't really a tree. We want to make FLOAT16 fall back to FLOAT32 when not available, but we also want FLOAT32 fall back to FLOAT16. By tracking the fallbacks per-format, we can achieve that. --- gdk/gdkmemoryformat.c | 184 +++++++++++++++++++++++++++++++++++ gdk/gdkmemoryformatprivate.h | 1 + gsk/gl/gskglcommandqueue.c | 39 ++------ 3 files changed, 195 insertions(+), 29 deletions(-) diff --git a/gdk/gdkmemoryformat.c b/gdk/gdkmemoryformat.c index 798f44c21d..eb6fafe297 100644 --- a/gdk/gdkmemoryformat.c +++ b/gdk/gdkmemoryformat.c @@ -331,6 +331,7 @@ struct _GdkMemoryFormatDescription gsize bytes_per_pixel; gsize alignment; GdkMemoryDepth depth; + const GdkMemoryFormat *fallbacks; struct { guint internal_format; guint format; @@ -362,6 +363,9 @@ static const GdkMemoryFormatDescription memory_formats[] = { .bytes_per_pixel = 4, .alignment = G_ALIGNOF (guchar), .depth = GDK_MEMORY_U8, + .fallbacks = (GdkMemoryFormat[]) { + -1, + }, .gl = { .internal_format = GL_RGBA8, .format = GL_BGRA, @@ -380,6 +384,9 @@ static const GdkMemoryFormatDescription memory_formats[] = { .bytes_per_pixel = 4, .alignment = G_ALIGNOF (guchar), .depth = GDK_MEMORY_U8, + .fallbacks = (GdkMemoryFormat[]) { + -1, + }, .gl = { .internal_format = GL_RGBA8, .format = GL_BGRA, @@ -398,6 +405,9 @@ static const GdkMemoryFormatDescription memory_formats[] = { .bytes_per_pixel = 4, .alignment = G_ALIGNOF (guchar), .depth = GDK_MEMORY_U8, + .fallbacks = (GdkMemoryFormat[]) { + -1, + }, .gl = { .internal_format = GL_RGBA8, .format = GL_RGBA, @@ -415,6 +425,9 @@ static const GdkMemoryFormatDescription memory_formats[] = { .bytes_per_pixel = 4, .alignment = G_ALIGNOF (guchar), .depth = GDK_MEMORY_U8, + .fallbacks = (GdkMemoryFormat[]) { + -1, + }, .gl = { .internal_format = GL_RGBA8, .format = GL_RGBA, @@ -433,6 +446,9 @@ static const GdkMemoryFormatDescription memory_formats[] = { .bytes_per_pixel = 4, .alignment = G_ALIGNOF (guchar), .depth = GDK_MEMORY_U8, + .fallbacks = (GdkMemoryFormat[]) { + -1, + }, .gl = { .internal_format = GL_RGBA8, .format = GL_BGRA, @@ -451,6 +467,9 @@ static const GdkMemoryFormatDescription memory_formats[] = { .bytes_per_pixel = 4, .alignment = G_ALIGNOF (guchar), .depth = GDK_MEMORY_U8, + .fallbacks = (GdkMemoryFormat[]) { + -1, + }, .gl = { .internal_format = GL_RGBA8, .format = GL_BGRA, @@ -469,6 +488,9 @@ static const GdkMemoryFormatDescription memory_formats[] = { .bytes_per_pixel = 4, .alignment = G_ALIGNOF (guchar), .depth = GDK_MEMORY_U8, + .fallbacks = (GdkMemoryFormat[]) { + -1, + }, .gl = { .internal_format = GL_RGBA8, .format = GL_RGBA, @@ -486,6 +508,9 @@ static const GdkMemoryFormatDescription memory_formats[] = { .bytes_per_pixel = 4, .alignment = G_ALIGNOF (guchar), .depth = GDK_MEMORY_U8, + .fallbacks = (GdkMemoryFormat[]) { + -1, + }, .gl = { .internal_format = GL_RGBA8, .format = GL_RGBA, @@ -504,6 +529,10 @@ static const GdkMemoryFormatDescription memory_formats[] = { .bytes_per_pixel = 4, .alignment = G_ALIGNOF (guchar), .depth = GDK_MEMORY_U8, + .fallbacks = (GdkMemoryFormat[]) { + GDK_MEMORY_R8G8B8A8_PREMULTIPLIED, + -1, + }, .gl = { .internal_format = GL_RGBA8, .format = GL_BGRA, @@ -522,6 +551,10 @@ static const GdkMemoryFormatDescription memory_formats[] = { .bytes_per_pixel = 4, .alignment = G_ALIGNOF (guchar), .depth = GDK_MEMORY_U8, + .fallbacks = (GdkMemoryFormat[]) { + GDK_MEMORY_R8G8B8A8_PREMULTIPLIED, + -1, + }, .gl = { .internal_format = GL_RGBA8, .format = GL_BGRA, @@ -540,6 +573,10 @@ static const GdkMemoryFormatDescription memory_formats[] = { .bytes_per_pixel = 4, .alignment = G_ALIGNOF (guchar), .depth = GDK_MEMORY_U8, + .fallbacks = (GdkMemoryFormat[]) { + GDK_MEMORY_R8G8B8A8_PREMULTIPLIED, + -1, + }, .gl = { .internal_format = GL_RGBA8, .format = GL_RGBA, @@ -557,6 +594,10 @@ static const GdkMemoryFormatDescription memory_formats[] = { .bytes_per_pixel = 4, .alignment = G_ALIGNOF (guchar), .depth = GDK_MEMORY_U8, + .fallbacks = (GdkMemoryFormat[]) { + GDK_MEMORY_R8G8B8A8_PREMULTIPLIED, + -1, + }, .gl = { .internal_format = GL_RGBA8, .format = GL_RGBA, @@ -575,6 +616,10 @@ static const GdkMemoryFormatDescription memory_formats[] = { .bytes_per_pixel = 3, .alignment = G_ALIGNOF (guchar), .depth = GDK_MEMORY_U8, + .fallbacks = (GdkMemoryFormat[]) { + GDK_MEMORY_R8G8B8A8_PREMULTIPLIED, + -1, + }, .gl = { .internal_format = GL_RGB8, .format = GL_RGB, @@ -592,6 +637,10 @@ static const GdkMemoryFormatDescription memory_formats[] = { .bytes_per_pixel = 3, .alignment = G_ALIGNOF (guchar), .depth = GDK_MEMORY_U8, + .fallbacks = (GdkMemoryFormat[]) { + GDK_MEMORY_R8G8B8A8_PREMULTIPLIED, + -1, + }, .gl = { .internal_format = GL_RGB8, .format = GL_BGR, @@ -610,6 +659,13 @@ static const GdkMemoryFormatDescription memory_formats[] = { .bytes_per_pixel = 6, .alignment = G_ALIGNOF (guint16), .depth = GDK_MEMORY_U16, + .fallbacks = (GdkMemoryFormat[]) { + GDK_MEMORY_R16G16B16A16_PREMULTIPLIED, + GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED, + GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED, + GDK_MEMORY_R8G8B8A8_PREMULTIPLIED, + -1, + }, .gl = { .internal_format = GL_RGB16, .format = GL_RGB, @@ -627,6 +683,12 @@ static const GdkMemoryFormatDescription memory_formats[] = { .bytes_per_pixel = 8, .alignment = G_ALIGNOF (guint16), .depth = GDK_MEMORY_U16, + .fallbacks = (GdkMemoryFormat[]) { + GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED, + GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED, + GDK_MEMORY_R8G8B8A8_PREMULTIPLIED, + -1, + }, .gl = { .internal_format = GL_RGBA16, .format = GL_RGBA, @@ -644,6 +706,12 @@ static const GdkMemoryFormatDescription memory_formats[] = { .bytes_per_pixel = 8, .alignment = G_ALIGNOF (guint16), .depth = GDK_MEMORY_U16, + .fallbacks = (GdkMemoryFormat[]) { + GDK_MEMORY_R32G32B32A32_FLOAT, + GDK_MEMORY_R16G16B16A16_FLOAT, + GDK_MEMORY_R8G8B8A8, + -1, + }, .gl = { .internal_format = GL_RGBA16, .format = GL_RGBA, @@ -661,6 +729,12 @@ static const GdkMemoryFormatDescription memory_formats[] = { .bytes_per_pixel = 6, .alignment = G_ALIGNOF (guint16), .depth = GDK_MEMORY_FLOAT16, + .fallbacks = (GdkMemoryFormat[]) { + GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED, + GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED, + GDK_MEMORY_R8G8B8A8_PREMULTIPLIED, + -1, + }, .gl = { .internal_format = GL_RGB16F, .format = GL_RGB, @@ -678,6 +752,11 @@ static const GdkMemoryFormatDescription memory_formats[] = { .bytes_per_pixel = 8, .alignment = G_ALIGNOF (guint16), .depth = GDK_MEMORY_FLOAT16, + .fallbacks = (GdkMemoryFormat[]) { + GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED, + GDK_MEMORY_R8G8B8A8_PREMULTIPLIED, + -1, + }, .gl = { .internal_format = GL_RGBA16F, .format = GL_RGBA, @@ -695,6 +774,11 @@ static const GdkMemoryFormatDescription memory_formats[] = { .bytes_per_pixel = 8, .alignment = G_ALIGNOF (guint16), .depth = GDK_MEMORY_FLOAT16, + .fallbacks = (GdkMemoryFormat[]) { + GDK_MEMORY_R32G32B32A32_FLOAT, + GDK_MEMORY_R8G8B8A8, + -1, + }, .gl = { .internal_format = GL_RGBA16F, .format = GL_RGBA, @@ -712,6 +796,12 @@ static const GdkMemoryFormatDescription memory_formats[] = { 12, .alignment = G_ALIGNOF (float), .depth = GDK_MEMORY_FLOAT32, + .fallbacks = (GdkMemoryFormat[]) { + GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED, + GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED, + GDK_MEMORY_R8G8B8A8_PREMULTIPLIED, + -1, + }, .gl = { .internal_format = GL_RGB32F, .format = GL_RGB, @@ -729,6 +819,11 @@ static const GdkMemoryFormatDescription memory_formats[] = { 16, .alignment = G_ALIGNOF (float), .depth = GDK_MEMORY_FLOAT32, + .fallbacks = (GdkMemoryFormat[]) { + GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED, + GDK_MEMORY_R8G8B8A8_PREMULTIPLIED, + -1, + }, .gl = { .internal_format = GL_RGBA32F, .format = GL_RGBA, @@ -746,6 +841,11 @@ static const GdkMemoryFormatDescription memory_formats[] = { 16, .alignment = G_ALIGNOF (float), .depth = GDK_MEMORY_FLOAT32, + .fallbacks = (GdkMemoryFormat[]) { + GDK_MEMORY_R16G16B16A16_FLOAT, + GDK_MEMORY_R8G8B8A8, + -1, + }, .gl = { .internal_format = GL_RGBA32F, .format = GL_RGBA, @@ -763,6 +863,10 @@ static const GdkMemoryFormatDescription memory_formats[] = { .bytes_per_pixel = 2, .alignment = G_ALIGNOF (guchar), .depth = GDK_MEMORY_U8, + .fallbacks = (GdkMemoryFormat[]) { + GDK_MEMORY_R8G8B8A8_PREMULTIPLIED, + -1, + }, .gl = { .internal_format = GL_RG8, .format = GL_RG, @@ -780,6 +884,10 @@ static const GdkMemoryFormatDescription memory_formats[] = { .bytes_per_pixel = 2, .alignment = G_ALIGNOF (guchar), .depth = GDK_MEMORY_U8, + .fallbacks = (GdkMemoryFormat[]) { + GDK_MEMORY_R8G8B8A8, + -1, + }, .gl = { .internal_format = GL_RG8, .format = GL_RG, @@ -797,6 +905,10 @@ static const GdkMemoryFormatDescription memory_formats[] = { .bytes_per_pixel = 1, .alignment = G_ALIGNOF (guchar), .depth = GDK_MEMORY_U8, + .fallbacks = (GdkMemoryFormat[]) { + GDK_MEMORY_R8G8B8A8_PREMULTIPLIED, + -1, + }, .gl = { .internal_format = GL_R8, .format = GL_RED, @@ -814,6 +926,13 @@ static const GdkMemoryFormatDescription memory_formats[] = { .bytes_per_pixel = 4, .alignment = G_ALIGNOF (guint16), .depth = GDK_MEMORY_U16, + .fallbacks = (GdkMemoryFormat[]) { + GDK_MEMORY_R16G16B16A16_PREMULTIPLIED, + GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED, + GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED, + GDK_MEMORY_R8G8B8A8_PREMULTIPLIED, + -1, + }, .gl = { .internal_format = GL_RG16, .format = GL_RG, @@ -831,6 +950,13 @@ static const GdkMemoryFormatDescription memory_formats[] = { .bytes_per_pixel = 4, .alignment = G_ALIGNOF (guint16), .depth = GDK_MEMORY_U16, + .fallbacks = (GdkMemoryFormat[]) { + GDK_MEMORY_R16G16B16A16, + GDK_MEMORY_R32G32B32A32_FLOAT, + GDK_MEMORY_R16G16B16A16_FLOAT, + GDK_MEMORY_R8G8B8A8, + -1, + }, .gl = { .internal_format = GL_RG16, .format = GL_RG, @@ -848,6 +974,13 @@ static const GdkMemoryFormatDescription memory_formats[] = { .bytes_per_pixel = 2, .alignment = G_ALIGNOF (guint16), .depth = GDK_MEMORY_U16, + .fallbacks = (GdkMemoryFormat[]) { + GDK_MEMORY_R16G16B16A16_PREMULTIPLIED, + GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED, + GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED, + GDK_MEMORY_R8G8B8A8_PREMULTIPLIED, + -1, + }, .gl = { .internal_format = GL_R16, .format = GL_RED, @@ -865,6 +998,10 @@ static const GdkMemoryFormatDescription memory_formats[] = { .bytes_per_pixel = 1, .alignment = G_ALIGNOF (guchar), .depth = GDK_MEMORY_U8, + .fallbacks = (GdkMemoryFormat[]) { + GDK_MEMORY_R8G8B8A8_PREMULTIPLIED, + -1, + }, .gl = { .internal_format = GL_R8, .format = GL_RED, @@ -882,6 +1019,13 @@ static const GdkMemoryFormatDescription memory_formats[] = { .bytes_per_pixel = 2, .alignment = G_ALIGNOF (guint16), .depth = GDK_MEMORY_U16, + .fallbacks = (GdkMemoryFormat[]) { + GDK_MEMORY_R16G16B16A16_PREMULTIPLIED, + GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED, + GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED, + GDK_MEMORY_R8G8B8A8_PREMULTIPLIED, + -1, + }, .gl = { .internal_format = GL_R16, .format = GL_RED, @@ -899,6 +1043,12 @@ static const GdkMemoryFormatDescription memory_formats[] = { .bytes_per_pixel = 2, .alignment = G_ALIGNOF (guint16), .depth = GDK_MEMORY_FLOAT16, + .fallbacks = (GdkMemoryFormat[]) { + GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED, + GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED, + GDK_MEMORY_R8G8B8A8_PREMULTIPLIED, + -1, + }, .gl = { .internal_format = GL_R16F, .format = GL_RED, @@ -916,6 +1066,12 @@ static const GdkMemoryFormatDescription memory_formats[] = { .bytes_per_pixel = 4, .alignment = G_ALIGNOF (float), .depth = GDK_MEMORY_FLOAT32, + .fallbacks = (GdkMemoryFormat[]) { + GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED, + GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED, + GDK_MEMORY_R8G8B8A8_PREMULTIPLIED, + -1, + }, .gl = { .internal_format = GL_R32F, .format = GL_RED, @@ -961,6 +1117,34 @@ gdk_memory_format_alignment (GdkMemoryFormat format) return memory_formats[format].alignment; } +/* + * gdk_memory_format_get_fallbacks: + * @format: a format + * + * Gets a list of fallback formats to use for @format. + * + * These formats are RGBA formats that ideally have a + * higher depth than the given format. They will always + * include a guaranteed supported format though, even + * if it is of lower quality. + * + * Fallbacks will use the same alpha format, ie a premultiplied + * format will never fall back to a straight alpha format and + * vice versa. + * Either may fall back to an opaque format. + * Opaque formats will fall back to premultiplied formats only. + * + * Use gdk_memory_format_get_premultiplied_formats() to transition + * between premultiplied and straight alpha if you need to. + * + * Returns: A list of fallbacks, terminated with -1 + **/ +const GdkMemoryFormat * +gdk_memory_format_get_fallbacks (GdkMemoryFormat format) +{ + return memory_formats[format].fallbacks; +} + /* * gdk_memory_format_get_depth: * @format: a memory format diff --git a/gdk/gdkmemoryformatprivate.h b/gdk/gdkmemoryformatprivate.h index 14ef556b87..94764a3ee5 100644 --- a/gdk/gdkmemoryformatprivate.h +++ b/gdk/gdkmemoryformatprivate.h @@ -44,6 +44,7 @@ GdkMemoryAlpha gdk_memory_format_alpha (GdkMemoryFormat gsize gdk_memory_format_bytes_per_pixel (GdkMemoryFormat format) G_GNUC_CONST; GdkMemoryFormat gdk_memory_format_get_premultiplied (GdkMemoryFormat format) G_GNUC_CONST; GdkMemoryFormat gdk_memory_format_get_straight (GdkMemoryFormat format) G_GNUC_CONST; +const GdkMemoryFormat * gdk_memory_format_get_fallbacks (GdkMemoryFormat format) G_GNUC_CONST; GdkMemoryDepth gdk_memory_format_get_depth (GdkMemoryFormat format) G_GNUC_CONST; GdkMemoryDepth gdk_memory_depth_merge (GdkMemoryDepth depth1, GdkMemoryDepth depth2) G_GNUC_CONST; diff --git a/gsk/gl/gskglcommandqueue.c b/gsk/gl/gskglcommandqueue.c index 6e9c96494b..d560919f31 100644 --- a/gsk/gl/gskglcommandqueue.c +++ b/gsk/gl/gskglcommandqueue.c @@ -1483,8 +1483,9 @@ memory_format_gl_format (GdkMemoryFormat data_format, GLint gl_swizzle[4]) { GdkGLMemoryFlags flags; - GdkMemoryDepth depth; GdkMemoryFormat alt_format; + const GdkMemoryFormat *fallbacks; + gsize i; /* No support for straight formats yet */ if (gdk_memory_format_alpha (data_format) == GDK_MEMORY_ALPHA_STRAIGHT) @@ -1516,45 +1517,25 @@ memory_format_gl_format (GdkMemoryFormat data_format, return data_format; } - /* Next, try the generic format for the given bit depth */ - depth = gdk_memory_format_get_depth (data_format); - data_format = gdk_memory_depth_get_format (depth); - flags = gdk_gl_context_get_format_flags (context, data_format); - if (((flags & (GDK_GL_FORMAT_USABLE | GDK_GL_FORMAT_FILTERABLE)) == (GDK_GL_FORMAT_USABLE | GDK_GL_FORMAT_FILTERABLE))) + /* Next, try the fallbacks */ + fallbacks = gdk_memory_format_get_fallbacks (data_format); + for (i = 0; fallbacks[i] != -1; i++) { - gdk_memory_format_gl_format (data_format, - gl_internalformat, - gl_format, - gl_type, - gl_swizzle); - return data_format; - } - - /* If the format is high depth, also try float32 */ - if (depth != GDK_MEMORY_U8) - { - flags = gdk_gl_context_get_format_flags (context, data_format); + flags = gdk_gl_context_get_format_flags (context, fallbacks[i]); if (((flags & (GDK_GL_FORMAT_USABLE | GDK_GL_FORMAT_FILTERABLE)) == (GDK_GL_FORMAT_USABLE | GDK_GL_FORMAT_FILTERABLE))) { - gdk_memory_format_gl_format (data_format, + gdk_memory_format_gl_format (fallbacks[i], gl_internalformat, gl_format, gl_type, gl_swizzle); - return data_format; + return fallbacks[i]; } } - /* If all else fails, pick the one format that's always supported */ - data_format = GDK_MEMORY_R8G8B8A8_PREMULTIPLIED; - g_assert ((gdk_gl_context_get_format_flags (context, data_format) & (GDK_GL_FORMAT_USABLE | GDK_GL_FORMAT_FILTERABLE)) == (GDK_GL_FORMAT_USABLE | GDK_GL_FORMAT_FILTERABLE)); - gdk_memory_format_gl_format (data_format, - gl_internalformat, - gl_format, - gl_type, - gl_swizzle); + g_assert_not_reached (); - return data_format; + return GDK_MEMORY_R8G8B8A8_PREMULTIPLIED; } static void