From cdc85232b22758b99b2574838bdfda473b978f27 Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Wed, 6 Oct 2021 03:33:24 +0200 Subject: [PATCH] egl: Implement HDR support If EGL supports: * no-config contexts * >8bits pixel formats * (optionally) floating point pixel formats Then select such a profile as the HDR format and use it when HDR is requested. --- gdk/gdkdisplay.c | 48 +++++++++++++++++++++++++++++++++-------- gdk/gdkdisplayprivate.h | 2 ++ gdk/gdkglcontext.c | 9 +++++++- gdk/gdksurface.c | 29 +++++++++++++++++++------ gdk/gdksurfaceprivate.h | 2 ++ 5 files changed, 74 insertions(+), 16 deletions(-) diff --git a/gdk/gdkdisplay.c b/gdk/gdkdisplay.c index cedd0856bc..25f940c47b 100644 --- a/gdk/gdkdisplay.c +++ b/gdk/gdkdisplay.c @@ -93,6 +93,7 @@ struct _GdkDisplayPrivate { #ifdef HAVE_EGL EGLDisplay egl_display; EGLConfig egl_config; + EGLConfig egl_config_hdr; #endif guint rgba : 1; @@ -1437,6 +1438,14 @@ gdk_display_get_egl_config (GdkDisplay *self) return priv->egl_config; } +gpointer +gdk_display_get_egl_config_hdr (GdkDisplay *self) +{ + GdkDisplayPrivate *priv = gdk_display_get_instance_private (self); + + return priv->egl_config; +} + static EGLDisplay gdk_display_create_egl_display (EGLenum platform, gpointer native_display) @@ -1477,7 +1486,8 @@ out: #define MAX_EGL_ATTRS 30 typedef enum { - GDK_EGL_CONFIG_PERFECT = (1 << 0) + GDK_EGL_CONFIG_PERFECT = (1 << 0), + GDK_EGL_CONFIG_HDR = (1 << 1), } GdkEGLConfigCreateFlags; static EGLConfig @@ -1502,14 +1512,21 @@ gdk_display_create_egl_config (GdkDisplay *self, attrs[i++] = EGL_RGB_BUFFER; attrs[i++] = EGL_RED_SIZE; - attrs[i++] = 8; + attrs[i++] = (flags & GDK_EGL_CONFIG_HDR) ? 9 : 8; attrs[i++] = EGL_GREEN_SIZE; - attrs[i++] = 8; + attrs[i++] = (flags & GDK_EGL_CONFIG_HDR) ? 9 : 8; attrs[i++] = EGL_BLUE_SIZE; - attrs[i++] = 8; + attrs[i++] = (flags & GDK_EGL_CONFIG_HDR) ? 9 : 8; attrs[i++] = EGL_ALPHA_SIZE; attrs[i++] = 8; + if (flags & GDK_EGL_CONFIG_HDR && + self->have_egl_pixel_format_float) + { + attrs[i++] = EGL_COLOR_COMPONENT_TYPE_EXT; + attrs[i++] = EGL_DONT_CARE; + } + attrs[i++] = EGL_NONE; g_assert (i < MAX_EGL_ATTRS); @@ -1700,23 +1717,36 @@ gdk_display_init_egl (GdkDisplay *self, epoxy_has_egl_extension (priv->egl_display, "EGL_EXT_swap_buffers_with_damage"); self->have_egl_no_config_context = epoxy_has_egl_extension (priv->egl_display, "EGL_KHR_no_config_context"); + self->have_egl_pixel_format_float = + 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, + GDK_EGL_CONFIG_HDR, + error); + if (priv->egl_config_hdr == NULL) + priv->egl_config_hdr = priv->egl_config; GDK_DISPLAY_NOTE (self, OPENGL, { char *ext = describe_extensions (priv->egl_display); - char *cfg = describe_egl_config (priv->egl_display, priv->egl_config); + 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); g_message ("EGL API version %d.%d found\n" " - Vendor: %s\n" " - Version: %s\n" " - Client APIs: %s\n" " - Extensions:\n" - "\t%s" - " - Selected fbconfig: %s", + "\t%s\n" + " - Selected fbconfig: %s\n" + " HDR fbconfig: %s", major, minor, eglQueryString (priv->egl_display, EGL_VENDOR), eglQueryString (priv->egl_display, EGL_VERSION), eglQueryString (priv->egl_display, EGL_CLIENT_APIS), - ext, cfg); - g_free (cfg); + ext, sdr_cfg, + priv->egl_config_hdr == priv->egl_config ? "none" : hdr_cfg); + g_free (hdr_cfg); + g_free (sdr_cfg); g_free (ext); }); diff --git a/gdk/gdkdisplayprivate.h b/gdk/gdkdisplayprivate.h index 3b7a18f4b3..4cb85b2ea4 100644 --- a/gdk/gdkdisplayprivate.h +++ b/gdk/gdkdisplayprivate.h @@ -109,6 +109,7 @@ struct _GdkDisplay guint have_egl_buffer_age : 1; guint have_egl_swap_buffers_with_damage : 1; guint have_egl_no_config_context : 1; + guint have_egl_pixel_format_float : 1; }; struct _GdkDisplayClass @@ -225,6 +226,7 @@ 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); void gdk_display_set_rgba (GdkDisplay *display, gboolean rgba); diff --git a/gdk/gdkglcontext.c b/gdk/gdkglcontext.c index 73b82e8d41..11c3f77dd4 100644 --- a/gdk/gdkglcontext.c +++ b/gdk/gdkglcontext.c @@ -633,10 +633,18 @@ gdk_gl_context_real_begin_frame (GdkDrawContext *draw_context, cairo_region_t *region) { GdkGLContext *context = GDK_GL_CONTEXT (draw_context); + G_GNUC_UNUSED GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (context); GdkSurface *surface; cairo_region_t *damage; int ww, wh; + surface = gdk_draw_context_get_surface (draw_context); + +#ifdef HAVE_EGL + if (priv->egl_context) + gdk_surface_ensure_egl_surface (surface, request_hdr); +#endif + damage = GDK_GL_CONTEXT_GET_CLASS (context)->get_damage (context); if (context->old_updated_area[1]) @@ -647,7 +655,6 @@ gdk_gl_context_real_begin_frame (GdkDrawContext *draw_context, cairo_region_union (region, damage); cairo_region_destroy (damage); - surface = gdk_draw_context_get_surface (draw_context); ww = gdk_surface_get_width (surface) * gdk_surface_get_scale_factor (surface); wh = gdk_surface_get_height (surface) * gdk_surface_get_scale_factor (surface); diff --git a/gdk/gdksurface.c b/gdk/gdksurface.c index c64c2a6a47..13d779a817 100644 --- a/gdk/gdksurface.c +++ b/gdk/gdksurface.c @@ -71,6 +71,7 @@ struct _GdkSurfacePrivate gpointer egl_native_window; #ifdef HAVE_EGL EGLSurface egl_surface; + gboolean egl_surface_hdr; #endif gpointer widget; @@ -1103,19 +1104,35 @@ gdk_surface_get_egl_surface (GdkSurface *self) { GdkSurfacePrivate *priv = gdk_surface_get_instance_private (self); - g_return_val_if_fail (priv->egl_native_window != NULL, NULL); + return priv->egl_surface; +} + +void +gdk_surface_ensure_egl_surface (GdkSurface *self, + gboolean hdr) +{ + 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 && + priv->egl_surface != NULL && + gdk_display_get_egl_config_hdr (display) != gdk_display_get_egl_config (display)) + { + eglDestroySurface (gdk_surface_get_display (self), priv->egl_surface); + priv->egl_surface = NULL; + } if (priv->egl_surface == NULL) { - GdkDisplay *display = gdk_surface_get_display (self); - priv->egl_surface = eglCreateWindowSurface (gdk_display_get_egl_display (display), - gdk_display_get_egl_config (display), + hdr ? gdk_display_get_egl_config_hdr (display) + : gdk_display_get_egl_config (display), (EGLNativeWindowType) priv->egl_native_window, NULL); + priv->egl_surface_hdr = hdr; } - - return priv->egl_surface; #endif } diff --git a/gdk/gdksurfaceprivate.h b/gdk/gdksurfaceprivate.h index ec9f177e5e..c53368574d 100644 --- a/gdk/gdksurfaceprivate.h +++ b/gdk/gdksurfaceprivate.h @@ -294,6 +294,8 @@ void gdk_surface_get_geometry (GdkSurface *surface, void gdk_surface_set_egl_native_window (GdkSurface *self, gpointer native_window); +void gdk_surface_ensure_egl_surface (GdkSurface *self, + gboolean hdr); gpointer /*EGLSurface*/ gdk_surface_get_egl_surface (GdkSurface *self); void gdk_surface_set_widget (GdkSurface *self,