From: Matthias Clasen Date: Mon, 29 May 2023 16:51:22 +0000 (-0400) Subject: gltexture: Rewrite downloading code X-Git-Tag: archive/raspbian/4.12.3+ds-1+rpi1~1^2^2^2~22^2~1^2~200^2~3 X-Git-Url: https://dgit.raspbian.org/?a=commitdiff_plain;h=1c72f46eed18e5f00af4dfca905973d8711e1e3d;p=gtk4.git gltexture: Rewrite downloading code For non-gles, make it handle unpremultiplied formats, and everything else, by downloading the texture in its preferred format and, in most cases, doing a gdk_memory_convert afterwards. For gles, keep using glReadPixels, but handle cases where the gl read format doesn't match the texture format by doing the necessary swizzling before calling gdk_memory_convert. --- diff --git a/gdk/gdkgltexture.c b/gdk/gdkgltexture.c index b51861b514..6e72af5403 100644 --- a/gdk/gdkgltexture.c +++ b/gdk/gdkgltexture.c @@ -138,6 +138,7 @@ static gboolean gdk_gl_texture_find_format (gboolean use_es, guint gl_major, guint gl_minor, + GdkMemoryAlpha alpha, GLint gl_format, GLint gl_type, GdkMemoryFormat *out_format) @@ -149,7 +150,7 @@ gdk_gl_texture_find_format (gboolean use_es, GLenum q_internal_format, q_format, q_type; GLint q_swizzle[4]; - if (gdk_memory_format_alpha (format) == GDK_MEMORY_ALPHA_STRAIGHT) + if (gdk_memory_format_alpha (format) != alpha) continue; if (!gdk_memory_format_gl_format (format, use_es, gl_major, gl_minor, &q_internal_format, &q_format, &q_type, &q_swizzle)) @@ -171,24 +172,56 @@ gdk_gl_texture_do_download (GdkGLTexture *self, gpointer download_) { GdkTexture *texture = GDK_TEXTURE (self); + GdkMemoryFormat format; gsize expected_stride; Download *download = download_; GLenum gl_internal_format, gl_format, gl_type; GLint gl_swizzle[4]; int major, minor; + format = gdk_texture_get_format (texture), expected_stride = texture->width * gdk_memory_format_bytes_per_pixel (download->format); gdk_gl_context_get_version (context, &major, &minor); - if (download->stride == expected_stride && - !gdk_gl_context_get_use_es (context) && - gdk_memory_format_gl_format (download->format, TRUE, major, minor, &gl_internal_format, &gl_format, &gl_type, &gl_swizzle)) + if (!gdk_gl_context_get_use_es (context) && + gdk_memory_format_gl_format (format, + FALSE, + major, minor, + &gl_internal_format, + &gl_format, &gl_type, &gl_swizzle)) { - glGetTexImage (GL_TEXTURE_2D, - 0, - gl_format, - gl_type, - download->data); + if (download->stride == expected_stride && + download->format == format) + { + glGetTexImage (GL_TEXTURE_2D, + 0, + gl_format, + gl_type, + download->data); + } + else + { + gsize stride = texture->width * gdk_memory_format_bytes_per_pixel (format); + guchar *pixels = g_malloc_n (stride, texture->height); + + glGetTexImage (GL_TEXTURE_2D, + 0, + gl_format, + gl_type, + pixels); + + gdk_memory_convert (download->data, + download->stride, + download->format, + pixels, + stride, + format, + texture->width, + texture->height); + + g_free (pixels); + + } } else { @@ -201,17 +234,26 @@ gdk_gl_texture_do_download (GdkGLTexture *self, glFramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, self->id, 0); if (gdk_gl_context_check_version (context, "4.3", "3.1")) { - gdk_gl_context_get_version (context, &major, &minor); glGetFramebufferParameteriv (GL_FRAMEBUFFER, GL_IMPLEMENTATION_COLOR_READ_FORMAT, &gl_read_format); glGetFramebufferParameteriv (GL_FRAMEBUFFER, GL_IMPLEMENTATION_COLOR_READ_TYPE, &gl_read_type); - if (!gdk_gl_texture_find_format (gdk_gl_context_get_use_es (context), major, minor, gl_read_format, gl_read_type, &actual_format)) - actual_format = GDK_MEMORY_R8G8B8A8_PREMULTIPLIED; /* pray */ + if (!gdk_gl_texture_find_format (TRUE, major, minor, gdk_memory_format_alpha (format), gl_read_format, gl_read_type, &actual_format)) + { + gl_read_format = GL_RGBA; + gl_read_type = GL_UNSIGNED_BYTE; + if (gdk_memory_format_alpha (format) == GDK_MEMORY_ALPHA_PREMULTIPLIED) + actual_format = GDK_MEMORY_R8G8B8A8_PREMULTIPLIED; /* pray */ + else + actual_format = GDK_MEMORY_R8G8B8A8; + } } else { gl_read_format = GL_RGBA; gl_read_type = GL_UNSIGNED_BYTE; - actual_format = GDK_MEMORY_R8G8B8A8_PREMULTIPLIED; + if (gdk_memory_format_alpha (format) == GDK_MEMORY_ALPHA_PREMULTIPLIED) + actual_format = GDK_MEMORY_R8G8B8A8_PREMULTIPLIED; /* pray */ + else + actual_format = GDK_MEMORY_R8G8B8A8; } if (download->format == actual_format && @@ -226,7 +268,8 @@ gdk_gl_texture_do_download (GdkGLTexture *self, else { gsize actual_bpp = gdk_memory_format_bytes_per_pixel (actual_format); - guchar *pixels = g_malloc_n (texture->width * actual_bpp, texture->height); + gsize stride = actual_bpp * texture->width; + guchar *pixels = g_malloc_n (stride, texture->height); glReadPixels (0, 0, texture->width, texture->height, @@ -234,11 +277,85 @@ gdk_gl_texture_do_download (GdkGLTexture *self, gl_read_type, pixels); + /* Fix up gles inadequacies */ + + if (gl_read_format == GL_RGBA && + gl_read_type == GL_UNSIGNED_BYTE && + (format == GDK_MEMORY_G8A8 || + format == GDK_MEMORY_G8A8_PREMULTIPLIED || + format == GDK_MEMORY_G8 || + format == GDK_MEMORY_A8)) + { + for (unsigned int y = 0; y < texture->height; y++) + { + for (unsigned int x = 0; x < texture->width; x++) + { + guchar *data = &pixels[y * stride + x * actual_bpp]; + if (format == GDK_MEMORY_G8A8 || + format == GDK_MEMORY_G8A8_PREMULTIPLIED) + { + data[3] = data[1]; + data[1] = data[0]; + data[2] = data[0]; + } + else if (format == GDK_MEMORY_G8) + { + data[1] = data[0]; + data[2] = data[0]; + data[3] = 0xff; + } + else if (format == GDK_MEMORY_A8) + { + data[3] = data[0]; + data[0] = 0; + data[1] = 0; + data[2] = 0; + } + } + } + } + + if (gl_read_format == GL_RGBA && + gl_read_type == GL_UNSIGNED_SHORT && + (format == GDK_MEMORY_G16A16 || + format == GDK_MEMORY_G16A16_PREMULTIPLIED || + format == GDK_MEMORY_G16 || + format == GDK_MEMORY_A16)) + { + for (unsigned int y = 0; y < texture->height; y++) + { + for (unsigned int x = 0; x < texture->width; x++) + { + guint16 *data = (guint16 *) &pixels[y * stride + x * actual_bpp]; + if (format == GDK_MEMORY_G16A16 || + format == GDK_MEMORY_G16A16_PREMULTIPLIED) + { + data[3] = data[1]; + data[1] = data[0]; + data[2] = data[0]; + } + else if (format == GDK_MEMORY_G16) + { + data[1] = data[0]; + data[2] = data[0]; + data[3] = 0xffff; + } + else if (format == GDK_MEMORY_A16) + { + data[3] = data[0]; + data[0] = 0; + data[1] = 0; + data[2] = 0; + } + } + } + } + gdk_memory_convert (download->data, download->stride, download->format, pixels, - texture->width * actual_bpp, + stride, actual_format, texture->width, texture->height);