v3dv: allow to create shader modules from NIR

This will come in handy when the driver needs to generate its own shaders,
such as for partial clears.

Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/6766>
diff --git a/src/broadcom/vulkan/v3dv_pipeline.c b/src/broadcom/vulkan/v3dv_pipeline.c
index ff74cc2..653a0e9 100644
--- a/src/broadcom/vulkan/v3dv_pipeline.c
+++ b/src/broadcom/vulkan/v3dv_pipeline.c
@@ -51,11 +51,13 @@
    assert(pCreateInfo->flags == 0);
 
    module = vk_alloc2(&device->alloc, pAllocator,
-                       sizeof(*module) + pCreateInfo->codeSize, 8,
-                       VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
+                      sizeof(*module) + pCreateInfo->codeSize, 8,
+                      VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
    if (module == NULL)
       return vk_error(NULL, VK_ERROR_OUT_OF_HOST_MEMORY);
 
+   module->nir = NULL;
+
    module->size = pCreateInfo->codeSize;
    memcpy(module->data, pCreateInfo->pCode, module->size);
 
@@ -77,6 +79,13 @@
    if (!module)
       return;
 
+   /* NIR modules (which are only created internally by the driver) are not
+    * dynamically allocated so we should never call this for them.
+    * Instead the driver is responsible for freeing the NIR code when it is
+    * no longer needed.
+    */
+   assert(module->nir == NULL);
+
    vk_free2(&device->alloc, pAllocator, module);
 }
 
@@ -329,22 +338,28 @@
    nir_shader *nir;
    const nir_shader_compiler_options *nir_options = &v3dv_nir_options;
 
-   uint32_t *spirv = (uint32_t *) stage->module->data;
-   assert(stage->module->size % 4 == 0);
+   if (!stage->module->nir) {
+      uint32_t *spirv = (uint32_t *) stage->module->data;
+      assert(stage->module->size % 4 == 0);
 
-   if (V3D_DEBUG & V3D_DEBUG_DUMP_SPIRV)
-      v3dv_print_spirv(stage->module->data, stage->module->size, stderr);
+      if (V3D_DEBUG & V3D_DEBUG_DUMP_SPIRV)
+         v3dv_print_spirv(stage->module->data, stage->module->size, stderr);
 
-   uint32_t num_spec_entries = 0;
-   struct nir_spirv_specialization *spec_entries = NULL;
+      uint32_t num_spec_entries = 0;
+      struct nir_spirv_specialization *spec_entries = NULL;
 
-   const struct spirv_to_nir_options spirv_options = default_spirv_options;
-   nir = spirv_to_nir(spirv, stage->module->size / 4,
-                      spec_entries, num_spec_entries,
-                      stage->stage, stage->entrypoint,
-                      &spirv_options, nir_options);
+      const struct spirv_to_nir_options spirv_options = default_spirv_options;
+      nir = spirv_to_nir(spirv, stage->module->size / 4,
+                         spec_entries, num_spec_entries,
+                         stage->stage, stage->entrypoint,
+                         &spirv_options, nir_options);
+      nir_validate_shader(nir, "after spirv_to_nir");
+      free(spec_entries);
+   } else {
+      nir = stage->module->nir;
+      nir_validate_shader(nir, "nir module");
+   }
    assert(nir->info.stage == stage->stage);
-   nir_validate_shader(nir, "after spirv_to_nir");
 
    if (V3D_DEBUG & (V3D_DEBUG_NIR |
                     v3d_debug_flag_for_shader_stage(stage->stage))) {
@@ -355,8 +370,6 @@
       fprintf(stderr, "\n");
    }
 
-   free(spec_entries);
-
    /* We have to lower away local variable initializers right before we
     * inline functions.  That way they get properly initialized at the top
     * of the function and not at the top of its caller.
diff --git a/src/broadcom/vulkan/v3dv_private.h b/src/broadcom/vulkan/v3dv_private.h
index 209a619..ed6a99c 100644
--- a/src/broadcom/vulkan/v3dv_private.h
+++ b/src/broadcom/vulkan/v3dv_private.h
@@ -765,6 +765,12 @@
 };
 
 struct v3dv_shader_module {
+   /* A NIR shader. We create NIR modules for shaders that are generated
+    * internally by the driver.
+    */
+   struct nir_shader *nir;
+
+   /* A SPIR-V shader */
    unsigned char sha1[20];
    uint32_t size;
    char data[0];