From 63edecd857b99afd20acc99f62343334eef715c9 Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Wed, 14 Jun 2023 10:18:47 +0200 Subject: [PATCH] vulkan: Make gsk_renderer_realize() work with NULL surface Pretty much copy what GL does and just use the default display to create GPU-related resources without the need for a display. This also adds gdk_display_create_vulkan_context() but I've kept it private because the Vulkan API is generally considered in flux, in particular with our pending attempts to redo how renderers work. --- gdk/gdkdisplay.c | 44 ++++++++++++++++++++++++++++++++++ gdk/gdkdisplayprivate.h | 3 +++ gdk/gdkvulkancontext.c | 8 +++++++ gsk/vulkan/gskvulkanrenderer.c | 23 +++++++++--------- 4 files changed, 67 insertions(+), 11 deletions(-) diff --git a/gdk/gdkdisplay.c b/gdk/gdkdisplay.c index 6f329bf8f2..c1a11672da 100644 --- a/gdk/gdkdisplay.c +++ b/gdk/gdkdisplay.c @@ -36,6 +36,7 @@ #include "gdkglcontextprivate.h" #include "gdkmonitorprivate.h" #include "gdkrectangle.h" +#include "gdkvulkancontext.h" #ifdef HAVE_EGL #include @@ -1216,6 +1217,49 @@ gdk_display_get_keymap (GdkDisplay *display) return GDK_DISPLAY_GET_CLASS (display)->get_keymap (display); } +/* + * gdk_display_create_vulkan_context: + * @self: a `GdkDisplay` + * @error: return location for an error + * + * Creates a new `GdkVulkanContext` for use with @display. + * + * The context can not be used to draw to surfaces, it can only be + * used for custom rendering or compute. + * + * If the creation of the `GdkVulkanContext` failed, @error will be set. + * + * Returns: (transfer full): the newly created `GdkVulkanContext`, or + * %NULL on error + */ +GdkVulkanContext * +gdk_display_create_vulkan_context (GdkDisplay *self, + GError **error) +{ + g_return_val_if_fail (GDK_IS_DISPLAY (self), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + if (gdk_display_get_debug_flags (self) & GDK_DEBUG_VULKAN_DISABLE) + { + g_set_error_literal (error, GDK_VULKAN_ERROR, GDK_VULKAN_ERROR_NOT_AVAILABLE, + _("Vulkan support disabled via GDK_DEBUG")); + return NULL; + } + + if (GDK_DISPLAY_GET_CLASS (self)->vk_extension_name == NULL) + { + g_set_error (error, GDK_VULKAN_ERROR, GDK_VULKAN_ERROR_UNSUPPORTED, + "The %s backend has no Vulkan support.", G_OBJECT_TYPE_NAME (self)); + return FALSE; + } + + return g_initable_new (GDK_DISPLAY_GET_CLASS (self)->vk_context_type, + NULL, + error, + "display", self, + NULL); +} + static void gdk_display_init_gl (GdkDisplay *self) { diff --git a/gdk/gdkdisplayprivate.h b/gdk/gdkdisplayprivate.h index 022b3f6f3f..8c2ae867b3 100644 --- a/gdk/gdkdisplayprivate.h +++ b/gdk/gdkdisplayprivate.h @@ -202,6 +202,9 @@ gulong _gdk_display_get_next_serial (GdkDisplay *display void _gdk_display_pause_events (GdkDisplay *display); void _gdk_display_unpause_events (GdkDisplay *display); +GdkVulkanContext * gdk_display_create_vulkan_context (GdkDisplay *self, + GError **error); + GdkGLContext * gdk_display_get_gl_context (GdkDisplay *display); gboolean gdk_display_init_egl (GdkDisplay *display, diff --git a/gdk/gdkvulkancontext.c b/gdk/gdkvulkancontext.c index ac16ec1551..a1a670a262 100644 --- a/gdk/gdkvulkancontext.c +++ b/gdk/gdkvulkancontext.c @@ -665,6 +665,7 @@ gdk_vulkan_context_real_init (GInitable *initable, GdkVulkanContext *context = GDK_VULKAN_CONTEXT (initable); GdkVulkanContextPrivate *priv = gdk_vulkan_context_get_instance_private (context); GdkDisplay *display = gdk_draw_context_get_display (GDK_DRAW_CONTEXT (context)); + GdkSurface *surface = gdk_draw_context_get_surface (GDK_DRAW_CONTEXT (context)); VkResult res; VkBool32 supported; uint32_t i; @@ -673,6 +674,13 @@ gdk_vulkan_context_real_init (GInitable *initable, if (!priv->vulkan_ref) return FALSE; + if (surface == NULL) + { + priv->image_format.format = VK_FORMAT_B8G8R8A8_UNORM; + priv->image_format.colorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR; + return TRUE; + } + res = GDK_VULKAN_CONTEXT_GET_CLASS (context)->create_surface (context, &priv->surface); if (res != VK_SUCCESS) { diff --git a/gsk/vulkan/gskvulkanrenderer.c b/gsk/vulkan/gskvulkanrenderer.c index aa94c1dab1..0a495e8679 100644 --- a/gsk/vulkan/gskvulkanrenderer.c +++ b/gsk/vulkan/gskvulkanrenderer.c @@ -12,6 +12,7 @@ #include "gskvulkanrenderprivate.h" #include "gskvulkanglyphcacheprivate.h" +#include "gdk/gdkdisplayprivate.h" #include "gdk/gdktextureprivate.h" #include "gdk/gdkprofilerprivate.h" @@ -139,20 +140,23 @@ static void gsk_vulkan_renderer_update_images_cb (GdkVulkanContext *context, GskVulkanRenderer *self) { - GdkSurface *window; + GdkSurface *surface; double scale; gsize width, height; guint i; + surface = gsk_renderer_get_surface (GSK_RENDERER (self)); + if (surface == NULL) + return; + gsk_vulkan_renderer_free_targets (self); self->n_targets = gdk_vulkan_context_get_n_images (context); self->targets = g_new (GskVulkanImage *, self->n_targets); - window = gsk_renderer_get_surface (GSK_RENDERER (self)); - scale = gdk_surface_get_scale (window); - width = (int) ceil (gdk_surface_get_width (window) * scale); - height = (int) ceil (gdk_surface_get_height (window) * scale); + scale = gdk_surface_get_scale (surface); + width = (int) ceil (gdk_surface_get_width (surface) * scale); + height = (int) ceil (gdk_surface_get_height (surface) * scale); for (i = 0; i < self->n_targets; i++) { @@ -203,13 +207,10 @@ gsk_vulkan_renderer_realize (GskRenderer *renderer, GskVulkanRenderer *self = GSK_VULKAN_RENDERER (renderer); if (surface == NULL) - { - g_set_error (error, GDK_VULKAN_ERROR, GDK_VULKAN_ERROR_UNSUPPORTED, - "The Vulkan renderer does not support surfaceless rendering yet."); - return FALSE; - } + self->vulkan = gdk_display_create_vulkan_context (gdk_display_get_default (), error); + else + self->vulkan = gdk_surface_create_vulkan_context (surface, error); - self->vulkan = gdk_surface_create_vulkan_context (surface, error); if (self->vulkan == NULL) return FALSE;