diff --git a/gdk/gdkmemoryformat.c b/gdk/gdkmemoryformat.c index 92b5f3c3a5..08a1e6efc1 100644 --- a/gdk/gdkmemoryformat.c +++ b/gdk/gdkmemoryformat.c @@ -1123,20 +1123,32 @@ gdk_memory_format_alignment (GdkMemoryFormat 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. + * 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 (unless + * @format is already guaranteed supported). * * 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. + * 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. + * Use gdk_memory_format_get_premultiplied() and + * gdk_memory_format_get_straight() to transition between + * premultiplied and straight alpha if you need to. * + * Use gdk_memory_format_gl_rgba_format() to get an equivalent RGBA + * format and swizzle. + * + * The expected order of operation when looking for supported formats + * is the following: + * + * 1. Try the format itself + * 2. If swizzling is supported, try the RGBA format with swizzling + * 3. If swizzling is not supported, try the RGBA without swizzling, + * and with CPU conversion + * 4. Try fallback formats + * * Returns: A list of fallbacks, terminated with -1 **/ const GdkMemoryFormat * diff --git a/gsk/gl/gskglcommandqueue.c b/gsk/gl/gskglcommandqueue.c index 42b492785e..263bfcad56 100644 --- a/gsk/gl/gskglcommandqueue.c +++ b/gsk/gl/gskglcommandqueue.c @@ -1605,7 +1605,6 @@ gsk_gl_command_queue_do_upload_texture_chunk (GskGLCommandQueue *self, start_time = GDK_PROFILER_CURRENT_TIME; } - glPixelStorei (GL_UNPACK_ALIGNMENT, gdk_memory_format_alignment (data_format)); /* GL_UNPACK_ROW_LENGTH is available on desktop GL, OpenGL ES >= 3.0, or if diff --git a/gsk/gl/gskgldriver.c b/gsk/gl/gskgldriver.c index 452b8c2b61..0eb57bbf35 100644 --- a/gsk/gl/gskgldriver.c +++ b/gsk/gl/gskgldriver.c @@ -807,6 +807,8 @@ gsk_gl_driver_import_dmabuf_texture (GskGLDriver *self, GskGLRenderTarget *render_target; guint prev_fbo; gboolean external; + GdkMemoryFormat format; + gboolean premultiply; gdk_gl_context_make_current (context); @@ -822,6 +824,8 @@ gsk_gl_driver_import_dmabuf_texture (GskGLDriver *self, } dmabuf = gdk_dmabuf_texture_get_dmabuf (texture); + format = gdk_texture_get_format (GDK_TEXTURE (texture)); + premultiply = gdk_memory_format_alpha (format) == GDK_MEMORY_ALPHA_STRAIGHT; texture_id = gdk_gl_context_import_dmabuf (context, width, height, @@ -830,12 +834,15 @@ gsk_gl_driver_import_dmabuf_texture (GskGLDriver *self, if (texture_id == 0) return 0; - if (!external) + if (!external && !premultiply) return texture_id; gsk_gl_driver_autorelease_texture (self, texture_id); - program = self->external; + if (external) + program = self->external; + else + program = self->premultiply; if (!gsk_gl_driver_create_render_target (self, width, height, GL_RGBA8, &render_target)) return texture_id; @@ -849,9 +856,20 @@ gsk_gl_driver_import_dmabuf_texture (GskGLDriver *self, set_viewport_for_size (self, program, width, height); reset_modelview (self, program); - gsk_gl_program_set_uniform_texture (program, - UNIFORM_EXTERNAL_SOURCE, 0, - GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE0, texture_id); + if (external) + { + gsk_gl_program_set_uniform_texture (program, + UNIFORM_EXTERNAL_SOURCE, 0, + GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE0, texture_id); + + gsk_gl_program_set_uniform1i (program, UNIFORM_PREMULTIPLY, 0, premultiply); + } + else + { + gsk_gl_program_set_uniform_texture (program, + UNIFORM_SHARED_SOURCE, 0, + GL_TEXTURE_2D, GL_TEXTURE0, texture_id); + } draw_rect (self->command_queue, 0, 0, width, height); diff --git a/gsk/gl/gskglprograms.defs b/gsk/gl/gskglprograms.defs index 2ed531d90b..0eabd8a9bd 100644 --- a/gsk/gl/gskglprograms.defs +++ b/gsk/gl/gskglprograms.defs @@ -96,4 +96,9 @@ GSK_GL_DEFINE_PROGRAM (unblurred_outset_shadow, GSK_GL_DEFINE_PROGRAM_NO_CLIP (external, GSK_GL_SHADER_SINGLE (GSK_GL_SHADER_RESOURCE ("external.glsl")), - GSK_GL_ADD_UNIFORM (1, EXTERNAL_SOURCE, u_external_source)) + GSK_GL_ADD_UNIFORM (1, EXTERNAL_SOURCE, u_external_source) + GSK_GL_ADD_UNIFORM (2, PREMULTIPLY, u_premultiply)) + +GSK_GL_DEFINE_PROGRAM_NO_CLIP (premultiply, + GSK_GL_SHADER_SINGLE (GSK_GL_SHADER_RESOURCE ("premultiply.glsl")), + GSK_GL_NO_UNIFORMS) diff --git a/gsk/gl/resources/external.glsl b/gsk/gl/resources/external.glsl index 955820927b..d2aaadd003 100644 --- a/gsk/gl/resources/external.glsl +++ b/gsk/gl/resources/external.glsl @@ -17,6 +17,8 @@ uniform samplerExternalOES u_external_source; uniform sampler2D u_external_source; #endif +uniform int u_premultiply; + void main() { /* Open-code this here, since GskTexture() expects a sampler2D */ #if defined(GSK_GLES) || defined(GSK_LEGACY) @@ -24,5 +26,9 @@ void main() { #else vec4 color = texture(u_external_source, vUv); #endif + + if (u_premultiply == 1) + color.rgb *= color.a; + gskSetOutputColor(color); } diff --git a/gsk/gl/resources/premultiply.glsl b/gsk/gl/resources/premultiply.glsl new file mode 100644 index 0000000000..892c2c4453 --- /dev/null +++ b/gsk/gl/resources/premultiply.glsl @@ -0,0 +1,19 @@ +// VERTEX_SHADER: +// premultiply.glsl + +void main() { + gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0); + + vUv = vec2(aUv.x, aUv.y); +} + +// FRAGMENT_SHADER: +// premultiply.glsl + +void main() { + vec4 color = GskTexture(u_source, vUv); + + color.rgb *= color.a; + + gskSetOutputColor(color); +} diff --git a/gsk/meson.build b/gsk/meson.build index 8efbd7d7ad..8b6e0a57b0 100644 --- a/gsk/meson.build +++ b/gsk/meson.build @@ -21,6 +21,7 @@ gsk_private_gl_shaders = [ 'gl/resources/filled_border.glsl', 'gl/resources/mask.glsl', 'gl/resources/external.glsl', + 'gl/resources/premultiply.glsl', ] gsk_public_sources = files([ diff --git a/tests/testdmabuf.c b/tests/testdmabuf.c index b272f11c80..6ca82bd47f 100644 --- a/tests/testdmabuf.c +++ b/tests/testdmabuf.c @@ -433,9 +433,11 @@ texture_builder_set_planes (GdkDmabufTextureBuilder *builder, static GdkTexture * make_dmabuf_texture (const char *filename, guint32 format, - gboolean disjoint) + gboolean disjoint, + gboolean premultiplied) { GdkTexture *texture; + GdkTextureDownloader *downloader; int width, height; gsize rgb_stride, rgb_size; guchar *rgb_data; @@ -459,7 +461,15 @@ make_dmabuf_texture (const char *filename, rgb_data = g_new0 (guchar, rgb_size); - gdk_texture_download (texture, rgb_data, rgb_stride); + downloader = gdk_texture_downloader_new (texture); + + if (premultiplied) + gdk_texture_downloader_set_format (downloader, GDK_MEMORY_B8G8R8A8_PREMULTIPLIED); + else + gdk_texture_downloader_set_format (downloader, GDK_MEMORY_B8G8R8A8); + + gdk_texture_downloader_download_into (downloader, rgb_data, rgb_stride); + gdk_texture_downloader_free (downloader); g_object_unref (texture); @@ -470,6 +480,7 @@ make_dmabuf_texture (const char *filename, gdk_dmabuf_texture_builder_set_height (builder, height); gdk_dmabuf_texture_builder_set_fourcc (builder, format); gdk_dmabuf_texture_builder_set_modifier (builder, DRM_FORMAT_MOD_LINEAR); + gdk_dmabuf_texture_builder_set_premultiplied (builder, premultiplied); if (format == DRM_FORMAT_XRGB8888 || format == DRM_FORMAT_ARGB8888) @@ -627,6 +638,7 @@ main (int argc, char *argv[]) char *filename; guint32 format; gboolean disjoint = FALSE; + gboolean premultiplied = TRUE; gboolean decorated = TRUE; unsigned int i; const char *save_filename = NULL; @@ -637,6 +649,8 @@ main (int argc, char *argv[]) disjoint = TRUE; else if (g_str_equal (argv[i], "--undecorated")) decorated = FALSE; + else if (g_str_equal (argv[i], "--unpremultiplied")) + premultiplied = FALSE; else if (g_str_equal (argv[i], "--download-to")) { i++; @@ -663,7 +677,7 @@ main (int argc, char *argv[]) /* Get the list of supported formats with GDK_DEBUG=opengl */ gdk_display_get_dmabuf_formats (gdk_display_get_default ()); - texture = make_dmabuf_texture (filename, format, disjoint); + texture = make_dmabuf_texture (filename, format, disjoint, premultiplied); if (save_filename) gdk_texture_save_to_png (texture, save_filename);