vulkan: Create multiple render objects
authorBenjamin Otte <otte@redhat.com>
Wed, 24 May 2023 14:55:18 +0000 (16:55 +0200)
committerBenjamin Otte <otte@redhat.com>
Sun, 4 Jun 2023 17:42:01 +0000 (19:42 +0200)
Sometimes the GPU is still busy when the next frame starts (like when
no-vsync benchmarking), so we need to keep all those resources alone and
create new ones.
That's what the render object is for, so we just create another one.

However, when we create too many, we'll starve the CPU. So we'll limit
it. Currently, that limit is at 4, but I've never reached it (I've also
not starved the GPU yet), so that number may want to be set lower/higher
in the future.

Note that this is different from the number of outstanding buffers, as
those are not busy on the GPU but on the compositor, and as such a
buffer may have not finished rendering but have been returend from the
compositor (very busy GPU) or have finished rendering but not been
returned from the compositor (very idle GPU).

gsk/vulkan/gskvulkanrender.c
gsk/vulkan/gskvulkanrenderer.c
gsk/vulkan/gskvulkanrenderprivate.h

index 1957e75e48d4117fc0ed487bc15deae63b1e6d1d..0e3d7dfaa4efceb3f620a3d1de064cc3d9910928 100644 (file)
@@ -350,6 +350,12 @@ gsk_vulkan_render_get_framebuffer (GskVulkanRender *self,
   return fb->framebuffer;
 }
 
+VkFence
+gsk_vulkan_render_get_fence (GskVulkanRender *self)
+{
+  return self->fence;
+}
+
 void
 gsk_vulkan_render_add_cleanup_image (GskVulkanRender *self,
                                      GskVulkanImage  *image)
index a14e6bd373f852801d4305af3fef21c7c186ce53..8c1b88c3156a37a0bfd2d3d71518f92464443cc5 100644 (file)
@@ -17,6 +17,8 @@
 
 #include <graphene.h>
 
+#define GSK_VULKAN_MAX_RENDERS 4
+
 typedef struct _GskVulkanTextureData GskVulkanTextureData;
 
 struct _GskVulkanTextureData {
@@ -51,7 +53,7 @@ struct _GskVulkanRenderer
   guint n_targets;
   GskVulkanImage **targets;
 
-  GskVulkanRender *render;
+  GskVulkanRender *renders[GSK_VULKAN_MAX_RENDERS];
 
   GSList *textures;
 
@@ -161,6 +163,38 @@ gsk_vulkan_renderer_update_images_cb (GdkVulkanContext  *context,
     }
 }
 
+static GskVulkanRender *
+gsk_vulkan_renderer_get_render (GskVulkanRenderer *self)
+{
+  VkFence fences[G_N_ELEMENTS (self->renders)];
+  VkDevice device;
+  guint i;
+
+  device = gdk_vulkan_context_get_device (self->vulkan);
+
+  while (TRUE)
+    {
+      for (i = 0; i < G_N_ELEMENTS (self->renders); i++)
+        {
+          if (self->renders[i] == NULL)
+            {
+              self->renders[i] = gsk_vulkan_render_new (GSK_RENDERER (self), self->vulkan);
+              return self->renders[i];
+            }
+
+          fences[i] = gsk_vulkan_render_get_fence (self->renders[i]);
+          if (vkGetFenceStatus (device, fences[i]) == VK_SUCCESS)
+            return self->renders[i];
+        }
+
+      GSK_VK_CHECK (vkWaitForFences, device,
+                                     G_N_ELEMENTS (fences),
+                                     fences,
+                                     VK_FALSE,
+                                     INT64_MAX);
+    }
+}
+
 static gboolean
 gsk_vulkan_renderer_realize (GskRenderer  *renderer,
                              GdkSurface   *surface,
@@ -185,8 +219,6 @@ gsk_vulkan_renderer_realize (GskRenderer  *renderer,
                     self);
   gsk_vulkan_renderer_update_images_cb (self->vulkan, self);
 
-  self->render = gsk_vulkan_render_new (renderer, self->vulkan);
-
   self->glyph_cache = gsk_vulkan_glyph_cache_new (renderer, self->vulkan);
 
   return TRUE;
@@ -197,6 +229,7 @@ gsk_vulkan_renderer_unrealize (GskRenderer *renderer)
 {
   GskVulkanRenderer *self = GSK_VULKAN_RENDERER (renderer);
   GSList *l;
+  guint i;
 
   g_clear_object (&self->glyph_cache);
 
@@ -209,7 +242,8 @@ gsk_vulkan_renderer_unrealize (GskRenderer *renderer)
     }
   g_clear_pointer (&self->textures, g_slist_free);
 
-  g_clear_pointer (&self->render, gsk_vulkan_render_free);
+  for (i = 0; i < G_N_ELEMENTS (self->renders); i++)
+    g_clear_pointer (&self->renders[i], gsk_vulkan_render_free);
 
   gsk_vulkan_renderer_free_targets (self);
   g_signal_handlers_disconnect_by_func(self->vulkan,
@@ -306,7 +340,7 @@ gsk_vulkan_renderer_render (GskRenderer          *renderer,
 #endif
 
   gdk_draw_context_begin_frame (GDK_DRAW_CONTEXT (self->vulkan), region);
-  render = self->render;
+  render = gsk_vulkan_renderer_get_render (self);
 
   render_region = get_render_region (self);
   draw_index = gdk_vulkan_context_get_draw_index (self->vulkan);
index 70771a078a27a51bb45339155c55195a0db85b92..dc7031b4054a9ddbed3ead9d747f524f689ca51d 100644 (file)
@@ -95,6 +95,7 @@ void                    gsk_vulkan_render_submit                        (GskVulk
 GdkTexture *            gsk_vulkan_render_download_target               (GskVulkanRender        *self);
 VkFramebuffer           gsk_vulkan_render_get_framebuffer               (GskVulkanRender        *self,
                                                                          GskVulkanImage         *image);
+VkFence                 gsk_vulkan_render_get_fence                     (GskVulkanRender        *self);
 
 G_END_DECLS