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