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];