vulkan: add vk_spec_info_to_nir_spirv util method
All vulkan drivers have been copying anv's code to convert VkSpecializationInfo into nir_spirv_specialization. Recently there was a Vulkan spec change on allowed values for VkSpecializationInfo, and all drivers got affected. This commits creates a new helper, and uses it on all Vulkan Mesa drivers. v2: use (uint8_t*) castings, instead of void*, to avoid C2036 with MSVC (detected by the CI, inspired on what radv was doing) Reviewed-by: Samuel Pitoiset <samuel.pitoiset@gmail.com> Reviewed-by: Jason Ekstrand <jason@jlekstrand.net> Reviewed-by: Samuel Iglesias Gonsálvez <siglesias@igalia.com> Reviewed-by: Boris Brezillon <boris.brezillon@collabora.com> Reviewed-By: Mike Blumenkrantz <michael.blumenkrantz@gmail.com> Reviewed-by: Juan A. Suarez <jasuarez@igalia.com> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/12047>
This commit is contained in:
parent
fec1a04c53
commit
476dc3c050
|
@ -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,
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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],
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue