vulkan: Cache VkRenderPasses in render object
authorBenjamin Otte <otte@redhat.com>
Sat, 8 Jul 2023 18:40:48 +0000 (20:40 +0200)
committerBenjamin Otte <otte@redhat.com>
Sun, 16 Jul 2023 10:13:00 +0000 (12:13 +0200)
Instead of recreating the same renderpass object in every frame and for
every offscreen, just reuse it.

Technically, we can save this per-renderer or even per-display (it
should really be cached by VkDevice), but we have no infrastructure for
that.

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

index 81be6277796cf48871d31e2301e6f6e678442bdf..e3bdc088ce06403111cbd66499326e614e3d523a 100644 (file)
@@ -58,6 +58,7 @@ struct _GskVulkanRender
   VkDescriptorPool descriptor_pool;
   VkDescriptorSet descriptor_sets[N_DESCRIPTOR_SETS];
   GHashTable *pipeline_cache;
+  GHashTable *render_pass_cache;
 
   GskVulkanImage *target;
 
@@ -72,6 +73,7 @@ struct _GskVulkanRender
 };
 
 typedef struct _PipelineCacheKey PipelineCacheKey;
+typedef struct _RenderPassCacheKey RenderPassCacheKey;
 
 struct _PipelineCacheKey
 {
@@ -80,6 +82,13 @@ struct _PipelineCacheKey
   VkFormat format;
 };
 
+struct _RenderPassCacheKey
+{
+  VkFormat format;
+  VkImageLayout from_layout;
+  VkImageLayout to_layout;
+};
+
 static guint
 pipeline_cache_key_hash (gconstpointer data)
 {
@@ -102,6 +111,28 @@ pipeline_cache_key_equal (gconstpointer a,
          keya->format == keyb->format;
 }
 
+static guint
+render_pass_cache_key_hash (gconstpointer data)
+{
+  const RenderPassCacheKey *key = data;
+
+  return (key->from_layout << 20) ^
+         (key->to_layout << 16) ^
+         (key->format);
+}
+
+static gboolean
+render_pass_cache_key_equal (gconstpointer a,
+                             gconstpointer b)
+{
+  const RenderPassCacheKey *keya = a;
+  const RenderPassCacheKey *keyb = b;
+
+  return keya->from_layout == keyb->from_layout &&
+         keya->to_layout == keyb->to_layout &&
+         keya->format == keyb->format;
+}
+
 static void
 gsk_vulkan_render_verbose_print (GskVulkanRender *self,
                                  const char      *heading)
@@ -310,6 +341,7 @@ gsk_vulkan_render_new (GskRenderer      *renderer,
 
   self->uploader = gsk_vulkan_uploader_new (self->vulkan, self->command_pool);
   self->pipeline_cache = g_hash_table_new (pipeline_cache_key_hash, pipeline_cache_key_equal);
+  self->render_pass_cache = g_hash_table_new (render_pass_cache_key_hash, render_pass_cache_key_equal);
 
 #ifdef G_ENABLE_DEBUG
   self->render_pass_counter = g_quark_from_static_string ("render-passes");
@@ -474,6 +506,69 @@ gsk_vulkan_render_get_pipeline (GskVulkanRender        *self,
   return pipeline;
 }
 
+VkRenderPass
+gsk_vulkan_render_get_render_pass (GskVulkanRender *self,
+                                   VkFormat         format,
+                                   VkImageLayout    from_layout,
+                                   VkImageLayout    to_layout)
+{
+  RenderPassCacheKey cache_key;
+  VkRenderPass render_pass;
+
+  cache_key = (RenderPassCacheKey) {
+    .format = format,
+    .from_layout = from_layout,
+    .to_layout = to_layout,
+  };
+  render_pass = g_hash_table_lookup (self->render_pass_cache, &cache_key);
+  if (render_pass)
+    return render_pass;
+
+  GSK_VK_CHECK (vkCreateRenderPass, gdk_vulkan_context_get_device (self->vulkan),
+                                    &(VkRenderPassCreateInfo) {
+                                        .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
+                                        .attachmentCount = 1,
+                                        .pAttachments = (VkAttachmentDescription[]) {
+                                           {
+                                              .format = format,
+                                              .samples = VK_SAMPLE_COUNT_1_BIT,
+                                              .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR,
+                                              .storeOp = VK_ATTACHMENT_STORE_OP_STORE,
+                                              .initialLayout = from_layout,
+                                              .finalLayout = to_layout
+                                           }
+                                        },
+                                        .subpassCount = 1,
+                                        .pSubpasses = (VkSubpassDescription []) {
+                                           {
+                                              .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,
+                                              .inputAttachmentCount = 0,
+                                              .colorAttachmentCount = 1,
+                                              .pColorAttachments = (VkAttachmentReference []) {
+                                                 {
+                                                    .attachment = 0,
+                                                     .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
+                                                  }
+                                               },
+                                               .pResolveAttachments = (VkAttachmentReference []) {
+                                                  {
+                                                     .attachment = VK_ATTACHMENT_UNUSED,
+                                                     .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
+                                                  }
+                                               },
+                                               .pDepthStencilAttachment = NULL,
+                                            }
+                                         },
+                                         .dependencyCount = 0
+                                      },
+                                      NULL,
+                                      &render_pass);
+
+  g_hash_table_insert (self->render_pass_cache, g_memdup (&cache_key, sizeof (RenderPassCacheKey)), render_pass);
+
+  return render_pass;
+}
+
 void
 gsk_vulkan_render_bind_descriptor_sets (GskVulkanRender *self,
                                         VkCommandBuffer  command_buffer)
@@ -793,6 +888,14 @@ gsk_vulkan_render_free (GskVulkanRender *self)
     }
   g_hash_table_unref (self->pipeline_cache);
 
+  g_hash_table_iter_init (&iter, self->render_pass_cache);
+  while (g_hash_table_iter_next (&iter, &key, &value))
+    {
+      g_free (key);
+      vkDestroyRenderPass (device, value, NULL);
+    }
+  g_hash_table_unref (self->render_pass_cache);
+
   g_clear_pointer (&self->uploader, gsk_vulkan_uploader_free);
 
 
index 1946b19618edae69be6527fe8922be8e873eda33..3a496a1ad788e642ce92c20d823d8fe87b2f5179 100644 (file)
@@ -109,7 +109,6 @@ gsk_vulkan_render_pass_new (GdkVulkanContext      *context,
                             gboolean               is_root)
 {
   GskVulkanRenderPass *self;
-  VkImageLayout final_layout;
 
   self = g_new0 (GskVulkanRenderPass, 1);
   self->vulkan = g_object_ref (context);
@@ -120,49 +119,22 @@ gsk_vulkan_render_pass_new (GdkVulkanContext      *context,
   self->viewport = *viewport;
   graphene_vec2_init_from_vec2 (&self->scale, scale);
 
-  if (!is_root) // this is a dependent pass
-    final_layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
+  if (is_root)
+    {
+      /* this is a swapchain target */
+      self->render_pass = gsk_vulkan_render_get_render_pass (render,
+                                                             gsk_vulkan_image_get_vk_format (target),
+                                                             VK_IMAGE_LAYOUT_UNDEFINED,
+                                                             VK_IMAGE_LAYOUT_PRESENT_SRC_KHR);
+    }
   else
-    final_layout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
-  GSK_VK_CHECK (vkCreateRenderPass, gdk_vulkan_context_get_device (self->vulkan),
-                                    &(VkRenderPassCreateInfo) {
-                                        .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
-                                        .attachmentCount = 1,
-                                        .pAttachments = (VkAttachmentDescription[]) {
-                                           {
-                                              .format = gsk_vulkan_image_get_vk_format (target),
-                                              .samples = VK_SAMPLE_COUNT_1_BIT,
-                                              .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR,
-                                              .storeOp = VK_ATTACHMENT_STORE_OP_STORE,
-                                              .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
-                                              .finalLayout = final_layout
-                                           }
-                                        },
-                                        .subpassCount = 1,
-                                        .pSubpasses = (VkSubpassDescription []) {
-                                           {
-                                              .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,
-                                              .inputAttachmentCount = 0,
-                                              .colorAttachmentCount = 1,
-                                              .pColorAttachments = (VkAttachmentReference []) {
-                                                 {
-                                                    .attachment = 0,
-                                                     .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
-                                                  }
-                                               },
-                                               .pResolveAttachments = (VkAttachmentReference []) {
-                                                  {
-                                                     .attachment = VK_ATTACHMENT_UNUSED,
-                                                     .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
-                                                  }
-                                               },
-                                               .pDepthStencilAttachment = NULL,
-                                            }
-                                         },
-                                         .dependencyCount = 0
-                                      },
-                                      NULL,
-                                      &self->render_pass);
+    {
+      /* this is an offscreen */
+      self->render_pass = gsk_vulkan_render_get_render_pass (render,
+                                                             gsk_vulkan_image_get_vk_format (target),
+                                                             VK_IMAGE_LAYOUT_UNDEFINED,
+                                                             VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
+    }
 
 #ifdef G_ENABLE_DEBUG
   if (fallback_pixels_quark == 0)
@@ -182,7 +154,6 @@ gsk_vulkan_render_pass_new (GdkVulkanContext      *context,
 void
 gsk_vulkan_render_pass_free (GskVulkanRenderPass *self)
 {
-  VkDevice device = gdk_vulkan_context_get_device (self->vulkan);
   GskVulkanOp *op;
   gsize i;
 
@@ -197,7 +168,6 @@ gsk_vulkan_render_pass_free (GskVulkanRenderPass *self)
   g_object_unref (self->vulkan);
   g_object_unref (self->target);
   cairo_region_destroy (self->clip);
-  vkDestroyRenderPass (device, self->render_pass, NULL);
 
   g_free (self);
 }
index 413e9894dd5056860e3b73648479fe982cbed0cd..603f57b2418ea03a1cfa214f5ea9d647bf8978f5 100644 (file)
@@ -35,6 +35,10 @@ VkPipeline              gsk_vulkan_render_get_pipeline                  (GskVulk
                                                                          const char             *clip_type,
                                                                          VkFormat                format,
                                                                          VkRenderPass            render_pass);
+VkRenderPass            gsk_vulkan_render_get_render_pass               (GskVulkanRender        *self,
+                                                                         VkFormat                format,
+                                                                         VkImageLayout           from_layout,
+                                                                         VkImageLayout           to_layout);
 gsize                   gsk_vulkan_render_get_image_descriptor          (GskVulkanRender        *self,
                                                                          GskVulkanImage         *source,
                                                                          GskVulkanRenderSampler  render_sampler);