vulkan: Make gsk_renderer_realize() work with NULL surface
authorBenjamin Otte <otte@redhat.com>
Wed, 14 Jun 2023 08:18:47 +0000 (10:18 +0200)
committerBenjamin Otte <otte@redhat.com>
Mon, 19 Jun 2023 12:13:03 +0000 (14:13 +0200)
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
gdk/gdkdisplayprivate.h
gdk/gdkvulkancontext.c
gsk/vulkan/gskvulkanrenderer.c

index 6f329bf8f2706de811e9e18ecf6221208328cccb..c1a11672da86c91684f2189fa928b9c170aedc26 100644 (file)
@@ -36,6 +36,7 @@
 #include "gdkglcontextprivate.h"
 #include "gdkmonitorprivate.h"
 #include "gdkrectangle.h"
+#include "gdkvulkancontext.h"
 
 #ifdef HAVE_EGL
 #include <epoxy/egl.h>
@@ -1216,6 +1217,49 @@ gdk_display_get_keymap (GdkDisplay *display)
   return GDK_DISPLAY_GET_CLASS (display)->get_keymap (display);
 }
 
+/*<private>
+ * 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)
 {
index 022b3f6f3f97d957e295e1ed0d067a953b13ee79..8c2ae867b36823cd0e6fcff0855846f06a428bdc 100644 (file)
@@ -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,
index ac16ec1551fec81f914aa07fd14cd9a1b54b8290..a1a670a26261ea21530c350fdebbcc064419435a 100644 (file)
@@ -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)
     {
index aa94c1dab1aa53ba0040c681cd03ab56c5e2c082..0a495e8679cbcac951baa040f879fe5ad10de03f 100644 (file)
@@ -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;