diff --git a/gdk/broadway/gdkcairocontext-broadway.c b/gdk/broadway/gdkcairocontext-broadway.c index 46fdbaf637..c2924bdf29 100644 --- a/gdk/broadway/gdkcairocontext-broadway.c +++ b/gdk/broadway/gdkcairocontext-broadway.c @@ -34,7 +34,7 @@ gdk_broadway_cairo_context_dispose (GObject *object) static void gdk_broadway_cairo_context_begin_frame (GdkDrawContext *draw_context, - gboolean request_hdr, + gboolean prefers_high_depth, cairo_region_t *region) { GdkBroadwayCairoContext *self = GDK_BROADWAY_CAIRO_CONTEXT (draw_context); diff --git a/gdk/broadway/gdkdrawcontext-broadway.c b/gdk/broadway/gdkdrawcontext-broadway.c index 660976bff5..da65aab78a 100644 --- a/gdk/broadway/gdkdrawcontext-broadway.c +++ b/gdk/broadway/gdkdrawcontext-broadway.c @@ -34,7 +34,7 @@ gdk_broadway_draw_context_dispose (GObject *object) static void gdk_broadway_draw_context_begin_frame (GdkDrawContext *draw_context, - gboolean request_hdr, + gboolean prefers_high_depth, cairo_region_t *region) { GdkBroadwayDrawContext *self = GDK_BROADWAY_DRAW_CONTEXT (draw_context); diff --git a/gdk/gdk.c b/gdk/gdk.c index b050c5916b..123b0413ef 100644 --- a/gdk/gdk.c +++ b/gdk/gdk.c @@ -129,7 +129,7 @@ static const GdkDebugKey gdk_debug_keys[] = { { "vulkan-disable", GDK_DEBUG_VULKAN_DISABLE, "Disable Vulkan support" }, { "vulkan-validate", GDK_DEBUG_VULKAN_VALIDATE, "Load the Vulkan validation layer" }, { "default-settings",GDK_DEBUG_DEFAULT_SETTINGS, "Force default values for xsettings", TRUE }, - { "hdr", GDK_DEBUG_HDR, "Use HDR rendering if possible", TRUE }, + { "high-depth", GDK_DEBUG_HIGH_DEPTH, "Use high bit depth rendering if possible", TRUE }, }; diff --git a/gdk/gdkcairo.c b/gdk/gdkcairo.c index ef8f5d2fb5..d69b9bc602 100644 --- a/gdk/gdkcairo.c +++ b/gdk/gdkcairo.c @@ -91,11 +91,7 @@ void gdk_cairo_surface_paint_pixbuf (cairo_surface_t *surface, const GdkPixbuf *pixbuf) { - int width, height; - guchar *gdk_pixels, *cairo_pixels; - int gdk_rowstride, cairo_stride; - int n_channels; - int j; + GdkTexture *texture; if (cairo_surface_status (surface) != CAIRO_STATUS_SUCCESS) return; @@ -111,71 +107,11 @@ gdk_cairo_surface_paint_pixbuf (cairo_surface_t *surface, cairo_surface_flush (surface); - width = gdk_pixbuf_get_width (pixbuf); - height = gdk_pixbuf_get_height (pixbuf); - gdk_pixels = gdk_pixbuf_get_pixels (pixbuf); - gdk_rowstride = gdk_pixbuf_get_rowstride (pixbuf); - n_channels = gdk_pixbuf_get_n_channels (pixbuf); - cairo_stride = cairo_image_surface_get_stride (surface); - cairo_pixels = cairo_image_surface_get_data (surface); - - for (j = height; j; j--) - { - guchar *p = gdk_pixels; - guchar *q = cairo_pixels; - - if (n_channels == 3) - { - guchar *end = p + 3 * width; - - while (p < end) - { -#if G_BYTE_ORDER == G_LITTLE_ENDIAN - q[0] = p[2]; - q[1] = p[1]; - q[2] = p[0]; - q[3] = 0xFF; -#else - q[0] = 0xFF; - q[1] = p[0]; - q[2] = p[1]; - q[3] = p[2]; -#endif - p += 3; - q += 4; - } - } - else - { - guchar *end = p + 4 * width; - guint t1,t2,t3; - -#define MULT(d,c,a,t) G_STMT_START { t = c * a + 0x80; d = ((t >> 8) + t) >> 8; } G_STMT_END - - while (p < end) - { -#if G_BYTE_ORDER == G_LITTLE_ENDIAN - MULT(q[0], p[2], p[3], t1); - MULT(q[1], p[1], p[3], t2); - MULT(q[2], p[0], p[3], t3); - q[3] = p[3]; -#else - q[0] = p[3]; - MULT(q[1], p[0], p[3], t1); - MULT(q[2], p[1], p[3], t2); - MULT(q[3], p[2], p[3], t3); -#endif - - p += 4; - q += 4; - } - -#undef MULT - } - - gdk_pixels += gdk_rowstride; - cairo_pixels += cairo_stride; - } + texture = gdk_texture_new_for_pixbuf (GDK_PIXBUF (pixbuf)); + gdk_texture_download (texture, + cairo_image_surface_get_data (surface), + cairo_image_surface_get_stride (surface)); + g_object_unref (texture); cairo_surface_mark_dirty (surface); } diff --git a/gdk/gdkdebug.h b/gdk/gdkdebug.h index 52460a7a82..acd2259440 100644 --- a/gdk/gdkdebug.h +++ b/gdk/gdkdebug.h @@ -50,7 +50,7 @@ typedef enum { GDK_DEBUG_VULKAN_DISABLE = 1 << 21, GDK_DEBUG_VULKAN_VALIDATE = 1 << 22, GDK_DEBUG_DEFAULT_SETTINGS= 1 << 23, - GDK_DEBUG_HDR = 1 << 24, + GDK_DEBUG_HIGH_DEPTH = 1 << 24, } GdkDebugFlags; extern guint _gdk_debug_flags; diff --git a/gdk/gdkdisplay.c b/gdk/gdkdisplay.c index 875cf5c82b..7d36f2e371 100644 --- a/gdk/gdkdisplay.c +++ b/gdk/gdkdisplay.c @@ -93,7 +93,7 @@ struct _GdkDisplayPrivate { #ifdef HAVE_EGL EGLDisplay egl_display; EGLConfig egl_config; - EGLConfig egl_config_hdr; + EGLConfig egl_config_high_depth; #endif guint rgba : 1; @@ -1439,11 +1439,11 @@ gdk_display_get_egl_config (GdkDisplay *self) } gpointer -gdk_display_get_egl_config_hdr (GdkDisplay *self) +gdk_display_get_egl_config_high_depth (GdkDisplay *self) { GdkDisplayPrivate *priv = gdk_display_get_instance_private (self); - return priv->egl_config_hdr; + return priv->egl_config_high_depth; } static EGLDisplay @@ -1721,16 +1721,16 @@ gdk_display_init_egl (GdkDisplay *self, epoxy_has_egl_extension (priv->egl_display, "EGL_EXT_pixel_format_float"); if (self->have_egl_no_config_context) - priv->egl_config_hdr = gdk_display_create_egl_config (self, + priv->egl_config_high_depth = gdk_display_create_egl_config (self, GDK_EGL_CONFIG_HDR, error); - if (priv->egl_config_hdr == NULL) - priv->egl_config_hdr = priv->egl_config; + if (priv->egl_config_high_depth == NULL) + priv->egl_config_high_depth = priv->egl_config; GDK_DISPLAY_NOTE (self, OPENGL, { char *ext = describe_extensions (priv->egl_display); - char *sdr_cfg = describe_egl_config (priv->egl_display, priv->egl_config); - char *hdr_cfg = describe_egl_config (priv->egl_display, priv->egl_config_hdr); + char *std_cfg = describe_egl_config (priv->egl_display, priv->egl_config); + char *hd_cfg = describe_egl_config (priv->egl_display, priv->egl_config_high_depth); g_message ("EGL API version %d.%d found\n" " - Vendor: %s\n" " - Version: %s\n" @@ -1738,15 +1738,15 @@ gdk_display_init_egl (GdkDisplay *self, " - Extensions:\n" "\t%s\n" " - Selected fbconfig: %s\n" - " HDR fbconfig: %s", + " high depth: %s", major, minor, eglQueryString (priv->egl_display, EGL_VENDOR), eglQueryString (priv->egl_display, EGL_VERSION), eglQueryString (priv->egl_display, EGL_CLIENT_APIS), - ext, sdr_cfg, - priv->egl_config_hdr == priv->egl_config ? "none" : hdr_cfg); - g_free (hdr_cfg); - g_free (sdr_cfg); + ext, std_cfg, + priv->egl_config_high_depth == priv->egl_config ? "none" : hd_cfg); + g_free (hd_cfg); + g_free (std_cfg); g_free (ext); }); diff --git a/gdk/gdkdisplayprivate.h b/gdk/gdkdisplayprivate.h index 4cb85b2ea4..cb80ad3f88 100644 --- a/gdk/gdkdisplayprivate.h +++ b/gdk/gdkdisplayprivate.h @@ -226,7 +226,8 @@ gboolean gdk_display_init_egl (GdkDisplay *display GError **error); gpointer gdk_display_get_egl_display (GdkDisplay *display); gpointer gdk_display_get_egl_config (GdkDisplay *display); -gpointer gdk_display_get_egl_config_hdr (GdkDisplay *display); +gpointer gdk_display_get_egl_config_high_depth + (GdkDisplay *display); void gdk_display_set_rgba (GdkDisplay *display, gboolean rgba); diff --git a/gdk/gdkdrawcontext.c b/gdk/gdkdrawcontext.c index b1988c4034..b51e1139dd 100644 --- a/gdk/gdkdrawcontext.c +++ b/gdk/gdkdrawcontext.c @@ -315,28 +315,30 @@ gdk_draw_context_begin_frame (GdkDrawContext *context, } /* - * @request_hdr: %TRUE to request high dynamic range. + * @prefers_high_depth: %TRUE to request a higher bit depth * - * If HDR is requested, GDK will see about providing a rendering target - * that supports high dynamic range. Typically this means a target supporting - * 16bit floating point pixels, but that is not guaranteed. + * If high depth is preferred, GDK will see about providing a rendering target + * that supports higher bit depth than 8 bits per channel. Typically this means + * a target supporting 16bit floating point pixels, but that is not guaranteed. * * This is only a request and if the GDK backend does not support HDR rendering * or does not consider it worthwhile, it may choose to not honor the request. - * It may also choose to provide HDR even if it was not requested. + * It may also choose to provide high depth even if it was not requested. * Typically the steps undertaken by a backend are: - * 1. Check if HDR is supported by this drawing backend. - * 2. Check if the compositor supports HDR. - * 3. Check if the compositor prefers SDR. This is usually the case when the attached - * monitors do not support HDR content or when the system is resource constrained. + * 1. Check if high depth is supported by this drawing backend. + * 2. Check if the compositor supports high depth. + * 3. Check if the compositor prefers regular bit depth. This is usually the case + * when the attached monitors do not support high depth content or when the + * system is resource constrained. * In either of those cases, the context will usually choose to not honor the request. * - * The rendering code must be able to deal with HDR and SDR content, no matter if HDR - * was requested. The request is only a hint and GDK is free to choose. + * The rendering code must be able to deal with content in any bit depth, no matter + * the preference. The prefers_high_depth argument is only a hint and GDK is free + * to choose. */ void gdk_draw_context_begin_frame_full (GdkDrawContext *context, - gboolean request_hdr, + gboolean prefers_high_depth, const cairo_region_t *region) { GdkDrawContextPrivate *priv = gdk_draw_context_get_instance_private (context); @@ -362,13 +364,13 @@ gdk_draw_context_begin_frame_full (GdkDrawContext *context, return; } - if (GDK_DISPLAY_DEBUG_CHECK (priv->display, HDR)) - request_hdr = TRUE; + if (GDK_DISPLAY_DEBUG_CHECK (priv->display, HIGH_DEPTH)) + prefers_high_depth = TRUE; priv->frame_region = cairo_region_copy (region); priv->surface->paint_context = g_object_ref (context); - GDK_DRAW_CONTEXT_GET_CLASS (context)->begin_frame (context, request_hdr, priv->frame_region); + GDK_DRAW_CONTEXT_GET_CLASS (context)->begin_frame (context, prefers_high_depth, priv->frame_region); } #ifdef HAVE_SYSPROF diff --git a/gdk/gdkdrawcontextprivate.h b/gdk/gdkdrawcontextprivate.h index 0171876d9d..4674d25f30 100644 --- a/gdk/gdkdrawcontextprivate.h +++ b/gdk/gdkdrawcontextprivate.h @@ -41,7 +41,7 @@ struct _GdkDrawContextClass GObjectClass parent_class; void (* begin_frame) (GdkDrawContext *context, - gboolean request_hdr, + gboolean prefers_high_depth, cairo_region_t *update_area); void (* end_frame) (GdkDrawContext *context, cairo_region_t *painted); @@ -51,7 +51,7 @@ struct _GdkDrawContextClass void gdk_draw_context_surface_resized (GdkDrawContext *context); void gdk_draw_context_begin_frame_full (GdkDrawContext *context, - gboolean request_hdr, + gboolean prefers_high_depth, const cairo_region_t *region); G_END_DECLS diff --git a/gdk/gdkglcontext.c b/gdk/gdkglcontext.c index 11c3f77dd4..5ea41cdeec 100644 --- a/gdk/gdkglcontext.c +++ b/gdk/gdkglcontext.c @@ -79,6 +79,7 @@ #include "gdkdebug.h" #include "gdkdisplayprivate.h" #include "gdkintl.h" +#include "gdkmemoryformatprivate.h" #include "gdkmemorytextureprivate.h" #include "gdkprofilerprivate.h" @@ -238,80 +239,39 @@ gdk_gl_context_upload_texture (GdkGLContext *context, { GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (context); guchar *copy = NULL; - GLint gl_internalformat; - GLint gl_format; - GLint gl_type; + GLenum gl_internalformat; + GLenum gl_format; + GLenum gl_type; gsize bpp; g_return_if_fail (GDK_IS_GL_CONTEXT (context)); - if (!priv->use_es && data_format == GDK_MEMORY_DEFAULT) /* Cairo surface format */ + if (!gdk_memory_format_gl_format (data_format, + priv->use_es, + &gl_internalformat, + &gl_format, + &gl_type)) { - gl_internalformat = GL_RGBA8; - gl_format = GL_BGRA; - gl_type = GL_UNSIGNED_INT_8_8_8_8_REV; - } - else if (data_format == GDK_MEMORY_R8G8B8) /* Pixmap non-alpha data */ - { - gl_internalformat = GL_RGBA8; - gl_format = GL_RGB; - gl_type = GL_UNSIGNED_BYTE; - } - else if (priv->use_es && data_format == GDK_MEMORY_B8G8R8) - { - gl_internalformat = GL_RGBA8; - gl_format = GL_BGR; - gl_type = GL_UNSIGNED_BYTE; - } - else if (data_format == GDK_MEMORY_R16G16B16) - { - gl_internalformat = GL_RGBA16; - gl_format = GL_RGB; - gl_type = GL_UNSIGNED_SHORT; - } - else if (data_format == GDK_MEMORY_R16G16B16A16_PREMULTIPLIED) - { - gl_internalformat = GL_RGBA16; - gl_format = GL_RGBA; - gl_type = GL_UNSIGNED_SHORT; - } - else if (data_format == GDK_MEMORY_R16G16B16_FLOAT) - { - gl_internalformat = GL_RGB16F; - gl_format = GL_RGB; - gl_type = GL_HALF_FLOAT; - } - else if (data_format == GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED) - { - gl_internalformat = GL_RGBA16F; - gl_format = GL_RGBA; - gl_type = GL_HALF_FLOAT; - } - else if (data_format == GDK_MEMORY_R32G32B32_FLOAT) - { - gl_internalformat = GL_RGB32F; - gl_format = GL_RGB; - gl_type = GL_FLOAT; - } - else if (data_format == GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED) - { - gl_internalformat = GL_RGBA32F; - gl_format = GL_RGBA; - gl_type = GL_FLOAT; - } - else /* Fall-back, convert to GLES format */ - { - copy = g_malloc (width * height * 4); + copy = g_malloc_n (width * 4, height); gdk_memory_convert (copy, width * 4, - GDK_MEMORY_CONVERT_GLES_RGBA, - data, stride, data_format, + GDK_MEMORY_R8G8B8A8_PREMULTIPLIED, + data, stride, + data_format, width, height); - data_format = GDK_MEMORY_R8G8B8A8_PREMULTIPLIED; - stride = width * 4; data = copy; - gl_internalformat = GL_RGBA8; - gl_format = GL_RGBA; - gl_type = GL_UNSIGNED_BYTE; + data_format = GDK_MEMORY_R8G8B8A8_PREMULTIPLIED; + if (!gdk_memory_format_gl_format (data_format, + priv->use_es, + &gl_internalformat, + &gl_format, + &gl_type)) + { + g_assert_not_reached (); + } + } + else + { + copy = NULL; } bpp = gdk_memory_format_bytes_per_pixel (data_format); @@ -629,7 +589,7 @@ gdk_gl_context_real_make_current (GdkGLContext *context, static void gdk_gl_context_real_begin_frame (GdkDrawContext *draw_context, - gboolean request_hdr, + gboolean prefers_high_depth, cairo_region_t *region) { GdkGLContext *context = GDK_GL_CONTEXT (draw_context); @@ -642,7 +602,7 @@ gdk_gl_context_real_begin_frame (GdkDrawContext *draw_context, #ifdef HAVE_EGL if (priv->egl_context) - gdk_surface_ensure_egl_surface (surface, request_hdr); + gdk_surface_ensure_egl_surface (surface, prefers_high_depth); #endif damage = GDK_GL_CONTEXT_GET_CLASS (context)->get_damage (context); diff --git a/gdk/gdkgltexture.c b/gdk/gdkgltexture.c index e2e292964d..e39fcd3fbb 100644 --- a/gdk/gdkgltexture.c +++ b/gdk/gdkgltexture.c @@ -21,6 +21,7 @@ #include "gdkgltextureprivate.h" #include "gdkdisplayprivate.h" +#include "gdkmemoryformatprivate.h" #include "gdkmemorytextureprivate.h" #include "gdktextureprivate.h" @@ -139,82 +140,29 @@ gdk_gl_texture_get_tex_image (GdkGLTexture *self, data); } } + static void gdk_gl_texture_do_download_texture (gpointer texture_, gpointer result_) { GdkTexture *texture = texture_; GdkTexture **result = result_; - GdkMemoryFormat format; - GLint internal_format, gl_format, gl_type; + guint gl_internalformat, gl_format, gl_type; guchar *data; gsize stride; GBytes *bytes; - glGetTexLevelParameteriv (GL_TEXTURE_2D, 0, GL_TEXTURE_INTERNAL_FORMAT, &internal_format); + if (!gdk_memory_format_gl_format (texture->format, + gdk_gl_context_get_use_es (gdk_gl_context_get_current ()), + &gl_internalformat, + &gl_format, + &gl_type)) + { + g_assert_not_reached (); + } - switch (internal_format) - { - case GL_RGB8: - format = GDK_MEMORY_R8G8B8; - gl_format = GL_RGB; - gl_type = GL_UNSIGNED_BYTE; - break; - - case GL_RGBA8: - format = GDK_MEMORY_R8G8B8A8_PREMULTIPLIED; - gl_format = GL_RGBA; - gl_type = GL_UNSIGNED_BYTE; - break; - - case GL_RGB16: - format = GDK_MEMORY_R16G16B16; - gl_format = GL_RGB; - gl_type = GL_UNSIGNED_SHORT; - break; - - case GL_RGBA16: - format = GDK_MEMORY_R16G16B16A16_PREMULTIPLIED; - gl_format = GL_RGBA; - gl_type = GL_UNSIGNED_SHORT; - break; - - case GL_RGB16F: - format = GDK_MEMORY_R16G16B16_FLOAT; - gl_format = GL_RGB; - gl_type = GL_HALF_FLOAT; - break; - - case GL_RGBA16F: - format = GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED; - gl_format = GL_RGBA; - gl_type = GL_HALF_FLOAT; - break; - - case GL_RGB32F: - format = GDK_MEMORY_R32G32B32_FLOAT; - gl_format = GL_RGB; - gl_type = GL_FLOAT; - break; - - case GL_RGBA32F: - format = GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED; - gl_format = GL_RGBA; - gl_type = GL_FLOAT; - break; - - default: - g_warning ("Texture in unexpected format 0x%X (%d). File a bug about adding it to GTK", internal_format, internal_format); - /* fallback to the dumbest possible format - * so that even age old GLES can do it */ - format = GDK_MEMORY_R8G8B8A8_PREMULTIPLIED; - gl_format = GL_RGBA; - gl_type = GL_UNSIGNED_BYTE; - break; - } - - stride = gdk_memory_format_bytes_per_pixel (format) * texture->width; - data = g_malloc (stride * texture->height); + stride = gdk_memory_format_bytes_per_pixel (texture->format) * texture->width; + data = g_malloc_n (stride, texture->height); gdk_gl_texture_get_tex_image (texture_, gl_format, @@ -224,7 +172,7 @@ gdk_gl_texture_do_download_texture (gpointer texture_, bytes = g_bytes_new_take (data, stride * texture->height); *result = gdk_memory_texture_new (texture->width, texture->height, - format, + texture->format, bytes, stride); @@ -377,6 +325,58 @@ gdk_gl_texture_release (GdkGLTexture *self) self->id = 0; } +static void +gdk_gl_texture_do_determine_format (gpointer texture_, + gpointer unused) +{ + GdkTexture *texture = texture_; + GLint internal_format; + + glGetTexLevelParameteriv (GL_TEXTURE_2D, 0, GL_TEXTURE_INTERNAL_FORMAT, &internal_format); + + switch (internal_format) + { + case GL_RGB8: + texture->format = GDK_MEMORY_R8G8B8; + break; + + case GL_RGBA8: + texture->format = GDK_MEMORY_R8G8B8A8_PREMULTIPLIED; + break; + + case GL_RGB16: + texture->format = GDK_MEMORY_R16G16B16; + break; + + case GL_RGBA16: + texture->format = GDK_MEMORY_R16G16B16A16_PREMULTIPLIED; + break; + + case GL_RGB16F: + texture->format = GDK_MEMORY_R16G16B16_FLOAT; + break; + + case GL_RGBA16F: + texture->format = GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED; + break; + + case GL_RGB32F: + texture->format = GDK_MEMORY_R32G32B32_FLOAT; + break; + + case GL_RGBA32F: + texture->format = GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED; + break; + + default: + g_warning ("Texture in unexpected format 0x%X (%d). File a bug about adding it to GTK", internal_format, internal_format); + /* fallback to the dumbest possible format + * so that even age old GLES can do it */ + texture->format = GDK_MEMORY_R8G8B8A8_PREMULTIPLIED; + break; + } +} + /** * gdk_gl_texture_new: * @context: a `GdkGLContext` @@ -420,6 +420,8 @@ gdk_gl_texture_new (GdkGLContext *context, self->destroy = destroy; self->data = data; + gdk_gl_texture_run (self, gdk_gl_texture_do_determine_format, NULL); + return GDK_TEXTURE (self); } diff --git a/gdk/gdkmemoryformat.c b/gdk/gdkmemoryformat.c new file mode 100644 index 0000000000..5af2bb8516 --- /dev/null +++ b/gdk/gdkmemoryformat.c @@ -0,0 +1,467 @@ +/* + * Copyright © 2021 Benjamin Otte + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + * + * Authors: Benjamin Otte + */ + +#include "config.h" + +#include "gdkmemoryformatprivate.h" + +#include "gsk/ngl/fp16private.h" + +#include + +typedef struct _GdkMemoryFormatDescription GdkMemoryFormatDescription; + +typedef enum { + GDK_MEMORY_ALPHA_PREMULTIPLIED, + GDK_MEMORY_ALPHA_STRAIGHT, + GDK_MEMORY_ALPHA_OPAQUE +} GdkMemoryAlpha; + +#define TYPED_FUNCS(name, T, R, G, B, A, bpp, scale) \ +static void \ +name ## _to_float (float *dest, \ + const guchar *src_data, \ + gsize n) \ +{ \ + for (gsize i = 0; i < n; i++) \ + { \ + T *src = (T *) (src_data + i * bpp); \ + dest[0] = (float) src[R] / scale; \ + dest[1] = (float) src[G] / scale; \ + dest[2] = (float) src[B] / scale; \ + if (A >= 0) dest[3] = (float) src[A] / scale; else dest[3] = 1.0; \ + dest += 4; \ + } \ +} \ +\ +static void \ +name ## _from_float (guchar *dest_data, \ + const float *src, \ + gsize n) \ +{ \ + for (gsize i = 0; i < n; i++) \ + { \ + T *dest = (T *) (dest_data + i * bpp); \ + dest[R] = CLAMP (src[0] * scale + 0.5, 0, scale); \ + dest[G] = CLAMP (src[1] * scale + 0.5, 0, scale); \ + dest[B] = CLAMP (src[2] * scale + 0.5, 0, scale); \ + if (A >= 0) dest[A] = CLAMP (src[3] * scale + 0.5, 0, scale); \ + src += 4; \ + } \ +} + +TYPED_FUNCS (b8g8r8a8_premultiplied, guchar, 2, 1, 0, 3, 4, 255) +TYPED_FUNCS (a8r8g8b8_premultiplied, guchar, 1, 2, 3, 0, 4, 255) +TYPED_FUNCS (r8g8b8a8_premultiplied, guchar, 0, 1, 2, 3, 4, 255) +TYPED_FUNCS (b8g8r8a8, guchar, 2, 1, 0, 3, 4, 255) +TYPED_FUNCS (a8r8g8b8, guchar, 1, 2, 3, 0, 4, 255) +TYPED_FUNCS (r8g8b8a8, guchar, 0, 1, 2, 3, 4, 255) +TYPED_FUNCS (a8b8g8r8, guchar, 3, 2, 1, 0, 4, 255) +TYPED_FUNCS (r8g8b8, guchar, 0, 1, 2, -1, 3, 255) +TYPED_FUNCS (b8g8r8, guchar, 2, 1, 0, -1, 3, 255) +TYPED_FUNCS (r16g16b16, guint16, 0, 1, 2, -1, 6, 65535) +TYPED_FUNCS (r16g16b16a16, guint16, 0, 1, 2, 3, 8, 65535) + +static void +r16g16b16_float_to_float (float *dest, + const guchar *src_data, + gsize n) +{ + guint16 *src = (guint16 *) src_data; + for (gsize i = 0; i < n; i++) + { + half_to_float (src, dest, 3); + dest[3] = 1.0; + dest += 4; + src += 3; + } +} + +static void +r16g16b16_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, dest, 3); + dest += 3; + src += 4; + } +} + +static void +r16g16b16a16_float_to_float (float *dest, + const guchar *src, + gsize n) +{ + half_to_float ((const guint16 *) src, dest, 4 * n); +} + +static void +r16g16b16a16_float_from_float (guchar *dest, + const float *src, + gsize n) +{ + float_to_half (src, (guint16 *) dest, 4 * n); +} + +static void +r32g32b32_float_to_float (float *dest, + const guchar *src_data, + gsize n) +{ + float *src = (float *) src_data; + for (gsize i = 0; i < n; i++) + { + dest[0] = src[0]; + dest[1] = src[1]; + dest[2] = src[2]; + dest[3] = 1.0; + dest += 4; + src += 3; + } +} + +static void +r32g32b32_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[0]; + dest[1] = src[1]; + dest[2] = src[2]; + dest += 3; + src += 4; + } +} + +static void +r32g32b32a32_float_to_float (float *dest, + const guchar *src, + gsize n) +{ + memcpy (dest, src, sizeof (float) * n * 4); +} + +static void +r32g32b32a32_float_from_float (guchar *dest, + const float *src, + gsize n) +{ + memcpy (dest, src, sizeof (float) * n * 4); +} + +struct _GdkMemoryFormatDescription +{ + GdkMemoryAlpha alpha; + gsize bytes_per_pixel; + gsize alignment; + gboolean prefers_high_depth; + gboolean supports_gles; + struct { + guint internal_format; + guint format; + guint type; + } gl; + /* no premultiplication going on here */ + void (* to_float) (float *, const guchar*, gsize); + void (* from_float) (guchar *, const float *, gsize); +}; + +#if G_BYTE_ORDER == G_LITTLE_ENDIAN +# define GDK_GL_UNSIGNED_BYTE_FLIPPED GL_UNSIGNED_INT_8_8_8_8 +#elif G_BYTE_ORDER == G_BIG_ENDIAN +# define GDK_GL_UNSIGNED_BYTE_FLIPPED GL_UNSIGNED_INT_8_8_8_8_REV +#else +# error "Define the right GL flags here" +#endif + +static const GdkMemoryFormatDescription memory_formats[GDK_MEMORY_N_FORMATS] = { + [GDK_MEMORY_B8G8R8A8_PREMULTIPLIED] = { + GDK_MEMORY_ALPHA_PREMULTIPLIED, + 4, + G_ALIGNOF (guchar), + FALSE, + FALSE, + { GL_RGBA8, GL_BGRA, GL_UNSIGNED_BYTE }, + b8g8r8a8_premultiplied_to_float, + b8g8r8a8_premultiplied_from_float, + }, + [GDK_MEMORY_A8R8G8B8_PREMULTIPLIED] = { + GDK_MEMORY_ALPHA_PREMULTIPLIED, + 4, + G_ALIGNOF (guchar), + FALSE, + FALSE, + { GL_RGBA8, GL_BGRA, GDK_GL_UNSIGNED_BYTE_FLIPPED }, + a8r8g8b8_premultiplied_to_float, + a8r8g8b8_premultiplied_from_float, + }, + [GDK_MEMORY_R8G8B8A8_PREMULTIPLIED] = { + GDK_MEMORY_ALPHA_PREMULTIPLIED, + 4, + G_ALIGNOF (guchar), + FALSE, + TRUE, + { GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE }, + r8g8b8a8_premultiplied_to_float, + r8g8b8a8_premultiplied_from_float, + }, + [GDK_MEMORY_B8G8R8A8] = { + GDK_MEMORY_ALPHA_STRAIGHT, + 4, + G_ALIGNOF (guchar), + FALSE, + FALSE, + { GL_RGBA8, GL_BGRA, GL_UNSIGNED_BYTE }, + b8g8r8a8_to_float, + b8g8r8a8_from_float, + }, + [GDK_MEMORY_A8R8G8B8] = { + GDK_MEMORY_ALPHA_STRAIGHT, + 4, + G_ALIGNOF (guchar), + FALSE, + FALSE, + { GL_RGBA8, GL_RGBA, GDK_GL_UNSIGNED_BYTE_FLIPPED }, + a8r8g8b8_to_float, + a8r8g8b8_from_float, + }, + [GDK_MEMORY_R8G8B8A8] = { + GDK_MEMORY_ALPHA_STRAIGHT, + 4, + G_ALIGNOF (guchar), + FALSE, + TRUE, + { GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE }, + r8g8b8a8_to_float, + r8g8b8a8_from_float, + }, + [GDK_MEMORY_A8B8G8R8] = { + GDK_MEMORY_ALPHA_STRAIGHT, + 4, + G_ALIGNOF (guchar), + FALSE, + FALSE, + { GL_RGBA8, GL_BGRA, GDK_GL_UNSIGNED_BYTE_FLIPPED }, + a8b8g8r8_to_float, + a8b8g8r8_from_float, + }, + [GDK_MEMORY_R8G8B8] = { + GDK_MEMORY_ALPHA_OPAQUE, + 3, + G_ALIGNOF (guchar), + FALSE, + TRUE, + { GL_RGBA8, GL_RGB, GL_UNSIGNED_BYTE }, + r8g8b8_to_float, + r8g8b8_from_float, + }, + [GDK_MEMORY_B8G8R8] = { + GDK_MEMORY_ALPHA_OPAQUE, + 3, + G_ALIGNOF (guchar), + FALSE, + FALSE, + { GL_RGB8, GL_BGR, GL_UNSIGNED_BYTE }, + b8g8r8_to_float, + b8g8r8_from_float, + }, + [GDK_MEMORY_R16G16B16] = { + GDK_MEMORY_ALPHA_OPAQUE, + 6, + G_ALIGNOF (guint16), + TRUE, + TRUE, + { GL_RGB16, GL_RGB, GL_UNSIGNED_SHORT }, + r16g16b16_to_float, + r16g16b16_from_float, + }, + [GDK_MEMORY_R16G16B16A16_PREMULTIPLIED] = { + GDK_MEMORY_ALPHA_PREMULTIPLIED, + 8, + G_ALIGNOF (guint16), + TRUE, + TRUE, + { GL_RGBA16, GL_RGBA, GL_UNSIGNED_SHORT }, + r16g16b16a16_to_float, + r16g16b16a16_from_float, + }, + [GDK_MEMORY_R16G16B16_FLOAT] = { + GDK_MEMORY_ALPHA_OPAQUE, + 6, + G_ALIGNOF (guint16), + TRUE, + TRUE, + { GL_RGB16F, GL_RGB, GL_HALF_FLOAT }, + r16g16b16_float_to_float, + r16g16b16_float_from_float, + }, + [GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED] = { + GDK_MEMORY_ALPHA_PREMULTIPLIED, + 8, + G_ALIGNOF (guint16), + TRUE, + TRUE, + { GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT }, + r16g16b16a16_float_to_float, + r16g16b16a16_float_from_float, + }, + [GDK_MEMORY_R32G32B32_FLOAT] = { + GDK_MEMORY_ALPHA_OPAQUE, + 12, + G_ALIGNOF (float), + TRUE, + TRUE, + { GL_RGB32F, GL_RGB, GL_FLOAT }, + r32g32b32_float_to_float, + r32g32b32_float_from_float, + }, + [GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED] = { + GDK_MEMORY_ALPHA_PREMULTIPLIED, + 16, + G_ALIGNOF (float), + TRUE, + TRUE, + { GL_RGBA32F, GL_RGBA, GL_FLOAT }, + r32g32b32a32_float_to_float, + r32g32b32a32_float_from_float, + } +}; + +gsize +gdk_memory_format_bytes_per_pixel (GdkMemoryFormat format) +{ + return memory_formats[format].bytes_per_pixel; +} + +gsize +gdk_memory_format_alignment (GdkMemoryFormat format) +{ + return memory_formats[format].alignment; +} + +/* + * gdk_memory_format_prefers_high_depth: + * @format: a memory format + * + * Checks if the given format benefits from being rendered + * in bit depths higher than 8bits per pixel. See + * gsk_render_node_prefers_high_depth() for more information + * on this. + * Usually this is the case when + * gdk_memory_format_bytes_per_pixel() is larger than 4. + * + * Returns: %TRUE if the format benefits from being + * composited in hgiher bit depths. + **/ +gboolean +gdk_memory_format_prefers_high_depth (GdkMemoryFormat format) +{ + return memory_formats[format].prefers_high_depth; +} + +gboolean +gdk_memory_format_gl_format (GdkMemoryFormat format, + gboolean gles, + guint *out_internal_format, + guint *out_format, + guint *out_type) +{ + *out_internal_format = memory_formats[format].gl.internal_format; + *out_format = memory_formats[format].gl.format; + *out_type = memory_formats[format].gl.type; + + if (memory_formats[format].alpha == GDK_MEMORY_ALPHA_STRAIGHT) + return FALSE; + + if (gles && !memory_formats[format].supports_gles) + return FALSE; + + return TRUE; +} + +static void +premultiply (float *rgba, + gsize n) +{ + for (gsize i = 0; i < n; i++) + { + rgba[0] *= rgba[3]; + rgba[1] *= rgba[3]; + rgba[2] *= rgba[3]; + rgba += 4; + } +} + +static void +unpremultiply (float *rgba, + gsize n) +{ + for (gsize i = 0; i < n; i++) + { + if (rgba[3] > 1/255.0) + { + rgba[0] /= rgba[3]; + rgba[1] /= rgba[3]; + rgba[2] /= rgba[3]; + } + rgba += 4; + } +} + +void +gdk_memory_convert (guchar *dest_data, + gsize dest_stride, + GdkMemoryFormat dest_format, + const guchar *src_data, + gsize src_stride, + GdkMemoryFormat src_format, + gsize width, + gsize height) +{ + const GdkMemoryFormatDescription *dest_desc = &memory_formats[dest_format]; + const GdkMemoryFormatDescription *src_desc = &memory_formats[src_format]; + float *tmp; + gsize y; + + g_assert (dest_format < GDK_MEMORY_N_FORMATS); + g_assert (src_format < GDK_MEMORY_N_FORMATS); + + tmp = g_new (float, width * 4); + + for (y = 0; y < height; y++) + { + src_desc->to_float (tmp, src_data, width); + if (src_desc->alpha == GDK_MEMORY_ALPHA_PREMULTIPLIED && dest_desc->alpha == GDK_MEMORY_ALPHA_STRAIGHT) + unpremultiply (tmp, width); + else if (src_desc->alpha == GDK_MEMORY_ALPHA_STRAIGHT && dest_desc->alpha != GDK_MEMORY_ALPHA_STRAIGHT) + premultiply (tmp, width); + dest_desc->from_float (dest_data, tmp, width); + src_data += src_stride; + dest_data += dest_stride; + } + + g_free (tmp); +} diff --git a/gdk/gdkmemoryformatprivate.h b/gdk/gdkmemoryformatprivate.h new file mode 100644 index 0000000000..344e47fade --- /dev/null +++ b/gdk/gdkmemoryformatprivate.h @@ -0,0 +1,48 @@ +/* + * Copyright © 2021 Benjamin Otte + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + * + * Authors: Benjamin Otte + */ + +#ifndef __GDK_MEMORY_CONVERT_PRIVATE_H__ +#define __GDK_MEMORY_CONVERT_PRIVATE_H__ + +#include "gdkmemorytexture.h" + +G_BEGIN_DECLS + +gsize gdk_memory_format_alignment (GdkMemoryFormat format) G_GNUC_CONST; +gsize gdk_memory_format_bytes_per_pixel (GdkMemoryFormat format) G_GNUC_CONST; +gboolean gdk_memory_format_prefers_high_depth(GdkMemoryFormat format) G_GNUC_CONST; +gboolean gdk_memory_format_gl_format (GdkMemoryFormat format, + gboolean gles, + guint *out_internal_format, + guint *out_format, + guint *out_type); + +void gdk_memory_convert (guchar *dest_data, + gsize dest_stride, + GdkMemoryFormat dest_format, + const guchar *src_data, + gsize src_stride, + GdkMemoryFormat src_format, + gsize width, + gsize height); + + +G_END_DECLS + +#endif /* __GDK_MEMORY_CONVERT_PRIVATE_H__ */ diff --git a/gdk/gdkmemorytexture.c b/gdk/gdkmemorytexture.c index 6c08ef531b..52723ef805 100644 --- a/gdk/gdkmemorytexture.c +++ b/gdk/gdkmemorytexture.c @@ -20,6 +20,8 @@ #include "config.h" #include "gdkmemorytextureprivate.h" + +#include "gdkmemoryformatprivate.h" #include "gsk/ngl/fp16private.h" /** @@ -32,8 +34,6 @@ struct _GdkMemoryTexture { GdkTexture parent_instance; - GdkMemoryFormat format; - GBytes *bytes; gsize stride; }; @@ -45,80 +45,6 @@ struct _GdkMemoryTextureClass G_DEFINE_TYPE (GdkMemoryTexture, gdk_memory_texture, GDK_TYPE_TEXTURE) -gsize -gdk_memory_format_bytes_per_pixel (GdkMemoryFormat format) -{ - switch (format) - { - case GDK_MEMORY_R8G8B8: - case GDK_MEMORY_B8G8R8: - return 3; - - case GDK_MEMORY_B8G8R8A8_PREMULTIPLIED: - case GDK_MEMORY_A8R8G8B8_PREMULTIPLIED: - case GDK_MEMORY_R8G8B8A8_PREMULTIPLIED: - case GDK_MEMORY_B8G8R8A8: - case GDK_MEMORY_A8R8G8B8: - case GDK_MEMORY_R8G8B8A8: - case GDK_MEMORY_A8B8G8R8: - return 4; - - case GDK_MEMORY_R16G16B16: - case GDK_MEMORY_R16G16B16_FLOAT: - return 6; - - case GDK_MEMORY_R16G16B16A16_PREMULTIPLIED: - case GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED: - return 8; - - case GDK_MEMORY_R32G32B32_FLOAT: - return 12; - - case GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED: - return 16; - - case GDK_MEMORY_N_FORMATS: - default: - g_assert_not_reached (); - return 4; - } -} - -static gsize -gdk_memory_format_alignment (GdkMemoryFormat format) -{ - switch (format) - { - case GDK_MEMORY_R8G8B8: - case GDK_MEMORY_B8G8R8: - case GDK_MEMORY_B8G8R8A8_PREMULTIPLIED: - case GDK_MEMORY_A8R8G8B8_PREMULTIPLIED: - case GDK_MEMORY_R8G8B8A8_PREMULTIPLIED: - case GDK_MEMORY_B8G8R8A8: - case GDK_MEMORY_A8R8G8B8: - case GDK_MEMORY_R8G8B8A8: - case GDK_MEMORY_A8B8G8R8: - return G_ALIGNOF (guchar); - - case GDK_MEMORY_R16G16B16: - case GDK_MEMORY_R16G16B16_FLOAT: - return G_ALIGNOF (guint16); - - case GDK_MEMORY_R16G16B16A16_PREMULTIPLIED: - case GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED: - return G_ALIGNOF (guint16); - - case GDK_MEMORY_R32G32B32_FLOAT: - case GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED: - return G_ALIGNOF (float); - - case GDK_MEMORY_N_FORMATS: - default: - g_assert_not_reached (); - return G_ALIGNOF (double); - } -} - static void gdk_memory_texture_dispose (GObject *object) { @@ -143,10 +69,10 @@ gdk_memory_texture_download (GdkTexture *texture, GdkMemoryTexture *self = GDK_MEMORY_TEXTURE (texture); gdk_memory_convert (data, stride, - GDK_MEMORY_CONVERT_DOWNLOAD, + GDK_MEMORY_DEFAULT, (guchar *) g_bytes_get_data (self->bytes, NULL), self->stride, - self->format, + texture->format, gdk_texture_get_width (texture), gdk_texture_get_height (texture)); } @@ -158,12 +84,14 @@ gdk_memory_texture_download_float (GdkTexture *texture, { GdkMemoryTexture *self = GDK_MEMORY_TEXTURE (texture); - gdk_memory_convert_to_float (data, stride, - (guchar *) g_bytes_get_data (self->bytes, NULL), - self->stride, - self->format, - gdk_texture_get_width (texture), - gdk_texture_get_height (texture)); + gdk_memory_convert ((guchar *) data, + stride * sizeof (float), + GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED, + (guchar *) g_bytes_get_data (self->bytes, NULL), + self->stride, + texture->format, + gdk_texture_get_width (texture), + gdk_texture_get_height (texture)); } static void @@ -254,19 +182,13 @@ gdk_memory_texture_new (int width, "height", height, NULL); - self->format = format; + GDK_TEXTURE (self)->format = format; self->bytes = bytes; self->stride = stride; return GDK_TEXTURE (self); } -GdkMemoryFormat -gdk_memory_texture_get_format (GdkMemoryTexture *self) -{ - return self->format; -} - const guchar * gdk_memory_texture_get_data (GdkMemoryTexture *self) { @@ -279,429 +201,3 @@ gdk_memory_texture_get_stride (GdkMemoryTexture *self) return self->stride; } -static void -convert_memcpy (guchar *dest_data, - gsize dest_stride, - const guchar *src_data, - gsize src_stride, - gsize width, - gsize height) -{ - gsize y; - - for (y = 0; y < height; y++) - memcpy (dest_data + y * dest_stride, src_data + y * src_stride, 4 * width); -} - -#define SWIZZLE(A,R,G,B) \ -static void \ -convert_swizzle ## A ## R ## G ## B (guchar *dest_data, \ - gsize dest_stride, \ - const guchar *src_data, \ - gsize src_stride, \ - gsize width, \ - gsize height) \ -{ \ - gsize x, y; \ -\ - for (y = 0; y < height; y++) \ - { \ - for (x = 0; x < width; x++) \ - { \ - dest_data[4 * x + A] = src_data[4 * x + 0]; \ - dest_data[4 * x + R] = src_data[4 * x + 1]; \ - dest_data[4 * x + G] = src_data[4 * x + 2]; \ - dest_data[4 * x + B] = src_data[4 * x + 3]; \ - } \ -\ - dest_data += dest_stride; \ - src_data += src_stride; \ - } \ -} - -SWIZZLE(3,2,1,0) -SWIZZLE(2,1,0,3) -SWIZZLE(3,0,1,2) -SWIZZLE(1,2,3,0) - -#define SWIZZLE_OPAQUE(A,R,G,B) \ -static void \ -convert_swizzle_opaque_## A ## R ## G ## B (guchar *dest_data, \ - gsize dest_stride, \ - const guchar *src_data, \ - gsize src_stride, \ - gsize width, \ - gsize height) \ -{ \ - gsize x, y; \ -\ - for (y = 0; y < height; y++) \ - { \ - for (x = 0; x < width; x++) \ - { \ - dest_data[4 * x + A] = 0xFF; \ - dest_data[4 * x + R] = src_data[3 * x + 0]; \ - dest_data[4 * x + G] = src_data[3 * x + 1]; \ - dest_data[4 * x + B] = src_data[3 * x + 2]; \ - } \ -\ - dest_data += dest_stride; \ - src_data += src_stride; \ - } \ -} - -SWIZZLE_OPAQUE(3,2,1,0) -SWIZZLE_OPAQUE(3,0,1,2) -SWIZZLE_OPAQUE(0,1,2,3) -SWIZZLE_OPAQUE(0,3,2,1) - -#define PREMULTIPLY(d,c,a) G_STMT_START { guint t = c * a + 0x80; d = ((t >> 8) + t) >> 8; } G_STMT_END -#define SWIZZLE_PREMULTIPLY(A,R,G,B, A2,R2,G2,B2) \ -static void \ -convert_swizzle_premultiply_ ## A ## R ## G ## B ## _ ## A2 ## R2 ## G2 ## B2 \ - (guchar *dest_data, \ - gsize dest_stride, \ - const guchar *src_data, \ - gsize src_stride, \ - gsize width, \ - gsize height) \ -{ \ - gsize x, y; \ -\ - for (y = 0; y < height; y++) \ - { \ - for (x = 0; x < width; x++) \ - { \ - dest_data[4 * x + A] = src_data[4 * x + A2]; \ - PREMULTIPLY(dest_data[4 * x + R], src_data[4 * x + R2], src_data[4 * x + A2]); \ - PREMULTIPLY(dest_data[4 * x + G], src_data[4 * x + G2], src_data[4 * x + A2]); \ - PREMULTIPLY(dest_data[4 * x + B], src_data[4 * x + B2], src_data[4 * x + A2]); \ - } \ -\ - dest_data += dest_stride; \ - src_data += src_stride; \ - } \ -} - -SWIZZLE_PREMULTIPLY (3,2,1,0, 3,2,1,0) -SWIZZLE_PREMULTIPLY (0,1,2,3, 3,2,1,0) -SWIZZLE_PREMULTIPLY (3,2,1,0, 0,1,2,3) -SWIZZLE_PREMULTIPLY (0,1,2,3, 0,1,2,3) -SWIZZLE_PREMULTIPLY (3,2,1,0, 3,0,1,2) -SWIZZLE_PREMULTIPLY (0,1,2,3, 3,0,1,2) -SWIZZLE_PREMULTIPLY (3,2,1,0, 0,3,2,1) -SWIZZLE_PREMULTIPLY (0,1,2,3, 0,3,2,1) -SWIZZLE_PREMULTIPLY (3,0,1,2, 3,2,1,0) -SWIZZLE_PREMULTIPLY (3,0,1,2, 0,1,2,3) -SWIZZLE_PREMULTIPLY (3,0,1,2, 3,0,1,2) -SWIZZLE_PREMULTIPLY (3,0,1,2, 0,3,2,1) - -#define CONVERT_FUNC(name,suffix,R,G,B,A,step) \ -static void \ -convert_ ## name ## _to_ ## suffix (guchar *dest_data, \ - gsize dest_stride, \ - const guchar *src_data, \ - gsize src_stride, \ - gsize width, \ - gsize height) \ -{ \ - gsize x, y; \ -\ - for (y = 0; y < height; y++) \ - { \ - for (x = 0; x < width; x++) \ - { \ - guchar conv[4]; \ - convert_pixel_ ## name (conv, src_data + step * x); \ - dest_data[4 * x + R] = conv[0]; \ - dest_data[4 * x + G] = conv[1]; \ - dest_data[4 * x + B] = conv[2]; \ - dest_data[4 * x + A] = conv[3]; \ - } \ -\ - dest_data += dest_stride; \ - src_data += src_stride; \ - } \ -} - -#define CONVERT_FUNCS(name,step) \ -CONVERT_FUNC(name, download_le, 2, 1, 0, 3, step) \ -CONVERT_FUNC(name, download_be, 1, 2, 3, 0, step) \ -CONVERT_FUNC(name, gles_rgba, 0, 1, 2, 3, step) \ - -static inline void -convert_pixel_rgb16 (guchar *dest_data, const guchar *src_data) -{ - const guint16 *src = (const guint16 *) src_data; - dest_data[0] = (guchar)(src[0] >> 8); - dest_data[1] = (guchar)(src[1] >> 8); - dest_data[2] = (guchar)(src[2] >> 8); - dest_data[3] = 0xFF; -} -CONVERT_FUNCS(rgb16, 3 * sizeof (guint16)) - -static inline void -convert_pixel_rgba16 (guchar *dest_data, const guchar *src_data) -{ - const guint16 *src = (const guint16 *) src_data; - dest_data[0] = (guchar)(src[0] >> 8); - dest_data[1] = (guchar)(src[1] >> 8); - dest_data[2] = (guchar)(src[2] >> 8); - dest_data[3] = (guchar)(src[3] >> 8); -} -CONVERT_FUNCS(rgba16, 4 * sizeof (guint16)) - -static inline void -convert_pixel_rgb16f (guchar *dest_data, const guchar *src_data) -{ - float src[4]; - guint16 tmp[4]; - memcpy(tmp, src_data, sizeof(guint16) * 3); - half_to_float4(tmp, src); - dest_data[0] = CLAMP (src[0] * 256.f, 0.f, 255.f); - dest_data[1] = CLAMP (src[1] * 256.f, 0.f, 255.f); - dest_data[2] = CLAMP (src[2] * 256.f, 0.f, 255.f); - dest_data[3] = 0xFF; -} -CONVERT_FUNCS(rgb16f, 3 * sizeof (guint16)) - -static inline void -convert_pixel_rgba16f (guchar *dest_data, const guchar *src_data) -{ - float src[4]; - half_to_float4((const guint16 *) src_data, src); - dest_data[0] = CLAMP (src[0] * 256.f, 0.f, 255.f); - dest_data[1] = CLAMP (src[1] * 256.f, 0.f, 255.f); - dest_data[2] = CLAMP (src[2] * 256.f, 0.f, 255.f); - dest_data[3] = CLAMP (src[3] * 256.f, 0.f, 255.f); -} -CONVERT_FUNCS(rgba16f, 4 * sizeof (guint16)) - -static inline void -convert_pixel_rgb32f (guchar *dest_data, const guchar *src_data) -{ - float *src = (float *) src_data; - dest_data[0] = CLAMP (src[0] * 256.f, 0.f, 255.f); - dest_data[1] = CLAMP (src[1] * 256.f, 0.f, 255.f); - dest_data[2] = CLAMP (src[2] * 256.f, 0.f, 255.f); - dest_data[3] = 0xFF; -} -CONVERT_FUNCS(rgb32f, 3 * sizeof (float)) - -static inline void -convert_pixel_rgba32f (guchar *dest_data, const guchar *src_data) -{ - float *src = (float *) src_data; - dest_data[0] = CLAMP (src[0] * 256.f, 0.f, 255.f); - dest_data[1] = CLAMP (src[1] * 256.f, 0.f, 255.f); - dest_data[2] = CLAMP (src[2] * 256.f, 0.f, 255.f); - dest_data[3] = CLAMP (src[3] * 256.f, 0.f, 255.f); -} -CONVERT_FUNCS(rgba32f, 4 * sizeof (float)) - -typedef void (* ConversionFunc) (guchar *dest_data, - gsize dest_stride, - const guchar *src_data, - gsize src_stride, - gsize width, - gsize height); - -static ConversionFunc converters[GDK_MEMORY_N_FORMATS][GDK_MEMORY_N_CONVERSIONS] = -{ - { convert_memcpy, convert_swizzle3210, convert_swizzle2103 }, - { convert_swizzle3210, convert_memcpy, convert_swizzle3012 }, - { convert_swizzle2103, convert_swizzle1230, convert_memcpy }, - { convert_swizzle_premultiply_3210_3210, convert_swizzle_premultiply_0123_3210, convert_swizzle_premultiply_3012_3210, }, - { convert_swizzle_premultiply_3210_0123, convert_swizzle_premultiply_0123_0123, convert_swizzle_premultiply_3012_0123 }, - { convert_swizzle_premultiply_3210_3012, convert_swizzle_premultiply_0123_3012, convert_swizzle_premultiply_3012_3012 }, - { convert_swizzle_premultiply_3210_0321, convert_swizzle_premultiply_0123_0321, convert_swizzle_premultiply_3012_0321 }, - { convert_swizzle_opaque_3210, convert_swizzle_opaque_0123, convert_swizzle_opaque_3012 }, - { convert_swizzle_opaque_3012, convert_swizzle_opaque_0321, convert_swizzle_opaque_3210 }, - { convert_rgb16_to_download_le, convert_rgb16_to_download_be, convert_rgb16_to_gles_rgba }, - { convert_rgba16_to_download_le, convert_rgba16_to_download_be, convert_rgba16_to_gles_rgba }, - { convert_rgb16f_to_download_le, convert_rgb16f_to_download_be, convert_rgb16f_to_gles_rgba }, - { convert_rgba16f_to_download_le, convert_rgba16f_to_download_be, convert_rgba16f_to_gles_rgba }, - { convert_rgb32f_to_download_le, convert_rgb32f_to_download_be, convert_rgb32f_to_gles_rgba }, - { convert_rgba32f_to_download_le, convert_rgba32f_to_download_be, convert_rgba32f_to_gles_rgba } -}; - -void -gdk_memory_convert (guchar *dest_data, - gsize dest_stride, - GdkMemoryConversion dest_format, - const guchar *src_data, - gsize src_stride, - GdkMemoryFormat src_format, - gsize width, - gsize height) -{ - g_assert (dest_format < 3); - g_assert (src_format < GDK_MEMORY_N_FORMATS); - - converters[src_format][dest_format] (dest_data, dest_stride, src_data, src_stride, width, height); -} - -#define CONVERT_FLOAT(R,G,B,A,premultiply) G_STMT_START {\ - for (y = 0; y < height; y++) \ - { \ - for (x = 0; x < width; x++) \ - { \ - if (A >= 0) \ - { \ - dest_data[4 * x + 0] = src_data[4 * x + R] / 255.0f; \ - dest_data[4 * x + 1] = src_data[4 * x + G] / 255.0f; \ - dest_data[4 * x + 2] = src_data[4 * x + B] / 255.0f; \ - dest_data[4 * x + 3] = src_data[4 * x + A] / 255.0f; \ - if (premultiply) \ - { \ - dest_data[4 * x + 0] *= dest_data[4 * x + 3]; \ - dest_data[4 * x + 1] *= dest_data[4 * x + 3]; \ - dest_data[4 * x + 2] *= dest_data[4 * x + 3]; \ - } \ - } \ - else \ - { \ - dest_data[4 * x + 0] = src_data[3 * x + R] / 255.0f; \ - dest_data[4 * x + 1] = src_data[3 * x + G] / 255.0f; \ - dest_data[4 * x + 2] = src_data[3 * x + B] / 255.0f; \ - dest_data[4 * x + 3] = 1.0; \ - } \ - } \ -\ - dest_data += dest_stride; \ - src_data += src_stride; \ - } \ -}G_STMT_END - -#define CONVERT_FLOAT_PIXEL(func,step) G_STMT_START{\ - for (y = 0; y < height; y++) \ - { \ - for (x = 0; x < width; x++) \ - { \ - func (dest_data + 4 * x, src_data + step * x); \ - } \ -\ - dest_data += dest_stride; \ - src_data += src_stride; \ - } \ -}G_STMT_END - -static inline void -convert_rgb16_to_float (float *dest, const guchar *src_data) -{ - const guint16 *src = (const guint16 *) src_data; - dest[0] = src[0] / 65535.f; - dest[1] = src[1] / 65535.f; - dest[2] = src[2] / 65535.f; - dest[3] = 1.0; -} - -static inline void -convert_rgba16_to_float (float *dest, const guchar *src_data) -{ - const guint16 *src = (const guint16 *) src_data; - dest[0] = src[0] / 65535.f; - dest[1] = src[1] / 65535.f; - dest[2] = src[2] / 65535.f; - dest[3] = src[3] / 65535.f; -} - -static inline void -convert_rgb16f_to_float (float *dest, const guchar *src_data) -{ - guint16 tmp[4]; - memcpy(tmp, src_data, sizeof(guint16) * 3); - tmp[3] = FP16_ONE; - half_to_float4 (tmp, dest); -} - -static inline void -convert_rgba16f_to_float (float *dest, const guchar *src_data) -{ - half_to_float4 ((const guint16 *) src_data, dest); -} - -static inline void -convert_rgb32f_to_float (float *dest, const guchar *src_data) -{ - const float *src = (const float *) src_data; - dest[0] = src[0]; - dest[1] = src[1]; - dest[2] = src[2]; - dest[3] = 1.0; -} - -static inline void -convert_rgba32f_to_float (float *dest, const guchar *src_data) -{ - const float *src = (const float *) src_data; - dest[0] = src[0]; - dest[1] = src[1]; - dest[2] = src[2]; - dest[3] = src[3]; -} - -void -gdk_memory_convert_to_float (float *dest_data, - gsize dest_stride, - const guchar *src_data, - gsize src_stride, - GdkMemoryFormat src_format, - gsize width, - gsize height) -{ - gsize x, y; - - switch (src_format) - { - case GDK_MEMORY_B8G8R8A8_PREMULTIPLIED: - CONVERT_FLOAT (2, 1, 0, 3, FALSE); - break; - case GDK_MEMORY_A8R8G8B8_PREMULTIPLIED: - CONVERT_FLOAT (1, 2, 3, 0, FALSE); - break; - case GDK_MEMORY_R8G8B8A8_PREMULTIPLIED: - CONVERT_FLOAT (0, 1, 2, 3, FALSE); - break; - case GDK_MEMORY_B8G8R8A8: - CONVERT_FLOAT (2, 1, 0, 3, TRUE); - break; - case GDK_MEMORY_A8R8G8B8: - CONVERT_FLOAT (1, 2, 3, 0, TRUE); - break; - case GDK_MEMORY_R8G8B8A8: - CONVERT_FLOAT (0, 1, 2, 3, TRUE); - break; - case GDK_MEMORY_A8B8G8R8: - CONVERT_FLOAT (3, 2, 1, 0, TRUE); - break; - case GDK_MEMORY_R8G8B8: - CONVERT_FLOAT (0, 1, 2, -1, FALSE); - break; - case GDK_MEMORY_B8G8R8: - CONVERT_FLOAT (2, 1, 0, -1, FALSE); - break; - case GDK_MEMORY_R16G16B16: - CONVERT_FLOAT_PIXEL (convert_rgb16_to_float, 3 * sizeof (guint16)); - break; - case GDK_MEMORY_R16G16B16A16_PREMULTIPLIED: - CONVERT_FLOAT_PIXEL (convert_rgba16_to_float, 4 * sizeof (guint16)); - break; - case GDK_MEMORY_R16G16B16_FLOAT: - CONVERT_FLOAT_PIXEL (convert_rgb16f_to_float, 3 * sizeof (guint16)); - break; - case GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED: - CONVERT_FLOAT_PIXEL (convert_rgba16f_to_float, 4 * sizeof (guint16)); - break; - case GDK_MEMORY_R32G32B32_FLOAT: - CONVERT_FLOAT_PIXEL (convert_rgb32f_to_float, 3 * sizeof (float)); - break; - case GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED: - CONVERT_FLOAT_PIXEL (convert_rgba32f_to_float, 4 * sizeof (float)); - break; - - case GDK_MEMORY_N_FORMATS: - default: - g_assert_not_reached(); - } -} diff --git a/gdk/gdkmemorytextureprivate.h b/gdk/gdkmemorytextureprivate.h index ddd9fd1c37..0cd5e91f27 100644 --- a/gdk/gdkmemorytextureprivate.h +++ b/gdk/gdkmemorytextureprivate.h @@ -29,45 +29,9 @@ G_BEGIN_DECLS #define GDK_MEMORY_GDK_PIXBUF_OPAQUE GDK_MEMORY_R8G8B8 #define GDK_MEMORY_GDK_PIXBUF_ALPHA GDK_MEMORY_R8G8B8A8 -typedef enum { - GDK_MEMORY_CONVERT_DOWNLOAD_LITTLE_ENDIAN, - GDK_MEMORY_CONVERT_DOWNLOAD_BIT_ENDIAN, - GDK_MEMORY_CONVERT_GLES_RGBA, - - GDK_MEMORY_N_CONVERSIONS -} GdkMemoryConversion; - -#if G_BYTE_ORDER == G_LITTLE_ENDIAN -#define GDK_MEMORY_CONVERT_DOWNLOAD GDK_MEMORY_CONVERT_DOWNLOAD_LITTLE_ENDIAN -#elif G_BYTE_ORDER == G_BIG_ENDIAN -#define GDK_MEMORY_CONVERT_DOWNLOAD GDK_MEMORY_CONVERT_DOWNLOAD_BIG_ENDIAN -#else -#error "Unknown byte order for GDK_MEMORY_CONVERT_DOWNLOAD" -#endif - -gsize gdk_memory_format_bytes_per_pixel (GdkMemoryFormat format); - -GdkMemoryFormat gdk_memory_texture_get_format (GdkMemoryTexture *self); const guchar * gdk_memory_texture_get_data (GdkMemoryTexture *self); gsize gdk_memory_texture_get_stride (GdkMemoryTexture *self); -void gdk_memory_convert (guchar *dest_data, - gsize dest_stride, - GdkMemoryConversion dest_format, - const guchar *src_data, - gsize src_stride, - GdkMemoryFormat src_format, - gsize width, - gsize height); - -void gdk_memory_convert_to_float (float *dest_data, - gsize dest_stride, - const guchar *src_data, - gsize src_stride, - GdkMemoryFormat src_format, - gsize width, - gsize height); - G_END_DECLS diff --git a/gdk/gdksurface.c b/gdk/gdksurface.c index 13d779a817..40d9c21b8f 100644 --- a/gdk/gdksurface.c +++ b/gdk/gdksurface.c @@ -71,7 +71,7 @@ struct _GdkSurfacePrivate gpointer egl_native_window; #ifdef HAVE_EGL EGLSurface egl_surface; - gboolean egl_surface_hdr; + gboolean egl_surface_high_depth; #endif gpointer widget; @@ -1109,16 +1109,16 @@ gdk_surface_get_egl_surface (GdkSurface *self) void gdk_surface_ensure_egl_surface (GdkSurface *self, - gboolean hdr) + gboolean high_depth) { GdkSurfacePrivate *priv = gdk_surface_get_instance_private (self); GdkDisplay *display = gdk_surface_get_display (self); g_return_if_fail (priv->egl_native_window != NULL); - if (priv->egl_surface_hdr != hdr && + if (priv->egl_surface_high_depth != high_depth && priv->egl_surface != NULL && - gdk_display_get_egl_config_hdr (display) != gdk_display_get_egl_config (display)) + gdk_display_get_egl_config_high_depth (display) != gdk_display_get_egl_config (display)) { eglDestroySurface (gdk_surface_get_display (self), priv->egl_surface); priv->egl_surface = NULL; @@ -1127,11 +1127,11 @@ gdk_surface_ensure_egl_surface (GdkSurface *self, if (priv->egl_surface == NULL) { priv->egl_surface = eglCreateWindowSurface (gdk_display_get_egl_display (display), - hdr ? gdk_display_get_egl_config_hdr (display) - : gdk_display_get_egl_config (display), + high_depth ? gdk_display_get_egl_config_high_depth (display) + : gdk_display_get_egl_config (display), (EGLNativeWindowType) priv->egl_native_window, NULL); - priv->egl_surface_hdr = hdr; + priv->egl_surface_high_depth = high_depth; } #endif } diff --git a/gdk/gdktexture.c b/gdk/gdktexture.c index b79b671a53..f4c5928c8d 100644 --- a/gdk/gdktexture.c +++ b/gdk/gdktexture.c @@ -808,6 +808,12 @@ gdk_texture_download_texture (GdkTexture *texture) return texture; } +GdkMemoryFormat +gdk_texture_get_format (GdkTexture *self) +{ + return self->format; +} + gboolean gdk_texture_set_render_data (GdkTexture *self, gpointer key, @@ -972,4 +978,3 @@ gdk_texture_save_to_tiff_bytes (GdkTexture *texture) return gdk_save_tiff (texture); } - diff --git a/gdk/gdktextureprivate.h b/gdk/gdktextureprivate.h index 814ed5d92c..994c9901f8 100644 --- a/gdk/gdktextureprivate.h +++ b/gdk/gdktextureprivate.h @@ -3,6 +3,8 @@ #include "gdktexture.h" +#include "gdkmemorytexture.h" + G_BEGIN_DECLS #define GDK_TEXTURE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_TEXTURE, GdkTextureClass)) @@ -13,6 +15,7 @@ struct _GdkTexture { GObject parent_instance; + GdkMemoryFormat format; int width; int height; @@ -42,6 +45,7 @@ cairo_surface_t * gdk_texture_download_surface (GdkTexture /* NB: GdkMemoryTexture */ GdkTexture * gdk_texture_download_texture (GdkTexture *texture); +GdkMemoryFormat gdk_texture_get_format (GdkTexture *self); gboolean gdk_texture_set_render_data (GdkTexture *self, gpointer key, gpointer data, diff --git a/gdk/gdkvulkancontext.c b/gdk/gdkvulkancontext.c index 2466c317b8..20c1860645 100644 --- a/gdk/gdkvulkancontext.c +++ b/gdk/gdkvulkancontext.c @@ -425,7 +425,7 @@ device_supports_incremental_present (VkPhysicalDevice device) static void gdk_vulkan_context_begin_frame (GdkDrawContext *draw_context, - gboolean request_hdr, + gboolean prefers_high_depth, cairo_region_t *region) { GdkVulkanContext *context = GDK_VULKAN_CONTEXT (draw_context); diff --git a/gdk/loaders/gdkpng.c b/gdk/loaders/gdkpng.c index 97e6dfffd0..9bdc5e3a43 100644 --- a/gdk/loaders/gdkpng.c +++ b/gdk/loaders/gdkpng.c @@ -20,6 +20,7 @@ #include "gdkpngprivate.h" #include "gdkintl.h" +#include "gdkmemoryformatprivate.h" #include "gdkmemorytextureprivate.h" #include "gdkprofilerprivate.h" #include "gdktexture.h" @@ -480,7 +481,7 @@ gdk_save_png (GdkTexture *texture) height = gdk_texture_get_height (texture); mtexture = gdk_texture_download_texture (texture); - format = gdk_memory_texture_get_format (GDK_MEMORY_TEXTURE (mtexture)); + format = gdk_texture_get_format (mtexture); switch (format) { diff --git a/gdk/loaders/gdktiff.c b/gdk/loaders/gdktiff.c index d7416391ee..d2d8dfdbde 100644 --- a/gdk/loaders/gdktiff.c +++ b/gdk/loaders/gdktiff.c @@ -20,6 +20,7 @@ #include "gdktiffprivate.h" #include "gdkintl.h" +#include "gdkmemoryformatprivate.h" #include "gdkmemorytextureprivate.h" #include "gdkprofilerprivate.h" #include "gdktexture.h" @@ -283,7 +284,7 @@ gdk_save_tiff (GdkTexture *texture) height = gdk_texture_get_height (texture); memory_texture = gdk_texture_download_texture (texture); - format = gdk_memory_texture_get_format (GDK_MEMORY_TEXTURE (memory_texture)); + format = gdk_texture_get_format (memory_texture); for (int i = 0; i < G_N_ELEMENTS (format_data); i++) { diff --git a/gdk/macos/gdkmacoscairocontext.c b/gdk/macos/gdkmacoscairocontext.c index 7a195ab063..73ba7cffa0 100644 --- a/gdk/macos/gdkmacoscairocontext.c +++ b/gdk/macos/gdkmacoscairocontext.c @@ -82,7 +82,7 @@ _gdk_macos_cairo_context_cairo_create (GdkCairoContext *cairo_context) static void _gdk_macos_cairo_context_begin_frame (GdkDrawContext *draw_context, - gboolean request_hdr, + gboolean prefers_high_depth, cairo_region_t *region) { GdkMacosCairoContext *self = (GdkMacosCairoContext *)draw_context; diff --git a/gdk/macos/gdkmacosglcontext.c b/gdk/macos/gdkmacosglcontext.c index 967648626c..313be91fb9 100644 --- a/gdk/macos/gdkmacosglcontext.c +++ b/gdk/macos/gdkmacosglcontext.c @@ -291,7 +291,7 @@ opaque_region_covers_surface (GdkMacosGLContext *self) static void gdk_macos_gl_context_begin_frame (GdkDrawContext *context, - gboolean request_hdr, + gboolean prefers_high_depth, cairo_region_t *painted) { GdkMacosGLContext *self = (GdkMacosGLContext *)context; @@ -345,7 +345,7 @@ gdk_macos_gl_context_begin_frame (GdkDrawContext *context, [self->gl_context update]; } - GDK_DRAW_CONTEXT_CLASS (gdk_macos_gl_context_parent_class)->begin_frame (context, request_hdr, painted); + GDK_DRAW_CONTEXT_CLASS (gdk_macos_gl_context_parent_class)->begin_frame (context, prefers_high_depth, painted); if (!self->is_attached) { diff --git a/gdk/meson.build b/gdk/meson.build index 06905233f8..0756f7667c 100644 --- a/gdk/meson.build +++ b/gdk/meson.build @@ -30,6 +30,7 @@ gdk_public_sources = files([ 'gdkhsla.c', 'gdkkeys.c', 'gdkkeyuni.c', + 'gdkmemoryformat.c', 'gdkmemorytexture.c', 'gdkmonitor.c', 'gdkpaintable.c', diff --git a/gdk/wayland/gdkcairocontext-wayland.c b/gdk/wayland/gdkcairocontext-wayland.c index e06eaa1096..e05ea6a7d9 100644 --- a/gdk/wayland/gdkcairocontext-wayland.c +++ b/gdk/wayland/gdkcairocontext-wayland.c @@ -144,7 +144,7 @@ gdk_wayland_cairo_context_create_surface (GdkWaylandCairoContext *self) static void gdk_wayland_cairo_context_begin_frame (GdkDrawContext *draw_context, - gboolean request_hdr, + gboolean prefers_high_depth, cairo_region_t *region) { GdkWaylandCairoContext *self = GDK_WAYLAND_CAIRO_CONTEXT (draw_context); diff --git a/gdk/wayland/gdkglcontext-wayland.c b/gdk/wayland/gdkglcontext-wayland.c index 9fc887367a..d631816286 100644 --- a/gdk/wayland/gdkglcontext-wayland.c +++ b/gdk/wayland/gdkglcontext-wayland.c @@ -47,12 +47,12 @@ G_DEFINE_TYPE (GdkWaylandGLContext, gdk_wayland_gl_context, GDK_TYPE_GL_CONTEXT) static void gdk_wayland_gl_context_begin_frame (GdkDrawContext *draw_context, - gboolean request_hdr, + gboolean prefers_high_depth, cairo_region_t *region) { gdk_wayland_surface_ensure_wl_egl_window (gdk_draw_context_get_surface (draw_context)); - GDK_DRAW_CONTEXT_CLASS (gdk_wayland_gl_context_parent_class)->begin_frame (draw_context, request_hdr, region); + GDK_DRAW_CONTEXT_CLASS (gdk_wayland_gl_context_parent_class)->begin_frame (draw_context, prefers_high_depth, region); glDrawBuffers (1, (GLenum[1]) { GL_BACK }); } diff --git a/gdk/win32/gdkcairocontext-win32.c b/gdk/win32/gdkcairocontext-win32.c index 65aef46b48..480baf7802 100644 --- a/gdk/win32/gdkcairocontext-win32.c +++ b/gdk/win32/gdkcairocontext-win32.c @@ -53,7 +53,7 @@ create_cairo_surface_for_surface (GdkSurface *surface, static void gdk_win32_cairo_context_begin_frame (GdkDrawContext *draw_context, - gboolean request_hdr, + gboolean prefers_high_depth, cairo_region_t *region) { GdkWin32CairoContext *self = GDK_WIN32_CAIRO_CONTEXT (draw_context); diff --git a/gdk/win32/gdkglcontext-win32-egl.c b/gdk/win32/gdkglcontext-win32-egl.c index 8d6bef9e17..1507dd8225 100644 --- a/gdk/win32/gdkglcontext-win32-egl.c +++ b/gdk/win32/gdkglcontext-win32-egl.c @@ -471,12 +471,12 @@ gdk_win32_gl_context_egl_make_current (GdkGLContext *context, static void gdk_win32_gl_context_egl_begin_frame (GdkDrawContext *draw_context, - gboolean request_hdr, + gboolean prefers_high_depth, cairo_region_t *update_area) { gdk_win32_surface_handle_queued_move_resize (draw_context); - GDK_DRAW_CONTEXT_CLASS (gdk_win32_gl_context_egl_parent_class)->begin_frame (draw_context, request_hdr, update_area); + GDK_DRAW_CONTEXT_CLASS (gdk_win32_gl_context_egl_parent_class)->begin_frame (draw_context, prefers_high_depth, update_area); } static void diff --git a/gdk/win32/gdkglcontext-win32-wgl.c b/gdk/win32/gdkglcontext-win32-wgl.c index 9f9bc257a3..ea5f377966 100644 --- a/gdk/win32/gdkglcontext-win32-wgl.c +++ b/gdk/win32/gdkglcontext-win32-wgl.c @@ -118,12 +118,12 @@ gdk_win32_gl_context_wgl_end_frame (GdkDrawContext *draw_context, static void gdk_win32_gl_context_wgl_begin_frame (GdkDrawContext *draw_context, - gboolean request_hdr, + gboolean prefers_high_depth, cairo_region_t *update_area) { gdk_win32_surface_handle_queued_move_resize (draw_context); - GDK_DRAW_CONTEXT_CLASS (gdk_win32_gl_context_wgl_parent_class)->begin_frame (draw_context, request_hdr, update_area); + GDK_DRAW_CONTEXT_CLASS (gdk_win32_gl_context_wgl_parent_class)->begin_frame (draw_context, prefers_high_depth, update_area); } static int diff --git a/gdk/win32/gdkvulkancontext-win32.c b/gdk/win32/gdkvulkancontext-win32.c index d82cb15d27..894bbfa548 100644 --- a/gdk/win32/gdkvulkancontext-win32.c +++ b/gdk/win32/gdkvulkancontext-win32.c @@ -68,12 +68,12 @@ gdk_win32_vulkan_context_create_surface (GdkVulkanContext *context, static void gdk_win32_vulkan_context_begin_frame (GdkDrawContext *draw_context, - gboolean request_hdr, + gboolean prefers_high_depth, cairo_region_t *update_area) { gdk_win32_surface_handle_queued_move_resize (draw_context); - GDK_DRAW_CONTEXT_CLASS (gdk_win32_vulkan_context_parent_class)->begin_frame (draw_context, request_hdr, update_area); + GDK_DRAW_CONTEXT_CLASS (gdk_win32_vulkan_context_parent_class)->begin_frame (draw_context, prefers_high_depth, update_area); } static void diff --git a/gdk/x11/gdkcairocontext-x11.c b/gdk/x11/gdkcairocontext-x11.c index e6accbb6ad..e25ec197a7 100644 --- a/gdk/x11/gdkcairocontext-x11.c +++ b/gdk/x11/gdkcairocontext-x11.c @@ -55,7 +55,7 @@ create_cairo_surface_for_surface (GdkSurface *surface) static void gdk_x11_cairo_context_begin_frame (GdkDrawContext *draw_context, - gboolean request_hdr, + gboolean prefers_high_depth, cairo_region_t *region) { GdkX11CairoContext *self = GDK_X11_CAIRO_CONTEXT (draw_context); diff --git a/gdk/x11/gdkglcontext-egl.c b/gdk/x11/gdkglcontext-egl.c index 39255ac881..67d730fcfb 100644 --- a/gdk/x11/gdkglcontext-egl.c +++ b/gdk/x11/gdkglcontext-egl.c @@ -61,10 +61,10 @@ gdk_x11_display_get_egl_display (GdkDisplay *display) static void gdk_x11_gl_context_egl_begin_frame (GdkDrawContext *draw_context, - gboolean request_hdr, + gboolean prefers_high_depth, cairo_region_t *region) { - GDK_DRAW_CONTEXT_CLASS (gdk_x11_gl_context_egl_parent_class)->begin_frame (draw_context, request_hdr, region); + GDK_DRAW_CONTEXT_CLASS (gdk_x11_gl_context_egl_parent_class)->begin_frame (draw_context, prefers_high_depth, region); glDrawBuffers (1, (GLenum[1]) { GL_BACK }); } diff --git a/gsk/gskrendernode.c b/gsk/gskrendernode.c index 9c4332fe01..6381d334d8 100644 --- a/gsk/gskrendernode.c +++ b/gsk/gskrendernode.c @@ -725,3 +725,8 @@ gsk_value_dup_render_node (const GValue *value) return gsk_render_node_ref (value->data[0].v_pointer); } +gboolean +gsk_render_node_prefers_high_depth (const GskRenderNode *node) +{ + return node->prefers_high_depth; +} diff --git a/gsk/gskrendernodeimpl.c b/gsk/gskrendernodeimpl.c index fd2a9e5d44..28cb14ae64 100644 --- a/gsk/gskrendernodeimpl.c +++ b/gsk/gskrendernodeimpl.c @@ -28,6 +28,7 @@ #include "gsktransformprivate.h" #include "gdk/gdktextureprivate.h" +#include "gdk/gdkmemoryformatprivate.h" #include "gdk/gdk-private.h" #include @@ -1560,6 +1561,8 @@ gsk_texture_node_new (GdkTexture *texture, self->texture = g_object_ref (texture); graphene_rect_init_from_rect (&node->bounds, bounds); + node->prefers_high_depth = gdk_memory_format_prefers_high_depth (gdk_texture_get_format (texture)); + return node; } @@ -2730,11 +2733,13 @@ gsk_container_node_new (GskRenderNode **children, self->children[0] = gsk_render_node_ref (children[0]); graphene_rect_init_from_rect (&bounds, &(children[0]->bounds)); + node->prefers_high_depth = gsk_render_node_prefers_high_depth (children[0]); for (guint i = 1; i < n_children; i++) { self->children[i] = gsk_render_node_ref (children[i]); graphene_rect_union (&bounds, &(children[i]->bounds), &bounds); + node->prefers_high_depth |= gsk_render_node_prefers_high_depth (children[i]); } graphene_rect_init_from_rect (&node->bounds, &bounds); @@ -2965,6 +2970,8 @@ gsk_transform_node_new (GskRenderNode *child, &child->bounds, &node->bounds); + node->prefers_high_depth = gsk_render_node_prefers_high_depth (child); + return node; } @@ -3100,6 +3107,8 @@ gsk_opacity_node_new (GskRenderNode *child, graphene_rect_init_from_rect (&node->bounds, &child->bounds); + node->prefers_high_depth = gsk_render_node_prefers_high_depth (child); + return node; } @@ -3302,6 +3311,8 @@ gsk_color_matrix_node_new (GskRenderNode *child, graphene_rect_init_from_rect (&node->bounds, &child->bounds); + node->prefers_high_depth = gsk_render_node_prefers_high_depth (child); + return node; } @@ -3451,6 +3462,8 @@ gsk_repeat_node_new (const graphene_rect_t *bounds, else graphene_rect_init_from_rect (&self->child_bounds, &child->bounds); + node->prefers_high_depth = gsk_render_node_prefers_high_depth (child); + return node; } @@ -3582,6 +3595,8 @@ gsk_clip_node_new (GskRenderNode *child, graphene_rect_intersection (&self->clip, &child->bounds, &node->bounds); + node->prefers_high_depth = gsk_render_node_prefers_high_depth (child); + return node; } @@ -3713,6 +3728,8 @@ gsk_rounded_clip_node_new (GskRenderNode *child, graphene_rect_intersection (&self->clip.bounds, &child->bounds, &node->bounds); + node->prefers_high_depth = gsk_render_node_prefers_high_depth (child); + return node; } @@ -3932,6 +3949,8 @@ gsk_shadow_node_new (GskRenderNode *child, gsk_shadow_node_get_bounds (self, &node->bounds); + node->prefers_high_depth = gsk_render_node_prefers_high_depth (child); + return node; } @@ -4125,6 +4144,8 @@ gsk_blend_node_new (GskRenderNode *bottom, graphene_rect_union (&bottom->bounds, &top->bounds, &node->bounds); + node->prefers_high_depth = gsk_render_node_prefers_high_depth (bottom) || gsk_render_node_prefers_high_depth (top); + return node; } @@ -4273,6 +4294,8 @@ gsk_cross_fade_node_new (GskRenderNode *start, graphene_rect_union (&start->bounds, &end->bounds, &node->bounds); + node->prefers_high_depth = gsk_render_node_prefers_high_depth (start) || gsk_render_node_prefers_high_depth (end); + return node; } @@ -4864,6 +4887,8 @@ gsk_blur_node_new (GskRenderNode *child, - clip_radius, - clip_radius); + node->prefers_high_depth = gsk_render_node_prefers_high_depth (child); + return node; } @@ -4986,6 +5011,8 @@ gsk_debug_node_new (GskRenderNode *child, graphene_rect_init_from_rect (&node->bounds, &child->bounds); + node->prefers_high_depth = gsk_render_node_prefers_high_depth (child); + return node; } @@ -5150,7 +5177,10 @@ gsk_gl_shader_node_new (GskGLShader *shader, { self->children = g_malloc_n (n_children, sizeof (GskRenderNode *)); for (guint i = 0; i < n_children; i++) - self->children[i] = gsk_render_node_ref (children[i]); + { + self->children[i] = gsk_render_node_ref (children[i]); + node->prefers_high_depth |= gsk_render_node_prefers_high_depth (children[i]); + } } return node; diff --git a/gsk/gskrendernodeprivate.h b/gsk/gskrendernodeprivate.h index ac20813b65..cdb75afd2f 100644 --- a/gsk/gskrendernodeprivate.h +++ b/gsk/gskrendernodeprivate.h @@ -27,6 +27,8 @@ struct _GskRenderNode gatomicrefcount ref_count; graphene_rect_t bounds; + + guint prefers_high_depth : 1; }; struct _GskRenderNodeClass @@ -109,6 +111,7 @@ GskRenderNode ** gsk_container_node_get_children (const GskRenderNode *no void gsk_transform_node_get_translate (const GskRenderNode *node, float *dx, float *dy); +gboolean gsk_render_node_prefers_high_depth (const GskRenderNode *node); G_END_DECLS diff --git a/gsk/ngl/gsknglcommandqueue.c b/gsk/ngl/gsknglcommandqueue.c index a5fbf0dc8d..8dde9ff269 100644 --- a/gsk/ngl/gsknglcommandqueue.c +++ b/gsk/ngl/gsknglcommandqueue.c @@ -26,6 +26,7 @@ #include #include +#include #include #include #include @@ -1231,6 +1232,7 @@ gboolean gsk_ngl_command_queue_create_render_target (GskNglCommandQueue *self, int width, int height, + int format, int min_filter, int mag_filter, guint *out_fbo_id, @@ -1247,6 +1249,7 @@ gsk_ngl_command_queue_create_render_target (GskNglCommandQueue *self, texture_id = gsk_ngl_command_queue_create_texture (self, width, height, + format, min_filter, mag_filter); if (texture_id == -1) @@ -1272,6 +1275,7 @@ int gsk_ngl_command_queue_create_texture (GskNglCommandQueue *self, int width, int height, + int format, int min_filter, int mag_filter) { @@ -1296,9 +1300,9 @@ gsk_ngl_command_queue_create_texture (GskNglCommandQueue *self, glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); if (gdk_gl_context_get_use_es (self->context)) - glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); + glTexImage2D (GL_TEXTURE_2D, 0, format, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); else - glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL); + glTexImage2D (GL_TEXTURE_2D, 0, format, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL); /* Restore the previous texture if it was set */ if (self->attachments->textures[0].id != 0) @@ -1353,7 +1357,7 @@ gsk_ngl_command_queue_upload_texture (GskNglCommandQueue *self, height = MAX (height, self->max_texture_size); } - texture_id = gsk_ngl_command_queue_create_texture (self, width, height, min_filter, mag_filter); + texture_id = gsk_ngl_command_queue_create_texture (self, width, height, GL_RGBA8, min_filter, mag_filter); if (texture_id == -1) return texture_id; @@ -1361,7 +1365,7 @@ gsk_ngl_command_queue_upload_texture (GskNglCommandQueue *self, { GdkMemoryTexture *memory_texture = GDK_MEMORY_TEXTURE (texture); data = gdk_memory_texture_get_data (memory_texture); - data_format = gdk_memory_texture_get_format (memory_texture); + data_format = gdk_texture_get_format (texture); data_stride = gdk_memory_texture_get_stride (memory_texture); } else diff --git a/gsk/ngl/gsknglcommandqueueprivate.h b/gsk/ngl/gsknglcommandqueueprivate.h index b13838d48e..40cca01162 100644 --- a/gsk/ngl/gsknglcommandqueueprivate.h +++ b/gsk/ngl/gsknglcommandqueueprivate.h @@ -290,12 +290,14 @@ int gsk_ngl_command_queue_upload_texture (GskNglCommandQue int gsk_ngl_command_queue_create_texture (GskNglCommandQueue *self, int width, int height, + int format, int min_filter, int mag_filter); guint gsk_ngl_command_queue_create_framebuffer (GskNglCommandQueue *self); gboolean gsk_ngl_command_queue_create_render_target (GskNglCommandQueue *self, int width, int height, + int format, int min_filter, int mag_filter, guint *out_fbo_id, diff --git a/gsk/ngl/gskngldriver.c b/gsk/ngl/gskngldriver.c index 3bf4ace071..87f2864241 100644 --- a/gsk/ngl/gskngldriver.c +++ b/gsk/ngl/gskngldriver.c @@ -183,6 +183,7 @@ gsk_ngl_driver_create_atlas (GskNglDriver *self) atlas->texture_id = gsk_ngl_command_queue_create_texture (self->command_queue, atlas->width, atlas->height, + GL_RGBA8, GL_LINEAR, GL_LINEAR); @@ -750,6 +751,7 @@ gsk_ngl_driver_load_texture (GskNglDriver *self, guint texture_id; int height; int width; + int format; g_return_val_if_fail (GSK_IS_NGL_DRIVER (self), 0); g_return_val_if_fail (GDK_IS_TEXTURE (texture), 0); @@ -757,6 +759,8 @@ gsk_ngl_driver_load_texture (GskNglDriver *self, context = self->command_queue->context; + format = GL_RGBA8; + if (GDK_IS_GL_TEXTURE (texture)) { GdkGLTexture *gl_texture = (GdkGLTexture *) texture; @@ -799,7 +803,7 @@ gsk_ngl_driver_load_texture (GskNglDriver *self, mag_filter); t = gsk_ngl_texture_new (texture_id, - width, height, min_filter, mag_filter, + width, height, format, min_filter, mag_filter, self->current_frame_id); g_hash_table_insert (self->textures, GUINT_TO_POINTER (texture_id), t); @@ -820,6 +824,7 @@ gsk_ngl_driver_load_texture (GskNglDriver *self, * @self: a `GskNglDriver` * @width: the width of the texture * @height: the height of the texture + * @format: format for the texture * @min_filter: GL_NEAREST or GL_LINEAR * @mag_filter: GL_NEAREST or GL_FILTER * @@ -827,6 +832,8 @@ gsk_ngl_driver_load_texture (GskNglDriver *self, * to upload data, map to a framebuffer, or other uses which may * modify the texture immediately. * + * Typical examples for @format are GK_RGBA8, GL_RGBA16F or GL_RGBA32F. + * * Use gsk_ngl_driver_release_texture() to release this texture back into * the pool so it may be reused later in the pipeline. * @@ -837,6 +844,7 @@ GskNglTexture * gsk_ngl_driver_create_texture (GskNglDriver *self, float width, float height, + int format, int min_filter, int mag_filter) { @@ -847,9 +855,11 @@ gsk_ngl_driver_create_texture (GskNglDriver *self, texture_id = gsk_ngl_command_queue_create_texture (self->command_queue, width, height, + format, min_filter, mag_filter); texture = gsk_ngl_texture_new (texture_id, width, height, + format, min_filter, mag_filter, self->current_frame_id); g_hash_table_insert (self->textures, @@ -896,6 +906,7 @@ gsk_ngl_driver_release_texture (GskNglDriver *self, * @self: a `GskNglDriver` * @width: the width for the render target * @height: the height for the render target + * @format: the format to use * @min_filter: the min filter to use for the texture * @mag_filter: the mag filter to use for the texture * @out_render_target: (out): a location for the render target @@ -904,6 +915,8 @@ gsk_ngl_driver_release_texture (GskNglDriver *self, * bound to that framebuffer of the size @width x @height and using the * appropriate filters. * + * Typical examples for @format are GK_RGBA8, GL_RGBA16F or GL_RGBA32F. + * * Use gsk_ngl_driver_release_render_target() when you are finished with * the render target to release it. You may steal the texture from the * render target when releasing it. @@ -915,6 +928,7 @@ gboolean gsk_ngl_driver_create_render_target (GskNglDriver *self, int width, int height, + int format, int min_filter, int mag_filter, GskNglRenderTarget **out_render_target) @@ -947,6 +961,7 @@ gsk_ngl_driver_create_render_target (GskNglDriver *self, if (gsk_ngl_command_queue_create_render_target (self->command_queue, width, height, + format, min_filter, mag_filter, &framebuffer_id, &texture_id)) { @@ -955,6 +970,7 @@ gsk_ngl_driver_create_render_target (GskNglDriver *self, render_target = g_slice_new0 (GskNglRenderTarget); render_target->min_filter = min_filter; render_target->mag_filter = mag_filter; + render_target->format = format; render_target->width = width; render_target->height = height; render_target->framebuffer_id = framebuffer_id; @@ -1014,6 +1030,7 @@ gsk_ngl_driver_release_render_target (GskNglDriver *self, texture = gsk_ngl_texture_new (render_target->texture_id, render_target->width, render_target->height, + render_target->format, render_target->min_filter, render_target->mag_filter, self->current_frame_id); @@ -1266,6 +1283,7 @@ gsk_ngl_driver_add_texture_slices (GskNglDriver *self, /* Allocate one Texture for the entire thing. */ t = gsk_ngl_texture_new (0, tex_width, tex_height, + GL_RGBA8, GL_NEAREST, GL_NEAREST, self->current_frame_id); diff --git a/gsk/ngl/gskngldriverprivate.h b/gsk/ngl/gskngldriverprivate.h index 9d40c81b2b..42b6263ec1 100644 --- a/gsk/ngl/gskngldriverprivate.h +++ b/gsk/ngl/gskngldriverprivate.h @@ -88,6 +88,7 @@ struct _GskNglRenderTarget guint texture_id; int min_filter; int mag_filter; + int format; int width; int height; }; @@ -144,6 +145,7 @@ GdkGLContext *gsk_ngl_driver_get_context (GskNglDriver gboolean gsk_ngl_driver_create_render_target (GskNglDriver *self, int width, int height, + int format, int min_filter, int mag_filter, GskNglRenderTarget **render_target); @@ -166,6 +168,7 @@ guint gsk_ngl_driver_load_texture (GskNglDriver GskNglTexture *gsk_ngl_driver_create_texture (GskNglDriver *self, float width, float height, + int format, int min_filter, int mag_filter); void gsk_ngl_driver_release_texture (GskNglDriver *self, diff --git a/gsk/ngl/gsknglglyphlibrary.c b/gsk/ngl/gsknglglyphlibrary.c index 33c86cc967..ede4f19105 100644 --- a/gsk/ngl/gsknglglyphlibrary.c +++ b/gsk/ngl/gsknglglyphlibrary.c @@ -21,7 +21,7 @@ #include "config.h" #include -#include +#include #include #include "gsknglcommandqueueprivate.h" @@ -237,7 +237,7 @@ gsk_ngl_glyph_library_upload_glyph (GskNglGlyphLibrary *self, pixel_data = free_data = g_malloc (width * height * 4); gdk_memory_convert (pixel_data, width * 4, - GDK_MEMORY_CONVERT_GLES_RGBA, + GDK_MEMORY_R8G8B8A8_PREMULTIPLIED, cairo_image_surface_get_data (surface), width * 4, GDK_MEMORY_DEFAULT, diff --git a/gsk/ngl/gskngliconlibrary.c b/gsk/ngl/gskngliconlibrary.c index ab4d1b4d6f..cfc662a9e6 100644 --- a/gsk/ngl/gskngliconlibrary.c +++ b/gsk/ngl/gskngliconlibrary.c @@ -21,7 +21,7 @@ #include "config.h" #include -#include +#include #include #include @@ -115,7 +115,7 @@ gsk_ngl_icon_library_add (GskNglIconLibrary *self, { pixel_data = free_data = g_malloc (width * height * 4); gdk_memory_convert (pixel_data, width * 4, - GDK_MEMORY_CONVERT_GLES_RGBA, + GDK_MEMORY_R8G8B8A8_PREMULTIPLIED, surface_data, cairo_image_surface_get_stride (surface), GDK_MEMORY_DEFAULT, width, height); gl_format = GL_RGBA; diff --git a/gsk/ngl/gsknglrenderer.c b/gsk/ngl/gsknglrenderer.c index cdb6717043..eea48b6e6d 100644 --- a/gsk/ngl/gsknglrenderer.c +++ b/gsk/ngl/gsknglrenderer.c @@ -22,8 +22,11 @@ #include #include +#include +#include #include #include +#include #include "gsknglcommandqueueprivate.h" #include "gskngldriverprivate.h" @@ -201,7 +204,9 @@ gsk_ngl_renderer_render (GskRenderer *renderer, viewport.size.height = gdk_surface_get_height (surface) * scale_factor; gdk_gl_context_make_current (self->context); - gdk_draw_context_begin_frame (GDK_DRAW_CONTEXT (self->context), update_area); + gdk_draw_context_begin_frame_full (GDK_DRAW_CONTEXT (self->context), + gsk_render_node_prefers_high_depth (root), + update_area); /* Must be called *AFTER* gdk_draw_context_begin_frame() */ render_region = get_render_region (surface, self->context); @@ -236,6 +241,7 @@ gsk_ngl_renderer_render_texture (GskRenderer *renderer, guint texture_id; int width; int height; + int format; g_assert (GSK_IS_NGL_RENDERER (renderer)); g_assert (root != NULL); @@ -243,8 +249,11 @@ gsk_ngl_renderer_render_texture (GskRenderer *renderer, width = ceilf (viewport->size.width); height = ceilf (viewport->size.height); + format = gsk_render_node_prefers_high_depth (root) ? GL_RGBA32F : GL_RGBA8; + if (gsk_ngl_driver_create_render_target (self->driver, width, height, + format, GL_NEAREST, GL_NEAREST, &render_target)) { diff --git a/gsk/ngl/gsknglrenderjob.c b/gsk/ngl/gsknglrenderjob.c index baf87f6461..e3436e10f4 100644 --- a/gsk/ngl/gsknglrenderjob.c +++ b/gsk/ngl/gsknglrenderjob.c @@ -162,6 +162,11 @@ struct _GskNglRenderJob /* If we should be rendering red zones over fallback nodes */ guint debug_fallback : 1; + + /* Format we want to use for intermediate textures, determined by + * looking at the format of the framebuffer we are rendering on. + */ + int target_format; }; typedef struct _GskNglRenderOffscreen @@ -198,6 +203,16 @@ static gboolean gsk_ngl_render_job_visit_node_with_offscreen (GskNglRenderJob const GskRenderNode *node, GskNglRenderOffscreen *offscreen); +static inline int +get_target_format (GskNglRenderJob *job, + const GskRenderNode *node) +{ + if (gsk_render_node_prefers_high_depth (node)) + return job->target_format; + + return GL_RGBA8; +} + static inline void init_full_texture_region (GskNglRenderOffscreen *offscreen) { @@ -1258,6 +1273,7 @@ blur_offscreen (GskNglRenderJob *job, if (!gsk_ngl_driver_create_render_target (job->driver, MAX (texture_to_blur_width, 1), MAX (texture_to_blur_height, 1), + job->target_format, GL_NEAREST, GL_NEAREST, &pass1)) return 0; @@ -1268,6 +1284,7 @@ blur_offscreen (GskNglRenderJob *job, if (!gsk_ngl_driver_create_render_target (job->driver, texture_to_blur_width, texture_to_blur_height, + job->target_format, GL_NEAREST, GL_NEAREST, &pass2)) return gsk_ngl_driver_release_render_target (job->driver, pass1, FALSE); @@ -2179,6 +2196,7 @@ gsk_ngl_render_job_visit_blurred_inset_shadow_node (GskNglRenderJob *job, if (!gsk_ngl_driver_create_render_target (job->driver, texture_width, texture_height, + get_target_format (job, node), GL_NEAREST, GL_NEAREST, &render_target)) g_assert_not_reached (); @@ -2449,6 +2467,7 @@ gsk_ngl_render_job_visit_blurred_outset_shadow_node (GskNglRenderJob *job, gsk_ngl_driver_create_render_target (job->driver, texture_width, texture_height, + get_target_format (job, node), GL_NEAREST, GL_NEAREST, &render_target); @@ -3856,6 +3875,7 @@ gsk_ngl_render_job_visit_node_with_offscreen (GskNglRenderJob *job, if (!gsk_ngl_driver_create_render_target (job->driver, scaled_width, scaled_height, + get_target_format (job, node), filter, filter, &render_target)) g_assert_not_reached (); @@ -3954,6 +3974,7 @@ gsk_ngl_render_job_render_flipped (GskNglRenderJob *job, if (!gsk_ngl_command_queue_create_render_target (job->command_queue, MAX (1, job->viewport.size.width), MAX (1, job->viewport.size.height), + job->target_format, GL_NEAREST, GL_NEAREST, &framebuffer_id, &texture_id)) return; @@ -4044,6 +4065,22 @@ gsk_ngl_render_job_set_debug_fallback (GskNglRenderJob *job, job->debug_fallback = !!debug_fallback; } +static int +get_framebuffer_format (guint framebuffer) +{ + int size; + + glBindFramebuffer (GL_FRAMEBUFFER, framebuffer); + glGetFramebufferAttachmentParameteriv (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE, &size); + + if (size >= 32) + return GL_RGBA32F; + else if (size >= 16) + return GL_RGBA16F; + else + return GL_RGBA8; +} + GskNglRenderJob * gsk_ngl_render_job_new (GskNglDriver *driver, const graphene_rect_t *viewport, @@ -4070,6 +4107,7 @@ gsk_ngl_render_job_new (GskNglDriver *driver, job->scale_x = scale_factor; job->scale_y = scale_factor; job->viewport = *viewport; + job->target_format = get_framebuffer_format (framebuffer); gsk_ngl_render_job_set_alpha (job, 1.0f); gsk_ngl_render_job_set_projection_from_rect (job, viewport, NULL); diff --git a/gsk/ngl/gskngltexture.c b/gsk/ngl/gskngltexture.c index 5ee38f69b6..c70d4d91b2 100644 --- a/gsk/ngl/gskngltexture.c +++ b/gsk/ngl/gskngltexture.c @@ -59,6 +59,7 @@ GskNglTexture * gsk_ngl_texture_new (guint texture_id, int width, int height, + int format, int min_filter, int mag_filter, gint64 frame_id) @@ -70,6 +71,7 @@ gsk_ngl_texture_new (guint texture_id, texture->link.data = texture; texture->min_filter = min_filter; texture->mag_filter = mag_filter; + texture->format = format; texture->width = width; texture->height = height; texture->last_used_in_frame = frame_id; diff --git a/gsk/ngl/gskngltexturelibrary.c b/gsk/ngl/gskngltexturelibrary.c index 7998ae9850..03b8e252f7 100644 --- a/gsk/ngl/gskngltexturelibrary.c +++ b/gsk/ngl/gskngltexturelibrary.c @@ -228,7 +228,7 @@ gsk_ngl_texture_library_pack_one (GskNglTextureLibrary *self, height = MIN (height, self->driver->command_queue->max_texture_size); } - texture = gsk_ngl_driver_create_texture (self->driver, width, height, GL_LINEAR, GL_LINEAR); + texture = gsk_ngl_driver_create_texture (self->driver, width, height, GL_RGBA8, GL_LINEAR, GL_LINEAR); texture->permanent = TRUE; return texture; diff --git a/gsk/ngl/gskngltextureprivate.h b/gsk/ngl/gskngltextureprivate.h index 1d9052f625..55ef48c4d3 100644 --- a/gsk/ngl/gskngltextureprivate.h +++ b/gsk/ngl/gskngltextureprivate.h @@ -67,6 +67,7 @@ struct _GskNglTexture int height; int min_filter; int mag_filter; + int format; /* Set when used by an atlas so we don't drop the texture */ guint permanent : 1; @@ -75,6 +76,7 @@ struct _GskNglTexture GskNglTexture *gsk_ngl_texture_new (guint texture_id, int width, int height, + int format, int min_filter, int mag_filter, gint64 frame_id); diff --git a/testsuite/gdk/texture.c b/testsuite/gdk/texture.c index fc1f728c7c..1a218ddd4a 100644 --- a/testsuite/gdk/texture.c +++ b/testsuite/gdk/texture.c @@ -1,6 +1,6 @@ #include -static gboolean +static void compare_pixels (int width, int height, guchar *data1, @@ -8,15 +8,17 @@ compare_pixels (int width, guchar *data2, gsize stride2) { - int i; - for (i = 0; i < height; i++) + int x, y; + for (y = 0; y < height; y++) { - gconstpointer p1 = data1 + i * stride1; - gconstpointer p2 = data2 + i * stride2; - if (memcmp (p1, p2, width * 4) != 0) - return FALSE; + const guint32 *p1 = (const guint32*) (data1 + y * stride1); + const guint32 *p2 = (const guint32*) (data2 + y * stride2); + + for (x = 0; x < width; x++) + { + g_assert_cmphex (p1[x], ==, p2[x]); + } } - return TRUE; } static void @@ -55,10 +57,10 @@ test_texture_from_pixbuf (void) cairo_paint (cr); cairo_destroy (cr); - g_assert_true (compare_pixels (width, height, - data, stride, - cairo_image_surface_get_data (surface), - cairo_image_surface_get_stride (surface))); + compare_pixels (width, height, + data, stride, + cairo_image_surface_get_data (surface), + cairo_image_surface_get_stride (surface)); g_free (data);