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

Author: Thomas H.P. Andersen <pho...@gmail.com>
Date:   Wed Oct 18 23:55:36 2023 +0200

nvk: pipeline shader cache

dEQP-VK.pipeline.monolithic.cache.*

Test run totals:
  Passed:        773/773 (100.0%)
  Failed:        0/773 (0.0%)
  Not supported: 0/773 (0.0%)
  Warnings:      0/773 (0.0%)
  Waived:        0/773 (0.0%)

Timing these test:
Before:
real    0m11,304s
user    0m9,442s
sys     0m0,477s

After:
real    0m3,470s
user    0m1,962s
sys     0m0,504s

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

---

 src/nouveau/vulkan/nvk_compute_pipeline.c  | 59 +++++++++++++++-----
 src/nouveau/vulkan/nvk_graphics_pipeline.c | 88 ++++++++++++++++++++++--------
 src/nouveau/vulkan/nvk_pipeline.c          |  3 -
 src/nouveau/vulkan/nvk_shader.c            | 87 ++++++++++++++++++++++++++++-
 src/nouveau/vulkan/nvk_shader.h            | 13 ++++-
 5 files changed, 208 insertions(+), 42 deletions(-)

diff --git a/src/nouveau/vulkan/nvk_compute_pipeline.c 
b/src/nouveau/vulkan/nvk_compute_pipeline.c
index ada9cee0cea..e9567fc3773 100644
--- a/src/nouveau/vulkan/nvk_compute_pipeline.c
+++ b/src/nouveau/vulkan/nvk_compute_pipeline.c
@@ -173,32 +173,63 @@ nvk_compute_pipeline_create(struct nvk_device *dev,
    VkPipelineCreateFlags2KHR pipeline_flags =
       vk_compute_pipeline_create_flags(pCreateInfo);
 
+   if (pipeline_flags &
+       VK_PIPELINE_CREATE_CAPTURE_INTERNAL_REPRESENTATIONS_BIT_KHR)
+      cache = NULL;
+
    struct vk_pipeline_robustness_state robustness;
    vk_pipeline_robustness_state_fill(&dev->vk, &robustness,
                                      pCreateInfo->pNext,
                                      pCreateInfo->stage.pNext);
 
-   nir_shader *nir;
-   result = nvk_shader_stage_to_nir(dev, &pCreateInfo->stage, &robustness,
-                                    cache, NULL, &nir);
-   if (result != VK_SUCCESS)
-      goto fail;
-
-   struct nvk_shader *shader = nvk_shader_init(dev);
-   pipeline->base.shaders[MESA_SHADER_COMPUTE] = shader;
-
-   nvk_lower_nir(dev, nir, &robustness, false, pipeline_layout, shader);
-
    unsigned char sha1[SHA1_DIGEST_LENGTH];
    nvk_hash_shader(sha1, &pCreateInfo->stage, &robustness, false,
                    pipeline_layout, NULL);
 
-   result = nvk_compile_nir(dev, nir, pipeline_flags, &robustness, NULL,
-                            shader);
-   ralloc_free(nir);
+   bool cache_hit = false;
+   struct vk_pipeline_cache_object *cache_obj = NULL;
+
+   if (cache) {
+      cache_obj = vk_pipeline_cache_lookup_object(cache, &sha1, sizeof(sha1),
+                                                  &nvk_shader_ops, &cache_hit);
+      pipeline->base.shaders[MESA_SHADER_COMPUTE] =
+         container_of(cache_obj, struct nvk_shader, base);
+      result = VK_SUCCESS;
+   }
+
+   if (!cache_obj) {
+      nir_shader *nir;
+      result = nvk_shader_stage_to_nir(dev, &pCreateInfo->stage, &robustness,
+                                       cache, NULL, &nir);
+      if (result != VK_SUCCESS)
+         goto fail;
+
+      struct nvk_shader *shader = nvk_shader_init(dev, sha1, 
SHA1_DIGEST_LENGTH);
+      if(shader == NULL)
+         return vk_error(dev, VK_ERROR_OUT_OF_HOST_MEMORY);
+
+      nvk_lower_nir(dev, nir, &robustness, false, pipeline_layout, shader);
+
+      result = nvk_compile_nir(dev, nir, pipeline_flags, &robustness, NULL, 
cache, shader);
+
+      if (result == VK_SUCCESS) {
+         cache_obj = &shader->base;
+
+         if (cache)
+            cache_obj = vk_pipeline_cache_add_object(cache, cache_obj);
+
+         pipeline->base.shaders[MESA_SHADER_COMPUTE] =
+            container_of(cache_obj, struct nvk_shader, base);
+      }
+
+      ralloc_free(nir);
+   }
+
    if (result != VK_SUCCESS)
       goto fail;
 
+   struct nvk_shader *shader = container_of(cache_obj, struct nvk_shader, 
base);
+
    result = nvk_shader_upload(dev, shader);
    if (result != VK_SUCCESS)
       goto fail;
diff --git a/src/nouveau/vulkan/nvk_graphics_pipeline.c 
b/src/nouveau/vulkan/nvk_graphics_pipeline.c
index eee88e7a0a1..26e5dd3dcf7 100644
--- a/src/nouveau/vulkan/nvk_graphics_pipeline.c
+++ b/src/nouveau/vulkan/nvk_graphics_pipeline.c
@@ -176,6 +176,10 @@ nvk_graphics_pipeline_create(struct nvk_device *dev,
    VkPipelineCreateFlags2KHR pipeline_flags =
       vk_graphics_pipeline_create_flags(pCreateInfo);
 
+   if (pipeline_flags &
+       VK_PIPELINE_CREATE_CAPTURE_INTERNAL_REPRESENTATIONS_BIT_KHR)
+      cache = NULL;
+
    struct vk_graphics_pipeline_all_state all;
    struct vk_graphics_pipeline_state state = {};
    result = vk_graphics_pipeline_state_fill(&dev->vk, &state, pCreateInfo,
@@ -186,6 +190,12 @@ nvk_graphics_pipeline_create(struct nvk_device *dev,
    nir_shader *nir[MESA_SHADER_STAGES] = {};
    struct vk_pipeline_robustness_state robustness[MESA_SHADER_STAGES];
 
+   struct vk_pipeline_cache_object *cache_objs[MESA_SHADER_STAGES] = {};
+
+   struct nak_fs_key fs_key_tmp, *fs_key = NULL;
+   nvk_populate_fs_key(&fs_key_tmp, state.ms, &state);
+   fs_key = &fs_key_tmp;
+
    for (uint32_t i = 0; i < pCreateInfo->stageCount; i++) {
       const VkPipelineShaderStageCreateInfo *sinfo = &pCreateInfo->pStages[i];
       gl_shader_stage stage = vk_to_mesa_shader_stage(sinfo->stage);
@@ -199,6 +209,33 @@ nvk_graphics_pipeline_create(struct nvk_device *dev,
 
       vk_pipeline_robustness_state_fill(&dev->vk, &robustness[stage],
                                         pCreateInfo->pNext, sinfo->pNext);
+   }
+
+   for (gl_shader_stage stage = 0; stage < MESA_SHADER_STAGES; stage++) {
+      const VkPipelineShaderStageCreateInfo *sinfo = infos[stage];
+      if (sinfo == NULL)
+         continue;
+
+      unsigned char sha1[SHA1_DIGEST_LENGTH];
+      nvk_hash_shader(sha1, sinfo, &robustness[stage],
+                      state.rp->view_mask != 0, pipeline_layout,
+                      stage == MESA_SHADER_FRAGMENT ? fs_key : NULL);
+
+      if (cache) {
+         bool cache_hit = false;
+         cache_objs[stage] = vk_pipeline_cache_lookup_object(cache, &sha1, 
sizeof(sha1),
+                                                             &nvk_shader_ops, 
&cache_hit);
+         if (cache_objs[stage]) {
+            pipeline->base.shaders[stage] =
+               container_of(cache_objs[stage], struct nvk_shader, base);
+         }
+      }
+   }
+
+   for (gl_shader_stage stage = 0; stage < MESA_SHADER_STAGES; stage++) {
+      const VkPipelineShaderStageCreateInfo *sinfo = infos[stage];
+      if (sinfo == NULL || cache_objs[stage])
+         continue;
 
       result = nvk_shader_stage_to_nir(dev, sinfo, &robustness[stage],
                                        cache, NULL, &nir[stage]);
@@ -216,33 +253,40 @@ nvk_graphics_pipeline_create(struct nvk_device *dev,
       if (sinfo == NULL)
          continue;
 
-      pipeline->base.shaders[stage] = nvk_shader_init(dev);
+      if (!cache_objs[stage]) {
+         unsigned char sha1[SHA1_DIGEST_LENGTH];
+         nvk_hash_shader(sha1, sinfo, &robustness[stage],
+                         state.rp->view_mask != 0, pipeline_layout,
+                         stage == MESA_SHADER_FRAGMENT ? fs_key : NULL);
 
-      nvk_lower_nir(dev, nir[stage], &robustness[stage],
-                    state.rp->view_mask != 0, pipeline_layout,
-                    pipeline->base.shaders[stage]);
-   }
+         struct nvk_shader *shader = nvk_shader_init(dev, sha1, 
SHA1_DIGEST_LENGTH);
+         if(shader == NULL) {
+            result = vk_error(dev, VK_ERROR_OUT_OF_HOST_MEMORY);
+            goto fail;
+         }
 
-   for (gl_shader_stage stage = 0; stage < MESA_SHADER_STAGES; stage++) {
-      const VkPipelineShaderStageCreateInfo *sinfo = infos[stage];
-      if (sinfo == NULL)
-         continue;
+         nvk_lower_nir(dev, nir[stage], &robustness[stage],
+                       state.rp->view_mask != 0, pipeline_layout, shader);
 
-      struct nak_fs_key fs_key_tmp, *fs_key = NULL;
-      if (stage == MESA_SHADER_FRAGMENT) {
-         nvk_populate_fs_key(&fs_key_tmp, state.ms, &state);
-         fs_key = &fs_key_tmp;
-      }
+         result = nvk_compile_nir(dev, nir[stage],
+                                  pipeline_flags, &robustness[stage],
+                                  stage == MESA_SHADER_FRAGMENT ? fs_key : 
NULL,
+                                  cache, shader);
 
-      unsigned char sha1[SHA1_DIGEST_LENGTH];
-      nvk_hash_shader(sha1, sinfo, &robustness[stage],
-                      state.rp->view_mask != 0,
-                      pipeline_layout, fs_key);
+         if (result == VK_SUCCESS) {
+            cache_objs[stage] = &shader->base;
+
+            if (cache)
+               cache_objs[stage] = vk_pipeline_cache_add_object(cache,
+                                                                
cache_objs[stage]);
+
+            pipeline->base.shaders[stage] =
+               container_of(cache_objs[stage], struct nvk_shader, base);
+         }
+
+         ralloc_free(nir[stage]);
+      }
 
-      result = nvk_compile_nir(dev, nir[stage], pipeline_flags,
-                               &robustness[stage], fs_key,
-                               pipeline->base.shaders[stage]);
-      ralloc_free(nir[stage]);
       if (result != VK_SUCCESS)
          goto fail;
 
diff --git a/src/nouveau/vulkan/nvk_pipeline.c 
b/src/nouveau/vulkan/nvk_pipeline.c
index 196c8bec457..2a467448553 100644
--- a/src/nouveau/vulkan/nvk_pipeline.c
+++ b/src/nouveau/vulkan/nvk_pipeline.c
@@ -32,9 +32,6 @@ nvk_pipeline_free(struct nvk_device *dev,
                   struct nvk_pipeline *pipeline,
                   const VkAllocationCallbacks *pAllocator)
 {
-   for (uint32_t s = 0; s < ARRAY_SIZE(pipeline->shaders); s++)
-      nvk_shader_finish(dev, pipeline->shaders[s]);
-
    vk_object_free(&dev->vk, pAllocator, pipeline);
 }
 
diff --git a/src/nouveau/vulkan/nvk_shader.c b/src/nouveau/vulkan/nvk_shader.c
index fe8d3c63bda..14cca62ab17 100644
--- a/src/nouveau/vulkan/nvk_shader.c
+++ b/src/nouveau/vulkan/nvk_shader.c
@@ -439,15 +439,21 @@ nvk_compile_nir_with_nak(struct nvk_physical_device *pdev,
 }
 
 struct nvk_shader *
-nvk_shader_init(struct nvk_device *dev)
+nvk_shader_init(struct nvk_device *dev, const void *key_data, size_t key_size)
 {
    VK_MULTIALLOC(ma);
    VK_MULTIALLOC_DECL(&ma, struct nvk_shader, shader, 1);
+   VK_MULTIALLOC_DECL_SIZE(&ma, char, obj_key_data, key_size);
 
    if (!vk_multialloc_zalloc(&ma, &dev->vk.alloc,
                              VK_SYSTEM_ALLOCATION_SCOPE_DEVICE))
       return NULL;
 
+   memcpy(obj_key_data, key_data, key_size);
+
+   vk_pipeline_cache_object_init(&dev->vk, &shader->base,
+                                 &nvk_shader_ops, obj_key_data, key_size);
+
    return shader;
 }
 
@@ -456,6 +462,7 @@ nvk_compile_nir(struct nvk_device *dev, nir_shader *nir,
                 VkPipelineCreateFlagBits2KHR pipeline_flags,
                 const struct vk_pipeline_robustness_state *rs,
                 const struct nak_fs_key *fs_key,
+                struct vk_pipeline_cache *cache,
                 struct nvk_shader *shader)
 {
    struct nvk_physical_device *pdev = nvk_device_physical(dev);
@@ -532,7 +539,7 @@ nvk_shader_finish(struct nvk_device *dev, struct nvk_shader 
*shader)
    if (shader->nak) {
       nak_shader_bin_destroy(shader->nak);
    } else {
-      /* This came from codegen, just free it */
+      /* This came from codegen or deserialize, just free it */
       free((void *)shader->code_ptr);
    }
 
@@ -574,3 +581,79 @@ nvk_hash_shader(unsigned char *hash,
 
    _mesa_sha1_final(&ctx, hash);
 }
+
+static bool
+nvk_shader_serialize(struct vk_pipeline_cache_object *object,
+                     struct blob *blob);
+
+static struct vk_pipeline_cache_object *
+nvk_shader_deserialize(struct vk_pipeline_cache *cache,
+                       const void *key_data,
+                       size_t key_size,
+                       struct blob_reader *blob);
+
+void
+nvk_shader_destroy(struct vk_device *_dev,
+                   struct vk_pipeline_cache_object *object)
+{
+   struct nvk_device *dev =
+      container_of(_dev, struct nvk_device, vk);
+   struct nvk_shader *shader =
+      container_of(object, struct nvk_shader, base);
+
+   nvk_shader_finish(dev, shader);
+}
+
+const struct vk_pipeline_cache_object_ops nvk_shader_ops = {
+   .serialize = nvk_shader_serialize,
+   .deserialize = nvk_shader_deserialize,
+   .destroy = nvk_shader_destroy,
+};
+
+static bool
+nvk_shader_serialize(struct vk_pipeline_cache_object *object,
+                     struct blob *blob)
+{
+   struct nvk_shader *shader =
+      container_of(object, struct nvk_shader, base);
+
+   blob_write_bytes(blob, &shader->info, sizeof(shader->info));
+   blob_write_bytes(blob, &shader->cbuf_map, sizeof(shader->cbuf_map));
+   blob_write_uint32(blob, shader->code_size);
+   blob_write_bytes(blob, shader->code_ptr, shader->code_size);
+
+   return true;
+}
+
+static struct vk_pipeline_cache_object *
+nvk_shader_deserialize(struct vk_pipeline_cache *cache,
+                       const void *key_data,
+                       size_t key_size,
+                       struct blob_reader *blob)
+{
+   struct nvk_device *dev =
+      container_of(cache->base.device, struct nvk_device, vk);
+   struct nvk_shader *shader =
+      nvk_shader_init(dev, key_data, key_size);
+
+   if (!shader)
+      return NULL;
+
+   blob_copy_bytes(blob, &shader->info, sizeof(shader->info));
+   blob_copy_bytes(blob, &shader->cbuf_map, sizeof(shader->cbuf_map));
+
+   shader->code_size = blob_read_uint32(blob);
+   void *code_ptr = malloc(shader->code_size);
+   if (!code_ptr)
+      goto fail;
+
+   blob_copy_bytes(blob, code_ptr, shader->code_size);
+   shader->code_ptr = code_ptr;
+
+   return &shader->base;
+
+fail:
+   /* nvk_shader_destroy frees both shader and shader->xfb */
+   nvk_shader_destroy(cache->base.device, &shader->base);
+   return NULL;
+}
diff --git a/src/nouveau/vulkan/nvk_shader.h b/src/nouveau/vulkan/nvk_shader.h
index 9ccbced4d73..dae7e6fef1b 100644
--- a/src/nouveau/vulkan/nvk_shader.h
+++ b/src/nouveau/vulkan/nvk_shader.h
@@ -8,6 +8,8 @@
 #include "nvk_private.h"
 #include "nvk_device_memory.h"
 
+#include "vk_pipeline_cache.h"
+
 #include "nak.h"
 #include "nir.h"
 #include "nouveau_bo.h"
@@ -46,6 +48,8 @@ struct nvk_cbuf_map {
 };
 
 struct nvk_shader {
+   struct vk_pipeline_cache_object base;
+
    struct nak_shader_info info;
    struct nvk_cbuf_map cbuf_map;
 
@@ -122,13 +126,16 @@ nvk_compile_nir(struct nvk_device *dev, nir_shader *nir,
                 VkPipelineCreateFlagBits2KHR pipeline_flags,
                 const struct vk_pipeline_robustness_state *rstate,
                 const struct nak_fs_key *fs_key,
+                struct vk_pipeline_cache *cache,
                 struct nvk_shader *shader);
 
 VkResult
 nvk_shader_upload(struct nvk_device *dev, struct nvk_shader *shader);
 
 struct nvk_shader *
-nvk_shader_init(struct nvk_device *dev);
+nvk_shader_init(struct nvk_device *dev, const void *key_data, size_t key_size);
+
+extern const struct vk_pipeline_cache_object_ops nvk_shader_ops;
 
 void
 nvk_shader_finish(struct nvk_device *dev, struct nvk_shader *shader);
@@ -141,6 +148,10 @@ nvk_hash_shader(unsigned char *hash,
                 const struct vk_pipeline_layout *layout,
                 const struct nak_fs_key *fs_key);
 
+void
+nvk_shader_destroy(struct vk_device *dev,
+                   struct vk_pipeline_cache_object *object);
+
 /* Codegen wrappers.
  *
  * TODO: Delete these once NAK supports everything.

Reply via email to