vulkan: Store shaders in the display
authorBenjamin Otte <otte@redhat.com>
Wed, 28 Jun 2023 03:43:53 +0000 (05:43 +0200)
committerBenjamin Otte <otte@redhat.com>
Sun, 16 Jul 2023 10:12:36 +0000 (12:12 +0200)
Have a resource path => vkShaderModule hash table instead of doing fancy
custom objects.

A benefit is that shader modules are now shared between all renderers
and pipelines.

gdk/gdkdisplayprivate.h
gdk/gdkvulkancontext.c
gdk/gdkvulkancontextprivate.h
gsk/meson.build
gsk/vulkan/gskvulkanpipeline.c
gsk/vulkan/gskvulkanshader.c [deleted file]
gsk/vulkan/gskvulkanshaderprivate.h [deleted file]

index 72353cf207da1c611273c30becc5b2e6ae0b1855..9e829f617f5957699f98873ebea952c08b0c0cbc 100644 (file)
@@ -104,6 +104,7 @@ struct _GdkDisplay
   gsize vk_pipeline_cache_size;
   char *vk_pipeline_cache_etag;
   guint vk_save_pipeline_cache_source;
+  GHashTable *vk_shader_modules;
 
   guint vulkan_refcount;
 #endif /* GDK_RENDERING_VULKAN */
index 4b7efecddcdb55ddcd6b084a05b919d036332070..50bf9f8c72027fc328d88262a30401c14eebfc8f 100644 (file)
@@ -1600,6 +1600,8 @@ gdk_display_create_vulkan_instance (GdkDisplay  *display,
 
   gdk_display_create_pipeline_cache (display);
 
+  display->vk_shader_modules = g_hash_table_new (g_str_hash, g_str_equal);
+
   return TRUE;
 }
 
@@ -1621,6 +1623,9 @@ gdk_display_ref_vulkan (GdkDisplay *display,
 void
 gdk_display_unref_vulkan (GdkDisplay *display)
 {
+  GHashTableIter iter;
+  gpointer key, value;
+
   g_return_if_fail (GDK_IS_DISPLAY (display));
   g_return_if_fail (display->vulkan_refcount > 0);
 
@@ -1628,6 +1633,16 @@ gdk_display_unref_vulkan (GdkDisplay *display)
   if (display->vulkan_refcount > 0)
     return;
 
+  display->vk_shader_modules = g_hash_table_new (g_str_hash, g_str_equal);
+  g_hash_table_iter_init (&iter, display->vk_shader_modules);
+  while (g_hash_table_iter_next (&iter, &key, &value))
+    {
+      g_free (key);
+      vkDestroyShaderModule (display->vk_device,
+                             value,
+                             NULL);
+    }
+
   if (display->vk_save_pipeline_cache_source)
     {
       gdk_vulkan_save_pipeline_cache_cb (display);
@@ -1654,6 +1669,47 @@ gdk_display_unref_vulkan (GdkDisplay *display)
   display->vk_instance = VK_NULL_HANDLE;
 }
 
+VkShaderModule
+gdk_display_get_vk_shader_module (GdkDisplay *self,
+                                  const char *resource_name)
+{
+  VkShaderModule shader;
+  GError *error = NULL;
+  GBytes *bytes;
+
+  shader = g_hash_table_lookup (self->vk_shader_modules, resource_name);
+  if (shader)
+    return shader;
+
+  bytes = g_resources_lookup_data (resource_name, 0, &error);
+  if (bytes == NULL)
+    {
+      GDK_DEBUG (VULKAN, "Error loading shader data: %s", error->message);
+      g_clear_error (&error);
+      return VK_NULL_HANDLE;
+    }
+
+  if (GDK_VK_CHECK (vkCreateShaderModule, self->vk_device,
+                                          &(VkShaderModuleCreateInfo) {
+                                              .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO,
+                                              .codeSize = g_bytes_get_size (bytes),
+                                              .pCode = (uint32_t *) g_bytes_get_data (bytes, NULL),
+                                          },
+                                          NULL,
+                                          &shader) == VK_SUCCESS)
+    {
+      g_hash_table_insert (self->vk_shader_modules, g_strdup (resource_name), shader);
+    }
+  else
+    {
+      shader = VK_NULL_HANDLE;
+    }
+
+  g_bytes_unref (bytes);
+
+  return shader;
+}
+
 #else /* GDK_RENDERING_VULKAN */
 
 static void
index 479dc86afc5f67918fd2f4fa800ec0ac88ad5cde..2c6a0ee4ae392317ff3d5a0b94f5eb315fe1e1a4 100644 (file)
@@ -73,6 +73,9 @@ gboolean                gdk_display_ref_vulkan                          (GdkDisp
                                                                          GError               **error);
 void                    gdk_display_unref_vulkan                        (GdkDisplay            *display);
 
+VkShaderModule          gdk_display_get_vk_shader_module                (GdkDisplay            *display,
+                                                                         const char            *resource_name);
+
 VkPipelineCache         gdk_vulkan_context_get_pipeline_cache           (GdkVulkanContext      *self);
 void                    gdk_vulkan_context_pipeline_cache_updated       (GdkVulkanContext      *self);
 
index df886cb4c9968e4978f2756947939829f800d44f..333b33f6a85cd8449f4fba7d8d2fc986b6121bba 100644 (file)
@@ -131,7 +131,6 @@ if have_vulkan
     'vulkan/gskvulkanrenderer.c',
     'vulkan/gskvulkanrenderpass.c',
     'vulkan/gskvulkanscissorop.c',
-    'vulkan/gskvulkanshader.c',
     'vulkan/gskvulkantextpipeline.c',
     'vulkan/gskvulkantexturepipeline.c',
     'vulkan/gskvulkantextureop.c',
index ca4699e6993136a1fb62874872d8ed32c73c2b69..1d4b2937f50c7496fa759acc924450b1266e0c9c 100644 (file)
@@ -3,7 +3,6 @@
 #include "gskvulkanpipelineprivate.h"
 
 #include "gskvulkanpushconstantsprivate.h"
-#include "gskvulkanshaderprivate.h"
 
 #include "gdk/gdkvulkancontextprivate.h"
 
@@ -19,9 +18,6 @@ struct _GskVulkanPipelinePrivate
 
   VkPipeline pipeline;
 
-  GskVulkanShader *vertex_shader;
-  GskVulkanShader *fragment_shader;
-
   gsize vertex_stride;
 };
 
@@ -39,9 +35,6 @@ gsk_vulkan_pipeline_finalize (GObject *gobject)
                      priv->pipeline,
                      NULL);
 
-  g_clear_pointer (&priv->fragment_shader, gsk_vulkan_shader_free);
-  g_clear_pointer (&priv->vertex_shader, gsk_vulkan_shader_free);
-
   G_OBJECT_CLASS (gsk_vulkan_pipeline_parent_class)->finalize (gobject);
 }
 
@@ -66,7 +59,9 @@ gsk_vulkan_pipeline_new (GType             pipeline_type,
   const VkPipelineVertexInputStateCreateInfo *vertex_input_state;
   GskVulkanPipelinePrivate *priv;
   GskVulkanPipeline *self;
+  GdkDisplay *display;
   VkDevice device;
+  char *vertex_shader_name, *fragment_shader_name;
 
   g_return_val_if_fail (g_type_is_a (pipeline_type, GSK_TYPE_VULKAN_PIPELINE), NULL);
   g_return_val_if_fail (layout != VK_NULL_HANDLE, NULL);
@@ -77,12 +72,13 @@ gsk_vulkan_pipeline_new (GType             pipeline_type,
 
   priv = gsk_vulkan_pipeline_get_instance_private (self);
 
+  display = gdk_draw_context_get_display (GDK_DRAW_CONTEXT (context));
   device = gdk_vulkan_context_get_device (context);
 
   priv->context = context;
 
-  priv->vertex_shader = gsk_vulkan_shader_new_from_resource (context, GSK_VULKAN_SHADER_VERTEX, shader_name, NULL);
-  priv->fragment_shader = gsk_vulkan_shader_new_from_resource (context, GSK_VULKAN_SHADER_FRAGMENT, shader_name, NULL);
+  vertex_shader_name = g_strconcat ("/org/gtk/libgsk/vulkan/", shader_name, ".vert.spv", NULL);
+  fragment_shader_name = g_strconcat ("/org/gtk/libgsk/vulkan/", shader_name, ".frag.spv", NULL);
 
   vertex_input_state = GSK_VULKAN_PIPELINE_GET_CLASS (self)->get_input_state_create_info (self);
   g_assert (vertex_input_state->vertexBindingDescriptionCount == 1);
@@ -95,8 +91,18 @@ gsk_vulkan_pipeline_new (GType             pipeline_type,
                                                .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
                                                .stageCount = 2,
                                                .pStages = (VkPipelineShaderStageCreateInfo[2]) {
-                                                   GST_VULKAN_SHADER_STAGE_CREATE_INFO (priv->vertex_shader),
-                                                   GST_VULKAN_SHADER_STAGE_CREATE_INFO (priv->fragment_shader)
+                                                   {
+                                                       .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
+                                                       .stage = VK_SHADER_STAGE_VERTEX_BIT,
+                                                       .module = gdk_display_get_vk_shader_module (display, vertex_shader_name),
+                                                       .pName = "main",
+                                                   },
+                                                   {
+                                                       .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
+                                                       .stage = VK_SHADER_STAGE_FRAGMENT_BIT,
+                                                       .module = gdk_display_get_vk_shader_module (display, fragment_shader_name),
+                                                       .pName = "main",
+                                                   },
                                                },
                                                .pVertexInputState = vertex_input_state,
                                                .pInputAssemblyState = &(VkPipelineInputAssemblyStateCreateInfo) {
@@ -162,6 +168,9 @@ gsk_vulkan_pipeline_new (GType             pipeline_type,
                                            NULL,
                                            &priv->pipeline);
 
+  g_free (fragment_shader_name);
+  g_free (vertex_shader_name);
+
   gdk_vulkan_context_pipeline_cache_updated (context);
 
   return self;
diff --git a/gsk/vulkan/gskvulkanshader.c b/gsk/vulkan/gskvulkanshader.c
deleted file mode 100644 (file)
index 1450f31..0000000
+++ /dev/null
@@ -1,102 +0,0 @@
-#include "config.h"
-
-#include "gskvulkanshaderprivate.h"
-#include "gskvulkanpipelineprivate.h"
-
-struct _GskVulkanShader
-{
-  GdkVulkanContext *vulkan;
-
-  GskVulkanShaderType type;
-  VkShaderModule vk_shader;
-};
-
-static GskVulkanShader *
-gsk_vulkan_shader_new_from_bytes (GdkVulkanContext     *context,
-                                  GskVulkanShaderType   type,
-                                  GBytes               *bytes,
-                                  GError              **error)
-{
-  GskVulkanShader *self;
-  VkShaderModule shader;
-  VkResult res;
-
-  res = GSK_VK_CHECK (vkCreateShaderModule, gdk_vulkan_context_get_device (context),
-                                            &(VkShaderModuleCreateInfo) {
-                                                .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO,
-                                                .codeSize = g_bytes_get_size (bytes),
-                                                .pCode = (uint32_t *) g_bytes_get_data (bytes, NULL),
-                                            },
-                                            NULL,
-                                            &shader);
-  if (res != VK_SUCCESS)
-    {
-      /* Someone invent better error categories plz */
-      g_set_error (error, GDK_VULKAN_ERROR, GDK_VULKAN_ERROR_UNSUPPORTED,
-                   "Could not create shader: %s", gdk_vulkan_strerror (res));
-      return NULL;
-    }
-
-  self = g_new0 (GskVulkanShader, 1);
-
-  self->vulkan = g_object_ref (context);
-  self->type = type;
-  self->vk_shader = shader;
-
-  return self;
-}
-
-GskVulkanShader *
-gsk_vulkan_shader_new_from_resource (GdkVulkanContext     *context,
-                                     GskVulkanShaderType   type,
-                                     const char           *resource_name,
-                                     GError              **error)
-{
-  GskVulkanShader *self;
-  GBytes *bytes;
-  GError *local_error = NULL;
-  char *path;
-
-  path = g_strconcat ("/org/gtk/libgsk/vulkan/",
-                      resource_name, 
-                      type == GSK_VULKAN_SHADER_VERTEX ? ".vert.spv" : ".frag.spv",
-                      NULL);
-  bytes = g_resources_lookup_data (path, 0, &local_error);
-  g_free (path);
-  if (bytes == NULL)
-    {
-      GSK_DEBUG (VULKAN, "Error loading shader data: %s", local_error->message);
-      g_propagate_error (error, local_error);
-      return NULL;
-    }
-
-  self = gsk_vulkan_shader_new_from_bytes (context, type, bytes, error);
-  g_bytes_unref (bytes);
-
-  return self;
-}
-
-void
-gsk_vulkan_shader_free (GskVulkanShader *self)
-{
-  vkDestroyShaderModule (gdk_vulkan_context_get_device (self->vulkan),
-                         self->vk_shader,
-                         NULL);
-
-  g_object_unref (self->vulkan);
-
-  g_free (self);
-}
-
-GskVulkanShaderType
-gsk_vulkan_shader_get_type (GskVulkanShader *shader)
-{
-  return shader->type;
-}
-
-VkShaderModule
-gsk_vulkan_shader_get_module (GskVulkanShader *shader)
-{
-  return shader->vk_shader;
-}
-
diff --git a/gsk/vulkan/gskvulkanshaderprivate.h b/gsk/vulkan/gskvulkanshaderprivate.h
deleted file mode 100644 (file)
index 3f35b6b..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-#pragma once
-
-#include <gdk/gdk.h>
-
-G_BEGIN_DECLS
-
-typedef enum {
-  GSK_VULKAN_SHADER_VERTEX,
-  GSK_VULKAN_SHADER_FRAGMENT
-} GskVulkanShaderType;
-
-typedef struct _GskVulkanShader GskVulkanShader;
-
-#define GST_VULKAN_SHADER_STAGE_CREATE_INFO(shader) \
-  (VkPipelineShaderStageCreateInfo) { \
-  .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, \
-  .stage = gsk_vulkan_shader_get_type (shader) == GSK_VULKAN_SHADER_VERTEX ? VK_SHADER_STAGE_VERTEX_BIT : VK_SHADER_STAGE_FRAGMENT_BIT, \
-  .module = gsk_vulkan_shader_get_module (shader), \
-  .pName = "main", \
-}
-
-GskVulkanShader *       gsk_vulkan_shader_new_from_resource             (GdkVulkanContext       *context,
-                                                                         GskVulkanShaderType     type,
-                                                                         const char             *resource_name,
-                                                                         GError                **error);
-void                    gsk_vulkan_shader_free                          (GskVulkanShader        *shader);
-
-GskVulkanShaderType     gsk_vulkan_shader_get_type                      (GskVulkanShader        *shader);
-VkShaderModule          gsk_vulkan_shader_get_module                    (GskVulkanShader        *shader);
-
-G_END_DECLS
-