gsk: Allow gsk_renderer_realize (renderer, NULL, NULL)
authorBenjamin Otte <otte@redhat.com>
Wed, 20 Oct 2021 18:30:08 +0000 (20:30 +0200)
committerBenjamin Otte <otte@redhat.com>
Wed, 20 Oct 2021 19:49:32 +0000 (21:49 +0200)
That way, we can use renderers without surfaces.

gsk/gl/gskglrenderer.c
gsk/gskcairorenderer.c
gsk/gskrenderer.c
gsk/vulkan/gskvulkanrenderer.c

index 0b1e9eddda7094035efe4b746c32cfd6695541e8..b222e2b07a4a894d5de08dc08990754fcae0a68f 100644 (file)
@@ -90,12 +90,10 @@ gsk_gl_renderer_realize (GskRenderer  *renderer,
   GskGLRenderer *self = (GskGLRenderer *)renderer;
   GdkGLContext *context = NULL;
   GskGLDriver *driver = NULL;
+  GdkDisplay *display;
   gboolean ret = FALSE;
   gboolean debug_shaders = FALSE;
 
-  g_assert (GSK_IS_GL_RENDERER (self));
-  g_assert (GDK_IS_SURFACE (surface));
-
   if (self->context != NULL)
     return TRUE;
 
@@ -103,8 +101,18 @@ gsk_gl_renderer_realize (GskRenderer  *renderer,
   g_assert (self->context == NULL);
   g_assert (self->command_queue == NULL);
 
-  if (!(context = gdk_surface_create_gl_context (surface, error)) ||
-      !gdk_gl_context_realize (context, error))
+  if (surface == NULL)
+    {
+      display = gdk_display_get_default (); /* FIXME: allow different displays somehow ? */
+      context = gdk_display_create_gl_context (display, error);
+    }
+  else
+    {
+      display = gdk_surface_get_display (surface);
+      context = gdk_surface_create_gl_context (surface, error);
+    }
+
+  if (!context || !gdk_gl_context_realize (context, error))
     goto failure;
 
 #ifdef G_ENABLE_DEBUG
@@ -112,7 +120,7 @@ gsk_gl_renderer_realize (GskRenderer  *renderer,
     debug_shaders = TRUE;
 #endif
 
-  if (!(driver = gsk_gl_driver_for_display (gdk_surface_get_display (surface), debug_shaders, error)))
+  if (!(driver = gsk_gl_driver_for_display (display, debug_shaders, error)))
     goto failure;
 
   self->command_queue = gsk_gl_driver_create_command_queue (driver, context);
index 074b54b97f8bf9e47655669d91b618c35d61c02b..3135acfdb12794883a75f297c1a575be4ff5c698 100644 (file)
@@ -59,7 +59,8 @@ gsk_cairo_renderer_realize (GskRenderer  *renderer,
 {
   GskCairoRenderer *self = GSK_CAIRO_RENDERER (renderer);
 
-  self->cairo_context = gdk_surface_create_cairo_context (surface);
+  if (surface)
+    self->cairo_context = gdk_surface_create_cairo_context (surface);
 
   return TRUE;
 }
index 7c35b051f92b1653b03a2eb75c9ce81cc58cd509..ff4ff976ce8e5b1e3c80d497ab398067bf9d8748 100644 (file)
@@ -103,7 +103,7 @@ static GParamSpec *gsk_renderer_properties[N_PROPS];
 
 static gboolean
 gsk_renderer_real_realize (GskRenderer  *self,
-                           GdkSurface    *surface,
+                           GdkSurface   *surface,
                            GError      **error)
 {
   GSK_RENDERER_WARN_NOT_IMPLEMENTED_METHOD (self, realize);
@@ -189,12 +189,12 @@ gsk_renderer_class_init (GskRendererClass *klass)
   /**
    * GskRenderer:realized: (attributes org.gtk.Property.get=gsk_renderer_is_realized)
    *
-   * Whether the renderer has been associated with a surface.
+   * Whether the renderer has been associated with a surface or draw context.
    */
   gsk_renderer_properties[PROP_REALIZED] =
     g_param_spec_boolean ("realized",
                           "Realized",
-                          "The renderer has been associated with a surface",
+                          "The renderer has been associated with a surface or draw context",
                           FALSE,
                           G_PARAM_READABLE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
 
@@ -281,11 +281,14 @@ gsk_renderer_is_realized (GskRenderer *renderer)
 /**
  * gsk_renderer_realize:
  * @renderer: a `GskRenderer`
- * @surface: the `GdkSurface` renderer will be used on
+ * @surface: (nullable): the `GdkSurface` renderer will be used on
  * @error: return location for an error
  *
  * Creates the resources needed by the @renderer to render the scene
  * graph.
+ *
+ * Since GTK 4.6, the surface may be `NULL`, which allows using
+ * renderers without having to create a surface.
  */
 gboolean
 gsk_renderer_realize (GskRenderer  *renderer,
@@ -296,10 +299,11 @@ gsk_renderer_realize (GskRenderer  *renderer,
 
   g_return_val_if_fail (GSK_IS_RENDERER (renderer), FALSE);
   g_return_val_if_fail (!gsk_renderer_is_realized (renderer), FALSE);
-  g_return_val_if_fail (GDK_IS_SURFACE (surface), FALSE);
+  g_return_val_if_fail (surface == NULL || GDK_IS_SURFACE (surface), FALSE);
   g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
 
-  priv->surface = g_object_ref (surface);
+  if (surface)
+    priv->surface = g_object_ref (surface);
 
   if (!GSK_RENDERER_GET_CLASS (renderer)->realize (renderer, surface, error))
     {
@@ -399,13 +403,15 @@ gsk_renderer_render_texture (GskRenderer           *renderer,
 
 /**
  * gsk_renderer_render:
- * @renderer: a `GskRenderer`
+ * @renderer: a realized `GskRenderer`
  * @root: a `GskRenderNode`
  * @region: (nullable): the `cairo_region_t` that must be redrawn or %NULL
  *   for the whole window
  *
- * Renders the scene graph, described by a tree of `GskRenderNode` instances,
- * ensuring that the given @region gets redrawn.
+ * Renders the scene graph, described by a tree of `GskRenderNode` instances
+ * to the renderer's surface,  ensuring that the given @region gets redrawn.
+ *
+ * If the renderer has no associated surface, this function does nothing.
  *
  * Renderers must ensure that changes of the contents given by the @root
  * node as well as the area given by @region are redrawn. They are however
@@ -428,6 +434,9 @@ gsk_renderer_render (GskRenderer          *renderer,
   g_return_if_fail (GSK_IS_RENDER_NODE (root));
   g_return_if_fail (priv->root_node == NULL);
 
+  if (priv->surface == NULL)
+    return;
+
   if (region == NULL || priv->prev_node == NULL || GSK_RENDERER_DEBUG_CHECK (renderer, FULL_REDRAW))
     {
       clip = cairo_region_create_rectangle (&(GdkRectangle) {
index c91b14a384a01ce391748c0dcd5a0e95752145c7..86f79848052b702fd3731e6e2abd7996632b149f 100644 (file)
@@ -114,12 +114,19 @@ gsk_vulkan_renderer_update_images_cb (GdkVulkanContext  *context,
 
 static gboolean
 gsk_vulkan_renderer_realize (GskRenderer  *renderer,
-                             GdkSurface    *window,
+                             GdkSurface   *surface,
                              GError      **error)
 {
   GskVulkanRenderer *self = GSK_VULKAN_RENDERER (renderer);
 
-  self->vulkan = gdk_surface_create_vulkan_context (window, error);
+  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_surface_create_vulkan_context (surface, error);
   if (self->vulkan == NULL)
     return FALSE;