Module: Mesa
Branch: main
Commit: 0f022c3076ee03eff309f98aefcae125140a4825
URL:    
http://cgit.freedesktop.org/mesa/mesa/commit/?id=0f022c3076ee03eff309f98aefcae125140a4825

Author: Connor Abbott <[email protected]>
Date:   Mon Sep  4 17:54:35 2023 +0200

tu: Create singleton "empty" shaders

The most important of these is the empty FS, which should cut down on
time spent in the compiler when we fast-link a pipeline where there is
only a library with the VS and no library with the empty FS. Source
engine is known to do this.

This is also necessary for shader objects where the "empty" shaders are
never created up-front. We will use these when a NULL shader is bound.

Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/25276>

---

 src/freedreno/vulkan/tu_device.cc   | 10 ++++++
 src/freedreno/vulkan/tu_device.h    |  2 ++
 src/freedreno/vulkan/tu_pipeline.cc | 44 +++++++++++------------
 src/freedreno/vulkan/tu_shader.cc   | 70 ++++++++++++++++++++++++++++++++++++-
 src/freedreno/vulkan/tu_shader.h    |  7 ++--
 5 files changed, 106 insertions(+), 27 deletions(-)

diff --git a/src/freedreno/vulkan/tu_device.cc 
b/src/freedreno/vulkan/tu_device.cc
index c7910079abd..78849469f18 100644
--- a/src/freedreno/vulkan/tu_device.cc
+++ b/src/freedreno/vulkan/tu_device.cc
@@ -2184,6 +2184,12 @@ tu_CreateDevice(VkPhysicalDevice physicalDevice,
    device->global_bo_map = global;
    tu_init_clear_blit_shaders(device);
 
+   result = tu_init_empty_shaders(device);
+   if (result != VK_SUCCESS) {
+      vk_startup_errorf(device->instance, result, "empty shaders");
+      goto fail_empty_shaders;
+   }
+
    global->predicate = 0;
    global->vtx_stats_query_not_running = 1;
    global->dbg_one = (uint32_t)-1;
@@ -2327,6 +2333,8 @@ fail_perfcntrs_pass_alloc:
 fail_pipeline_cache:
    tu_destroy_dynamic_rendering(device);
 fail_dynamic_rendering:
+   tu_destroy_empty_shaders(device);
+fail_empty_shaders:
    tu_destroy_clear_blit_shaders(device);
 fail_global_bo_map:
    tu_bo_finish(device, device->global_bo);
@@ -2377,6 +2385,8 @@ tu_DestroyDevice(VkDevice _device, const 
VkAllocationCallbacks *pAllocator)
 
    tu_destroy_clear_blit_shaders(device);
 
+   tu_destroy_empty_shaders(device);
+
    tu_destroy_dynamic_rendering(device);
 
    ir3_compiler_destroy(device->compiler);
diff --git a/src/freedreno/vulkan/tu_device.h b/src/freedreno/vulkan/tu_device.h
index f84734a3d42..286789af6e8 100644
--- a/src/freedreno/vulkan/tu_device.h
+++ b/src/freedreno/vulkan/tu_device.h
@@ -287,6 +287,8 @@ struct tu_device
    struct ir3_shader *global_shaders[GLOBAL_SH_COUNT];
    uint64_t global_shader_va[GLOBAL_SH_COUNT];
 
+   struct tu_shader *empty_tcs, *empty_tes, *empty_gs, *empty_fs;
+
    uint32_t vsc_draw_strm_pitch;
    uint32_t vsc_prim_strm_pitch;
    BITSET_DECLARE(custom_border_color, TU_BORDER_COLOR_COUNT);
diff --git a/src/freedreno/vulkan/tu_pipeline.cc 
b/src/freedreno/vulkan/tu_pipeline.cc
index ba56cfd54c5..21c94faac02 100644
--- a/src/freedreno/vulkan/tu_pipeline.cc
+++ b/src/freedreno/vulkan/tu_pipeline.cc
@@ -1766,8 +1766,7 @@ tu_pipeline_builder_compile_shaders(struct 
tu_pipeline_builder *builder,
    const VkPipelineCreationFeedbackCreateInfo *creation_feedback =
       vk_find_struct_const(builder->create_info->pNext, 
PIPELINE_CREATION_FEEDBACK_CREATE_INFO);
 
-   bool must_compile =
-      builder->state & VK_GRAPHICS_PIPELINE_LIBRARY_FRAGMENT_SHADER_BIT_EXT;
+   bool must_compile = false;
    for (uint32_t i = 0; i < builder->create_info->stageCount; i++) {
       if (!(builder->active_stages & builder->create_info->pStages[i].stage))
          continue;
@@ -1854,9 +1853,7 @@ tu_pipeline_builder_compile_shaders(struct 
tu_pipeline_builder *builder,
       
       for (gl_shader_stage stage = MESA_SHADER_VERTEX; stage < ARRAY_SIZE(nir);
            stage = (gl_shader_stage) (stage + 1)) {
-         if (stage_infos[stage] || nir[stage] ||
-             (stage == MESA_SHADER_FRAGMENT &&
-              (builder->state & 
VK_GRAPHICS_PIPELINE_LIBRARY_FRAGMENT_SHADER_BIT_EXT))) {
+         if (stage_infos[stage] || nir[stage]) {
             bool shader_application_cache_hit;
             shader_sha1[20] = (unsigned char) stage;
             shaders[stage] =
@@ -1920,16 +1917,6 @@ tu_pipeline_builder_compile_shaders(struct 
tu_pipeline_builder *builder,
       stage_feedbacks[stage].duration += os_time_get_nano() - stage_start;
    }
 
-   if (!nir[MESA_SHADER_FRAGMENT] &&
-       (builder->state & 
VK_GRAPHICS_PIPELINE_LIBRARY_FRAGMENT_SHADER_BIT_EXT)) {
-         const nir_shader_compiler_options *nir_options =
-            ir3_get_compiler_options(builder->device->compiler);
-         nir_builder fs_b = 
nir_builder_init_simple_shader(MESA_SHADER_FRAGMENT,
-                                                           nir_options,
-                                                           "noop_fs");
-         nir[MESA_SHADER_FRAGMENT] = fs_b.shader;
-   }
-
    if (executable_info) {
       for (gl_shader_stage stage = MESA_SHADER_VERTEX;
            stage < ARRAY_SIZE(nir);
@@ -2020,14 +2007,25 @@ done:
     */
    if (builder->state &
        VK_GRAPHICS_PIPELINE_LIBRARY_PRE_RASTERIZATION_SHADERS_BIT_EXT) {
-      for (gl_shader_stage stage = MESA_SHADER_TESS_CTRL; stage <= 
MESA_SHADER_GEOMETRY;
-           stage = (gl_shader_stage) (stage + 1)) {
-         if (!shaders[stage]) {
-            result = tu_empty_shader_create(builder->device, &shaders[stage],
-                                            stage);
-            if (result != VK_SUCCESS)
-               goto fail;
-         }
+      if (!shaders[MESA_SHADER_TESS_CTRL]) {
+         shaders[MESA_SHADER_TESS_CTRL] = builder->device->empty_tcs;
+         vk_pipeline_cache_object_ref(&shaders[MESA_SHADER_TESS_CTRL]->base);
+      }
+      if (!shaders[MESA_SHADER_TESS_EVAL]) {
+         shaders[MESA_SHADER_TESS_EVAL] = builder->device->empty_tes;
+         vk_pipeline_cache_object_ref(&shaders[MESA_SHADER_TESS_EVAL]->base);
+      }
+      if (!shaders[MESA_SHADER_GEOMETRY]) {
+         shaders[MESA_SHADER_GEOMETRY] = builder->device->empty_gs;
+         vk_pipeline_cache_object_ref(&shaders[MESA_SHADER_GEOMETRY]->base);
+      }
+   }
+
+   if (builder->state &
+       VK_GRAPHICS_PIPELINE_LIBRARY_FRAGMENT_SHADER_BIT_EXT) {
+      if (!shaders[MESA_SHADER_FRAGMENT]) {
+         shaders[MESA_SHADER_FRAGMENT] = builder->device->empty_fs;
+         vk_pipeline_cache_object_ref(&shaders[MESA_SHADER_FRAGMENT]->base);
       }
    }
 
diff --git a/src/freedreno/vulkan/tu_shader.cc 
b/src/freedreno/vulkan/tu_shader.cc
index 8013858877a..b3f9b3163ac 100644
--- a/src/freedreno/vulkan/tu_shader.cc
+++ b/src/freedreno/vulkan/tu_shader.cc
@@ -2289,7 +2289,7 @@ tu_shader_create(struct tu_device *dev,
    return VK_SUCCESS;
 }
 
-VkResult
+static VkResult
 tu_empty_shader_create(struct tu_device *dev,
                        struct tu_shader **shader_out,
                        gl_shader_stage stage)
@@ -2322,6 +2322,74 @@ tu_empty_shader_create(struct tu_device *dev,
    return VK_SUCCESS;
 }
 
+static VkResult
+tu_empty_fs_create(struct tu_device *dev, struct tu_shader **shader)
+{
+   struct ir3_shader_key key = {};
+   const struct ir3_shader_options options = {};
+   struct ir3_stream_output_info so_info = {};
+   const nir_shader_compiler_options *nir_options =
+      ir3_get_compiler_options(dev->compiler);
+   nir_builder fs_b;
+
+   fs_b = nir_builder_init_simple_shader(MESA_SHADER_FRAGMENT, nir_options,
+                                         "noop_fs");
+
+   *shader = tu_shader_init(dev, NULL, 0);
+   if (!*shader)
+      return VK_ERROR_OUT_OF_HOST_MEMORY;
+
+   struct ir3_shader *ir3_shader =
+      ir3_shader_from_nir(dev->compiler, fs_b.shader, &options, &so_info);
+   (*shader)->variant = ir3_shader_create_variant(ir3_shader, &key, false);
+
+   return tu_upload_shader(dev, *shader);
+}
+
+VkResult
+tu_init_empty_shaders(struct tu_device *dev)
+{
+   VkResult result;
+
+   result = tu_empty_shader_create(dev, &dev->empty_tcs, 
MESA_SHADER_TESS_CTRL);
+   if (result != VK_SUCCESS)
+      goto out;
+
+   result = tu_empty_shader_create(dev, &dev->empty_tes, 
MESA_SHADER_TESS_EVAL);
+   if (result != VK_SUCCESS)
+      goto out;
+
+   result = tu_empty_shader_create(dev, &dev->empty_gs, MESA_SHADER_GEOMETRY);
+   if (result != VK_SUCCESS)
+      goto out;
+
+   result = tu_empty_fs_create(dev, &dev->empty_fs);
+   if (result != VK_SUCCESS)
+      goto out;
+
+   return VK_SUCCESS;
+
+out:
+   if (dev->empty_tcs)
+      vk_pipeline_cache_object_unref(&dev->vk, &dev->empty_tcs->base);
+   if (dev->empty_tes)
+      vk_pipeline_cache_object_unref(&dev->vk, &dev->empty_tes->base);
+   if (dev->empty_gs)
+      vk_pipeline_cache_object_unref(&dev->vk, &dev->empty_gs->base);
+   if (dev->empty_fs)
+      vk_pipeline_cache_object_unref(&dev->vk, &dev->empty_fs->base);
+   return result;
+}
+
+void
+tu_destroy_empty_shaders(struct tu_device *dev)
+{
+   vk_pipeline_cache_object_unref(&dev->vk, &dev->empty_tcs->base);
+   vk_pipeline_cache_object_unref(&dev->vk, &dev->empty_tes->base);
+   vk_pipeline_cache_object_unref(&dev->vk, &dev->empty_gs->base);
+   vk_pipeline_cache_object_unref(&dev->vk, &dev->empty_fs->base);
+}
+
 void
 tu_shader_destroy(struct tu_device *dev,
                   struct tu_shader *shader)
diff --git a/src/freedreno/vulkan/tu_shader.h b/src/freedreno/vulkan/tu_shader.h
index 270e1dea05e..a89ebe07d9d 100644
--- a/src/freedreno/vulkan/tu_shader.h
+++ b/src/freedreno/vulkan/tu_shader.h
@@ -122,9 +122,10 @@ tu_shader_create(struct tu_device *dev,
                  bool executable_info);
 
 VkResult
-tu_empty_shader_create(struct tu_device *device,
-                       struct tu_shader **shader_out,
-                       gl_shader_stage stage);
+tu_init_empty_shaders(struct tu_device *device);
+
+void
+tu_destroy_empty_shaders(struct tu_device *device);
 
 void
 tu_shader_destroy(struct tu_device *dev,

Reply via email to