diff --git a/src/amd/vulkan/radv_shader.c b/src/amd/vulkan/radv_shader.c index 513ec560a5e..c9f402870d8 100644 --- a/src/amd/vulkan/radv_shader.c +++ b/src/amd/vulkan/radv_shader.c @@ -461,55 +461,8 @@ radv_shader_compile_to_nir(struct radv_device *device, struct vk_shader_module * radv_print_spirv(module->data, module->size, stderr); uint32_t num_spec_entries = 0; - struct nir_spirv_specialization *spec_entries = NULL; - if (spec_info && spec_info->mapEntryCount > 0) { - num_spec_entries = spec_info->mapEntryCount; - spec_entries = calloc(num_spec_entries, sizeof(*spec_entries)); - for (uint32_t i = 0; i < num_spec_entries; i++) { - VkSpecializationMapEntry entry = spec_info->pMapEntries[i]; - const void *data = (uint8_t *)spec_info->pData + entry.offset; - assert((uint8_t *)data + entry.size <= - (uint8_t *)spec_info->pData + spec_info->dataSize); - - spec_entries[i].id = spec_info->pMapEntries[i].constantID; - switch (entry.size) { - case 8: - memcpy(&spec_entries[i].value.u64, data, sizeof(uint64_t)); - break; - case 4: - memcpy(&spec_entries[i].value.u32, data, sizeof(uint32_t)); - break; - case 2: - memcpy(&spec_entries[i].value.u16, data, sizeof(uint16_t)); - break; - case 1: - memcpy(&spec_entries[i].value.u8, data, sizeof(uint8_t)); - break; - case 0: - /* The Vulkan spec says: - * - * "For a constantID specialization constant declared in a shader, size must match - * the byte size of the constantID. If the specialization constant is of type - * boolean, size must be the byte size of VkBool32." - * - * Therefore, since only scalars can be decorated as specialization constants, we can - * assume that if it doesn't have a size of 1, 2, 4, or 8, any use in a shader would - * be invalid usage. The spec further says: - * - * "If a constantID value is not a specialization constant ID used in the shader, - * that map entry does not affect the behavior of the pipeline." - * - * so we should ignore any invalid specialization constants rather than crash or - * error out when we see one. - */ - break; - default: - assert(!"Invalid spec constant size"); - break; - } - } - } - + struct nir_spirv_specialization *spec_entries = + vk_spec_info_to_nir_spirv(spec_info, &num_spec_entries); struct radv_shader_debug_data spirv_debug_data = { .device = device, .module = module, diff --git a/src/broadcom/vulkan/v3dv_pipeline.c b/src/broadcom/vulkan/v3dv_pipeline.c index d4e673163bd..4447e4d0d84 100644 --- a/src/broadcom/vulkan/v3dv_pipeline.c +++ b/src/broadcom/vulkan/v3dv_pipeline.c @@ -426,48 +426,6 @@ preprocess_nir(nir_shader *nir) nir_optimize(nir, false); } -/* FIXME: This is basically the same code at anv, tu and radv. Move to common - * place? - */ -static struct nir_spirv_specialization* -vk_spec_info_to_nir_spirv(const VkSpecializationInfo *spec_info, - uint32_t *out_num_spec_entries) -{ - if (spec_info == NULL || spec_info->mapEntryCount == 0) - return NULL; - - uint32_t num_spec_entries = spec_info->mapEntryCount; - struct nir_spirv_specialization *spec_entries = calloc(num_spec_entries, sizeof(*spec_entries)); - - for (uint32_t i = 0; i < num_spec_entries; i++) { - VkSpecializationMapEntry entry = spec_info->pMapEntries[i]; - const void *data = spec_info->pData + entry.offset; - assert(data + entry.size <= spec_info->pData + spec_info->dataSize); - - spec_entries[i].id = spec_info->pMapEntries[i].constantID; - switch (entry.size) { - case 8: - spec_entries[i].value.u64 = *(const uint64_t *)data; - break; - case 4: - spec_entries[i].value.u32 = *(const uint32_t *)data; - break; - case 2: - spec_entries[i].value.u16 = *(const uint16_t *)data; - break; - case 1: - spec_entries[i].value.u8 = *(const uint8_t *)data; - break; - default: - assert(!"Invalid spec constant size"); - break; - } - } - - *out_num_spec_entries = num_spec_entries; - return spec_entries; -} - static nir_shader * shader_module_compile_to_nir(struct v3dv_device *device, struct v3dv_pipeline_stage *stage) diff --git a/src/freedreno/vulkan/tu_shader.c b/src/freedreno/vulkan/tu_shader.c index 1530d07c296..578bcdb041c 100644 --- a/src/freedreno/vulkan/tu_shader.c +++ b/src/freedreno/vulkan/tu_shader.c @@ -95,40 +95,9 @@ tu_spirv_to_nir(struct tu_device *dev, /* convert VkSpecializationInfo */ const VkSpecializationInfo *spec_info = stage_info->pSpecializationInfo; - struct nir_spirv_specialization *spec = NULL; uint32_t num_spec = 0; - if (spec_info && spec_info->mapEntryCount) { - spec = calloc(spec_info->mapEntryCount, sizeof(*spec)); - if (!spec) - return NULL; - - for (uint32_t i = 0; i < spec_info->mapEntryCount; i++) { - const VkSpecializationMapEntry *entry = &spec_info->pMapEntries[i]; - const void *data = spec_info->pData + entry->offset; - assert(data + entry->size <= spec_info->pData + spec_info->dataSize); - spec[i].id = entry->constantID; - switch (entry->size) { - case 8: - spec[i].value.u64 = *(const uint64_t *)data; - break; - case 4: - spec[i].value.u32 = *(const uint32_t *)data; - break; - case 2: - spec[i].value.u16 = *(const uint16_t *)data; - break; - case 1: - spec[i].value.u8 = *(const uint8_t *)data; - break; - default: - assert(!"Invalid spec constant size"); - break; - } - spec[i].defined_on_module = false; - } - - num_spec = spec_info->mapEntryCount; - } + struct nir_spirv_specialization *spec = + vk_spec_info_to_nir_spirv(spec_info, &num_spec); struct vk_shader_module *module = vk_shader_module_from_handle(stage_info->module); diff --git a/src/gallium/frontends/lavapipe/lvp_pipeline.c b/src/gallium/frontends/lavapipe/lvp_pipeline.c index 899587baec1..8be8701d9df 100644 --- a/src/gallium/frontends/lavapipe/lvp_pipeline.c +++ b/src/gallium/frontends/lavapipe/lvp_pipeline.c @@ -441,37 +441,9 @@ lvp_shader_compile_to_ir(struct lvp_pipeline *pipeline, assert(module->size % 4 == 0); uint32_t num_spec_entries = 0; - struct nir_spirv_specialization *spec_entries = NULL; - if (spec_info && spec_info->mapEntryCount > 0) { - num_spec_entries = spec_info->mapEntryCount; - spec_entries = calloc(num_spec_entries, sizeof(*spec_entries)); - for (uint32_t i = 0; i < num_spec_entries; i++) { - VkSpecializationMapEntry entry = spec_info->pMapEntries[i]; - const void *data = - (char *)spec_info->pData + entry.offset; - assert((const char *)((char *)data + entry.size) <= - (char *)spec_info->pData + spec_info->dataSize); + struct nir_spirv_specialization *spec_entries = + vk_spec_info_to_nir_spirv(spec_info, &num_spec_entries); - spec_entries[i].id = entry.constantID; - switch (entry.size) { - case 8: - spec_entries[i].value.u64 = *(const uint64_t *)data; - break; - case 4: - spec_entries[i].value.u32 = *(const uint32_t *)data; - break; - case 2: - spec_entries[i].value.u16 = *(const uint16_t *)data; - break; - case 1: - spec_entries[i].value.u8 = *(const uint8_t *)data; - break; - default: - assert(!"Invalid spec constant size"); - break; - } - } - } struct lvp_device *pdevice = pipeline->device; const struct spirv_to_nir_options spirv_options = { .environment = NIR_SPIRV_VULKAN, diff --git a/src/intel/vulkan/anv_pipeline.c b/src/intel/vulkan/anv_pipeline.c index a3349a591b5..845976f4170 100644 --- a/src/intel/vulkan/anv_pipeline.c +++ b/src/intel/vulkan/anv_pipeline.c @@ -94,54 +94,8 @@ anv_shader_compile_to_nir(struct anv_device *device, assert(module->size % 4 == 0); uint32_t num_spec_entries = 0; - struct nir_spirv_specialization *spec_entries = NULL; - if (spec_info && spec_info->mapEntryCount > 0) { - num_spec_entries = spec_info->mapEntryCount; - spec_entries = calloc(num_spec_entries, sizeof(*spec_entries)); - for (uint32_t i = 0; i < num_spec_entries; i++) { - VkSpecializationMapEntry entry = spec_info->pMapEntries[i]; - const void *data = spec_info->pData + entry.offset; - assert(data + entry.size <= spec_info->pData + spec_info->dataSize); - - spec_entries[i].id = spec_info->pMapEntries[i].constantID; - switch (entry.size) { - case 8: - spec_entries[i].value.u64 = *(const uint64_t *)data; - break; - case 4: - spec_entries[i].value.u32 = *(const uint32_t *)data; - break; - case 2: - spec_entries[i].value.u16 = *(const uint16_t *)data; - break; - case 1: - spec_entries[i].value.u8 = *(const uint8_t *)data; - break; - case 0: - default: - /* The Vulkan spec says: - * - * "For a constantID specialization constant declared in a - * shader, size must match the byte size of the constantID. If - * the specialization constant is of type boolean, size must be - * the byte size of VkBool32." - * - * Therefore, since only scalars can be decorated as - * specialization constants, we can assume that if it doesn't have - * a size of 1, 2, 4, or 8, any use in a shader would be invalid - * usage. The spec further says: - * - * "If a constantID value is not a specialization constant ID - * used in the shader, that map entry does not affect the - * behavior of the pipeline." - * - * so we should ignore any invalid specialization constants rather - * than crash or error out when we see one. - */ - break; - } - } - } + struct nir_spirv_specialization *spec_entries = + vk_spec_info_to_nir_spirv(spec_info, &num_spec_entries); struct anv_spirv_debug_data spirv_debug_data = { .device = device, diff --git a/src/panfrost/vulkan/panvk_shader.c b/src/panfrost/vulkan/panvk_shader.c index 756ad24e011..a34e7f50da8 100644 --- a/src/panfrost/vulkan/panvk_shader.c +++ b/src/panfrost/vulkan/panvk_shader.c @@ -34,6 +34,8 @@ #include "panfrost-quirks.h" #include "pan_shader.h" +#include "vk_util.h" + static nir_shader * panvk_spirv_to_nir(const void *code, size_t codesize, @@ -50,41 +52,9 @@ panvk_spirv_to_nir(const void *code, }; /* convert VkSpecializationInfo */ - struct nir_spirv_specialization *spec = NULL; uint32_t num_spec = 0; - if (spec_info && spec_info->mapEntryCount) { - spec = malloc(sizeof(*spec) * spec_info->mapEntryCount); - if (!spec) - return NULL; - - for (uint32_t i = 0; i < spec_info->mapEntryCount; i++) { - const VkSpecializationMapEntry *entry = &spec_info->pMapEntries[i]; - const void *data = spec_info->pData + entry->offset; - assert(data + entry->size <= spec_info->pData + spec_info->dataSize); - spec[i].id = entry->constantID; - switch (entry->size) { - case 8: - spec[i].value.u64 = *(const uint64_t *)data; - break; - case 4: - spec[i].value.u32 = *(const uint32_t *)data; - break; - case 2: - spec[i].value.u16 = *(const uint16_t *)data; - break; - case 1: - spec[i].value.u8 = *(const uint8_t *)data; - break; - default: - assert(!"Invalid spec constant size"); - break; - } - - spec[i].defined_on_module = false; - } - - num_spec = spec_info->mapEntryCount; - } + struct nir_spirv_specialization *spec = + vk_spec_info_to_nir_spirv(spec_info, &num_spec); nir_shader *nir = spirv_to_nir(code, codesize / sizeof(uint32_t), spec, num_spec, stage, entry_point_name, diff --git a/src/vulkan/util/meson.build b/src/vulkan/util/meson.build index 3865d68f6c0..d8089775a88 100644 --- a/src/vulkan/util/meson.build +++ b/src/vulkan/util/meson.build @@ -113,7 +113,7 @@ libvulkan_util = static_library( [files_vulkan_util, vk_common_entrypoints, vk_dispatch_table, vk_enum_to_str, vk_extensions], include_directories : [inc_include, inc_src, inc_gallium], - dependencies : [vulkan_wsi_deps, idep_mesautil], + dependencies : [vulkan_wsi_deps, idep_mesautil, idep_nir_headers], # For glsl_type_singleton link_with : libcompiler, c_args : [vulkan_wsi_args], diff --git a/src/vulkan/util/vk_util.c b/src/vulkan/util/vk_util.c index 116a78fa212..68d444e1607 100644 --- a/src/vulkan/util/vk_util.c +++ b/src/vulkan/util/vk_util.c @@ -29,6 +29,8 @@ #include "vk_util.h" #include "util/debug.h" +#include "compiler/spirv/nir_spirv.h" + uint32_t vk_get_driver_version(void) { const char *minor_string = strchr(PACKAGE_VERSION, '.'); @@ -79,3 +81,63 @@ vk_warn_non_conformant_implementation(const char *driver_name) fprintf(stderr, "WARNING: %s is not a conformant Vulkan implementation, " "testing use only.\n", driver_name); } + +struct nir_spirv_specialization* +vk_spec_info_to_nir_spirv(const VkSpecializationInfo *spec_info, + uint32_t *out_num_spec_entries) +{ + if (spec_info == NULL || spec_info->mapEntryCount == 0) + return NULL; + + uint32_t num_spec_entries = spec_info->mapEntryCount; + struct nir_spirv_specialization *spec_entries = + calloc(num_spec_entries, sizeof(*spec_entries)); + + for (uint32_t i = 0; i < num_spec_entries; i++) { + VkSpecializationMapEntry entry = spec_info->pMapEntries[i]; + const void *data = (uint8_t *)spec_info->pData + entry.offset; + assert((uint8_t *)data + entry.size <= + (uint8_t *)spec_info->pData + spec_info->dataSize); + + spec_entries[i].id = spec_info->pMapEntries[i].constantID; + switch (entry.size) { + case 8: + spec_entries[i].value.u64 = *(const uint64_t *)data; + break; + case 4: + spec_entries[i].value.u32 = *(const uint32_t *)data; + break; + case 2: + spec_entries[i].value.u16 = *(const uint16_t *)data; + break; + case 1: + spec_entries[i].value.u8 = *(const uint8_t *)data; + break; + case 0: + default: + /* The Vulkan spec says: + * + * "For a constantID specialization constant declared in a + * shader, size must match the byte size of the constantID. If + * the specialization constant is of type boolean, size must be + * the byte size of VkBool32." + * + * Therefore, since only scalars can be decorated as + * specialization constants, we can assume that if it doesn't have + * a size of 1, 2, 4, or 8, any use in a shader would be invalid + * usage. The spec further says: + * + * "If a constantID value is not a specialization constant ID + * used in the shader, that map entry does not affect the + * behavior of the pipeline." + * + * so we should ignore any invalid specialization constants rather + * than crash or error out when we see one. + */ + break; + } + } + + *out_num_spec_entries = num_spec_entries; + return spec_entries; +} diff --git a/src/vulkan/util/vk_util.h b/src/vulkan/util/vk_util.h index 30132338944..5dbce23b53e 100644 --- a/src/vulkan/util/vk_util.h +++ b/src/vulkan/util/vk_util.h @@ -272,6 +272,12 @@ mesa_to_vk_shader_stage(gl_shader_stage mesa_stage) (_i)++, (_draw) = (const VkMultiDrawInfoEXT*)((const uint8_t*)(_draw) + (_stride))) +struct nir_spirv_specialization; + +struct nir_spirv_specialization* +vk_spec_info_to_nir_spirv(const VkSpecializationInfo *spec_info, + uint32_t *out_num_spec_entries); + #ifdef __cplusplus } #endif