summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/SCsub1
-rw-r--r--drivers/spirv-reflect/SCsub16
-rw-r--r--drivers/vulkan/rendering_device_vulkan.cpp255
-rw-r--r--servers/visual/rasterizer_rd/shader_compiler_rd.cpp2
-rw-r--r--thirdparty/spirv-reflect/include/spirv/unified1/spirv.h1077
-rw-r--r--thirdparty/spirv-reflect/spirv_reflect.c4442
-rw-r--r--thirdparty/spirv-reflect/spirv_reflect.h2045
7 files changed, 7828 insertions, 10 deletions
diff --git a/drivers/SCsub b/drivers/SCsub
index 072addc2b3..48befd213c 100644
--- a/drivers/SCsub
+++ b/drivers/SCsub
@@ -33,6 +33,7 @@ else:
# Core dependencies
SConscript("png/SCsub")
+SConscript("spirv-reflect/SCsub")
if env['vsproj']:
import os
diff --git a/drivers/spirv-reflect/SCsub b/drivers/spirv-reflect/SCsub
new file mode 100644
index 0000000000..f6b40ac433
--- /dev/null
+++ b/drivers/spirv-reflect/SCsub
@@ -0,0 +1,16 @@
+#!/usr/bin/env python
+
+Import('env')
+
+env_spirv_reflect = env.Clone()
+
+thirdparty_dir = "#thirdparty/spirv-reflect/"
+thirdparty_sources = [
+ "spirv_reflect.c"
+]
+
+thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources]
+
+env_spirv_reflect.add_source_files(env.drivers_sources, thirdparty_sources)
+
+Export('env')
diff --git a/drivers/vulkan/rendering_device_vulkan.cpp b/drivers/vulkan/rendering_device_vulkan.cpp
index b2d5a3781c..7f4ebd5134 100644
--- a/drivers/vulkan/rendering_device_vulkan.cpp
+++ b/drivers/vulkan/rendering_device_vulkan.cpp
@@ -1,10 +1,11 @@
#include "rendering_device_vulkan.h"
-#include "drivers/vulkan/vulkan_context.h"
-
#include "core/hashfuncs.h"
+#include "core/os/file_access.h"
#include "core/project_settings.h"
+#include "drivers/vulkan/vulkan_context.h"
#include "thirdparty/glslang/SPIRV/GlslangToSpv.h"
#include "thirdparty/glslang/glslang/Include/Types.h"
+#include "thirdparty/spirv-reflect/spirv_reflect.h"
void RenderingDeviceVulkan::_add_dependency(RID p_id, RID p_depends_on) {
@@ -2371,7 +2372,6 @@ PoolVector<uint8_t> RenderingDeviceVulkan::texture_get_data(RID p_texture, uint3
image_copy_region.extent.depth = mm_depth;
vkCmdCopyImage(command_buffer, tex->image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &image_copy_region);
- print_line("copying mipmap " + itos(i) + " w: " + itos(mm_width) + " h " + itos(mm_height) + " d " + itos(mm_depth));
}
}
@@ -3568,7 +3568,7 @@ RID RenderingDeviceVulkan::shader_create_from_source(const Vector<ShaderStageSou
glslang::TShader::ForbidIncluder includer;
//descriptor layouts
- Vector<Vector<VkDescriptorSetLayoutBinding> > bindings;
+ Vector<Vector<VkDescriptorSetLayoutBinding> > set_bindings;
Vector<Vector<UniformInfo> > uniform_info;
Shader::PushConstant push_constant;
push_constant.push_constant_size = 0;
@@ -3652,11 +3652,27 @@ RID RenderingDeviceVulkan::shader_create_from_source(const Vector<ShaderStageSou
return RID();
}
+#if 0
//obtain bindings for descriptor layout
program.mapIO();
program.buildReflection(EShReflectionAllBlockVariables);
//program.dumpReflection();
+ for (int j = 0; j < program.getNumUniformBlocks(); j++) {
+ const glslang::TObjectReflection &reflection = program.getUniformBlock(j);
+ if (reflection.getType()->getBasicType() == glslang::EbtBlock && reflection.getType()->getQualifier().storage == glslang::EvqUniform && reflection.getType()->getQualifier().layoutPushConstant) {
+ uint32_t len = reflection.size;
+ if (push_constant_debug.push_constant_size != 0 && push_constant_debug.push_constant_size != len) {
+ print_line("eep");
+ }
+
+ push_constant_debug.push_constant_size = len;
+ push_constant_debug.push_constants_vk_stage |= shader_stage_masks[p_stages[i].shader_stage];
+ //print_line("Debug stage " + String(shader_stage_names[p_stages[i].shader_stage]) + " push constant size: " + itos(push_constant_debug.push_constant_size));
+ }
+ }
+
+
for (int j = 0; j < program.getNumUniformVariables(); j++) {
if (!_uniform_add_binding(bindings, uniform_info, program.getUniform(j), p_stages[i].shader_stage, push_constant, r_error)) {
return RID();
@@ -3698,11 +3714,233 @@ RID RenderingDeviceVulkan::shader_create_from_source(const Vector<ShaderStageSou
fragment_outputs = program.getNumPipeOutputs();
}
+#endif
std::vector<uint32_t> SpirV;
spv::SpvBuildLogger logger;
glslang::SpvOptions spvOptions;
glslang::GlslangToSpv(*program.getIntermediate(stages[p_stages[i].shader_stage]), SpirV, &logger, &spvOptions);
+ {
+ SpvReflectShaderModule module;
+ SpvReflectResult result = spvReflectCreateShaderModule(SpirV.size() * sizeof(uint32_t), &SpirV[0], &module);
+ ERR_FAIL_COND_V_MSG(result != SPV_REFLECT_RESULT_SUCCESS, RID(),
+ "Reflection of SPIR-V shader stage '" + String(shader_stage_names[p_stages[i].shader_stage]) + "' failed parsing shader.");
+
+ uint32_t binding_count = 0;
+ result = spvReflectEnumerateDescriptorBindings(&module, &binding_count, NULL);
+ ERR_FAIL_COND_V_MSG(result != SPV_REFLECT_RESULT_SUCCESS, RID(),
+ "Reflection of SPIR-V shader stage '" + String(shader_stage_names[p_stages[i].shader_stage]) + "' failed enumerating descriptor bindings.");
+
+ uint32_t stage = p_stages[i].shader_stage;
+
+ if (binding_count > 0) {
+
+ //Parse bindings
+
+ Vector<SpvReflectDescriptorBinding *> bindings;
+ bindings.resize(binding_count);
+ result = spvReflectEnumerateDescriptorBindings(&module, &binding_count, bindings.ptrw());
+
+ ERR_FAIL_COND_V_MSG(result != SPV_REFLECT_RESULT_SUCCESS, RID(),
+ "Reflection of SPIR-V shader stage '" + String(shader_stage_names[p_stages[i].shader_stage]) + "' failed getting descriptor bindings.");
+
+ for (uint32_t j = 0; j < binding_count; j++) {
+ const SpvReflectDescriptorBinding &binding = *bindings[j];
+
+ VkDescriptorSetLayoutBinding layout_binding;
+ UniformInfo info;
+
+ bool need_array_dimensions = false;
+ bool need_block_size = false;
+
+ switch (binding.descriptor_type) {
+ case SPV_REFLECT_DESCRIPTOR_TYPE_SAMPLER: {
+ layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER;
+ info.type = UNIFORM_TYPE_SAMPLER;
+ need_array_dimensions = true;
+ } break;
+ case SPV_REFLECT_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER: {
+ layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
+ info.type = UNIFORM_TYPE_SAMPLER_WITH_TEXTURE;
+ need_array_dimensions = true;
+ } break;
+ case SPV_REFLECT_DESCRIPTOR_TYPE_SAMPLED_IMAGE: {
+ layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
+ info.type = UNIFORM_TYPE_TEXTURE;
+ need_array_dimensions = true;
+ } break;
+ case SPV_REFLECT_DESCRIPTOR_TYPE_STORAGE_IMAGE: {
+ layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
+ info.type = UNIFORM_TYPE_IMAGE;
+ need_array_dimensions = true;
+ } break;
+ case SPV_REFLECT_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER: {
+ layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER;
+ info.type = UNIFORM_TYPE_TEXTURE_BUFFER;
+ need_array_dimensions = true;
+ } break;
+ case SPV_REFLECT_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER: {
+ layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER;
+ info.type = UNIFORM_TYPE_IMAGE_BUFFER;
+ need_array_dimensions = true;
+ } break;
+ case SPV_REFLECT_DESCRIPTOR_TYPE_UNIFORM_BUFFER: {
+ layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
+ info.type = UNIFORM_TYPE_UNIFORM_BUFFER;
+ need_block_size = true;
+ } break;
+ case SPV_REFLECT_DESCRIPTOR_TYPE_STORAGE_BUFFER: {
+ layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
+ info.type = UNIFORM_TYPE_STORAGE_BUFFER;
+ need_block_size = true;
+ } break;
+ case SPV_REFLECT_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC: {
+ ERR_PRINT("Dynamic uniform buffer not supported.");
+ continue;
+ } break;
+ case SPV_REFLECT_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC: {
+ ERR_PRINT("Dynamic storage buffer not supported.");
+ continue;
+ } break;
+ case SPV_REFLECT_DESCRIPTOR_TYPE_INPUT_ATTACHMENT: {
+ layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT;
+ info.type = UNIFORM_TYPE_INPUT_ATTACHMENT;
+ } break;
+ }
+
+ if (need_array_dimensions) {
+ if (binding.array.dims_count == 0) {
+ info.length = 1;
+ } else {
+ for (uint32_t k = 0; k < binding.array.dims_count; k++) {
+ if (k == 0) {
+ info.length = binding.array.dims[0];
+ } else {
+ info.length *= binding.array.dims[k];
+ }
+ }
+ }
+
+ layout_binding.descriptorCount = info.length;
+
+ } else if (need_block_size) {
+ info.length = binding.block.size;
+ layout_binding.descriptorCount = 1;
+ } else {
+ info.length = 0;
+ layout_binding.descriptorCount = 1;
+ }
+
+ info.binding = binding.binding;
+ uint32_t set = binding.set;
+
+ //print_line("Stage: " + String(shader_stage_names[stage]) + " set=" + itos(set) + " binding=" + itos(info.binding) + " type=" + shader_uniform_names[info.type] + " length=" + itos(info.length));
+
+ ERR_FAIL_COND_V_MSG(set >= MAX_UNIFORM_SETS, RID(),
+ "On shader stage '" + String(shader_stage_names[stage]) + "', uniform '" + binding.name + "' uses a set (" + itos(set) + ") index larger than what is supported (" + itos(MAX_UNIFORM_SETS) + ").");
+
+ ERR_FAIL_COND_V_MSG(set >= limits.maxBoundDescriptorSets, RID(),
+ "On shader stage '" + String(shader_stage_names[stage]) + "', uniform '" + binding.name + "' uses a set (" + itos(set) + ") index larger than what is supported by the hardware (" + itos(limits.maxBoundDescriptorSets) + ").");
+
+ if (set < (uint32_t)set_bindings.size()) {
+ //check if this already exists
+ bool exists = false;
+ for (int k = 0; k < set_bindings[set].size(); k++) {
+ if (set_bindings[set][k].binding == (uint32_t)info.binding) {
+ //already exists, verify that it's the same type
+ ERR_FAIL_COND_V_MSG(set_bindings[set][k].descriptorType != layout_binding.descriptorType, RID(),
+ "On shader stage '" + String(shader_stage_names[stage]) + "', uniform '" + binding.name + "' trying to re-use location for set=" + itos(set) + ", binding=" + itos(info.binding) + " with different uniform type.");
+
+ //also, verify that it's the same size
+ ERR_FAIL_COND_V_MSG(set_bindings[set][k].descriptorCount != layout_binding.descriptorCount || uniform_info[set][k].length != info.length, RID(),
+ "On shader stage '" + String(shader_stage_names[stage]) + "', uniform '" + binding.name + "' trying to re-use location for set=" + itos(set) + ", binding=" + itos(info.binding) + " with different uniform size.");
+
+ //just append stage mask and return
+ set_bindings.write[set].write[k].stageFlags |= shader_stage_masks[stage];
+ uniform_info.write[set].write[k].stages |= 1 << stage;
+ exists = true;
+ }
+ }
+
+ if (exists) {
+ continue; //merged
+ }
+ }
+
+ layout_binding.binding = info.binding;
+ layout_binding.stageFlags = shader_stage_masks[stage];
+ layout_binding.pImmutableSamplers = NULL; //no support for this yet
+
+ info.stages = 1 << stage;
+ info.binding = info.binding;
+
+ if (set >= (uint32_t)set_bindings.size()) {
+ set_bindings.resize(set + 1);
+ uniform_info.resize(set + 1);
+ }
+
+ set_bindings.write[set].push_back(layout_binding);
+ uniform_info.write[set].push_back(info);
+ }
+ }
+
+ if (stage == SHADER_STAGE_FRAGMENT) {
+
+ uint32_t ov_count = 0;
+ result = spvReflectEnumerateOutputVariables(&module, &ov_count, NULL);
+ ERR_FAIL_COND_V_MSG(result != SPV_REFLECT_RESULT_SUCCESS, RID(),
+ "Reflection of SPIR-V shader stage '" + String(shader_stage_names[p_stages[i].shader_stage]) + "' failed enumerating output variables.");
+
+ if (ov_count) {
+ Vector<SpvReflectInterfaceVariable *> output_vars;
+ output_vars.resize(ov_count);
+
+ result = spvReflectEnumerateOutputVariables(&module, &ov_count, output_vars.ptrw());
+ ERR_FAIL_COND_V_MSG(result != SPV_REFLECT_RESULT_SUCCESS, RID(),
+ "Reflection of SPIR-V shader stage '" + String(shader_stage_names[p_stages[i].shader_stage]) + "' failed obtaining output variables.");
+
+ for (uint32_t j = 0; j < ov_count; j++) {
+ if (output_vars[j]) {
+ fragment_outputs = MAX(fragment_outputs, output_vars[j]->location + 1);
+ }
+ }
+ }
+ }
+ uint32_t pc_count = 0;
+ result = spvReflectEnumeratePushConstantBlocks(&module, &pc_count, NULL);
+ ERR_FAIL_COND_V_MSG(result != SPV_REFLECT_RESULT_SUCCESS, RID(),
+ "Reflection of SPIR-V shader stage '" + String(shader_stage_names[p_stages[i].shader_stage]) + "' failed enumerating push constants.");
+
+ if (pc_count) {
+ ERR_FAIL_COND_V_MSG(pc_count > 1, RID(),
+ "Reflection of SPIR-V shader stage '" + String(shader_stage_names[p_stages[i].shader_stage]) + "': Only one push constant is supported, which should be the same across shader stages.");
+
+ Vector<SpvReflectBlockVariable *> pconstants;
+ pconstants.resize(pc_count);
+ result = spvReflectEnumeratePushConstantBlocks(&module, &pc_count, pconstants.ptrw());
+ ERR_FAIL_COND_V_MSG(result != SPV_REFLECT_RESULT_SUCCESS, RID(),
+ "Reflection of SPIR-V shader stage '" + String(shader_stage_names[p_stages[i].shader_stage]) + "' failed obtaining push constants.");
+#if 0
+ if (pconstants[0] == NULL) {
+ FileAccess *f = FileAccess::open("res://popo.spv", FileAccess::WRITE);
+ f->store_buffer((const uint8_t *)&SpirV[0], SpirV.size() * sizeof(uint32_t));
+ memdelete(f);
+ }
+#endif
+
+ ERR_FAIL_COND_V_MSG(push_constant.push_constant_size && push_constant.push_constant_size != pconstants[0]->size, RID(),
+ "Reflection of SPIR-V shader stage '" + String(shader_stage_names[p_stages[i].shader_stage]) + "': Push constant block must be the same across shader stages.");
+
+ push_constant.push_constant_size = pconstants[0]->size;
+ push_constant.push_constants_vk_stage |= shader_stage_masks[stage];
+
+ //print_line("Stage: " + String(shader_stage_names[stage]) + " push constant of size=" + itos(push_constant.push_constant_size));
+ }
+
+ // Destroy the reflection data when no longer required.
+ spvReflectDestroyShaderModule(&module);
+ }
+
spirv_code.push_back(SpirV);
stages_processed |= (1 << p_stages[i].shader_stage);
@@ -3758,15 +3996,15 @@ RID RenderingDeviceVulkan::shader_create_from_source(const Vector<ShaderStageSou
if (success) {
- for (int i = 0; i < bindings.size(); i++) {
+ for (int i = 0; i < set_bindings.size(); i++) {
//empty ones are fine if they were not used according to spec (binding count will be 0)
VkDescriptorSetLayoutCreateInfo layout_create_info;
layout_create_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
layout_create_info.pNext = NULL;
layout_create_info.flags = 0;
- layout_create_info.bindingCount = bindings[i].size();
- layout_create_info.pBindings = bindings[i].ptr();
+ layout_create_info.bindingCount = set_bindings[i].size();
+ layout_create_info.pBindings = set_bindings[i].ptr();
VkDescriptorSetLayout layout;
VkResult res = vkCreateDescriptorSetLayout(device, &layout_create_info, NULL, &layout);
@@ -4108,7 +4346,7 @@ RID RenderingDeviceVulkan::uniform_set_create(const Vector<Uniform> &p_uniforms,
const Uniform &uniform = uniforms[uniform_idx];
ERR_FAIL_COND_V_MSG(uniform.type != set_uniform.type, RID(),
- "Mismatch uniform type for binding (" + itos(set_uniform.binding) + ").");
+ "Mismatch uniform type for binding (" + itos(set_uniform.binding) + "). Expected '" + shader_uniform_names[set_uniform.type] + "', supplied: '" + shader_uniform_names[uniform.type] + "'.");
VkWriteDescriptorSet write; //common header
write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
@@ -6048,7 +6286,6 @@ void RenderingDeviceVulkan::initialize(VulkanContext *p_context) {
}
texture_upload_region_size_px = GLOBAL_DEF("rendering/vulkan/staging_buffer/texture_upload_region_size_px", 64);
texture_upload_region_size_px = nearest_power_of_2_templated(texture_upload_region_size_px);
- print_line("update size: " + itos(texture_upload_region_size_px));
frames_drawn = frame_count; //start from frame count, so everything else is immediately old
diff --git a/servers/visual/rasterizer_rd/shader_compiler_rd.cpp b/servers/visual/rasterizer_rd/shader_compiler_rd.cpp
index 76b1a288e6..b43fabce59 100644
--- a/servers/visual/rasterizer_rd/shader_compiler_rd.cpp
+++ b/servers/visual/rasterizer_rd/shader_compiler_rd.cpp
@@ -410,7 +410,7 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge
r_gen_code.uniform_total_size = offset;
print_line("uniform total: " + itos(r_gen_code.uniform_total_size));
if (r_gen_code.uniform_total_size % 16 != 0) { //UBO sizes must be multiples of 16
- //r_gen_code.uniform_total_size += 16 - (r_gen_code.uniform_total_size % 16);
+ r_gen_code.uniform_total_size += 16 - (r_gen_code.uniform_total_size % 16);
}
#else
// add up
diff --git a/thirdparty/spirv-reflect/include/spirv/unified1/spirv.h b/thirdparty/spirv-reflect/include/spirv/unified1/spirv.h
new file mode 100644
index 0000000000..a61a2d2935
--- /dev/null
+++ b/thirdparty/spirv-reflect/include/spirv/unified1/spirv.h
@@ -0,0 +1,1077 @@
+/*
+** Copyright (c) 2014-2018 The Khronos Group Inc.
+**
+** Permission is hereby granted, free of charge, to any person obtaining a copy
+** of this software and/or associated documentation files (the "Materials"),
+** to deal in the Materials without restriction, including without limitation
+** the rights to use, copy, modify, merge, publish, distribute, sublicense,
+** and/or sell copies of the Materials, and to permit persons to whom the
+** Materials are furnished to do so, subject to the following conditions:
+**
+** The above copyright notice and this permission notice shall be included in
+** all copies or substantial portions of the Materials.
+**
+** MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS KHRONOS
+** STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS SPECIFICATIONS AND
+** HEADER INFORMATION ARE LOCATED AT https://www.khronos.org/registry/
+**
+** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+** OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+** THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+** FROM,OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE USE OR OTHER DEALINGS
+** IN THE MATERIALS.
+*/
+
+/*
+** This header is automatically generated by the same tool that creates
+** the Binary Section of the SPIR-V specification.
+*/
+
+/*
+** Enumeration tokens for SPIR-V, in various styles:
+** C, C++, C++11, JSON, Lua, Python
+**
+** - C will have tokens with a "Spv" prefix, e.g.: SpvSourceLanguageGLSL
+** - C++ will have tokens in the "spv" name space, e.g.: spv::SourceLanguageGLSL
+** - C++11 will use enum classes in the spv namespace, e.g.: spv::SourceLanguage::GLSL
+** - Lua will use tables, e.g.: spv.SourceLanguage.GLSL
+** - Python will use dictionaries, e.g.: spv['SourceLanguage']['GLSL']
+**
+** Some tokens act like mask values, which can be OR'd together,
+** while others are mutually exclusive. The mask-like ones have
+** "Mask" in their name, and a parallel enum that has the shift
+** amount (1 << x) for each corresponding enumerant.
+*/
+
+#ifndef spirv_H
+#define spirv_H
+
+typedef unsigned int SpvId;
+
+#define SPV_VERSION 0x10300
+#define SPV_REVISION 1
+
+static const unsigned int SpvMagicNumber = 0x07230203;
+static const unsigned int SpvVersion = 0x00010300;
+static const unsigned int SpvRevision = 1;
+static const unsigned int SpvOpCodeMask = 0xffff;
+static const unsigned int SpvWordCountShift = 16;
+
+typedef enum SpvSourceLanguage_ {
+ SpvSourceLanguageUnknown = 0,
+ SpvSourceLanguageESSL = 1,
+ SpvSourceLanguageGLSL = 2,
+ SpvSourceLanguageOpenCL_C = 3,
+ SpvSourceLanguageOpenCL_CPP = 4,
+ SpvSourceLanguageHLSL = 5,
+ SpvSourceLanguageMax = 0x7fffffff,
+} SpvSourceLanguage;
+
+typedef enum SpvExecutionModel_ {
+ SpvExecutionModelVertex = 0,
+ SpvExecutionModelTessellationControl = 1,
+ SpvExecutionModelTessellationEvaluation = 2,
+ SpvExecutionModelGeometry = 3,
+ SpvExecutionModelFragment = 4,
+ SpvExecutionModelGLCompute = 5,
+ SpvExecutionModelKernel = 6,
+ SpvExecutionModelMax = 0x7fffffff,
+} SpvExecutionModel;
+
+typedef enum SpvAddressingModel_ {
+ SpvAddressingModelLogical = 0,
+ SpvAddressingModelPhysical32 = 1,
+ SpvAddressingModelPhysical64 = 2,
+ SpvAddressingModelMax = 0x7fffffff,
+} SpvAddressingModel;
+
+typedef enum SpvMemoryModel_ {
+ SpvMemoryModelSimple = 0,
+ SpvMemoryModelGLSL450 = 1,
+ SpvMemoryModelOpenCL = 2,
+ SpvMemoryModelMax = 0x7fffffff,
+} SpvMemoryModel;
+
+typedef enum SpvExecutionMode_ {
+ SpvExecutionModeInvocations = 0,
+ SpvExecutionModeSpacingEqual = 1,
+ SpvExecutionModeSpacingFractionalEven = 2,
+ SpvExecutionModeSpacingFractionalOdd = 3,
+ SpvExecutionModeVertexOrderCw = 4,
+ SpvExecutionModeVertexOrderCcw = 5,
+ SpvExecutionModePixelCenterInteger = 6,
+ SpvExecutionModeOriginUpperLeft = 7,
+ SpvExecutionModeOriginLowerLeft = 8,
+ SpvExecutionModeEarlyFragmentTests = 9,
+ SpvExecutionModePointMode = 10,
+ SpvExecutionModeXfb = 11,
+ SpvExecutionModeDepthReplacing = 12,
+ SpvExecutionModeDepthGreater = 14,
+ SpvExecutionModeDepthLess = 15,
+ SpvExecutionModeDepthUnchanged = 16,
+ SpvExecutionModeLocalSize = 17,
+ SpvExecutionModeLocalSizeHint = 18,
+ SpvExecutionModeInputPoints = 19,
+ SpvExecutionModeInputLines = 20,
+ SpvExecutionModeInputLinesAdjacency = 21,
+ SpvExecutionModeTriangles = 22,
+ SpvExecutionModeInputTrianglesAdjacency = 23,
+ SpvExecutionModeQuads = 24,
+ SpvExecutionModeIsolines = 25,
+ SpvExecutionModeOutputVertices = 26,
+ SpvExecutionModeOutputPoints = 27,
+ SpvExecutionModeOutputLineStrip = 28,
+ SpvExecutionModeOutputTriangleStrip = 29,
+ SpvExecutionModeVecTypeHint = 30,
+ SpvExecutionModeContractionOff = 31,
+ SpvExecutionModeInitializer = 33,
+ SpvExecutionModeFinalizer = 34,
+ SpvExecutionModeSubgroupSize = 35,
+ SpvExecutionModeSubgroupsPerWorkgroup = 36,
+ SpvExecutionModeSubgroupsPerWorkgroupId = 37,
+ SpvExecutionModeLocalSizeId = 38,
+ SpvExecutionModeLocalSizeHintId = 39,
+ SpvExecutionModePostDepthCoverage = 4446,
+ SpvExecutionModeStencilRefReplacingEXT = 5027,
+ SpvExecutionModeMax = 0x7fffffff,
+} SpvExecutionMode;
+
+typedef enum SpvStorageClass_ {
+ SpvStorageClassUniformConstant = 0,
+ SpvStorageClassInput = 1,
+ SpvStorageClassUniform = 2,
+ SpvStorageClassOutput = 3,
+ SpvStorageClassWorkgroup = 4,
+ SpvStorageClassCrossWorkgroup = 5,
+ SpvStorageClassPrivate = 6,
+ SpvStorageClassFunction = 7,
+ SpvStorageClassGeneric = 8,
+ SpvStorageClassPushConstant = 9,
+ SpvStorageClassAtomicCounter = 10,
+ SpvStorageClassImage = 11,
+ SpvStorageClassStorageBuffer = 12,
+ SpvStorageClassMax = 0x7fffffff,
+} SpvStorageClass;
+
+typedef enum SpvDim_ {
+ SpvDim1D = 0,
+ SpvDim2D = 1,
+ SpvDim3D = 2,
+ SpvDimCube = 3,
+ SpvDimRect = 4,
+ SpvDimBuffer = 5,
+ SpvDimSubpassData = 6,
+ SpvDimMax = 0x7fffffff,
+} SpvDim;
+
+typedef enum SpvSamplerAddressingMode_ {
+ SpvSamplerAddressingModeNone = 0,
+ SpvSamplerAddressingModeClampToEdge = 1,
+ SpvSamplerAddressingModeClamp = 2,
+ SpvSamplerAddressingModeRepeat = 3,
+ SpvSamplerAddressingModeRepeatMirrored = 4,
+ SpvSamplerAddressingModeMax = 0x7fffffff,
+} SpvSamplerAddressingMode;
+
+typedef enum SpvSamplerFilterMode_ {
+ SpvSamplerFilterModeNearest = 0,
+ SpvSamplerFilterModeLinear = 1,
+ SpvSamplerFilterModeMax = 0x7fffffff,
+} SpvSamplerFilterMode;
+
+typedef enum SpvImageFormat_ {
+ SpvImageFormatUnknown = 0,
+ SpvImageFormatRgba32f = 1,
+ SpvImageFormatRgba16f = 2,
+ SpvImageFormatR32f = 3,
+ SpvImageFormatRgba8 = 4,
+ SpvImageFormatRgba8Snorm = 5,
+ SpvImageFormatRg32f = 6,
+ SpvImageFormatRg16f = 7,
+ SpvImageFormatR11fG11fB10f = 8,
+ SpvImageFormatR16f = 9,
+ SpvImageFormatRgba16 = 10,
+ SpvImageFormatRgb10A2 = 11,
+ SpvImageFormatRg16 = 12,
+ SpvImageFormatRg8 = 13,
+ SpvImageFormatR16 = 14,
+ SpvImageFormatR8 = 15,
+ SpvImageFormatRgba16Snorm = 16,
+ SpvImageFormatRg16Snorm = 17,
+ SpvImageFormatRg8Snorm = 18,
+ SpvImageFormatR16Snorm = 19,
+ SpvImageFormatR8Snorm = 20,
+ SpvImageFormatRgba32i = 21,
+ SpvImageFormatRgba16i = 22,
+ SpvImageFormatRgba8i = 23,
+ SpvImageFormatR32i = 24,
+ SpvImageFormatRg32i = 25,
+ SpvImageFormatRg16i = 26,
+ SpvImageFormatRg8i = 27,
+ SpvImageFormatR16i = 28,
+ SpvImageFormatR8i = 29,
+ SpvImageFormatRgba32ui = 30,
+ SpvImageFormatRgba16ui = 31,
+ SpvImageFormatRgba8ui = 32,
+ SpvImageFormatR32ui = 33,
+ SpvImageFormatRgb10a2ui = 34,
+ SpvImageFormatRg32ui = 35,
+ SpvImageFormatRg16ui = 36,
+ SpvImageFormatRg8ui = 37,
+ SpvImageFormatR16ui = 38,
+ SpvImageFormatR8ui = 39,
+ SpvImageFormatMax = 0x7fffffff,
+} SpvImageFormat;
+
+typedef enum SpvImageChannelOrder_ {
+ SpvImageChannelOrderR = 0,
+ SpvImageChannelOrderA = 1,
+ SpvImageChannelOrderRG = 2,
+ SpvImageChannelOrderRA = 3,
+ SpvImageChannelOrderRGB = 4,
+ SpvImageChannelOrderRGBA = 5,
+ SpvImageChannelOrderBGRA = 6,
+ SpvImageChannelOrderARGB = 7,
+ SpvImageChannelOrderIntensity = 8,
+ SpvImageChannelOrderLuminance = 9,
+ SpvImageChannelOrderRx = 10,
+ SpvImageChannelOrderRGx = 11,
+ SpvImageChannelOrderRGBx = 12,
+ SpvImageChannelOrderDepth = 13,
+ SpvImageChannelOrderDepthStencil = 14,
+ SpvImageChannelOrdersRGB = 15,
+ SpvImageChannelOrdersRGBx = 16,
+ SpvImageChannelOrdersRGBA = 17,
+ SpvImageChannelOrdersBGRA = 18,
+ SpvImageChannelOrderABGR = 19,
+ SpvImageChannelOrderMax = 0x7fffffff,
+} SpvImageChannelOrder;
+
+typedef enum SpvImageChannelDataType_ {
+ SpvImageChannelDataTypeSnormInt8 = 0,
+ SpvImageChannelDataTypeSnormInt16 = 1,
+ SpvImageChannelDataTypeUnormInt8 = 2,
+ SpvImageChannelDataTypeUnormInt16 = 3,
+ SpvImageChannelDataTypeUnormShort565 = 4,
+ SpvImageChannelDataTypeUnormShort555 = 5,
+ SpvImageChannelDataTypeUnormInt101010 = 6,
+ SpvImageChannelDataTypeSignedInt8 = 7,
+ SpvImageChannelDataTypeSignedInt16 = 8,
+ SpvImageChannelDataTypeSignedInt32 = 9,
+ SpvImageChannelDataTypeUnsignedInt8 = 10,
+ SpvImageChannelDataTypeUnsignedInt16 = 11,
+ SpvImageChannelDataTypeUnsignedInt32 = 12,
+ SpvImageChannelDataTypeHalfFloat = 13,
+ SpvImageChannelDataTypeFloat = 14,
+ SpvImageChannelDataTypeUnormInt24 = 15,
+ SpvImageChannelDataTypeUnormInt101010_2 = 16,
+ SpvImageChannelDataTypeMax = 0x7fffffff,
+} SpvImageChannelDataType;
+
+typedef enum SpvImageOperandsShift_ {
+ SpvImageOperandsBiasShift = 0,
+ SpvImageOperandsLodShift = 1,
+ SpvImageOperandsGradShift = 2,
+ SpvImageOperandsConstOffsetShift = 3,
+ SpvImageOperandsOffsetShift = 4,
+ SpvImageOperandsConstOffsetsShift = 5,
+ SpvImageOperandsSampleShift = 6,
+ SpvImageOperandsMinLodShift = 7,
+ SpvImageOperandsMax = 0x7fffffff,
+} SpvImageOperandsShift;
+
+typedef enum SpvImageOperandsMask_ {
+ SpvImageOperandsMaskNone = 0,
+ SpvImageOperandsBiasMask = 0x00000001,
+ SpvImageOperandsLodMask = 0x00000002,
+ SpvImageOperandsGradMask = 0x00000004,
+ SpvImageOperandsConstOffsetMask = 0x00000008,
+ SpvImageOperandsOffsetMask = 0x00000010,
+ SpvImageOperandsConstOffsetsMask = 0x00000020,
+ SpvImageOperandsSampleMask = 0x00000040,
+ SpvImageOperandsMinLodMask = 0x00000080,
+} SpvImageOperandsMask;
+
+typedef enum SpvFPFastMathModeShift_ {
+ SpvFPFastMathModeNotNaNShift = 0,
+ SpvFPFastMathModeNotInfShift = 1,
+ SpvFPFastMathModeNSZShift = 2,
+ SpvFPFastMathModeAllowRecipShift = 3,
+ SpvFPFastMathModeFastShift = 4,
+ SpvFPFastMathModeMax = 0x7fffffff,
+} SpvFPFastMathModeShift;
+
+typedef enum SpvFPFastMathModeMask_ {
+ SpvFPFastMathModeMaskNone = 0,
+ SpvFPFastMathModeNotNaNMask = 0x00000001,
+ SpvFPFastMathModeNotInfMask = 0x00000002,
+ SpvFPFastMathModeNSZMask = 0x00000004,
+ SpvFPFastMathModeAllowRecipMask = 0x00000008,
+ SpvFPFastMathModeFastMask = 0x00000010,
+} SpvFPFastMathModeMask;
+
+typedef enum SpvFPRoundingMode_ {
+ SpvFPRoundingModeRTE = 0,
+ SpvFPRoundingModeRTZ = 1,
+ SpvFPRoundingModeRTP = 2,
+ SpvFPRoundingModeRTN = 3,
+ SpvFPRoundingModeMax = 0x7fffffff,
+} SpvFPRoundingMode;
+
+typedef enum SpvLinkageType_ {
+ SpvLinkageTypeExport = 0,
+ SpvLinkageTypeImport = 1,
+ SpvLinkageTypeMax = 0x7fffffff,
+} SpvLinkageType;
+
+typedef enum SpvAccessQualifier_ {
+ SpvAccessQualifierReadOnly = 0,
+ SpvAccessQualifierWriteOnly = 1,
+ SpvAccessQualifierReadWrite = 2,
+ SpvAccessQualifierMax = 0x7fffffff,
+} SpvAccessQualifier;
+
+typedef enum SpvFunctionParameterAttribute_ {
+ SpvFunctionParameterAttributeZext = 0,
+ SpvFunctionParameterAttributeSext = 1,
+ SpvFunctionParameterAttributeByVal = 2,
+ SpvFunctionParameterAttributeSret = 3,
+ SpvFunctionParameterAttributeNoAlias = 4,
+ SpvFunctionParameterAttributeNoCapture = 5,
+ SpvFunctionParameterAttributeNoWrite = 6,
+ SpvFunctionParameterAttributeNoReadWrite = 7,
+ SpvFunctionParameterAttributeMax = 0x7fffffff,
+} SpvFunctionParameterAttribute;
+
+typedef enum SpvDecoration_ {
+ SpvDecorationRelaxedPrecision = 0,
+ SpvDecorationSpecId = 1,
+ SpvDecorationBlock = 2,
+ SpvDecorationBufferBlock = 3,
+ SpvDecorationRowMajor = 4,
+ SpvDecorationColMajor = 5,
+ SpvDecorationArrayStride = 6,
+ SpvDecorationMatrixStride = 7,
+ SpvDecorationGLSLShared = 8,
+ SpvDecorationGLSLPacked = 9,
+ SpvDecorationCPacked = 10,
+ SpvDecorationBuiltIn = 11,
+ SpvDecorationNoPerspective = 13,
+ SpvDecorationFlat = 14,
+ SpvDecorationPatch = 15,
+ SpvDecorationCentroid = 16,
+ SpvDecorationSample = 17,
+ SpvDecorationInvariant = 18,
+ SpvDecorationRestrict = 19,
+ SpvDecorationAliased = 20,
+ SpvDecorationVolatile = 21,
+ SpvDecorationConstant = 22,
+ SpvDecorationCoherent = 23,
+ SpvDecorationNonWritable = 24,
+ SpvDecorationNonReadable = 25,
+ SpvDecorationUniform = 26,
+ SpvDecorationSaturatedConversion = 28,
+ SpvDecorationStream = 29,
+ SpvDecorationLocation = 30,
+ SpvDecorationComponent = 31,
+ SpvDecorationIndex = 32,
+ SpvDecorationBinding = 33,
+ SpvDecorationDescriptorSet = 34,
+ SpvDecorationOffset = 35,
+ SpvDecorationXfbBuffer = 36,
+ SpvDecorationXfbStride = 37,
+ SpvDecorationFuncParamAttr = 38,
+ SpvDecorationFPRoundingMode = 39,
+ SpvDecorationFPFastMathMode = 40,
+ SpvDecorationLinkageAttributes = 41,
+ SpvDecorationNoContraction = 42,
+ SpvDecorationInputAttachmentIndex = 43,
+ SpvDecorationAlignment = 44,
+ SpvDecorationMaxByteOffset = 45,
+ SpvDecorationAlignmentId = 46,
+ SpvDecorationMaxByteOffsetId = 47,
+ SpvDecorationExplicitInterpAMD = 4999,
+ SpvDecorationOverrideCoverageNV = 5248,
+ SpvDecorationPassthroughNV = 5250,
+ SpvDecorationViewportRelativeNV = 5252,
+ SpvDecorationSecondaryViewportRelativeNV = 5256,
+ SpvDecorationHlslCounterBufferGOOGLE = 5634,
+ SpvDecorationHlslSemanticGOOGLE = 5635,
+ SpvDecorationMax = 0x7fffffff,
+} SpvDecoration;
+
+typedef enum SpvBuiltIn_ {
+ SpvBuiltInPosition = 0,
+ SpvBuiltInPointSize = 1,
+ SpvBuiltInClipDistance = 3,
+ SpvBuiltInCullDistance = 4,
+ SpvBuiltInVertexId = 5,
+ SpvBuiltInInstanceId = 6,
+ SpvBuiltInPrimitiveId = 7,
+ SpvBuiltInInvocationId = 8,
+ SpvBuiltInLayer = 9,
+ SpvBuiltInViewportIndex = 10,
+ SpvBuiltInTessLevelOuter = 11,
+ SpvBuiltInTessLevelInner = 12,
+ SpvBuiltInTessCoord = 13,
+ SpvBuiltInPatchVertices = 14,
+ SpvBuiltInFragCoord = 15,
+ SpvBuiltInPointCoord = 16,
+ SpvBuiltInFrontFacing = 17,
+ SpvBuiltInSampleId = 18,
+ SpvBuiltInSamplePosition = 19,
+ SpvBuiltInSampleMask = 20,
+ SpvBuiltInFragDepth = 22,
+ SpvBuiltInHelperInvocation = 23,
+ SpvBuiltInNumWorkgroups = 24,
+ SpvBuiltInWorkgroupSize = 25,
+ SpvBuiltInWorkgroupId = 26,
+ SpvBuiltInLocalInvocationId = 27,
+ SpvBuiltInGlobalInvocationId = 28,
+ SpvBuiltInLocalInvocationIndex = 29,
+ SpvBuiltInWorkDim = 30,
+ SpvBuiltInGlobalSize = 31,
+ SpvBuiltInEnqueuedWorkgroupSize = 32,
+ SpvBuiltInGlobalOffset = 33,
+ SpvBuiltInGlobalLinearId = 34,
+ SpvBuiltInSubgroupSize = 36,
+ SpvBuiltInSubgroupMaxSize = 37,
+ SpvBuiltInNumSubgroups = 38,
+ SpvBuiltInNumEnqueuedSubgroups = 39,
+ SpvBuiltInSubgroupId = 40,
+ SpvBuiltInSubgroupLocalInvocationId = 41,
+ SpvBuiltInVertexIndex = 42,
+ SpvBuiltInInstanceIndex = 43,
+ SpvBuiltInSubgroupEqMask = 4416,
+ SpvBuiltInSubgroupEqMaskKHR = 4416,
+ SpvBuiltInSubgroupGeMask = 4417,
+ SpvBuiltInSubgroupGeMaskKHR = 4417,
+ SpvBuiltInSubgroupGtMask = 4418,
+ SpvBuiltInSubgroupGtMaskKHR = 4418,
+ SpvBuiltInSubgroupLeMask = 4419,
+ SpvBuiltInSubgroupLeMaskKHR = 4419,
+ SpvBuiltInSubgroupLtMask = 4420,
+ SpvBuiltInSubgroupLtMaskKHR = 4420,
+ SpvBuiltInBaseVertex = 4424,
+ SpvBuiltInBaseInstance = 4425,
+ SpvBuiltInDrawIndex = 4426,
+ SpvBuiltInDeviceIndex = 4438,
+ SpvBuiltInViewIndex = 4440,
+ SpvBuiltInBaryCoordNoPerspAMD = 4992,
+ SpvBuiltInBaryCoordNoPerspCentroidAMD = 4993,
+ SpvBuiltInBaryCoordNoPerspSampleAMD = 4994,
+ SpvBuiltInBaryCoordSmoothAMD = 4995,
+ SpvBuiltInBaryCoordSmoothCentroidAMD = 4996,
+ SpvBuiltInBaryCoordSmoothSampleAMD = 4997,
+ SpvBuiltInBaryCoordPullModelAMD = 4998,
+ SpvBuiltInFragStencilRefEXT = 5014,
+ SpvBuiltInViewportMaskNV = 5253,
+ SpvBuiltInSecondaryPositionNV = 5257,
+ SpvBuiltInSecondaryViewportMaskNV = 5258,
+ SpvBuiltInPositionPerViewNV = 5261,
+ SpvBuiltInViewportMaskPerViewNV = 5262,
+ SpvBuiltInFullyCoveredEXT = 5264,
+ SpvBuiltInMax = 0x7fffffff,
+} SpvBuiltIn;
+
+typedef enum SpvSelectionControlShift_ {
+ SpvSelectionControlFlattenShift = 0,
+ SpvSelectionControlDontFlattenShift = 1,
+ SpvSelectionControlMax = 0x7fffffff,
+} SpvSelectionControlShift;
+
+typedef enum SpvSelectionControlMask_ {
+ SpvSelectionControlMaskNone = 0,
+ SpvSelectionControlFlattenMask = 0x00000001,
+ SpvSelectionControlDontFlattenMask = 0x00000002,
+} SpvSelectionControlMask;
+
+typedef enum SpvLoopControlShift_ {
+ SpvLoopControlUnrollShift = 0,
+ SpvLoopControlDontUnrollShift = 1,
+ SpvLoopControlDependencyInfiniteShift = 2,
+ SpvLoopControlDependencyLengthShift = 3,
+ SpvLoopControlMax = 0x7fffffff,
+} SpvLoopControlShift;
+
+typedef enum SpvLoopControlMask_ {
+ SpvLoopControlMaskNone = 0,
+ SpvLoopControlUnrollMask = 0x00000001,
+ SpvLoopControlDontUnrollMask = 0x00000002,
+ SpvLoopControlDependencyInfiniteMask = 0x00000004,
+ SpvLoopControlDependencyLengthMask = 0x00000008,
+} SpvLoopControlMask;
+
+typedef enum SpvFunctionControlShift_ {
+ SpvFunctionControlInlineShift = 0,
+ SpvFunctionControlDontInlineShift = 1,
+ SpvFunctionControlPureShift = 2,
+ SpvFunctionControlConstShift = 3,
+ SpvFunctionControlMax = 0x7fffffff,
+} SpvFunctionControlShift;
+
+typedef enum SpvFunctionControlMask_ {
+ SpvFunctionControlMaskNone = 0,
+ SpvFunctionControlInlineMask = 0x00000001,
+ SpvFunctionControlDontInlineMask = 0x00000002,
+ SpvFunctionControlPureMask = 0x00000004,
+ SpvFunctionControlConstMask = 0x00000008,
+} SpvFunctionControlMask;
+
+typedef enum SpvMemorySemanticsShift_ {
+ SpvMemorySemanticsAcquireShift = 1,
+ SpvMemorySemanticsReleaseShift = 2,
+ SpvMemorySemanticsAcquireReleaseShift = 3,
+ SpvMemorySemanticsSequentiallyConsistentShift = 4,
+ SpvMemorySemanticsUniformMemoryShift = 6,
+ SpvMemorySemanticsSubgroupMemoryShift = 7,
+ SpvMemorySemanticsWorkgroupMemoryShift = 8,
+ SpvMemorySemanticsCrossWorkgroupMemoryShift = 9,
+ SpvMemorySemanticsAtomicCounterMemoryShift = 10,
+ SpvMemorySemanticsImageMemoryShift = 11,
+ SpvMemorySemanticsMax = 0x7fffffff,
+} SpvMemorySemanticsShift;
+
+typedef enum SpvMemorySemanticsMask_ {
+ SpvMemorySemanticsMaskNone = 0,
+ SpvMemorySemanticsAcquireMask = 0x00000002,
+ SpvMemorySemanticsReleaseMask = 0x00000004,
+ SpvMemorySemanticsAcquireReleaseMask = 0x00000008,
+ SpvMemorySemanticsSequentiallyConsistentMask = 0x00000010,
+ SpvMemorySemanticsUniformMemoryMask = 0x00000040,
+ SpvMemorySemanticsSubgroupMemoryMask = 0x00000080,
+ SpvMemorySemanticsWorkgroupMemoryMask = 0x00000100,
+ SpvMemorySemanticsCrossWorkgroupMemoryMask = 0x00000200,
+ SpvMemorySemanticsAtomicCounterMemoryMask = 0x00000400,
+ SpvMemorySemanticsImageMemoryMask = 0x00000800,
+} SpvMemorySemanticsMask;
+
+typedef enum SpvMemoryAccessShift_ {
+ SpvMemoryAccessVolatileShift = 0,
+ SpvMemoryAccessAlignedShift = 1,
+ SpvMemoryAccessNontemporalShift = 2,
+ SpvMemoryAccessMax = 0x7fffffff,
+} SpvMemoryAccessShift;
+
+typedef enum SpvMemoryAccessMask_ {
+ SpvMemoryAccessMaskNone = 0,
+ SpvMemoryAccessVolatileMask = 0x00000001,
+ SpvMemoryAccessAlignedMask = 0x00000002,
+ SpvMemoryAccessNontemporalMask = 0x00000004,
+} SpvMemoryAccessMask;
+
+typedef enum SpvScope_ {
+ SpvScopeCrossDevice = 0,
+ SpvScopeDevice = 1,
+ SpvScopeWorkgroup = 2,
+ SpvScopeSubgroup = 3,
+ SpvScopeInvocation = 4,
+ SpvScopeMax = 0x7fffffff,
+} SpvScope;
+
+typedef enum SpvGroupOperation_ {
+ SpvGroupOperationReduce = 0,
+ SpvGroupOperationInclusiveScan = 1,
+ SpvGroupOperationExclusiveScan = 2,
+ SpvGroupOperationClusteredReduce = 3,
+ SpvGroupOperationPartitionedReduceNV = 6,
+ SpvGroupOperationPartitionedInclusiveScanNV = 7,
+ SpvGroupOperationPartitionedExclusiveScanNV = 8,
+ SpvGroupOperationMax = 0x7fffffff,
+} SpvGroupOperation;
+
+typedef enum SpvKernelEnqueueFlags_ {
+ SpvKernelEnqueueFlagsNoWait = 0,
+ SpvKernelEnqueueFlagsWaitKernel = 1,
+ SpvKernelEnqueueFlagsWaitWorkGroup = 2,
+ SpvKernelEnqueueFlagsMax = 0x7fffffff,
+} SpvKernelEnqueueFlags;
+
+typedef enum SpvKernelProfilingInfoShift_ {
+ SpvKernelProfilingInfoCmdExecTimeShift = 0,
+ SpvKernelProfilingInfoMax = 0x7fffffff,
+} SpvKernelProfilingInfoShift;
+
+typedef enum SpvKernelProfilingInfoMask_ {
+ SpvKernelProfilingInfoMaskNone = 0,
+ SpvKernelProfilingInfoCmdExecTimeMask = 0x00000001,
+} SpvKernelProfilingInfoMask;
+
+typedef enum SpvCapability_ {
+ SpvCapabilityMatrix = 0,
+ SpvCapabilityShader = 1,
+ SpvCapabilityGeometry = 2,
+ SpvCapabilityTessellation = 3,
+ SpvCapabilityAddresses = 4,
+ SpvCapabilityLinkage = 5,
+ SpvCapabilityKernel = 6,
+ SpvCapabilityVector16 = 7,
+ SpvCapabilityFloat16Buffer = 8,
+ SpvCapabilityFloat16 = 9,
+ SpvCapabilityFloat64 = 10,
+ SpvCapabilityInt64 = 11,
+ SpvCapabilityInt64Atomics = 12,
+ SpvCapabilityImageBasic = 13,
+ SpvCapabilityImageReadWrite = 14,
+ SpvCapabilityImageMipmap = 15,
+ SpvCapabilityPipes = 17,
+ SpvCapabilityGroups = 18,
+ SpvCapabilityDeviceEnqueue = 19,
+ SpvCapabilityLiteralSampler = 20,
+ SpvCapabilityAtomicStorage = 21,
+ SpvCapabilityInt16 = 22,
+ SpvCapabilityTessellationPointSize = 23,
+ SpvCapabilityGeometryPointSize = 24,
+ SpvCapabilityImageGatherExtended = 25,
+ SpvCapabilityStorageImageMultisample = 27,
+ SpvCapabilityUniformBufferArrayDynamicIndexing = 28,
+ SpvCapabilitySampledImageArrayDynamicIndexing = 29,
+ SpvCapabilityStorageBufferArrayDynamicIndexing = 30,
+ SpvCapabilityStorageImageArrayDynamicIndexing = 31,
+ SpvCapabilityClipDistance = 32,
+ SpvCapabilityCullDistance = 33,
+ SpvCapabilityImageCubeArray = 34,
+ SpvCapabilitySampleRateShading = 35,
+ SpvCapabilityImageRect = 36,
+ SpvCapabilitySampledRect = 37,
+ SpvCapabilityGenericPointer = 38,
+ SpvCapabilityInt8 = 39,
+ SpvCapabilityInputAttachment = 40,
+ SpvCapabilitySparseResidency = 41,
+ SpvCapabilityMinLod = 42,
+ SpvCapabilitySampled1D = 43,
+ SpvCapabilityImage1D = 44,
+ SpvCapabilitySampledCubeArray = 45,
+ SpvCapabilitySampledBuffer = 46,
+ SpvCapabilityImageBuffer = 47,
+ SpvCapabilityImageMSArray = 48,
+ SpvCapabilityStorageImageExtendedFormats = 49,
+ SpvCapabilityImageQuery = 50,
+ SpvCapabilityDerivativeControl = 51,
+ SpvCapabilityInterpolationFunction = 52,
+ SpvCapabilityTransformFeedback = 53,
+ SpvCapabilityGeometryStreams = 54,
+ SpvCapabilityStorageImageReadWithoutFormat = 55,
+ SpvCapabilityStorageImageWriteWithoutFormat = 56,
+ SpvCapabilityMultiViewport = 57,
+ SpvCapabilitySubgroupDispatch = 58,
+ SpvCapabilityNamedBarrier = 59,
+ SpvCapabilityPipeStorage = 60,
+ SpvCapabilityGroupNonUniform = 61,
+ SpvCapabilityGroupNonUniformVote = 62,
+ SpvCapabilityGroupNonUniformArithmetic = 63,
+ SpvCapabilityGroupNonUniformBallot = 64,
+ SpvCapabilityGroupNonUniformShuffle = 65,
+ SpvCapabilityGroupNonUniformShuffleRelative = 66,
+ SpvCapabilityGroupNonUniformClustered = 67,
+ SpvCapabilityGroupNonUniformQuad = 68,
+ SpvCapabilitySubgroupBallotKHR = 4423,
+ SpvCapabilityDrawParameters = 4427,
+ SpvCapabilitySubgroupVoteKHR = 4431,
+ SpvCapabilityStorageBuffer16BitAccess = 4433,
+ SpvCapabilityStorageUniformBufferBlock16 = 4433,
+ SpvCapabilityStorageUniform16 = 4434,
+ SpvCapabilityUniformAndStorageBuffer16BitAccess = 4434,
+ SpvCapabilityStoragePushConstant16 = 4435,
+ SpvCapabilityStorageInputOutput16 = 4436,
+ SpvCapabilityDeviceGroup = 4437,
+ SpvCapabilityMultiView = 4439,
+ SpvCapabilityVariablePointersStorageBuffer = 4441,
+ SpvCapabilityVariablePointers = 4442,
+ SpvCapabilityAtomicStorageOps = 4445,
+ SpvCapabilitySampleMaskPostDepthCoverage = 4447,
+ SpvCapabilityFloat16ImageAMD = 5008,
+ SpvCapabilityImageGatherBiasLodAMD = 5009,
+ SpvCapabilityFragmentMaskAMD = 5010,
+ SpvCapabilityStencilExportEXT = 5013,
+ SpvCapabilityImageReadWriteLodAMD = 5015,
+ SpvCapabilitySampleMaskOverrideCoverageNV = 5249,
+ SpvCapabilityGeometryShaderPassthroughNV = 5251,
+ SpvCapabilityShaderViewportIndexLayerEXT = 5254,
+ SpvCapabilityShaderViewportIndexLayerNV = 5254,
+ SpvCapabilityShaderViewportMaskNV = 5255,
+ SpvCapabilityShaderStereoViewNV = 5259,
+ SpvCapabilityPerViewAttributesNV = 5260,
+ SpvCapabilityFragmentFullyCoveredEXT = 5265,
+ SpvCapabilityGroupNonUniformPartitionedNV = 5297,
+ SpvCapabilitySubgroupShuffleINTEL = 5568,
+ SpvCapabilitySubgroupBufferBlockIOINTEL = 5569,
+ SpvCapabilitySubgroupImageBlockIOINTEL = 5570,
+ SpvCapabilityMax = 0x7fffffff,
+} SpvCapability;
+
+typedef enum SpvOp_ {
+ SpvOpNop = 0,
+ SpvOpUndef = 1,
+ SpvOpSourceContinued = 2,
+ SpvOpSource = 3,
+ SpvOpSourceExtension = 4,
+ SpvOpName = 5,
+ SpvOpMemberName = 6,
+ SpvOpString = 7,
+ SpvOpLine = 8,
+ SpvOpExtension = 10,
+ SpvOpExtInstImport = 11,
+ SpvOpExtInst = 12,
+ SpvOpMemoryModel = 14,
+ SpvOpEntryPoint = 15,
+ SpvOpExecutionMode = 16,
+ SpvOpCapability = 17,
+ SpvOpTypeVoid = 19,
+ SpvOpTypeBool = 20,
+ SpvOpTypeInt = 21,
+ SpvOpTypeFloat = 22,
+ SpvOpTypeVector = 23,
+ SpvOpTypeMatrix = 24,
+ SpvOpTypeImage = 25,
+ SpvOpTypeSampler = 26,
+ SpvOpTypeSampledImage = 27,
+ SpvOpTypeArray = 28,
+ SpvOpTypeRuntimeArray = 29,
+ SpvOpTypeStruct = 30,
+ SpvOpTypeOpaque = 31,
+ SpvOpTypePointer = 32,
+ SpvOpTypeFunction = 33,
+ SpvOpTypeEvent = 34,
+ SpvOpTypeDeviceEvent = 35,
+ SpvOpTypeReserveId = 36,
+ SpvOpTypeQueue = 37,
+ SpvOpTypePipe = 38,
+ SpvOpTypeForwardPointer = 39,
+ SpvOpConstantTrue = 41,
+ SpvOpConstantFalse = 42,
+ SpvOpConstant = 43,
+ SpvOpConstantComposite = 44,
+ SpvOpConstantSampler = 45,
+ SpvOpConstantNull = 46,
+ SpvOpSpecConstantTrue = 48,
+ SpvOpSpecConstantFalse = 49,
+ SpvOpSpecConstant = 50,
+ SpvOpSpecConstantComposite = 51,
+ SpvOpSpecConstantOp = 52,
+ SpvOpFunction = 54,
+ SpvOpFunctionParameter = 55,
+ SpvOpFunctionEnd = 56,
+ SpvOpFunctionCall = 57,
+ SpvOpVariable = 59,
+ SpvOpImageTexelPointer = 60,
+ SpvOpLoad = 61,
+ SpvOpStore = 62,
+ SpvOpCopyMemory = 63,
+ SpvOpCopyMemorySized = 64,
+ SpvOpAccessChain = 65,
+ SpvOpInBoundsAccessChain = 66,
+ SpvOpPtrAccessChain = 67,
+ SpvOpArrayLength = 68,
+ SpvOpGenericPtrMemSemantics = 69,
+ SpvOpInBoundsPtrAccessChain = 70,
+ SpvOpDecorate = 71,
+ SpvOpMemberDecorate = 72,
+ SpvOpDecorationGroup = 73,
+ SpvOpGroupDecorate = 74,
+ SpvOpGroupMemberDecorate = 75,
+ SpvOpVectorExtractDynamic = 77,
+ SpvOpVectorInsertDynamic = 78,
+ SpvOpVectorShuffle = 79,
+ SpvOpCompositeConstruct = 80,
+ SpvOpCompositeExtract = 81,
+ SpvOpCompositeInsert = 82,
+ SpvOpCopyObject = 83,
+ SpvOpTranspose = 84,
+ SpvOpSampledImage = 86,
+ SpvOpImageSampleImplicitLod = 87,
+ SpvOpImageSampleExplicitLod = 88,
+ SpvOpImageSampleDrefImplicitLod = 89,
+ SpvOpImageSampleDrefExplicitLod = 90,
+ SpvOpImageSampleProjImplicitLod = 91,
+ SpvOpImageSampleProjExplicitLod = 92,
+ SpvOpImageSampleProjDrefImplicitLod = 93,
+ SpvOpImageSampleProjDrefExplicitLod = 94,
+ SpvOpImageFetch = 95,
+ SpvOpImageGather = 96,
+ SpvOpImageDrefGather = 97,
+ SpvOpImageRead = 98,
+ SpvOpImageWrite = 99,
+ SpvOpImage = 100,
+ SpvOpImageQueryFormat = 101,
+ SpvOpImageQueryOrder = 102,
+ SpvOpImageQuerySizeLod = 103,
+ SpvOpImageQuerySize = 104,
+ SpvOpImageQueryLod = 105,
+ SpvOpImageQueryLevels = 106,
+ SpvOpImageQuerySamples = 107,
+ SpvOpConvertFToU = 109,
+ SpvOpConvertFToS = 110,
+ SpvOpConvertSToF = 111,
+ SpvOpConvertUToF = 112,
+ SpvOpUConvert = 113,
+ SpvOpSConvert = 114,
+ SpvOpFConvert = 115,
+ SpvOpQuantizeToF16 = 116,
+ SpvOpConvertPtrToU = 117,
+ SpvOpSatConvertSToU = 118,
+ SpvOpSatConvertUToS = 119,
+ SpvOpConvertUToPtr = 120,
+ SpvOpPtrCastToGeneric = 121,
+ SpvOpGenericCastToPtr = 122,
+ SpvOpGenericCastToPtrExplicit = 123,
+ SpvOpBitcast = 124,
+ SpvOpSNegate = 126,
+ SpvOpFNegate = 127,
+ SpvOpIAdd = 128,
+ SpvOpFAdd = 129,
+ SpvOpISub = 130,
+ SpvOpFSub = 131,
+ SpvOpIMul = 132,
+ SpvOpFMul = 133,
+ SpvOpUDiv = 134,
+ SpvOpSDiv = 135,
+ SpvOpFDiv = 136,
+ SpvOpUMod = 137,
+ SpvOpSRem = 138,
+ SpvOpSMod = 139,
+ SpvOpFRem = 140,
+ SpvOpFMod = 141,
+ SpvOpVectorTimesScalar = 142,
+ SpvOpMatrixTimesScalar = 143,
+ SpvOpVectorTimesMatrix = 144,
+ SpvOpMatrixTimesVector = 145,
+ SpvOpMatrixTimesMatrix = 146,
+ SpvOpOuterProduct = 147,
+ SpvOpDot = 148,
+ SpvOpIAddCarry = 149,
+ SpvOpISubBorrow = 150,
+ SpvOpUMulExtended = 151,
+ SpvOpSMulExtended = 152,
+ SpvOpAny = 154,
+ SpvOpAll = 155,
+ SpvOpIsNan = 156,
+ SpvOpIsInf = 157,
+ SpvOpIsFinite = 158,
+ SpvOpIsNormal = 159,
+ SpvOpSignBitSet = 160,
+ SpvOpLessOrGreater = 161,
+ SpvOpOrdered = 162,
+ SpvOpUnordered = 163,
+ SpvOpLogicalEqual = 164,
+ SpvOpLogicalNotEqual = 165,
+ SpvOpLogicalOr = 166,
+ SpvOpLogicalAnd = 167,
+ SpvOpLogicalNot = 168,
+ SpvOpSelect = 169,
+ SpvOpIEqual = 170,
+ SpvOpINotEqual = 171,
+ SpvOpUGreaterThan = 172,
+ SpvOpSGreaterThan = 173,
+ SpvOpUGreaterThanEqual = 174,
+ SpvOpSGreaterThanEqual = 175,
+ SpvOpULessThan = 176,
+ SpvOpSLessThan = 177,
+ SpvOpULessThanEqual = 178,
+ SpvOpSLessThanEqual = 179,
+ SpvOpFOrdEqual = 180,
+ SpvOpFUnordEqual = 181,
+ SpvOpFOrdNotEqual = 182,
+ SpvOpFUnordNotEqual = 183,
+ SpvOpFOrdLessThan = 184,
+ SpvOpFUnordLessThan = 185,
+ SpvOpFOrdGreaterThan = 186,
+ SpvOpFUnordGreaterThan = 187,
+ SpvOpFOrdLessThanEqual = 188,
+ SpvOpFUnordLessThanEqual = 189,
+ SpvOpFOrdGreaterThanEqual = 190,
+ SpvOpFUnordGreaterThanEqual = 191,
+ SpvOpShiftRightLogical = 194,
+ SpvOpShiftRightArithmetic = 195,
+ SpvOpShiftLeftLogical = 196,
+ SpvOpBitwiseOr = 197,
+ SpvOpBitwiseXor = 198,
+ SpvOpBitwiseAnd = 199,
+ SpvOpNot = 200,
+ SpvOpBitFieldInsert = 201,
+ SpvOpBitFieldSExtract = 202,
+ SpvOpBitFieldUExtract = 203,
+ SpvOpBitReverse = 204,
+ SpvOpBitCount = 205,
+ SpvOpDPdx = 207,
+ SpvOpDPdy = 208,
+ SpvOpFwidth = 209,
+ SpvOpDPdxFine = 210,
+ SpvOpDPdyFine = 211,
+ SpvOpFwidthFine = 212,
+ SpvOpDPdxCoarse = 213,
+ SpvOpDPdyCoarse = 214,
+ SpvOpFwidthCoarse = 215,
+ SpvOpEmitVertex = 218,
+ SpvOpEndPrimitive = 219,
+ SpvOpEmitStreamVertex = 220,
+ SpvOpEndStreamPrimitive = 221,
+ SpvOpControlBarrier = 224,
+ SpvOpMemoryBarrier = 225,
+ SpvOpAtomicLoad = 227,
+ SpvOpAtomicStore = 228,
+ SpvOpAtomicExchange = 229,
+ SpvOpAtomicCompareExchange = 230,
+ SpvOpAtomicCompareExchangeWeak = 231,
+ SpvOpAtomicIIncrement = 232,
+ SpvOpAtomicIDecrement = 233,
+ SpvOpAtomicIAdd = 234,
+ SpvOpAtomicISub = 235,
+ SpvOpAtomicSMin = 236,
+ SpvOpAtomicUMin = 237,
+ SpvOpAtomicSMax = 238,
+ SpvOpAtomicUMax = 239,
+ SpvOpAtomicAnd = 240,
+ SpvOpAtomicOr = 241,
+ SpvOpAtomicXor = 242,
+ SpvOpPhi = 245,
+ SpvOpLoopMerge = 246,
+ SpvOpSelectionMerge = 247,
+ SpvOpLabel = 248,
+ SpvOpBranch = 249,
+ SpvOpBranchConditional = 250,
+ SpvOpSwitch = 251,
+ SpvOpKill = 252,
+ SpvOpReturn = 253,
+ SpvOpReturnValue = 254,
+ SpvOpUnreachable = 255,
+ SpvOpLifetimeStart = 256,
+ SpvOpLifetimeStop = 257,
+ SpvOpGroupAsyncCopy = 259,
+ SpvOpGroupWaitEvents = 260,
+ SpvOpGroupAll = 261,
+ SpvOpGroupAny = 262,
+ SpvOpGroupBroadcast = 263,
+ SpvOpGroupIAdd = 264,
+ SpvOpGroupFAdd = 265,
+ SpvOpGroupFMin = 266,
+ SpvOpGroupUMin = 267,
+ SpvOpGroupSMin = 268,
+ SpvOpGroupFMax = 269,
+ SpvOpGroupUMax = 270,
+ SpvOpGroupSMax = 271,
+ SpvOpReadPipe = 274,
+ SpvOpWritePipe = 275,
+ SpvOpReservedReadPipe = 276,
+ SpvOpReservedWritePipe = 277,
+ SpvOpReserveReadPipePackets = 278,
+ SpvOpReserveWritePipePackets = 279,
+ SpvOpCommitReadPipe = 280,
+ SpvOpCommitWritePipe = 281,
+ SpvOpIsValidReserveId = 282,
+ SpvOpGetNumPipePackets = 283,
+ SpvOpGetMaxPipePackets = 284,
+ SpvOpGroupReserveReadPipePackets = 285,
+ SpvOpGroupReserveWritePipePackets = 286,
+ SpvOpGroupCommitReadPipe = 287,
+ SpvOpGroupCommitWritePipe = 288,
+ SpvOpEnqueueMarker = 291,
+ SpvOpEnqueueKernel = 292,
+ SpvOpGetKernelNDrangeSubGroupCount = 293,
+ SpvOpGetKernelNDrangeMaxSubGroupSize = 294,
+ SpvOpGetKernelWorkGroupSize = 295,
+ SpvOpGetKernelPreferredWorkGroupSizeMultiple = 296,
+ SpvOpRetainEvent = 297,
+ SpvOpReleaseEvent = 298,
+ SpvOpCreateUserEvent = 299,
+ SpvOpIsValidEvent = 300,
+ SpvOpSetUserEventStatus = 301,
+ SpvOpCaptureEventProfilingInfo = 302,
+ SpvOpGetDefaultQueue = 303,
+ SpvOpBuildNDRange = 304,
+ SpvOpImageSparseSampleImplicitLod = 305,
+ SpvOpImageSparseSampleExplicitLod = 306,
+ SpvOpImageSparseSampleDrefImplicitLod = 307,
+ SpvOpImageSparseSampleDrefExplicitLod = 308,
+ SpvOpImageSparseSampleProjImplicitLod = 309,
+ SpvOpImageSparseSampleProjExplicitLod = 310,
+ SpvOpImageSparseSampleProjDrefImplicitLod = 311,
+ SpvOpImageSparseSampleProjDrefExplicitLod = 312,
+ SpvOpImageSparseFetch = 313,
+ SpvOpImageSparseGather = 314,
+ SpvOpImageSparseDrefGather = 315,
+ SpvOpImageSparseTexelsResident = 316,
+ SpvOpNoLine = 317,
+ SpvOpAtomicFlagTestAndSet = 318,
+ SpvOpAtomicFlagClear = 319,
+ SpvOpImageSparseRead = 320,
+ SpvOpSizeOf = 321,
+ SpvOpTypePipeStorage = 322,
+ SpvOpConstantPipeStorage = 323,
+ SpvOpCreatePipeFromPipeStorage = 324,
+ SpvOpGetKernelLocalSizeForSubgroupCount = 325,
+ SpvOpGetKernelMaxNumSubgroups = 326,
+ SpvOpTypeNamedBarrier = 327,
+ SpvOpNamedBarrierInitialize = 328,
+ SpvOpMemoryNamedBarrier = 329,
+ SpvOpModuleProcessed = 330,
+ SpvOpExecutionModeId = 331,
+ SpvOpDecorateId = 332,
+ SpvOpGroupNonUniformElect = 333,
+ SpvOpGroupNonUniformAll = 334,
+ SpvOpGroupNonUniformAny = 335,
+ SpvOpGroupNonUniformAllEqual = 336,
+ SpvOpGroupNonUniformBroadcast = 337,
+ SpvOpGroupNonUniformBroadcastFirst = 338,
+ SpvOpGroupNonUniformBallot = 339,
+ SpvOpGroupNonUniformInverseBallot = 340,
+ SpvOpGroupNonUniformBallotBitExtract = 341,
+ SpvOpGroupNonUniformBallotBitCount = 342,
+ SpvOpGroupNonUniformBallotFindLSB = 343,
+ SpvOpGroupNonUniformBallotFindMSB = 344,
+ SpvOpGroupNonUniformShuffle = 345,
+ SpvOpGroupNonUniformShuffleXor = 346,
+ SpvOpGroupNonUniformShuffleUp = 347,
+ SpvOpGroupNonUniformShuffleDown = 348,
+ SpvOpGroupNonUniformIAdd = 349,
+ SpvOpGroupNonUniformFAdd = 350,
+ SpvOpGroupNonUniformIMul = 351,
+ SpvOpGroupNonUniformFMul = 352,
+ SpvOpGroupNonUniformSMin = 353,
+ SpvOpGroupNonUniformUMin = 354,
+ SpvOpGroupNonUniformFMin = 355,
+ SpvOpGroupNonUniformSMax = 356,
+ SpvOpGroupNonUniformUMax = 357,
+ SpvOpGroupNonUniformFMax = 358,
+ SpvOpGroupNonUniformBitwiseAnd = 359,
+ SpvOpGroupNonUniformBitwiseOr = 360,
+ SpvOpGroupNonUniformBitwiseXor = 361,
+ SpvOpGroupNonUniformLogicalAnd = 362,
+ SpvOpGroupNonUniformLogicalOr = 363,
+ SpvOpGroupNonUniformLogicalXor = 364,
+ SpvOpGroupNonUniformQuadBroadcast = 365,
+ SpvOpGroupNonUniformQuadSwap = 366,
+ SpvOpSubgroupBallotKHR = 4421,
+ SpvOpSubgroupFirstInvocationKHR = 4422,
+ SpvOpSubgroupAllKHR = 4428,
+ SpvOpSubgroupAnyKHR = 4429,
+ SpvOpSubgroupAllEqualKHR = 4430,
+ SpvOpSubgroupReadInvocationKHR = 4432,
+ SpvOpGroupIAddNonUniformAMD = 5000,
+ SpvOpGroupFAddNonUniformAMD = 5001,
+ SpvOpGroupFMinNonUniformAMD = 5002,
+ SpvOpGroupUMinNonUniformAMD = 5003,
+ SpvOpGroupSMinNonUniformAMD = 5004,
+ SpvOpGroupFMaxNonUniformAMD = 5005,
+ SpvOpGroupUMaxNonUniformAMD = 5006,
+ SpvOpGroupSMaxNonUniformAMD = 5007,
+ SpvOpFragmentMaskFetchAMD = 5011,
+ SpvOpFragmentFetchAMD = 5012,
+ SpvOpGroupNonUniformPartitionNV = 5296,
+ SpvOpSubgroupShuffleINTEL = 5571,
+ SpvOpSubgroupShuffleDownINTEL = 5572,
+ SpvOpSubgroupShuffleUpINTEL = 5573,
+ SpvOpSubgroupShuffleXorINTEL = 5574,
+ SpvOpSubgroupBlockReadINTEL = 5575,
+ SpvOpSubgroupBlockWriteINTEL = 5576,
+ SpvOpSubgroupImageBlockReadINTEL = 5577,
+ SpvOpSubgroupImageBlockWriteINTEL = 5578,
+ SpvOpDecorateStringGOOGLE = 5632,
+ SpvOpMemberDecorateStringGOOGLE = 5633,
+ SpvOpMax = 0x7fffffff,
+} SpvOp;
+
+#endif // #ifndef spirv_H
+
diff --git a/thirdparty/spirv-reflect/spirv_reflect.c b/thirdparty/spirv-reflect/spirv_reflect.c
new file mode 100644
index 0000000000..3df963d1ae
--- /dev/null
+++ b/thirdparty/spirv-reflect/spirv_reflect.c
@@ -0,0 +1,4442 @@
+/*
+ Copyright 2017-2018 Google Inc.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+#include "spirv_reflect.h"
+#include <assert.h>
+#include <stdbool.h>
+#include <string.h>
+
+#if defined(WIN32)
+ #define _CRTDBG_MAP_ALLOC
+ #include <stdlib.h>
+ #include <crtdbg.h>
+#else
+ #include <stdlib.h>
+#endif
+
+// Temporary enums until these make it into SPIR-V/Vulkan
+// clang-format off
+enum {
+ SpvReflectOpDecorateId = 332,
+ SpvReflectOpDecorateStringGOOGLE = 5632,
+ SpvReflectOpMemberDecorateStringGOOGLE = 5633,
+ SpvReflectDecorationHlslCounterBufferGOOGLE = 5634,
+ SpvReflectDecorationHlslSemanticGOOGLE = 5635
+};
+// clang-format on
+
+// clang-format off
+enum {
+ SPIRV_STARTING_WORD_INDEX = 5,
+ SPIRV_WORD_SIZE = sizeof(uint32_t),
+ SPIRV_BYTE_WIDTH = 8,
+ SPIRV_MINIMUM_FILE_SIZE = SPIRV_STARTING_WORD_INDEX * SPIRV_WORD_SIZE,
+ SPIRV_DATA_ALIGNMENT = 4 * SPIRV_WORD_SIZE, // 16
+ SPIRV_ACCESS_CHAIN_INDEX_OFFSET = 4,
+};
+// clang-format on
+
+// clang-format off
+enum {
+ INVALID_VALUE = 0xFFFFFFFF,
+};
+// clang-format on
+
+// clang-format off
+enum {
+ MAX_NODE_NAME_LENGTH = 1024,
+};
+// clang-format on
+
+// clang-format off
+enum {
+ IMAGE_SAMPLED = 1,
+ IMAGE_STORAGE = 2
+};
+// clang-format on
+
+// clang-format off
+typedef struct ArrayTraits {
+ uint32_t element_type_id;
+ uint32_t length_id;
+} ArrayTraits;
+// clang-format on
+
+// clang-format off
+typedef struct ImageTraits {
+ uint32_t sampled_type_id;
+ SpvDim dim;
+ uint32_t depth;
+ uint32_t arrayed;
+ uint32_t ms;
+ uint32_t sampled;
+ SpvImageFormat image_format;
+} ImageTraits;
+// clang-format on
+
+// clang-format off
+typedef struct NumberDecoration {
+ uint32_t word_offset;
+ uint32_t value;
+} NumberDecoration;
+// clang-format on
+
+// clang-format off
+typedef struct StringDecoration {
+ uint32_t word_offset;
+ const char* value;
+} StringDecoration;
+// clang-format on
+
+// clang-format off
+typedef struct Decorations {
+ bool is_block;
+ bool is_buffer_block;
+ bool is_row_major;
+ bool is_column_major;
+ bool is_built_in;
+ bool is_noperspective;
+ bool is_flat;
+ bool is_non_writable;
+ NumberDecoration set;
+ NumberDecoration binding;
+ NumberDecoration input_attachment_index;
+ NumberDecoration location;
+ NumberDecoration offset;
+ NumberDecoration uav_counter_buffer;
+ StringDecoration semantic;
+ uint32_t array_stride;
+ uint32_t matrix_stride;
+ SpvBuiltIn built_in;
+} Decorations;
+// clang-format on
+
+// clang-format off
+typedef struct Node {
+ uint32_t result_id;
+ SpvOp op;
+ uint32_t result_type_id;
+ uint32_t type_id;
+ SpvStorageClass storage_class;
+ uint32_t word_offset;
+ uint32_t word_count;
+ bool is_type;
+
+ ArrayTraits array_traits;
+ ImageTraits image_traits;
+ uint32_t image_type_id;
+
+ const char* name;
+ Decorations decorations;
+ uint32_t member_count;
+ const char** member_names;
+ Decorations* member_decorations;
+} Node;
+// clang-format on
+
+// clang-format off
+typedef struct String {
+ uint32_t result_id;
+ const char* string;
+} String;
+// clang-format on
+
+// clang-format off
+typedef struct Function {
+ uint32_t id;
+ uint32_t callee_count;
+ uint32_t* callees;
+ struct Function** callee_ptrs;
+ uint32_t accessed_ptr_count;
+ uint32_t* accessed_ptrs;
+} Function;
+// clang-format on
+
+// clang-format off
+typedef struct AccessChain {
+ uint32_t result_id;
+ uint32_t result_type_id;
+ //
+ // Pointing to the base of a composite object.
+ // Generally the id of descriptor block variable
+ uint32_t base_id;
+ //
+ // From spec:
+ // The first index in Indexes will select the
+ // top-level member/element/component/element
+ // of the base composite
+ uint32_t index_count;
+ uint32_t* indexes;
+} AccessChain;
+// clang-format on
+
+// clang-format off
+typedef struct Parser {
+ size_t spirv_word_count;
+ uint32_t* spirv_code;
+ uint32_t string_count;
+ String* strings;
+ SpvSourceLanguage source_language;
+ uint32_t source_language_version;
+ uint32_t source_file_id;
+ String source_embedded;
+ size_t node_count;
+ Node* nodes;
+ uint32_t entry_point_count;
+ uint32_t function_count;
+ Function* functions;
+ uint32_t access_chain_count;
+ AccessChain* access_chains;
+
+ uint32_t type_count;
+ uint32_t descriptor_count;
+ uint32_t push_constant_count;
+} Parser;
+// clang-format on
+
+static uint32_t Max(uint32_t a, uint32_t b)
+{
+ return a > b ? a : b;
+}
+
+static uint32_t RoundUp(uint32_t value, uint32_t multiple)
+{
+ assert(multiple && ((multiple & (multiple - 1)) == 0));
+ return (value + multiple - 1) & ~(multiple - 1);
+}
+
+#define IsNull(ptr) \
+ (ptr == NULL)
+
+#define IsNotNull(ptr) \
+ (ptr != NULL)
+
+#define SafeFree(ptr) \
+ { \
+ if (ptr != NULL) { \
+ free((void*)ptr); \
+ ptr = NULL; \
+ } \
+ }
+
+static int SortCompareUint32(const void* a, const void* b)
+{
+ const uint32_t* p_a = (const uint32_t*)a;
+ const uint32_t* p_b = (const uint32_t*)b;
+
+ return (int)*p_a - (int)*p_b;
+}
+
+//
+// De-duplicates a sorted array and returns the new size.
+//
+// Note: The array doesn't actually need to be sorted, just
+// arranged into "runs" so that all the entries with one
+// value are adjacent.
+//
+static size_t DedupSortedUint32(uint32_t* arr, size_t size)
+{
+ if (size == 0) {
+ return 0;
+ }
+ size_t dedup_idx = 0;
+ for (size_t i = 0; i < size; ++i) {
+ if (arr[dedup_idx] != arr[i]) {
+ ++dedup_idx;
+ arr[dedup_idx] = arr[i];
+ }
+ }
+ return dedup_idx+1;
+}
+
+static bool SearchSortedUint32(const uint32_t* arr, size_t size, uint32_t target)
+{
+ size_t lo = 0;
+ size_t hi = size;
+ while (lo < hi) {
+ size_t mid = (hi - lo) / 2 + lo;
+ if (arr[mid] == target) {
+ return true;
+ } else if (arr[mid] < target) {
+ lo = mid+1;
+ } else {
+ hi = mid;
+ }
+ }
+ return false;
+}
+
+static SpvReflectResult IntersectSortedUint32(
+ const uint32_t* p_arr0,
+ size_t arr0_size,
+ const uint32_t* p_arr1,
+ size_t arr1_size,
+ uint32_t** pp_res,
+ size_t* res_size
+)
+{
+ *res_size = 0;
+ const uint32_t* arr0_end = p_arr0 + arr0_size;
+ const uint32_t* arr1_end = p_arr1 + arr1_size;
+
+ const uint32_t* idx0 = p_arr0;
+ const uint32_t* idx1 = p_arr1;
+ while (idx0 != arr0_end && idx1 != arr1_end) {
+ if (*idx0 < *idx1) {
+ ++idx0;
+ } else if (*idx0 > *idx1) {
+ ++idx1;
+ } else {
+ ++*res_size;
+ ++idx0;
+ ++idx1;
+ }
+ }
+
+ *pp_res = NULL;
+ if (*res_size > 0) {
+ *pp_res = (uint32_t*)calloc(*res_size, sizeof(**pp_res));
+ if (IsNull(*pp_res)) {
+ return SPV_REFLECT_RESULT_ERROR_ALLOC_FAILED;
+ }
+ uint32_t* idxr = *pp_res;
+ idx0 = p_arr0;
+ idx1 = p_arr1;
+ while (idx0 != arr0_end && idx1 != arr1_end) {
+ if (*idx0 < *idx1) {
+ ++idx0;
+ } else if (*idx0 > *idx1) {
+ ++idx1;
+ } else {
+ *(idxr++) = *idx0;
+ ++idx0;
+ ++idx1;
+ }
+ }
+ }
+ return SPV_REFLECT_RESULT_SUCCESS;
+}
+
+
+static bool InRange(const Parser* p_parser, uint32_t index)
+{
+ bool in_range = false;
+ if (IsNotNull(p_parser)) {
+ in_range = (index < p_parser->spirv_word_count);
+ }
+ return in_range;
+}
+
+static SpvReflectResult ReadU32(Parser* p_parser, uint32_t word_offset, uint32_t* p_value)
+{
+ assert(IsNotNull(p_parser));
+ assert(IsNotNull(p_parser->spirv_code));
+ assert(InRange(p_parser, word_offset));
+ SpvReflectResult result = SPV_REFLECT_RESULT_ERROR_SPIRV_UNEXPECTED_EOF;
+ if (IsNotNull(p_parser) && IsNotNull(p_parser->spirv_code) && InRange(p_parser, word_offset)) {
+ *p_value = *(p_parser->spirv_code + word_offset);
+ result = SPV_REFLECT_RESULT_SUCCESS;
+ }
+ return result;
+}
+
+#define CHECKED_READU32(parser, word_offset, value) \
+ { \
+ SpvReflectResult checked_readu32_result = ReadU32(parser, \
+ word_offset, (uint32_t*)&(value)); \
+ if (checked_readu32_result != SPV_REFLECT_RESULT_SUCCESS) { \
+ return checked_readu32_result; \
+ } \
+ }
+
+#define CHECKED_READU32_CAST(parser, word_offset, cast_to_type, value) \
+ { \
+ uint32_t checked_readu32_cast_u32 = UINT32_MAX; \
+ SpvReflectResult checked_readu32_cast_result = ReadU32(parser, \
+ word_offset, \
+ (uint32_t*)&(checked_readu32_cast_u32)); \
+ if (checked_readu32_cast_result != SPV_REFLECT_RESULT_SUCCESS) { \
+ return checked_readu32_cast_result; \
+ } \
+ value = (cast_to_type)checked_readu32_cast_u32; \
+ }
+
+#define IF_READU32(result, parser, word_offset, value) \
+ if ((result) == SPV_REFLECT_RESULT_SUCCESS) { \
+ result = ReadU32(parser, word_offset, (uint32_t*)&(value)); \
+ }
+
+#define IF_READU32_CAST(result, parser, word_offset, cast_to_type, value) \
+ if ((result) == SPV_REFLECT_RESULT_SUCCESS) { \
+ uint32_t if_readu32_cast_u32 = UINT32_MAX; \
+ result = ReadU32(parser, word_offset, &if_readu32_cast_u32); \
+ if ((result) == SPV_REFLECT_RESULT_SUCCESS) { \
+ value = (cast_to_type)if_readu32_cast_u32; \
+ } \
+ }
+
+static SpvReflectResult ReadStr(
+ Parser* p_parser,
+ uint32_t word_offset,
+ uint32_t word_index,
+ uint32_t word_count,
+ uint32_t* p_buf_size,
+ char* p_buf
+)
+{
+ uint32_t limit = (word_offset + word_count);
+ assert(IsNotNull(p_parser));
+ assert(IsNotNull(p_parser->spirv_code));
+ assert(InRange(p_parser, limit));
+ SpvReflectResult result = SPV_REFLECT_RESULT_ERROR_SPIRV_UNEXPECTED_EOF;
+ if (IsNotNull(p_parser) && IsNotNull(p_parser->spirv_code) && InRange(p_parser, limit)) {
+ const char* c_str = (const char*)(p_parser->spirv_code + word_offset + word_index);
+ uint32_t n = word_count * SPIRV_WORD_SIZE;
+ uint32_t length_with_terminator = 0;
+ for (uint32_t i = 0; i < n; ++i) {
+ char c = *(c_str + i);
+ if (c == 0) {
+ length_with_terminator = i + 1;
+ break;
+ }
+ }
+
+ if (length_with_terminator > 0) {
+ result = SPV_REFLECT_RESULT_ERROR_NULL_POINTER;
+ if (IsNotNull(p_buf_size) && IsNotNull(p_buf)) {
+ result = SPV_REFLECT_RESULT_ERROR_RANGE_EXCEEDED;
+ if (length_with_terminator <= *p_buf_size) {
+ memset(p_buf, 0, *p_buf_size);
+ memcpy(p_buf, c_str, length_with_terminator);
+ result = SPV_REFLECT_RESULT_SUCCESS;
+ }
+ }
+ else {
+ if (IsNotNull(p_buf_size)) {
+ *p_buf_size = length_with_terminator;
+ result = SPV_REFLECT_RESULT_SUCCESS;
+ }
+ }
+ }
+ }
+ return result;
+}
+
+static SpvReflectDecorationFlags ApplyDecorations(const Decorations* p_decoration_fields)
+{
+ SpvReflectDecorationFlags decorations = SPV_REFLECT_DECORATION_NONE;
+ if (p_decoration_fields->is_block) {
+ decorations |= SPV_REFLECT_DECORATION_BLOCK;
+ }
+ if (p_decoration_fields->is_buffer_block) {
+ decorations |= SPV_REFLECT_DECORATION_BUFFER_BLOCK;
+ }
+ if (p_decoration_fields->is_row_major) {
+ decorations |= SPV_REFLECT_DECORATION_ROW_MAJOR;
+ }
+ if (p_decoration_fields->is_column_major) {
+ decorations |= SPV_REFLECT_DECORATION_COLUMN_MAJOR;
+ }
+ if (p_decoration_fields->is_built_in) {
+ decorations |= SPV_REFLECT_DECORATION_BUILT_IN;
+ }
+ if (p_decoration_fields->is_noperspective) {
+ decorations |= SPV_REFLECT_DECORATION_NOPERSPECTIVE;
+ }
+ if (p_decoration_fields->is_flat) {
+ decorations |= SPV_REFLECT_DECORATION_FLAT;
+ }
+ if (p_decoration_fields->is_non_writable) {
+ decorations |= SPV_REFLECT_DECORATION_NON_WRITABLE;
+ }
+ return decorations;
+}
+
+static void ApplyNumericTraits(const SpvReflectTypeDescription* p_type, SpvReflectNumericTraits* p_numeric_traits)
+{
+ memcpy(p_numeric_traits, &p_type->traits.numeric, sizeof(p_type->traits.numeric));
+}
+
+static void ApplyArrayTraits(const SpvReflectTypeDescription* p_type, SpvReflectArrayTraits* p_array_traits)
+{
+ memcpy(p_array_traits, &p_type->traits.array, sizeof(p_type->traits.array));
+}
+
+static Node* FindNode(Parser* p_parser, uint32_t result_id)
+{
+ Node* p_node = NULL;
+ for (size_t i = 0; i < p_parser->node_count; ++i) {
+ Node* p_elem = &(p_parser->nodes[i]);
+ if (p_elem->result_id == result_id) {
+ p_node = p_elem;
+ break;
+ }
+ }
+ return p_node;
+}
+
+static SpvReflectTypeDescription* FindType(SpvReflectShaderModule* p_module, uint32_t type_id)
+{
+ SpvReflectTypeDescription* p_type = NULL;
+ for (size_t i = 0; i < p_module->_internal->type_description_count; ++i) {
+ SpvReflectTypeDescription* p_elem = &(p_module->_internal->type_descriptions[i]);
+ if (p_elem->id == type_id) {
+ p_type = p_elem;
+ break;
+ }
+ }
+ return p_type;
+}
+
+static SpvReflectResult CreateParser(size_t size, void* p_code, Parser* p_parser)
+{
+ if (p_code == NULL) {
+ return SPV_REFLECT_RESULT_ERROR_NULL_POINTER;
+ }
+
+ if (size < SPIRV_MINIMUM_FILE_SIZE) {
+ return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_CODE_SIZE;
+ }
+ if ((size % 4) != 0) {
+ return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_CODE_SIZE;
+ }
+
+ p_parser->spirv_word_count = size / SPIRV_WORD_SIZE;
+ p_parser->spirv_code = (uint32_t*)p_code;
+
+ if (p_parser->spirv_code[0] != SpvMagicNumber) {
+ return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_MAGIC_NUMBER;
+ }
+
+ return SPV_REFLECT_RESULT_SUCCESS;
+}
+
+static void DestroyParser(Parser* p_parser)
+{
+ if (!IsNull(p_parser->nodes)) {
+ // Free nodes
+ for (size_t i = 0; i < p_parser->node_count; ++i) {
+ Node* p_node = &(p_parser->nodes[i]);
+ if (IsNotNull(p_node->member_names)) {
+ SafeFree(p_node->member_names);
+ }
+ if (IsNotNull(p_node->member_decorations)) {
+ SafeFree(p_node->member_decorations);
+ }
+ }
+
+ // Free functions
+ for (size_t i = 0; i < p_parser->function_count; ++i) {
+ SafeFree(p_parser->functions[i].callees);
+ SafeFree(p_parser->functions[i].callee_ptrs);
+ SafeFree(p_parser->functions[i].accessed_ptrs);
+ }
+
+ // Free access chains
+ for (uint32_t i = 0; i < p_parser->access_chain_count; ++i) {
+ SafeFree(p_parser->access_chains[i].indexes);
+ }
+
+ SafeFree(p_parser->nodes);
+ SafeFree(p_parser->strings);
+ SafeFree(p_parser->functions);
+ SafeFree(p_parser->access_chains);
+ p_parser->node_count = 0;
+ }
+}
+
+static SpvReflectResult ParseNodes(Parser* p_parser)
+{
+ assert(IsNotNull(p_parser));
+ assert(IsNotNull(p_parser->spirv_code));
+
+ uint32_t* p_spirv = p_parser->spirv_code;
+ uint32_t spirv_word_index = SPIRV_STARTING_WORD_INDEX;
+
+ // Count nodes
+ uint32_t node_count = 0;
+ while (spirv_word_index < p_parser->spirv_word_count) {
+ uint32_t word = p_spirv[spirv_word_index];
+ SpvOp op = (SpvOp)(word & 0xFFFF);
+ uint32_t node_word_count = (word >> 16) & 0xFFFF;
+ if (node_word_count == 0) {
+ return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_INSTRUCTION;
+ }
+ if (op == SpvOpAccessChain) {
+ ++(p_parser->access_chain_count);
+ }
+ spirv_word_index += node_word_count;
+ ++node_count;
+ }
+
+ if (node_count == 0) {
+ return SPV_REFLECT_RESULT_ERROR_SPIRV_UNEXPECTED_EOF;
+ }
+
+ // Allocate nodes
+ p_parser->node_count = node_count;
+ p_parser->nodes = (Node*)calloc(p_parser->node_count, sizeof(*(p_parser->nodes)));
+ if (IsNull(p_parser->nodes)) {
+ return SPV_REFLECT_RESULT_ERROR_ALLOC_FAILED;
+ }
+ // Mark all nodes with an invalid state
+ for (uint32_t i = 0; i < node_count; ++i) {
+ p_parser->nodes[i].op = (SpvOp)INVALID_VALUE;
+ p_parser->nodes[i].storage_class = (SpvStorageClass)INVALID_VALUE;
+ p_parser->nodes[i].decorations.set.value = (uint32_t)INVALID_VALUE;
+ p_parser->nodes[i].decorations.binding.value = (uint32_t)INVALID_VALUE;
+ p_parser->nodes[i].decorations.location.value = (uint32_t)INVALID_VALUE;
+ p_parser->nodes[i].decorations.offset.value = (uint32_t)INVALID_VALUE;
+ p_parser->nodes[i].decorations.uav_counter_buffer.value = (uint32_t)INVALID_VALUE;
+ p_parser->nodes[i].decorations.built_in = (SpvBuiltIn)INVALID_VALUE;
+ }
+ // Mark source file id node
+ p_parser->source_file_id = (uint32_t)INVALID_VALUE;
+
+ // Function node
+ uint32_t function_node = (uint32_t)INVALID_VALUE;
+
+ // Allocate access chain
+ if (p_parser->access_chain_count > 0) {
+ p_parser->access_chains = (AccessChain*)calloc(p_parser->access_chain_count, sizeof(*(p_parser->access_chains)));
+ if (IsNull(p_parser->access_chains)) {
+ return SPV_REFLECT_RESULT_ERROR_ALLOC_FAILED;
+ }
+ }
+
+ // Parse nodes
+ uint32_t node_index = 0;
+ uint32_t access_chain_index = 0;
+ spirv_word_index = SPIRV_STARTING_WORD_INDEX;
+ while (spirv_word_index < p_parser->spirv_word_count) {
+ uint32_t word = p_spirv[spirv_word_index];
+ SpvOp op = (SpvOp)(word & 0xFFFF);
+ uint32_t node_word_count = (word >> 16) & 0xFFFF;
+
+ Node* p_node = &(p_parser->nodes[node_index]);
+ p_node->op = op;
+ p_node->word_offset = spirv_word_index;
+ p_node->word_count = node_word_count;
+
+ switch (p_node->op) {
+ default: break;
+
+ case SpvOpString: {
+ ++(p_parser->string_count);
+ }
+ break;
+
+ case SpvOpSource: {
+ CHECKED_READU32_CAST(p_parser, p_node->word_offset + 1, SpvSourceLanguage, p_parser->source_language);
+ CHECKED_READU32(p_parser, p_node->word_offset + 2, p_parser->source_language_version);
+ if (p_node->word_count >= 4) {
+ CHECKED_READU32(p_parser, p_node->word_offset + 3, p_parser->source_file_id);
+ }
+ }
+ break;
+
+ case SpvOpEntryPoint: {
+ ++(p_parser->entry_point_count);
+ }
+ break;
+
+ case SpvOpName:
+ case SpvOpMemberName:
+ {
+ uint32_t member_offset = (p_node->op == SpvOpMemberName) ? 1 : 0;
+ uint32_t name_start = p_node->word_offset + member_offset + 2;
+ p_node->name = (const char*)(p_parser->spirv_code + name_start);
+ }
+ break;
+
+ case SpvOpTypeStruct:
+ {
+ p_node->member_count = p_node->word_count - 2;
+ } // Fall through
+ case SpvOpTypeVoid:
+ case SpvOpTypeBool:
+ case SpvOpTypeInt:
+ case SpvOpTypeFloat:
+ case SpvOpTypeVector:
+ case SpvOpTypeMatrix:
+ case SpvOpTypeSampler:
+ case SpvOpTypeOpaque:
+ case SpvOpTypeFunction:
+ case SpvOpTypeEvent:
+ case SpvOpTypeDeviceEvent:
+ case SpvOpTypeReserveId:
+ case SpvOpTypeQueue:
+ case SpvOpTypePipe:
+ {
+ CHECKED_READU32(p_parser, p_node->word_offset + 1, p_node->result_id);
+ p_node->is_type = true;
+ }
+ break;
+
+ case SpvOpTypeImage: {
+ CHECKED_READU32(p_parser, p_node->word_offset + 1, p_node->result_id);
+ CHECKED_READU32(p_parser, p_node->word_offset + 2, p_node->image_traits.sampled_type_id);
+ CHECKED_READU32(p_parser, p_node->word_offset + 3, p_node->image_traits.dim);
+ CHECKED_READU32(p_parser, p_node->word_offset + 4, p_node->image_traits.depth);
+ CHECKED_READU32(p_parser, p_node->word_offset + 5, p_node->image_traits.arrayed);
+ CHECKED_READU32(p_parser, p_node->word_offset + 6, p_node->image_traits.ms);
+ CHECKED_READU32(p_parser, p_node->word_offset + 7, p_node->image_traits.sampled);
+ CHECKED_READU32(p_parser, p_node->word_offset + 8, p_node->image_traits.image_format);
+ p_node->is_type = true;
+ }
+ break;
+
+ case SpvOpTypeSampledImage: {
+ CHECKED_READU32(p_parser, p_node->word_offset + 1, p_node->result_id);
+ CHECKED_READU32(p_parser, p_node->word_offset + 2, p_node->image_type_id);
+ p_node->is_type = true;
+ }
+ break;
+
+ case SpvOpTypeArray: {
+ CHECKED_READU32(p_parser, p_node->word_offset + 1, p_node->result_id);
+ CHECKED_READU32(p_parser, p_node->word_offset + 2, p_node->array_traits.element_type_id);
+ CHECKED_READU32(p_parser, p_node->word_offset + 3, p_node->array_traits.length_id);
+ p_node->is_type = true;
+ }
+ break;
+
+ case SpvOpTypeRuntimeArray: {
+ CHECKED_READU32(p_parser, p_node->word_offset + 1, p_node->result_id);
+ CHECKED_READU32(p_parser, p_node->word_offset + 2, p_node->array_traits.element_type_id);
+ p_node->is_type = true;
+ }
+ break;
+
+ case SpvOpTypePointer: {
+ CHECKED_READU32(p_parser, p_node->word_offset + 1, p_node->result_id);
+ CHECKED_READU32(p_parser, p_node->word_offset + 2, p_node->storage_class);
+ CHECKED_READU32(p_parser, p_node->word_offset + 3, p_node->type_id);
+ p_node->is_type = true;
+ }
+ break;
+
+ case SpvOpTypeForwardPointer:
+ {
+ CHECKED_READU32(p_parser, p_node->word_offset + 1, p_node->result_id);
+ CHECKED_READU32(p_parser, p_node->word_offset + 2, p_node->storage_class);
+ p_node->is_type = true;
+ }
+ break;
+
+ case SpvOpConstantTrue:
+ case SpvOpConstantFalse:
+ case SpvOpConstant:
+ case SpvOpConstantComposite:
+ case SpvOpConstantSampler:
+ case SpvOpConstantNull: {
+ CHECKED_READU32(p_parser, p_node->word_offset + 1, p_node->result_type_id);
+ CHECKED_READU32(p_parser, p_node->word_offset + 2, p_node->result_id);
+ }
+ break;
+
+ case SpvOpSpecConstantTrue:
+ case SpvOpSpecConstantFalse:
+ case SpvOpSpecConstant:
+ case SpvOpSpecConstantComposite:
+ case SpvOpSpecConstantOp: {
+ CHECKED_READU32(p_parser, p_node->word_offset + 1, p_node->result_type_id);
+ CHECKED_READU32(p_parser, p_node->word_offset + 2, p_node->result_id);
+ }
+ break;
+
+ case SpvOpVariable:
+ {
+ CHECKED_READU32(p_parser, p_node->word_offset + 1, p_node->type_id);
+ CHECKED_READU32(p_parser, p_node->word_offset + 2, p_node->result_id);
+ CHECKED_READU32(p_parser, p_node->word_offset + 3, p_node->storage_class);
+ }
+ break;
+
+ case SpvOpLoad:
+ {
+ // Only load enough so OpDecorate can reference the node, skip the remaining operands.
+ CHECKED_READU32(p_parser, p_node->word_offset + 1, p_node->result_type_id);
+ CHECKED_READU32(p_parser, p_node->word_offset + 2, p_node->result_id);
+ }
+ break;
+
+ case SpvOpAccessChain:
+ {
+ AccessChain* p_access_chain = &(p_parser->access_chains[access_chain_index]);
+ CHECKED_READU32(p_parser, p_node->word_offset + 1, p_access_chain->result_type_id);
+ CHECKED_READU32(p_parser, p_node->word_offset + 2, p_access_chain->result_id);
+ CHECKED_READU32(p_parser, p_node->word_offset + 3, p_access_chain->base_id);
+ //
+ // SPIRV_ACCESS_CHAIN_INDEX_OFFSET (4) is the number of words up until the first index:
+ // [Node, Result Type Id, Result Id, Base Id, <Indexes>]
+ //
+ p_access_chain->index_count = (node_word_count - SPIRV_ACCESS_CHAIN_INDEX_OFFSET);
+ if (p_access_chain->index_count > 0) {
+ p_access_chain->indexes = (uint32_t*)calloc(p_access_chain->index_count, sizeof(*(p_access_chain->indexes)));
+ if (IsNull( p_access_chain->indexes)) {
+ return SPV_REFLECT_RESULT_ERROR_ALLOC_FAILED;
+ }
+ // Parse any index values for access chain
+ for (uint32_t index_index = 0; index_index < p_access_chain->index_count; ++index_index) {
+ // Read index id
+ uint32_t index_id = 0;
+ CHECKED_READU32(p_parser, p_node->word_offset + SPIRV_ACCESS_CHAIN_INDEX_OFFSET + index_index, index_id);
+ // Find OpConstant node that contains index value
+ Node* p_index_value_node = FindNode(p_parser, index_id);
+ if ((p_index_value_node != NULL) && (p_index_value_node->op == SpvOpConstant)) {
+ // Read index value
+ uint32_t index_value = UINT32_MAX;
+ CHECKED_READU32(p_parser, p_index_value_node->word_offset + 3, index_value);
+ assert(index_value != UINT32_MAX);
+ // Write index value to array
+ p_access_chain->indexes[index_index] = index_value;
+ }
+ }
+ }
+ ++access_chain_index;
+ }
+ break;
+
+ case SpvOpFunction:
+ {
+ CHECKED_READU32(p_parser, p_node->word_offset + 2, p_node->result_id);
+ // Count function definitions, not function declarations. To determine
+ // the difference, set an in-function variable, and then if an OpLabel
+ // is reached before the end of the function increment the function
+ // count.
+ function_node = node_index;
+ }
+ break;
+
+ case SpvOpLabel:
+ {
+ if (function_node != (uint32_t)INVALID_VALUE) {
+ Node* p_func_node = &(p_parser->nodes[function_node]);
+ CHECKED_READU32(p_parser, p_func_node->word_offset + 2, p_func_node->result_id);
+ ++(p_parser->function_count);
+ }
+ } // Fall through
+
+ case SpvOpFunctionEnd:
+ {
+ function_node = (uint32_t)INVALID_VALUE;
+ }
+ break;
+ }
+
+ if (p_node->is_type) {
+ ++(p_parser->type_count);
+ }
+
+ spirv_word_index += node_word_count;
+ ++node_index;
+ }
+
+ return SPV_REFLECT_RESULT_SUCCESS;
+}
+
+static SpvReflectResult ParseStrings(Parser* p_parser)
+{
+ assert(IsNotNull(p_parser));
+ assert(IsNotNull(p_parser->spirv_code));
+ assert(IsNotNull(p_parser->nodes));
+
+ // Early out
+ if (p_parser->string_count == 0) {
+ return SPV_REFLECT_RESULT_SUCCESS;
+ }
+
+ if (IsNotNull(p_parser) && IsNotNull(p_parser->spirv_code) && IsNotNull(p_parser->nodes)) {
+ // Allocate string storage
+ p_parser->strings = (String*)calloc(p_parser->string_count, sizeof(*(p_parser->strings)));
+
+ uint32_t string_index = 0;
+ for (size_t i = 0; i < p_parser->node_count; ++i) {
+ Node* p_node = &(p_parser->nodes[i]);
+ if (p_node->op != SpvOpString) {
+ continue;
+ }
+
+ // Paranoid check against string count
+ assert(string_index < p_parser->string_count);
+ if (string_index >= p_parser->string_count) {
+ return SPV_REFLECT_RESULT_ERROR_COUNT_MISMATCH;
+ }
+
+ // Result id
+ String* p_string = &(p_parser->strings[string_index]);
+ CHECKED_READU32(p_parser, p_node->word_offset + 1, p_string->result_id);
+
+ // String
+ uint32_t string_start = p_node->word_offset + 2;
+ p_string->string = (const char*)(p_parser->spirv_code + string_start);
+
+ // Increment string index
+ ++string_index;
+ }
+ }
+
+ return SPV_REFLECT_RESULT_SUCCESS;
+}
+
+static SpvReflectResult ParseSource(Parser* p_parser, SpvReflectShaderModule* p_module)
+{
+ assert(IsNotNull(p_parser));
+ assert(IsNotNull(p_parser->spirv_code));
+
+ if (IsNotNull(p_parser) && IsNotNull(p_parser->spirv_code)) {
+ // Source file
+ if (IsNotNull(p_parser->strings)) {
+ for (uint32_t i = 0; i < p_parser->string_count; ++i) {
+ String* p_string = &(p_parser->strings[i]);
+ if (p_string->result_id == p_parser->source_file_id) {
+ p_module->source_file = p_string->string;
+ break;
+ }
+ }
+ }
+ }
+
+ return SPV_REFLECT_RESULT_SUCCESS;
+}
+
+static SpvReflectResult ParseFunction(Parser* p_parser, Node* p_func_node, Function* p_func, size_t first_label_index)
+{
+ p_func->id = p_func_node->result_id;
+
+ p_func->callee_count = 0;
+ p_func->accessed_ptr_count = 0;
+
+ for (size_t i = first_label_index; i < p_parser->node_count; ++i) {
+ Node* p_node = &(p_parser->nodes[i]);
+ if (p_node->op == SpvOpFunctionEnd) {
+ break;
+ }
+ switch (p_node->op) {
+ case SpvOpFunctionCall: {
+ ++(p_func->callee_count);
+ }
+ break;
+ case SpvOpLoad:
+ case SpvOpAccessChain:
+ case SpvOpInBoundsAccessChain:
+ case SpvOpPtrAccessChain:
+ case SpvOpArrayLength:
+ case SpvOpGenericPtrMemSemantics:
+ case SpvOpInBoundsPtrAccessChain:
+ case SpvOpStore:
+ {
+ ++(p_func->accessed_ptr_count);
+ }
+ break;
+ case SpvOpCopyMemory:
+ case SpvOpCopyMemorySized:
+ {
+ p_func->accessed_ptr_count += 2;
+ }
+ break;
+ default: break;
+ }
+ }
+
+ if (p_func->callee_count > 0) {
+ p_func->callees = (uint32_t*)calloc(p_func->callee_count,
+ sizeof(*(p_func->callees)));
+ if (IsNull(p_func->callees)) {
+ return SPV_REFLECT_RESULT_ERROR_ALLOC_FAILED;
+ }
+ }
+
+ if (p_func->accessed_ptr_count > 0) {
+ p_func->accessed_ptrs = (uint32_t*)calloc(p_func->accessed_ptr_count,
+ sizeof(*(p_func->accessed_ptrs)));
+ if (IsNull(p_func->accessed_ptrs)) {
+ return SPV_REFLECT_RESULT_ERROR_ALLOC_FAILED;
+ }
+ }
+
+ p_func->callee_count = 0;
+ p_func->accessed_ptr_count = 0;
+ for (size_t i = first_label_index; i < p_parser->node_count; ++i) {
+ Node* p_node = &(p_parser->nodes[i]);
+ if (p_node->op == SpvOpFunctionEnd) {
+ break;
+ }
+ switch (p_node->op) {
+ case SpvOpFunctionCall: {
+ CHECKED_READU32(p_parser, p_node->word_offset + 3,
+ p_func->callees[p_func->callee_count]);
+ (++p_func->callee_count);
+ }
+ break;
+ case SpvOpLoad:
+ case SpvOpAccessChain:
+ case SpvOpInBoundsAccessChain:
+ case SpvOpPtrAccessChain:
+ case SpvOpArrayLength:
+ case SpvOpGenericPtrMemSemantics:
+ case SpvOpInBoundsPtrAccessChain:
+ {
+ CHECKED_READU32(p_parser, p_node->word_offset + 3,
+ p_func->accessed_ptrs[p_func->accessed_ptr_count]);
+ (++p_func->accessed_ptr_count);
+ }
+ break;
+ case SpvOpStore:
+ {
+ CHECKED_READU32(p_parser, p_node->word_offset + 2,
+ p_func->accessed_ptrs[p_func->accessed_ptr_count]);
+ (++p_func->accessed_ptr_count);
+ }
+ break;
+ case SpvOpCopyMemory:
+ case SpvOpCopyMemorySized:
+ {
+ CHECKED_READU32(p_parser, p_node->word_offset + 2,
+ p_func->accessed_ptrs[p_func->accessed_ptr_count]);
+ (++p_func->accessed_ptr_count);
+ CHECKED_READU32(p_parser, p_node->word_offset + 3,
+ p_func->accessed_ptrs[p_func->accessed_ptr_count]);
+ (++p_func->accessed_ptr_count);
+ }
+ break;
+ default: break;
+ }
+ }
+
+ if (p_func->callee_count > 0) {
+ qsort(p_func->callees, p_func->callee_count,
+ sizeof(*(p_func->callees)), SortCompareUint32);
+ }
+ p_func->callee_count = (uint32_t)DedupSortedUint32(p_func->callees,
+ p_func->callee_count);
+
+ if (p_func->accessed_ptr_count > 0) {
+ qsort(p_func->accessed_ptrs, p_func->accessed_ptr_count,
+ sizeof(*(p_func->accessed_ptrs)), SortCompareUint32);
+ }
+ p_func->accessed_ptr_count = (uint32_t)DedupSortedUint32(p_func->accessed_ptrs,
+ p_func->accessed_ptr_count);
+
+ return SPV_REFLECT_RESULT_SUCCESS;
+}
+
+static int SortCompareFunctions(const void* a, const void* b)
+{
+ const Function* af = (const Function*)a;
+ const Function* bf = (const Function*)b;
+ return (int)af->id - (int)bf->id;
+}
+
+static SpvReflectResult ParseFunctions(Parser* p_parser)
+{
+ assert(IsNotNull(p_parser));
+ assert(IsNotNull(p_parser->spirv_code));
+ assert(IsNotNull(p_parser->nodes));
+
+ if (IsNotNull(p_parser) && IsNotNull(p_parser->spirv_code) && IsNotNull(p_parser->nodes)) {
+ if (p_parser->function_count == 0) {
+ return SPV_REFLECT_RESULT_SUCCESS;
+ }
+
+ p_parser->functions = (Function*)calloc(p_parser->function_count,
+ sizeof(*(p_parser->functions)));
+ if (IsNull(p_parser->functions)) {
+ return SPV_REFLECT_RESULT_ERROR_ALLOC_FAILED;
+ }
+
+ size_t function_index = 0;
+ for (size_t i = 0; i < p_parser->node_count; ++i) {
+ Node* p_node = &(p_parser->nodes[i]);
+ if (p_node->op != SpvOpFunction) {
+ continue;
+ }
+
+ // Skip over function declarations that aren't definitions
+ bool func_definition = false;
+ // Intentionally reuse i to avoid iterating over these nodes more than
+ // once
+ for (; i < p_parser->node_count; ++i) {
+ if (p_parser->nodes[i].op == SpvOpLabel) {
+ func_definition = true;
+ break;
+ }
+ if (p_parser->nodes[i].op == SpvOpFunctionEnd) {
+ break;
+ }
+ }
+ if (!func_definition) {
+ continue;
+ }
+
+ Function* p_function = &(p_parser->functions[function_index]);
+
+ SpvReflectResult result = ParseFunction(p_parser, p_node, p_function, i);
+ if (result != SPV_REFLECT_RESULT_SUCCESS) {
+ return result;
+ }
+
+ ++function_index;
+ }
+
+ qsort(p_parser->functions, p_parser->function_count,
+ sizeof(*(p_parser->functions)), SortCompareFunctions);
+
+ // Once they're sorted, link the functions with pointers to improve graph
+ // traversal efficiency
+ for (size_t i = 0; i < p_parser->function_count; ++i) {
+ Function* p_func = &(p_parser->functions[i]);
+ if (p_func->callee_count == 0) {
+ continue;
+ }
+ p_func->callee_ptrs = (Function**)calloc(p_func->callee_count,
+ sizeof(*(p_func->callee_ptrs)));
+ for (size_t j = 0, k = 0; j < p_func->callee_count; ++j) {
+ while (p_parser->functions[k].id != p_func->callees[j]) {
+ ++k;
+ if (k >= p_parser->function_count) {
+ // Invalid called function ID somewhere
+ return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE;
+ }
+ }
+ p_func->callee_ptrs[j] = &(p_parser->functions[k]);
+ }
+ }
+ }
+
+ return SPV_REFLECT_RESULT_SUCCESS;
+}
+
+static SpvReflectResult ParseMemberCounts(Parser* p_parser)
+{
+ assert(IsNotNull(p_parser));
+ assert(IsNotNull(p_parser->spirv_code));
+ assert(IsNotNull(p_parser->nodes));
+
+ if (IsNotNull(p_parser) && IsNotNull(p_parser->spirv_code) && IsNotNull(p_parser->nodes)) {
+ for (size_t i = 0; i < p_parser->node_count; ++i) {
+ Node* p_node = &(p_parser->nodes[i]);
+ if ((p_node->op != SpvOpMemberName) && (p_node->op != SpvOpMemberDecorate)) {
+ continue;
+ }
+
+ uint32_t target_id = 0;
+ uint32_t member_index = (uint32_t)INVALID_VALUE;
+ CHECKED_READU32(p_parser, p_node->word_offset + 1, target_id);
+ CHECKED_READU32(p_parser, p_node->word_offset + 2, member_index);
+ Node* p_target_node = FindNode(p_parser, target_id);
+ // Not all nodes get parsed, so FindNode returning NULL is expected.
+ if (IsNull(p_target_node)) {
+ continue;
+ }
+
+ if (member_index == INVALID_VALUE) {
+ return SPV_REFLECT_RESULT_ERROR_RANGE_EXCEEDED;
+ }
+
+ p_target_node->member_count = Max(p_target_node->member_count, member_index + 1);
+ }
+
+ for (uint32_t i = 0; i < p_parser->node_count; ++i) {
+ Node* p_node = &(p_parser->nodes[i]);
+ if (p_node->member_count == 0) {
+ continue;
+ }
+
+ p_node->member_names = (const char **)calloc(p_node->member_count, sizeof(*(p_node->member_names)));
+ if (IsNull(p_node->member_names)) {
+ return SPV_REFLECT_RESULT_ERROR_ALLOC_FAILED;
+ }
+
+ p_node->member_decorations = (Decorations*)calloc(p_node->member_count, sizeof(*(p_node->member_decorations)));
+ if (IsNull(p_node->member_decorations)) {
+ return SPV_REFLECT_RESULT_ERROR_ALLOC_FAILED;
+ }
+ }
+ }
+ return SPV_REFLECT_RESULT_SUCCESS;
+}
+
+static SpvReflectResult ParseNames(Parser* p_parser)
+{
+ assert(IsNotNull(p_parser));
+ assert(IsNotNull(p_parser->spirv_code));
+ assert(IsNotNull(p_parser->nodes));
+
+ if (IsNotNull(p_parser) && IsNotNull(p_parser->spirv_code) && IsNotNull(p_parser->nodes)) {
+ for (size_t i = 0; i < p_parser->node_count; ++i) {
+ Node* p_node = &(p_parser->nodes[i]);
+ if ((p_node->op != SpvOpName) && (p_node->op != SpvOpMemberName)) {
+ continue;
+ }
+
+ uint32_t target_id = 0;
+ CHECKED_READU32(p_parser, p_node->word_offset + 1, target_id);
+ Node* p_target_node = FindNode(p_parser, target_id);
+ // Not all nodes get parsed, so FindNode returning NULL is expected.
+ if (IsNull(p_target_node)) {
+ continue;
+ }
+
+ const char** pp_target_name = &(p_target_node->name);
+ if (p_node->op == SpvOpMemberName) {
+ uint32_t member_index = UINT32_MAX;
+ CHECKED_READU32(p_parser, p_node->word_offset + 2, member_index);
+ pp_target_name = &(p_target_node->member_names[member_index]);
+ }
+
+ *pp_target_name = p_node->name;
+ }
+ }
+ return SPV_REFLECT_RESULT_SUCCESS;
+}
+
+static SpvReflectResult ParseDecorations(Parser* p_parser)
+{
+ for (uint32_t i = 0; i < p_parser->node_count; ++i) {
+ Node* p_node = &(p_parser->nodes[i]);
+
+ if (((uint32_t)p_node->op != (uint32_t)SpvOpDecorate) &&
+ ((uint32_t)p_node->op != (uint32_t)SpvOpMemberDecorate) &&
+ ((uint32_t)p_node->op != (uint32_t)SpvReflectOpDecorateId) &&
+ ((uint32_t)p_node->op != (uint32_t)SpvReflectOpDecorateStringGOOGLE) &&
+ ((uint32_t)p_node->op != (uint32_t)SpvReflectOpMemberDecorateStringGOOGLE))
+ {
+ continue;
+ }
+
+ // Need to adjust the read offset if this is a member decoration
+ uint32_t member_offset = 0;
+ if (p_node->op == SpvOpMemberDecorate) {
+ member_offset = 1;
+ }
+
+ // Get decoration
+ uint32_t decoration = (uint32_t)INVALID_VALUE;
+ CHECKED_READU32(p_parser, p_node->word_offset + member_offset + 2, decoration);
+
+ // Filter out the decoration that do not affect reflection, otherwise
+ // there will be random crashes because the nodes aren't found.
+ bool skip = false;
+ switch (decoration) {
+ default: {
+ skip = true;
+ }
+ break;
+ case SpvDecorationBlock:
+ case SpvDecorationBufferBlock:
+ case SpvDecorationColMajor:
+ case SpvDecorationRowMajor:
+ case SpvDecorationArrayStride:
+ case SpvDecorationMatrixStride:
+ case SpvDecorationBuiltIn:
+ case SpvDecorationNoPerspective:
+ case SpvDecorationFlat:
+ case SpvDecorationNonWritable:
+ case SpvDecorationLocation:
+ case SpvDecorationBinding:
+ case SpvDecorationDescriptorSet:
+ case SpvDecorationOffset:
+ case SpvDecorationInputAttachmentIndex:
+ case SpvReflectDecorationHlslCounterBufferGOOGLE:
+ case SpvReflectDecorationHlslSemanticGOOGLE: {
+ skip = false;
+ }
+ break;
+ }
+ if (skip) {
+ continue;
+ }
+
+ // Find target target node
+ uint32_t target_id = 0;
+ CHECKED_READU32(p_parser, p_node->word_offset + 1, target_id);
+ Node* p_target_node = FindNode(p_parser, target_id);
+ if (IsNull(p_target_node)) {
+ return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE;
+ }
+ // Get decorations
+ Decorations* p_target_decorations = &(p_target_node->decorations);
+ // Update pointer if this is a member member decoration
+ if (p_node->op == SpvOpMemberDecorate) {
+ uint32_t member_index = (uint32_t)INVALID_VALUE;
+ CHECKED_READU32(p_parser, p_node->word_offset + 2, member_index);
+ p_target_decorations = &(p_target_node->member_decorations[member_index]);
+ }
+
+ switch (decoration) {
+ default: break;
+
+ case SpvDecorationBlock: {
+ p_target_decorations->is_block = true;
+ }
+ break;
+
+ case SpvDecorationBufferBlock: {
+ p_target_decorations->is_buffer_block = true;
+ }
+ break;
+
+ case SpvDecorationColMajor: {
+ p_target_decorations->is_column_major = true;
+ }
+ break;
+
+ case SpvDecorationRowMajor: {
+ p_target_decorations->is_row_major = true;
+ }
+ break;
+
+ case SpvDecorationArrayStride: {
+ uint32_t word_offset = p_node->word_offset + member_offset + 3;
+ CHECKED_READU32(p_parser, word_offset, p_target_decorations->array_stride);
+ }
+ break;
+
+ case SpvDecorationMatrixStride: {
+ uint32_t word_offset = p_node->word_offset + member_offset + 3;
+ CHECKED_READU32(p_parser, word_offset, p_target_decorations->matrix_stride);
+ }
+ break;
+
+ case SpvDecorationBuiltIn: {
+ p_target_decorations->is_built_in = true;
+ uint32_t word_offset = p_node->word_offset + member_offset + 3;
+ CHECKED_READU32_CAST(p_parser, word_offset, SpvBuiltIn, p_target_decorations->built_in);
+ }
+ break;
+
+ case SpvDecorationNoPerspective: {
+ p_target_decorations->is_noperspective = true;
+ }
+ break;
+
+ case SpvDecorationFlat: {
+ p_target_decorations->is_flat = true;
+ }
+ break;
+
+ case SpvDecorationNonWritable: {
+ p_target_decorations->is_non_writable = true;
+ }
+ break;
+
+ case SpvDecorationLocation: {
+ uint32_t word_offset = p_node->word_offset + member_offset + 3;
+ CHECKED_READU32(p_parser, word_offset, p_target_decorations->location.value);
+ p_target_decorations->location.word_offset = word_offset;
+ }
+ break;
+
+ case SpvDecorationBinding: {
+ uint32_t word_offset = p_node->word_offset + member_offset+ 3;
+ CHECKED_READU32(p_parser, word_offset, p_target_decorations->binding.value);
+ p_target_decorations->binding.word_offset = word_offset;
+ }
+ break;
+
+ case SpvDecorationDescriptorSet: {
+ uint32_t word_offset = p_node->word_offset + member_offset+ 3;
+ CHECKED_READU32(p_parser, word_offset, p_target_decorations->set.value);
+ p_target_decorations->set.word_offset = word_offset;
+ }
+ break;
+
+ case SpvDecorationOffset: {
+ uint32_t word_offset = p_node->word_offset + member_offset+ 3;
+ CHECKED_READU32(p_parser, word_offset, p_target_decorations->offset.value);
+ p_target_decorations->offset.word_offset = word_offset;
+ }
+ break;
+
+ case SpvDecorationInputAttachmentIndex: {
+ uint32_t word_offset = p_node->word_offset + member_offset+ 3;
+ CHECKED_READU32(p_parser, word_offset, p_target_decorations->input_attachment_index.value);
+ p_target_decorations->input_attachment_index.word_offset = word_offset;
+ }
+ break;
+
+ case SpvReflectDecorationHlslCounterBufferGOOGLE: {
+ uint32_t word_offset = p_node->word_offset + member_offset+ 3;
+ CHECKED_READU32(p_parser, word_offset, p_target_decorations->uav_counter_buffer.value);
+ p_target_decorations->uav_counter_buffer.word_offset = word_offset;
+ }
+ break;
+
+ case SpvReflectDecorationHlslSemanticGOOGLE: {
+ uint32_t word_offset = p_node->word_offset + member_offset + 3;
+ p_target_decorations->semantic.value = (const char*)(p_parser->spirv_code + word_offset);
+ p_target_decorations->semantic.word_offset = word_offset;
+ }
+ break;
+ }
+ }
+ return SPV_REFLECT_RESULT_SUCCESS;
+}
+
+static SpvReflectResult EnumerateAllUniforms(
+ SpvReflectShaderModule* p_module,
+ size_t* p_uniform_count,
+ uint32_t** pp_uniforms
+)
+{
+ *p_uniform_count = p_module->descriptor_binding_count;
+ if (*p_uniform_count == 0) {
+ return SPV_REFLECT_RESULT_SUCCESS;
+ }
+ *pp_uniforms = (uint32_t*)calloc(*p_uniform_count, sizeof(**pp_uniforms));
+
+ if (IsNull(*pp_uniforms)) {
+ return SPV_REFLECT_RESULT_ERROR_ALLOC_FAILED;
+ }
+
+ for (size_t i = 0; i < *p_uniform_count; ++i) {
+ (*pp_uniforms)[i] = p_module->descriptor_bindings[i].spirv_id;
+ }
+ qsort(*pp_uniforms, *p_uniform_count, sizeof(**pp_uniforms),
+ SortCompareUint32);
+ return SPV_REFLECT_RESULT_SUCCESS;
+}
+
+static SpvReflectResult ParseType(
+ Parser* p_parser,
+ Node* p_node,
+ Decorations* p_struct_member_decorations,
+ SpvReflectShaderModule* p_module,
+ SpvReflectTypeDescription* p_type
+)
+{
+ SpvReflectResult result = SPV_REFLECT_RESULT_SUCCESS;
+
+ if (p_node->member_count > 0) {
+ p_type->member_count = p_node->member_count;
+ p_type->members = (SpvReflectTypeDescription*)calloc(p_type->member_count, sizeof(*(p_type->members)));
+ if (IsNotNull(p_type->members)) {
+ // Mark all members types with an invalid state
+ for (size_t i = 0; i < p_type->members->member_count; ++i) {
+ SpvReflectTypeDescription* p_member_type = &(p_type->members[i]);
+ p_member_type->id = (uint32_t)INVALID_VALUE;
+ p_member_type->op = (SpvOp)INVALID_VALUE;
+ p_member_type->storage_class = (SpvStorageClass)INVALID_VALUE;
+ }
+ }
+ else {
+ result = SPV_REFLECT_RESULT_ERROR_ALLOC_FAILED;
+ }
+ }
+
+ if (result == SPV_REFLECT_RESULT_SUCCESS) {
+ // Since the parse descends on type information, these will get overwritten
+ // if not guarded against assignment. Only assign if the id is invalid.
+ if (p_type->id == INVALID_VALUE) {
+ p_type->id = p_node->result_id;
+ p_type->op = p_node->op;
+ p_type->decoration_flags = 0;
+ }
+ // Top level types need to pick up decorations from all types below it.
+ // Issue and fix here: https://github.com/chaoticbob/SPIRV-Reflect/issues/64
+ p_type->decoration_flags = ApplyDecorations(&p_node->decorations);
+
+ switch (p_node->op) {
+ default: break;
+ case SpvOpTypeVoid:
+ p_type->type_flags |= SPV_REFLECT_TYPE_FLAG_VOID;
+ break;
+
+ case SpvOpTypeBool:
+ p_type->type_flags |= SPV_REFLECT_TYPE_FLAG_BOOL;
+ break;
+
+ case SpvOpTypeInt: {
+ p_type->type_flags |= SPV_REFLECT_TYPE_FLAG_INT;
+ IF_READU32(result, p_parser, p_node->word_offset + 2, p_type->traits.numeric.scalar.width);
+ IF_READU32(result, p_parser, p_node->word_offset + 3, p_type->traits.numeric.scalar.signedness);
+ }
+ break;
+
+ case SpvOpTypeFloat: {
+ p_type->type_flags |= SPV_REFLECT_TYPE_FLAG_FLOAT;
+ IF_READU32(result, p_parser, p_node->word_offset + 2, p_type->traits.numeric.scalar.width);
+ }
+ break;
+
+ case SpvOpTypeVector: {
+ p_type->type_flags |= SPV_REFLECT_TYPE_FLAG_VECTOR;
+ uint32_t component_type_id = (uint32_t)INVALID_VALUE;
+ IF_READU32(result, p_parser, p_node->word_offset + 2, component_type_id);
+ IF_READU32(result, p_parser, p_node->word_offset + 3, p_type->traits.numeric.vector.component_count);
+ // Parse component type
+ Node* p_next_node = FindNode(p_parser, component_type_id);
+ if (IsNotNull(p_next_node)) {
+ result = ParseType(p_parser, p_next_node, NULL, p_module, p_type);
+ }
+ else {
+ result = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE;
+ }
+ }
+ break;
+
+ case SpvOpTypeMatrix: {
+ p_type->type_flags |= SPV_REFLECT_TYPE_FLAG_MATRIX;
+ uint32_t column_type_id = (uint32_t)INVALID_VALUE;
+ IF_READU32(result, p_parser, p_node->word_offset + 2, column_type_id);
+ IF_READU32(result, p_parser, p_node->word_offset + 3, p_type->traits.numeric.matrix.column_count);
+ Node* p_next_node = FindNode(p_parser, column_type_id);
+ if (IsNotNull(p_next_node)) {
+ result = ParseType(p_parser, p_next_node, NULL, p_module, p_type);
+ }
+ else {
+ result = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE;
+ }
+ p_type->traits.numeric.matrix.row_count = p_type->traits.numeric.vector.component_count;
+ p_type->traits.numeric.matrix.stride = p_node->decorations.matrix_stride;
+ // NOTE: Matrix stride is decorated using OpMemberDecoreate - not OpDecoreate.
+ if (IsNotNull(p_struct_member_decorations)) {
+ p_type->traits.numeric.matrix.stride = p_struct_member_decorations->matrix_stride;
+ }
+ }
+ break;
+
+ case SpvOpTypeImage: {
+ p_type->type_flags |= SPV_REFLECT_TYPE_FLAG_EXTERNAL_IMAGE;
+ IF_READU32_CAST(result, p_parser, p_node->word_offset + 3, SpvDim, p_type->traits.image.dim);
+ IF_READU32(result, p_parser, p_node->word_offset + 4, p_type->traits.image.depth);
+ IF_READU32(result, p_parser, p_node->word_offset + 5, p_type->traits.image.arrayed);
+ IF_READU32(result, p_parser, p_node->word_offset + 6, p_type->traits.image.ms);
+ IF_READU32(result, p_parser, p_node->word_offset + 7, p_type->traits.image.sampled);
+ IF_READU32_CAST(result, p_parser, p_node->word_offset + 8, SpvImageFormat, p_type->traits.image.image_format);
+ }
+ break;
+
+ case SpvOpTypeSampler: {
+ p_type->type_flags |= SPV_REFLECT_TYPE_FLAG_EXTERNAL_SAMPLER;
+ }
+ break;
+
+ case SpvOpTypeSampledImage: {
+ p_type->type_flags |= SPV_REFLECT_TYPE_FLAG_EXTERNAL_SAMPLED_IMAGE;
+ uint32_t image_type_id = (uint32_t)INVALID_VALUE;
+ IF_READU32(result, p_parser, p_node->word_offset + 2, image_type_id);
+ Node* p_next_node = FindNode(p_parser, image_type_id);
+ if (IsNotNull(p_next_node)) {
+ result = ParseType(p_parser, p_next_node, NULL, p_module, p_type);
+ }
+ else {
+ result = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE;
+ }
+ }
+ break;
+
+ case SpvOpTypeArray: {
+ p_type->type_flags |= SPV_REFLECT_TYPE_FLAG_ARRAY;
+ if (result == SPV_REFLECT_RESULT_SUCCESS) {
+ uint32_t element_type_id = (uint32_t)INVALID_VALUE;
+ uint32_t length_id = (uint32_t)INVALID_VALUE;
+ IF_READU32(result, p_parser, p_node->word_offset + 2, element_type_id);
+ IF_READU32(result, p_parser, p_node->word_offset + 3, length_id);
+ // NOTE: Array stride is decorated using OpDecorate instead of
+ // OpMemberDecorate, even if the array is apart of a struct.
+ p_type->traits.array.stride = p_node->decorations.array_stride;
+ // Get length for current dimension
+ Node* p_length_node = FindNode(p_parser, length_id);
+ if (IsNotNull(p_length_node)) {
+ if (p_length_node->op == SpvOpSpecConstant ||
+ p_length_node->op == SpvOpSpecConstantOp) {
+ p_type->traits.array.dims[p_type->traits.array.dims_count] = 0xFFFFFFFF;
+ p_type->traits.array.dims_count += 1;
+ } else {
+ uint32_t length = 0;
+ IF_READU32(result, p_parser, p_length_node->word_offset + 3, length);
+ if (result == SPV_REFLECT_RESULT_SUCCESS) {
+ // Write the array dim and increment the count and offset
+ p_type->traits.array.dims[p_type->traits.array.dims_count] = length;
+ p_type->traits.array.dims_count += 1;
+ } else {
+ result = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE;
+ }
+ }
+ // Parse next dimension or element type
+ Node* p_next_node = FindNode(p_parser, element_type_id);
+ if (IsNotNull(p_next_node)) {
+ result = ParseType(p_parser, p_next_node, NULL, p_module, p_type);
+ }
+ }
+ else {
+ result = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE;
+ }
+ }
+ }
+ break;
+
+ case SpvOpTypeRuntimeArray: {
+ uint32_t element_type_id = (uint32_t)INVALID_VALUE;
+ IF_READU32(result, p_parser, p_node->word_offset + 2, element_type_id);
+ // Parse next dimension or element type
+ Node* p_next_node = FindNode(p_parser, element_type_id);
+ if (IsNotNull(p_next_node)) {
+ result = ParseType(p_parser, p_next_node, NULL, p_module, p_type);
+ }
+ else {
+ result = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE;
+ }
+ }
+ break;
+
+ case SpvOpTypeStruct: {
+ p_type->type_flags |= SPV_REFLECT_TYPE_FLAG_STRUCT;
+ p_type->type_flags |= SPV_REFLECT_TYPE_FLAG_EXTERNAL_BLOCK;
+ uint32_t word_index = 2;
+ uint32_t member_index = 0;
+ for (; word_index < p_node->word_count; ++word_index, ++member_index) {
+ uint32_t member_id = (uint32_t)INVALID_VALUE;
+ IF_READU32(result, p_parser, p_node->word_offset + word_index, member_id);
+ // Find member node
+ Node* p_member_node = FindNode(p_parser, member_id);
+ if (IsNull(p_member_node)) {
+ result = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE;
+ break;
+ }
+
+ // Member decorations
+ Decorations* p_member_decorations = &p_node->member_decorations[member_index];
+
+ assert(member_index < p_type->member_count);
+ // Parse member type
+ SpvReflectTypeDescription* p_member_type = &(p_type->members[member_index]);
+ p_member_type->id = member_id;
+ p_member_type->op = p_member_node->op;
+ result = ParseType(p_parser, p_member_node, p_member_decorations, p_module, p_member_type);
+ if (result != SPV_REFLECT_RESULT_SUCCESS) {
+ break;
+ }
+ // This looks wrong
+ //p_member_type->type_name = p_member_node->name;
+ p_member_type->struct_member_name = p_node->member_names[member_index];
+ }
+ }
+ break;
+
+ case SpvOpTypeOpaque: break;
+
+ case SpvOpTypePointer: {
+ IF_READU32_CAST(result, p_parser, p_node->word_offset + 2, SpvStorageClass, p_type->storage_class);
+ uint32_t type_id = (uint32_t)INVALID_VALUE;
+ IF_READU32(result, p_parser, p_node->word_offset + 3, type_id);
+ // Parse type
+ Node* p_next_node = FindNode(p_parser, type_id);
+ if (IsNotNull(p_next_node)) {
+ result = ParseType(p_parser, p_next_node, NULL, p_module, p_type);
+ }
+ else {
+ result = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE;
+ }
+ }
+ break;
+ }
+
+ if (result == SPV_REFLECT_RESULT_SUCCESS) {
+ // Names get assigned on the way down. Guard against names
+ // get overwritten on the way up.
+ if (IsNull(p_type->type_name)) {
+ p_type->type_name = p_node->name;
+ }
+ }
+ }
+
+ return result;
+}
+
+static SpvReflectResult ParseTypes(Parser* p_parser, SpvReflectShaderModule* p_module)
+{
+ if (p_parser->type_count == 0) {
+ return SPV_REFLECT_RESULT_SUCCESS;
+ }
+
+ p_module->_internal->type_description_count = p_parser->type_count;
+ p_module->_internal->type_descriptions = (SpvReflectTypeDescription*)calloc(p_module->_internal->type_description_count,
+ sizeof(*(p_module->_internal->type_descriptions)));
+ if (IsNull(p_module->_internal->type_descriptions)) {
+ return SPV_REFLECT_RESULT_ERROR_ALLOC_FAILED;
+ }
+
+ // Mark all types with an invalid state
+ for (size_t i = 0; i < p_module->_internal->type_description_count; ++i) {
+ SpvReflectTypeDescription* p_type = &(p_module->_internal->type_descriptions[i]);
+ p_type->id = (uint32_t)INVALID_VALUE;
+ p_type->op = (SpvOp)INVALID_VALUE;
+ p_type->storage_class = (SpvStorageClass)INVALID_VALUE;
+ }
+
+ size_t type_index = 0;
+ for (size_t i = 0; i < p_parser->node_count; ++i) {
+ Node* p_node = &(p_parser->nodes[i]);
+ if (! p_node->is_type) {
+ continue;
+ }
+
+ SpvReflectTypeDescription* p_type = &(p_module->_internal->type_descriptions[type_index]);
+ SpvReflectResult result = ParseType(p_parser, p_node, NULL, p_module, p_type);
+ if (result != SPV_REFLECT_RESULT_SUCCESS) {
+ return result;
+ }
+ ++type_index;
+ }
+ return SPV_REFLECT_RESULT_SUCCESS;
+}
+
+static int SortCompareDescriptorBinding(const void* a, const void* b)
+{
+ const SpvReflectDescriptorBinding* p_elem_a = (const SpvReflectDescriptorBinding*)a;
+ const SpvReflectDescriptorBinding* p_elem_b = (const SpvReflectDescriptorBinding*)b;
+ int value = (int)(p_elem_a->binding) - (int)(p_elem_b->binding);
+ if (value == 0) {
+ // use spirv-id as a tiebreaker to ensure a stable ordering, as they're guaranteed
+ // unique.
+ assert(p_elem_a->spirv_id != p_elem_b->spirv_id);
+ value = (int)(p_elem_a->spirv_id) - (int)(p_elem_b->spirv_id);
+ }
+ return value;
+}
+
+static SpvReflectResult ParseDescriptorBindings(Parser* p_parser, SpvReflectShaderModule* p_module)
+{
+ p_module->descriptor_binding_count = 0;
+ for (size_t i = 0; i < p_parser->node_count; ++i) {
+ Node* p_node = &(p_parser->nodes[i]);
+ if ((p_node->op != SpvOpVariable) ||
+ ((p_node->storage_class != SpvStorageClassUniform) && (p_node->storage_class != SpvStorageClassUniformConstant)))
+ {
+ continue;
+ }
+ if ((p_node->decorations.set.value == INVALID_VALUE) || (p_node->decorations.binding.value == INVALID_VALUE)) {
+ continue;
+ }
+
+ p_module->descriptor_binding_count += 1;
+ }
+
+ if (p_module->descriptor_binding_count == 0) {
+ return SPV_REFLECT_RESULT_SUCCESS;
+ }
+
+ p_module->descriptor_bindings = (SpvReflectDescriptorBinding*)calloc(p_module->descriptor_binding_count, sizeof(*(p_module->descriptor_bindings)));
+ if (IsNull(p_module->descriptor_bindings)) {
+ return SPV_REFLECT_RESULT_ERROR_ALLOC_FAILED;
+ }
+
+ // Mark all types with an invalid state
+ for (uint32_t descriptor_index = 0; descriptor_index < p_module->descriptor_binding_count; ++descriptor_index) {
+ SpvReflectDescriptorBinding* p_descriptor = &(p_module->descriptor_bindings[descriptor_index]);
+ p_descriptor->binding = (uint32_t)INVALID_VALUE;
+ p_descriptor->input_attachment_index = (uint32_t)INVALID_VALUE;
+ p_descriptor->set = (uint32_t)INVALID_VALUE;
+ p_descriptor->descriptor_type = (SpvReflectDescriptorType)INVALID_VALUE;
+ p_descriptor->uav_counter_id = (uint32_t)INVALID_VALUE;
+ }
+
+ size_t descriptor_index = 0;
+ for (size_t i = 0; i < p_parser->node_count; ++i) {
+ Node* p_node = &(p_parser->nodes[i]);
+ if ((p_node->op != SpvOpVariable) ||
+ ((p_node->storage_class != SpvStorageClassUniform) && (p_node->storage_class != SpvStorageClassUniformConstant)))\
+ {
+ continue;
+ }
+ if ((p_node->decorations.set.value == INVALID_VALUE) || (p_node->decorations.binding.value == INVALID_VALUE)) {
+ continue;
+ }
+
+ SpvReflectTypeDescription* p_type = FindType(p_module, p_node->type_id);
+ if (IsNull(p_type)) {
+ return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE;
+ }
+ // If the type is a pointer, resolve it
+ if (p_type->op == SpvOpTypePointer) {
+ // Find the type's node
+ Node* p_type_node = FindNode(p_parser, p_type->id);
+ if (IsNull(p_type_node)) {
+ return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE;
+ }
+ // Should be the resolved type
+ p_type = FindType(p_module, p_type_node->type_id);
+ if (IsNull(p_type)) {
+ return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE;
+ }
+ }
+
+ SpvReflectDescriptorBinding* p_descriptor = &p_module->descriptor_bindings[descriptor_index];
+ p_descriptor->spirv_id = p_node->result_id;
+ p_descriptor->name = p_node->name;
+ p_descriptor->binding = p_node->decorations.binding.value;
+ p_descriptor->input_attachment_index = p_node->decorations.input_attachment_index.value;
+ p_descriptor->set = p_node->decorations.set.value;
+ p_descriptor->count = 1;
+ p_descriptor->uav_counter_id = p_node->decorations.uav_counter_buffer.value;
+ p_descriptor->type_description = p_type;
+
+ // Copy image traits
+ if ((p_type->type_flags & SPV_REFLECT_TYPE_FLAG_EXTERNAL_MASK) == SPV_REFLECT_TYPE_FLAG_EXTERNAL_IMAGE) {
+ memcpy(&p_descriptor->image, &p_type->traits.image, sizeof(p_descriptor->image));
+ }
+
+ // This is a workaround for: https://github.com/KhronosGroup/glslang/issues/1096
+ {
+ const uint32_t resource_mask = SPV_REFLECT_TYPE_FLAG_EXTERNAL_SAMPLED_IMAGE | SPV_REFLECT_TYPE_FLAG_EXTERNAL_IMAGE;
+ if ((p_type->type_flags & resource_mask) == resource_mask) {
+ memcpy(&p_descriptor->image, &p_type->traits.image, sizeof(p_descriptor->image));
+ }
+ }
+
+ // Copy array traits
+ if (p_type->traits.array.dims_count > 0) {
+ p_descriptor->array.dims_count = p_type->traits.array.dims_count;
+ for (uint32_t dim_index = 0; dim_index < p_type->traits.array.dims_count; ++dim_index) {
+ uint32_t dim_value = p_type->traits.array.dims[dim_index];
+ p_descriptor->array.dims[dim_index] = dim_value;
+ p_descriptor->count *= dim_value;
+ }
+ }
+
+ // Count
+
+
+ p_descriptor->word_offset.binding = p_node->decorations.binding.word_offset;
+ p_descriptor->word_offset.set = p_node->decorations.set.word_offset;
+
+ ++descriptor_index;
+ }
+
+ if (p_module->descriptor_binding_count > 0) {
+ qsort(p_module->descriptor_bindings,
+ p_module->descriptor_binding_count,
+ sizeof(*(p_module->descriptor_bindings)),
+ SortCompareDescriptorBinding);
+ }
+
+ return SPV_REFLECT_RESULT_SUCCESS;
+}
+
+static SpvReflectResult ParseDescriptorType(SpvReflectShaderModule* p_module)
+{
+ if (p_module->descriptor_binding_count == 0) {
+ return SPV_REFLECT_RESULT_SUCCESS;
+ }
+
+ for (uint32_t descriptor_index = 0; descriptor_index < p_module->descriptor_binding_count; ++descriptor_index) {
+ SpvReflectDescriptorBinding* p_descriptor = &(p_module->descriptor_bindings[descriptor_index]);
+ SpvReflectTypeDescription* p_type = p_descriptor->type_description;
+
+ switch (p_type->type_flags & SPV_REFLECT_TYPE_FLAG_EXTERNAL_MASK) {
+ default: assert(false && "unknown type flag"); break;
+
+ case SPV_REFLECT_TYPE_FLAG_EXTERNAL_IMAGE: {
+ if (p_descriptor->image.dim == SpvDimBuffer) {
+ switch (p_descriptor->image.sampled) {
+ default: assert(false && "unknown texel buffer sampled value"); break;
+ case IMAGE_SAMPLED: p_descriptor->descriptor_type = SPV_REFLECT_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER; break;
+ case IMAGE_STORAGE: p_descriptor->descriptor_type = SPV_REFLECT_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER; break;
+ }
+ }
+ else if(p_descriptor->image.dim == SpvDimSubpassData) {
+ p_descriptor->descriptor_type = SPV_REFLECT_DESCRIPTOR_TYPE_INPUT_ATTACHMENT;
+ }
+ else {
+ switch (p_descriptor->image.sampled) {
+ default: assert(false && "unknown image sampled value"); break;
+ case IMAGE_SAMPLED: p_descriptor->descriptor_type = SPV_REFLECT_DESCRIPTOR_TYPE_SAMPLED_IMAGE; break;
+ case IMAGE_STORAGE: p_descriptor->descriptor_type = SPV_REFLECT_DESCRIPTOR_TYPE_STORAGE_IMAGE; break;
+ }
+ }
+ }
+ break;
+
+ case SPV_REFLECT_TYPE_FLAG_EXTERNAL_SAMPLER: {
+ p_descriptor->descriptor_type = SPV_REFLECT_DESCRIPTOR_TYPE_SAMPLER;
+ }
+ break;
+
+ case (SPV_REFLECT_TYPE_FLAG_EXTERNAL_SAMPLED_IMAGE | SPV_REFLECT_TYPE_FLAG_EXTERNAL_IMAGE): {
+ // This is a workaround for: https://github.com/KhronosGroup/glslang/issues/1096
+ if (p_descriptor->image.dim == SpvDimBuffer) {
+ switch (p_descriptor->image.sampled) {
+ default: assert(false && "unknown texel buffer sampled value"); break;
+ case IMAGE_SAMPLED: p_descriptor->descriptor_type = SPV_REFLECT_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER; break;
+ case IMAGE_STORAGE: p_descriptor->descriptor_type = SPV_REFLECT_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER; break;
+ }
+ }
+ else {
+ p_descriptor->descriptor_type = SPV_REFLECT_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
+ }
+ }
+ break;
+
+ case SPV_REFLECT_TYPE_FLAG_EXTERNAL_BLOCK: {
+ if (p_type->decoration_flags & SPV_REFLECT_DECORATION_BLOCK) {
+ p_descriptor->descriptor_type = SPV_REFLECT_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
+ }
+ else if (p_type->decoration_flags & SPV_REFLECT_DECORATION_BUFFER_BLOCK) {
+ p_descriptor->descriptor_type = SPV_REFLECT_DESCRIPTOR_TYPE_STORAGE_BUFFER;
+ }
+ else {
+ assert(false && "unknown struct");
+ }
+ }
+ break;
+ }
+
+ switch (p_descriptor->descriptor_type) {
+ case SPV_REFLECT_DESCRIPTOR_TYPE_SAMPLER : p_descriptor->resource_type = SPV_REFLECT_RESOURCE_FLAG_SAMPLER; break;
+ case SPV_REFLECT_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER : p_descriptor->resource_type = (SpvReflectResourceType)(SPV_REFLECT_RESOURCE_FLAG_SAMPLER | SPV_REFLECT_RESOURCE_FLAG_SRV); break;
+ case SPV_REFLECT_DESCRIPTOR_TYPE_SAMPLED_IMAGE : p_descriptor->resource_type = SPV_REFLECT_RESOURCE_FLAG_SRV; break;
+ case SPV_REFLECT_DESCRIPTOR_TYPE_STORAGE_IMAGE : p_descriptor->resource_type = SPV_REFLECT_RESOURCE_FLAG_UAV; break;
+ case SPV_REFLECT_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER : p_descriptor->resource_type = SPV_REFLECT_RESOURCE_FLAG_SRV; break;
+ case SPV_REFLECT_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER : p_descriptor->resource_type = SPV_REFLECT_RESOURCE_FLAG_UAV; break;
+ case SPV_REFLECT_DESCRIPTOR_TYPE_UNIFORM_BUFFER : p_descriptor->resource_type = SPV_REFLECT_RESOURCE_FLAG_CBV; break;
+ case SPV_REFLECT_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC : p_descriptor->resource_type = SPV_REFLECT_RESOURCE_FLAG_CBV; break;
+ case SPV_REFLECT_DESCRIPTOR_TYPE_STORAGE_BUFFER : p_descriptor->resource_type = SPV_REFLECT_RESOURCE_FLAG_UAV; break;
+ case SPV_REFLECT_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC : p_descriptor->resource_type = SPV_REFLECT_RESOURCE_FLAG_UAV; break;
+
+ case SPV_REFLECT_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
+ break;
+ }
+ }
+
+ return SPV_REFLECT_RESULT_SUCCESS;
+}
+
+static SpvReflectResult ParseUAVCounterBindings(SpvReflectShaderModule* p_module)
+{
+ char name[MAX_NODE_NAME_LENGTH];
+ const char* k_count_tag = "@count";
+
+ for (uint32_t descriptor_index = 0; descriptor_index < p_module->descriptor_binding_count; ++descriptor_index) {
+ SpvReflectDescriptorBinding* p_descriptor = &(p_module->descriptor_bindings[descriptor_index]);
+
+ if (p_descriptor->descriptor_type != SPV_REFLECT_DESCRIPTOR_TYPE_STORAGE_BUFFER) {
+ continue;
+ }
+
+ SpvReflectDescriptorBinding* p_counter_descriptor = NULL;
+ // Use UAV counter buffer id if present...
+ if (p_descriptor->uav_counter_id != UINT32_MAX) {
+ for (uint32_t counter_descriptor_index = 0; counter_descriptor_index < p_module->descriptor_binding_count; ++counter_descriptor_index) {
+ SpvReflectDescriptorBinding* p_test_counter_descriptor = &(p_module->descriptor_bindings[counter_descriptor_index]);
+ if (p_test_counter_descriptor->descriptor_type != SPV_REFLECT_DESCRIPTOR_TYPE_STORAGE_BUFFER) {
+ continue;
+ }
+ if (p_descriptor->uav_counter_id == p_test_counter_descriptor->spirv_id) {
+ p_counter_descriptor = p_test_counter_descriptor;
+ break;
+ }
+ }
+ }
+ // ...otherwise use old @count convention.
+ else {
+ const size_t descriptor_name_length = p_descriptor->name? strlen(p_descriptor->name): 0;
+
+ memset(name, 0, MAX_NODE_NAME_LENGTH);
+ memcpy(name, p_descriptor->name, descriptor_name_length);
+#if defined(WIN32)
+ strcat_s(name, MAX_NODE_NAME_LENGTH, k_count_tag);
+#else
+ strcat(name, k_count_tag);
+#endif
+
+ for (uint32_t counter_descriptor_index = 0; counter_descriptor_index < p_module->descriptor_binding_count; ++counter_descriptor_index) {
+ SpvReflectDescriptorBinding* p_test_counter_descriptor = &(p_module->descriptor_bindings[counter_descriptor_index]);
+ if (p_test_counter_descriptor->descriptor_type != SPV_REFLECT_DESCRIPTOR_TYPE_STORAGE_BUFFER) {
+ continue;
+ }
+ if (p_test_counter_descriptor->name && strcmp(name, p_test_counter_descriptor->name) == 0) {
+ p_counter_descriptor = p_test_counter_descriptor;
+ break;
+ }
+ }
+ }
+
+ if (p_counter_descriptor != NULL) {
+ p_descriptor->uav_counter_binding = p_counter_descriptor;
+ }
+ }
+
+ return SPV_REFLECT_RESULT_SUCCESS;
+}
+
+static SpvReflectResult ParseDescriptorBlockVariable(
+ Parser* p_parser,
+ SpvReflectShaderModule* p_module,
+ SpvReflectTypeDescription* p_type,
+ SpvReflectBlockVariable* p_var
+)
+{
+ bool has_non_writable = false;
+
+ if (IsNotNull(p_type->members) && (p_type->member_count > 0)) {
+ p_var->member_count = p_type->member_count;
+ p_var->members = (SpvReflectBlockVariable*)calloc(p_var->member_count, sizeof(*p_var->members));
+ if (IsNull(p_var->members)) {
+ return SPV_REFLECT_RESULT_ERROR_ALLOC_FAILED;
+ }
+
+ Node* p_type_node = FindNode(p_parser, p_type->id);
+ if (IsNull(p_type_node)) {
+ return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE;
+ }
+ // Resolve to element type if current type is array or run time array
+ if (p_type_node->op == SpvOpTypeArray) {
+ while (p_type_node->op == SpvOpTypeArray) {
+ p_type_node = FindNode(p_parser, p_type_node->array_traits.element_type_id);
+ if (IsNull(p_type_node)) {
+ return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE;
+ }
+ }
+ }
+ else if(p_type_node->op == SpvOpTypeRuntimeArray) {
+ // Element type description
+ p_type = FindType(p_module, p_type_node->array_traits.element_type_id);
+ if (IsNull(p_type)) {
+ return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE;
+ }
+ // Element type node
+ p_type_node = FindNode(p_parser, p_type->id);
+ if (IsNull(p_type_node)) {
+ return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE;
+ }
+ }
+
+ // Parse members
+ for (uint32_t member_index = 0; member_index < p_type->member_count; ++member_index) {
+ SpvReflectTypeDescription* p_member_type = &p_type->members[member_index];
+ SpvReflectBlockVariable* p_member_var = &p_var->members[member_index];
+ bool is_struct = (p_member_type->type_flags & SPV_REFLECT_TYPE_FLAG_STRUCT) == SPV_REFLECT_TYPE_FLAG_STRUCT;
+ if (is_struct) {
+ SpvReflectResult result = ParseDescriptorBlockVariable(p_parser, p_module, p_member_type, p_member_var);
+ if (result != SPV_REFLECT_RESULT_SUCCESS) {
+ return result;
+ }
+ }
+
+ p_member_var->name = p_type_node->member_names[member_index];
+ p_member_var->offset = p_type_node->member_decorations[member_index].offset.value;
+ p_member_var->decoration_flags = ApplyDecorations(&p_type_node->member_decorations[member_index]);
+ p_member_var->flags |= SPV_REFLECT_VARIABLE_FLAGS_UNUSED;
+ if (!has_non_writable && (p_member_var->decoration_flags & SPV_REFLECT_DECORATION_NON_WRITABLE)) {
+ has_non_writable = true;
+ }
+ ApplyNumericTraits(p_member_type, &p_member_var->numeric);
+ if (p_member_type->op == SpvOpTypeArray) {
+ ApplyArrayTraits(p_member_type, &p_member_var->array);
+ }
+
+ p_member_var->type_description = p_member_type;
+ }
+ }
+
+ p_var->name = p_type->type_name;
+ p_var->type_description = p_type;
+ if (has_non_writable) {
+ p_var->decoration_flags |= SPV_REFLECT_DECORATION_NON_WRITABLE;
+ }
+
+ return SPV_REFLECT_RESULT_SUCCESS;
+}
+
+static SpvReflectResult ParseDescriptorBlockVariableSizes(
+ Parser* p_parser,
+ SpvReflectShaderModule* p_module,
+ bool is_parent_root,
+ bool is_parent_aos,
+ bool is_parent_rta,
+ SpvReflectBlockVariable* p_var
+)
+{
+ if (p_var->member_count == 0) {
+ return SPV_REFLECT_RESULT_SUCCESS;
+ }
+
+ // Absolute offsets
+ for (uint32_t member_index = 0; member_index < p_var->member_count; ++member_index) {
+ SpvReflectBlockVariable* p_member_var = &p_var->members[member_index];
+ if (is_parent_root) {
+ p_member_var->absolute_offset = p_member_var->offset;
+ }
+ else {
+ p_member_var->absolute_offset = is_parent_aos ? 0 : p_member_var->offset + p_var->absolute_offset;
+ }
+ }
+
+ // Size
+ for (uint32_t member_index = 0; member_index < p_var->member_count; ++member_index) {
+ SpvReflectBlockVariable* p_member_var = &p_var->members[member_index];
+ SpvReflectTypeDescription* p_member_type = p_member_var->type_description;
+
+ switch (p_member_type->op) {
+ case SpvOpTypeBool: {
+ p_member_var->size = SPIRV_WORD_SIZE;
+ }
+ break;
+
+ case SpvOpTypeInt:
+ case SpvOpTypeFloat: {
+ p_member_var->size = p_member_type->traits.numeric.scalar.width / SPIRV_BYTE_WIDTH;
+ }
+ break;
+
+ case SpvOpTypeVector: {
+ uint32_t size = p_member_type->traits.numeric.vector.component_count *
+ (p_member_type->traits.numeric.scalar.width / SPIRV_BYTE_WIDTH);
+ p_member_var->size = size;
+ }
+ break;
+
+ case SpvOpTypeMatrix: {
+ if (p_member_var->decoration_flags & SPV_REFLECT_DECORATION_COLUMN_MAJOR) {
+ p_member_var->size = p_member_var->numeric.matrix.column_count * p_member_var->numeric.matrix.stride;
+ }
+ else if (p_member_var->decoration_flags & SPV_REFLECT_DECORATION_ROW_MAJOR) {
+ p_member_var->size = p_member_var->numeric.matrix.row_count * p_member_var->numeric.matrix.stride;
+ }
+ }
+ break;
+
+ case SpvOpTypeArray: {
+ // If array of structs, parse members first...
+ bool is_struct = (p_member_type->type_flags & SPV_REFLECT_TYPE_FLAG_STRUCT) == SPV_REFLECT_TYPE_FLAG_STRUCT;
+ if (is_struct) {
+ SpvReflectResult result = ParseDescriptorBlockVariableSizes(p_parser, p_module, false, true, is_parent_rta, p_member_var);
+ if (result != SPV_REFLECT_RESULT_SUCCESS) {
+ return result;
+ }
+ }
+ // ...then array
+ uint32_t element_count = (p_member_var->array.dims_count > 0 ? 1 : 0);
+ for (uint32_t i = 0; i < p_member_var->array.dims_count; ++i) {
+ element_count *= p_member_var->array.dims[i];
+ }
+ p_member_var->size = element_count * p_member_var->array.stride;
+ }
+ break;
+
+ case SpvOpTypeRuntimeArray: {
+ bool is_struct = (p_member_type->type_flags & SPV_REFLECT_TYPE_FLAG_STRUCT) == SPV_REFLECT_TYPE_FLAG_STRUCT;
+ if (is_struct) {
+ SpvReflectResult result = ParseDescriptorBlockVariableSizes(p_parser, p_module, false, true, true, p_member_var);
+ if (result != SPV_REFLECT_RESULT_SUCCESS) {
+ return result;
+ }
+ }
+ }
+ break;
+
+ case SpvOpTypeStruct: {
+ SpvReflectResult result = ParseDescriptorBlockVariableSizes(p_parser, p_module, false, is_parent_aos, is_parent_rta, p_member_var);
+ if (result != SPV_REFLECT_RESULT_SUCCESS) {
+ return result;
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ // Parse padded size using offset difference for all member except for the last entry...
+ for (uint32_t member_index = 0; member_index < (p_var->member_count - 1); ++member_index) {
+ SpvReflectBlockVariable* p_member_var = &p_var->members[member_index];
+ SpvReflectBlockVariable* p_next_member_var = &p_var->members[member_index + 1];
+ p_member_var->padded_size = p_next_member_var->offset - p_member_var->offset;
+ if (p_member_var->size > p_member_var->padded_size) {
+ p_member_var->size = p_member_var->padded_size;
+ }
+ if (is_parent_rta) {
+ p_member_var->padded_size = p_member_var->size;
+ }
+ }
+ // ...last entry just gets rounded up to near multiple of SPIRV_DATA_ALIGNMENT, which is 16 and
+ // subtract the offset.
+ if (p_var->member_count > 0) {
+ SpvReflectBlockVariable* p_member_var = &p_var->members[p_var->member_count - 1];
+ p_member_var->padded_size = RoundUp(p_member_var->offset + p_member_var->size, SPIRV_DATA_ALIGNMENT) - p_member_var->offset;
+ if (p_member_var->size > p_member_var->padded_size) {
+ p_member_var->size = p_member_var->padded_size;
+ }
+ if (is_parent_rta) {
+ p_member_var->padded_size = p_member_var->size;
+ }
+ }
+
+ // @TODO validate this with assertion
+ p_var->size = p_var->members[p_var->member_count - 1].offset +
+ p_var->members[p_var->member_count - 1].padded_size;
+ p_var->padded_size = p_var->size;
+
+ return SPV_REFLECT_RESULT_SUCCESS;
+}
+
+static SpvReflectResult ParseDescriptorBlockVariableUsage(
+ Parser* p_parser,
+ SpvReflectShaderModule* p_module,
+ AccessChain* p_access_chain,
+ uint32_t index_index,
+ SpvOp override_op_type,
+ SpvReflectBlockVariable* p_var
+)
+{
+ (void)p_parser;
+ (void)p_access_chain;
+ (void)p_var;
+
+ // Clear the current variable's USED flag
+ p_var->flags &= ~SPV_REFLECT_VARIABLE_FLAGS_UNUSED;
+
+ // Parsing arrays requires overriding the op type for
+ // for the lowest dim's element type.
+ SpvOp op_type = p_var->type_description->op;
+ if (override_op_type != (SpvOp)INVALID_VALUE) {
+ op_type = override_op_type;
+ }
+
+ switch (op_type) {
+ default: break;
+
+ case SpvOpTypeArray: {
+ // Parse through array's type hierarchy to find the actual/non-array element type
+ SpvReflectTypeDescription* p_type = p_var->type_description;
+ while ((p_type->op == SpvOpTypeArray) && (index_index < p_access_chain->index_count)) {
+ // Find the array element type id
+ Node* p_node = FindNode(p_parser, p_type->id);
+ if (p_node == NULL) {
+ return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE;
+ }
+ uint32_t element_type_id = p_node->array_traits.element_type_id;
+ // Get the array element type
+ p_type = FindType(p_module, element_type_id);
+ if (p_type == NULL) {
+ return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE;
+ }
+ // Next access index
+ index_index += 1;
+ }
+ // Parse current var again with a type override and advanced index index
+ SpvReflectResult result = ParseDescriptorBlockVariableUsage(
+ p_parser,
+ p_module,
+ p_access_chain,
+ index_index,
+ p_type->op,
+ p_var);
+ if (result != SPV_REFLECT_RESULT_SUCCESS) {
+ return result;
+ }
+ }
+ break;
+
+ case SpvOpTypeStruct: {
+ assert(p_var->member_count > 0);
+ if (p_var->member_count == 0) {
+ return SPV_REFLECT_RESULT_ERROR_SPIRV_UNEXPECTED_BLOCK_DATA;
+ }
+
+ uint32_t index = p_access_chain->indexes[index_index];
+
+ if (index >= p_var->member_count) {
+ return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_BLOCK_MEMBER_REFERENCE;
+ }
+
+ SpvReflectBlockVariable* p_member_var = &p_var->members[index];
+ if (index_index < p_access_chain->index_count) {
+ SpvReflectResult result = ParseDescriptorBlockVariableUsage(
+ p_parser,
+ p_module,
+ p_access_chain,
+ index_index + 1,
+ (SpvOp)INVALID_VALUE,
+ p_member_var);
+ if (result != SPV_REFLECT_RESULT_SUCCESS) {
+ return result;
+ }
+ }
+ }
+ break;
+ }
+
+ return SPV_REFLECT_RESULT_SUCCESS;
+}
+
+static SpvReflectResult ParseDescriptorBlocks(Parser* p_parser, SpvReflectShaderModule* p_module)
+{
+ if (p_module->descriptor_binding_count == 0) {
+ return SPV_REFLECT_RESULT_SUCCESS;
+ }
+
+ for (uint32_t descriptor_index = 0; descriptor_index < p_module->descriptor_binding_count; ++descriptor_index) {
+ SpvReflectDescriptorBinding* p_descriptor = &(p_module->descriptor_bindings[descriptor_index]);
+ SpvReflectTypeDescription* p_type = p_descriptor->type_description;
+ if ((p_descriptor->descriptor_type != SPV_REFLECT_DESCRIPTOR_TYPE_UNIFORM_BUFFER) &&
+ (p_descriptor->descriptor_type != SPV_REFLECT_DESCRIPTOR_TYPE_STORAGE_BUFFER) )
+ {
+ continue;
+ }
+
+ // Mark UNUSED
+ p_descriptor->block.flags |= SPV_REFLECT_VARIABLE_FLAGS_UNUSED;
+ // Parse descriptor block
+ SpvReflectResult result = ParseDescriptorBlockVariable(p_parser, p_module, p_type, &p_descriptor->block);
+ if (result != SPV_REFLECT_RESULT_SUCCESS) {
+ return result;
+ }
+
+ for (uint32_t access_chain_index = 0; access_chain_index < p_parser->access_chain_count; ++access_chain_index) {
+ AccessChain* p_access_chain = &(p_parser->access_chains[access_chain_index]);
+ // Skip any access chains that aren't touching this descriptor block
+ if (p_descriptor->spirv_id != p_access_chain->base_id) {
+ continue;
+ }
+ result = ParseDescriptorBlockVariableUsage(
+ p_parser,
+ p_module,
+ p_access_chain,
+ 0,
+ (SpvOp)INVALID_VALUE,
+ &p_descriptor->block);
+ if (result != SPV_REFLECT_RESULT_SUCCESS) {
+ return result;
+ }
+ }
+
+ p_descriptor->block.name = p_descriptor->name;
+
+ bool is_parent_rta = (p_descriptor->descriptor_type == SPV_REFLECT_DESCRIPTOR_TYPE_STORAGE_BUFFER);
+ result = ParseDescriptorBlockVariableSizes(p_parser, p_module, true, false, is_parent_rta, &p_descriptor->block);
+ if (result != SPV_REFLECT_RESULT_SUCCESS) {
+ return result;
+ }
+
+ if (is_parent_rta) {
+ p_descriptor->block.size = 0;
+ p_descriptor->block.padded_size = 0;
+ }
+ }
+
+ return SPV_REFLECT_RESULT_SUCCESS;
+}
+
+static SpvReflectResult ParseFormat(
+ const SpvReflectTypeDescription* p_type,
+ SpvReflectFormat* p_format
+)
+{
+ SpvReflectResult result = SPV_REFLECT_RESULT_ERROR_INTERNAL_ERROR;
+ bool signedness = p_type->traits.numeric.scalar.signedness;
+ if (p_type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) {
+ uint32_t component_count = p_type->traits.numeric.vector.component_count;
+ if (p_type->type_flags & SPV_REFLECT_TYPE_FLAG_FLOAT) {
+ switch (component_count) {
+ case 2: *p_format = SPV_REFLECT_FORMAT_R32G32_SFLOAT; break;
+ case 3: *p_format = SPV_REFLECT_FORMAT_R32G32B32_SFLOAT; break;
+ case 4: *p_format = SPV_REFLECT_FORMAT_R32G32B32A32_SFLOAT; break;
+ }
+ result = SPV_REFLECT_RESULT_SUCCESS;
+ }
+ else if (p_type->type_flags & (SPV_REFLECT_TYPE_FLAG_INT | SPV_REFLECT_TYPE_FLAG_BOOL)) {
+ switch (component_count) {
+ case 2: *p_format = signedness ? SPV_REFLECT_FORMAT_R32G32_SINT : SPV_REFLECT_FORMAT_R32G32_UINT; break;
+ case 3: *p_format = signedness ? SPV_REFLECT_FORMAT_R32G32B32_SINT : SPV_REFLECT_FORMAT_R32G32B32_UINT; break;
+ case 4: *p_format = signedness ? SPV_REFLECT_FORMAT_R32G32B32A32_SINT : SPV_REFLECT_FORMAT_R32G32B32A32_UINT; break;
+ }
+ result = SPV_REFLECT_RESULT_SUCCESS;
+ }
+ }
+ else if (p_type->type_flags & SPV_REFLECT_TYPE_FLAG_FLOAT) {
+ *p_format = SPV_REFLECT_FORMAT_R32_SFLOAT;
+ result = SPV_REFLECT_RESULT_SUCCESS;
+ }
+ else if (p_type->type_flags & (SPV_REFLECT_TYPE_FLAG_INT | SPV_REFLECT_TYPE_FLAG_BOOL)) {
+ if (signedness) {
+ *p_format = SPV_REFLECT_FORMAT_R32_SINT;
+ result = SPV_REFLECT_RESULT_SUCCESS;
+ }
+ else {
+ *p_format = SPV_REFLECT_FORMAT_R32_UINT;
+ result = SPV_REFLECT_RESULT_SUCCESS;
+ }
+ }
+ else if (p_type->type_flags & SPV_REFLECT_TYPE_FLAG_STRUCT) {
+ *p_format = SPV_REFLECT_FORMAT_UNDEFINED;
+ result = SPV_REFLECT_RESULT_SUCCESS;
+ }
+ return result;
+}
+
+static SpvReflectResult ParseInterfaceVariable(
+ Parser* p_parser,
+ const Decorations* p_type_node_decorations,
+ SpvReflectShaderModule* p_module,
+ SpvReflectTypeDescription* p_type,
+ SpvReflectInterfaceVariable* p_var,
+ bool* p_has_built_in
+)
+{
+ Node* p_type_node = FindNode(p_parser, p_type->id);
+ if (IsNull(p_type_node)) {
+ return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE;
+ }
+
+ if (p_type->member_count > 0) {
+ p_var->member_count = p_type->member_count;
+ p_var->members = (SpvReflectInterfaceVariable*)calloc(p_var->member_count, sizeof(*p_var->members));
+ if (IsNull(p_var->members)) {
+ return SPV_REFLECT_RESULT_ERROR_ALLOC_FAILED;
+ }
+
+ for (uint32_t member_index = 0; member_index < p_type_node->member_count; ++member_index) {
+ Decorations* p_member_decorations = &p_type_node->member_decorations[member_index];
+ SpvReflectTypeDescription* p_member_type = &p_type->members[member_index];
+ SpvReflectInterfaceVariable* p_member_var = &p_var->members[member_index];
+ SpvReflectResult result = ParseInterfaceVariable(p_parser, p_member_decorations, p_module, p_member_type, p_member_var, p_has_built_in);
+ if (result != SPV_REFLECT_RESULT_SUCCESS) {
+ return result;
+ }
+ }
+ }
+
+ p_var->name = p_type_node->name;
+ p_var->decoration_flags = ApplyDecorations(p_type_node_decorations);
+ p_var->built_in = p_type_node_decorations->built_in;
+ ApplyNumericTraits(p_type, &p_var->numeric);
+ if (p_type->op == SpvOpTypeArray) {
+ ApplyArrayTraits(p_type, &p_var->array);
+ }
+
+ p_var->type_description = p_type;
+
+ *p_has_built_in |= p_type_node_decorations->is_built_in;
+
+ SpvReflectResult result = ParseFormat(p_var->type_description, &p_var->format);
+ if (result != SPV_REFLECT_RESULT_SUCCESS) {
+ return result;
+ }
+
+ return SPV_REFLECT_RESULT_SUCCESS;
+}
+
+static SpvReflectResult ParseInterfaceVariables(
+ Parser* p_parser,
+ SpvReflectShaderModule* p_module,
+ SpvReflectEntryPoint* p_entry,
+ size_t io_var_count,
+ uint32_t* io_vars
+)
+{
+ if (io_var_count == 0) {
+ return SPV_REFLECT_RESULT_SUCCESS;
+ }
+
+ p_entry->input_variable_count = 0;
+ p_entry->output_variable_count = 0;
+ for (size_t i = 0; i < io_var_count; ++i) {
+ uint32_t var_result_id = *(io_vars + i);
+ Node* p_node = FindNode(p_parser, var_result_id);
+ if (IsNull(p_node)) {
+ return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE;
+ }
+
+ if (p_node->storage_class == SpvStorageClassInput) {
+ p_entry->input_variable_count += 1;
+ }
+ else if (p_node->storage_class == SpvStorageClassOutput) {
+ p_entry->output_variable_count += 1;
+ }
+ }
+
+ if (p_entry->input_variable_count > 0) {
+ p_entry->input_variables = (SpvReflectInterfaceVariable*)calloc(p_entry->input_variable_count, sizeof(*(p_entry->input_variables)));
+ if (IsNull(p_entry->input_variables)) {
+ return SPV_REFLECT_RESULT_ERROR_ALLOC_FAILED;
+ }
+ }
+
+
+ if (p_entry->output_variable_count > 0) {
+ p_entry->output_variables = (SpvReflectInterfaceVariable*)calloc(p_entry->output_variable_count, sizeof(*(p_entry->output_variables)));
+ if (IsNull(p_entry->output_variables)) {
+ return SPV_REFLECT_RESULT_ERROR_ALLOC_FAILED;
+ }
+ }
+
+ size_t input_index = 0;
+ size_t output_index = 0;
+ for (size_t i = 0; i < io_var_count; ++i) {
+ uint32_t var_result_id = *(io_vars + i);
+ Node* p_node = FindNode(p_parser, var_result_id);
+ if (IsNull(p_node)) {
+ return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE;
+ }
+
+ SpvReflectTypeDescription* p_type = FindType(p_module, p_node->type_id);
+ if (IsNull(p_node)) {
+ return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE;
+ }
+ // If the type is a pointer, resolve it
+ if (p_type->op == SpvOpTypePointer) {
+ // Find the type's node
+ Node* p_type_node = FindNode(p_parser, p_type->id);
+ if (IsNull(p_type_node)) {
+ return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE;
+ }
+ // Should be the resolved type
+ p_type = FindType(p_module, p_type_node->type_id);
+ if (IsNull(p_type)) {
+ return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE;
+ }
+ }
+
+ Node* p_type_node = FindNode(p_parser, p_type->id);
+ if (IsNull(p_type_node)) {
+ return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE;
+ }
+
+ SpvReflectInterfaceVariable* p_var = NULL;
+ if (p_node->storage_class == SpvStorageClassInput) {
+ p_var = &(p_entry->input_variables[input_index]);
+ p_var->storage_class = SpvStorageClassInput;
+ ++input_index;
+ }
+ else if (p_node->storage_class == SpvStorageClassOutput) {
+ p_var = &(p_entry->output_variables[output_index]);
+ p_var->storage_class = SpvStorageClassOutput;
+ ++output_index;
+ } else {
+ // interface variables can only have input or output storage classes;
+ // anything else is either a new addition or an error.
+ assert(false && "Unsupported storage class for interface variable");
+ return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_STORAGE_CLASS;
+ }
+
+ bool has_built_in = p_node->decorations.is_built_in;
+ SpvReflectResult result = ParseInterfaceVariable(
+ p_parser,
+ &p_type_node->decorations,
+ p_module,
+ p_type,
+ p_var,
+ &has_built_in);
+ if (result != SPV_REFLECT_RESULT_SUCCESS) {
+ return result;
+ }
+
+ // SPIR-V result id
+ p_var->spirv_id = p_node->result_id;
+ // Name
+ p_var->name = p_node->name;
+ // Semantic
+ p_var->semantic = p_node->decorations.semantic.value;
+
+ // Decorate with built-in if any member is built-in
+ if (has_built_in) {
+ p_var->decoration_flags |= SPV_REFLECT_DECORATION_BUILT_IN;
+ }
+
+ // Location is decorated on OpVariable node, not the type node.
+ p_var->location = p_node->decorations.location.value;
+ p_var->word_offset.location = p_node->decorations.location.word_offset;
+
+ // Built in
+ if (p_node->decorations.is_built_in) {
+ p_var->built_in = p_node->decorations.built_in;
+ }
+ }
+
+ return SPV_REFLECT_RESULT_SUCCESS;
+}
+
+static SpvReflectResult EnumerateAllPushConstants(
+ SpvReflectShaderModule* p_module,
+ size_t* p_push_constant_count,
+ uint32_t** p_push_constants
+)
+{
+ *p_push_constant_count = p_module->push_constant_block_count;
+ if (*p_push_constant_count == 0) {
+ return SPV_REFLECT_RESULT_SUCCESS;
+ }
+ *p_push_constants = (uint32_t*)calloc(*p_push_constant_count, sizeof(**p_push_constants));
+
+ if (IsNull(*p_push_constants)) {
+ return SPV_REFLECT_RESULT_ERROR_ALLOC_FAILED;
+ }
+
+ for (size_t i = 0; i < *p_push_constant_count; ++i) {
+ (*p_push_constants)[i] = p_module->push_constant_blocks[i].spirv_id;
+ }
+ qsort(*p_push_constants, *p_push_constant_count, sizeof(**p_push_constants),
+ SortCompareUint32);
+ return SPV_REFLECT_RESULT_SUCCESS;
+}
+
+static SpvReflectResult TraverseCallGraph(
+ Parser* p_parser,
+ Function* p_func,
+ size_t* p_func_count,
+ uint32_t* p_func_ids,
+ uint32_t depth
+)
+{
+ if (depth > p_parser->function_count) {
+ // Vulkan does not permit recursion (Vulkan spec Appendix A):
+ // "Recursion: The static function-call graph for an entry point must not
+ // contain cycles."
+ return SPV_REFLECT_RESULT_ERROR_SPIRV_RECURSION;
+ }
+ if (IsNotNull(p_func_ids)) {
+ p_func_ids[(*p_func_count)++] = p_func->id;
+ } else {
+ ++*p_func_count;
+ }
+ for (size_t i = 0; i < p_func->callee_count; ++i) {
+ SpvReflectResult result = TraverseCallGraph(
+ p_parser, p_func->callee_ptrs[i], p_func_count, p_func_ids, depth + 1);
+ if (result != SPV_REFLECT_RESULT_SUCCESS) {
+ return result;
+ }
+ }
+ return SPV_REFLECT_RESULT_SUCCESS;
+}
+
+static SpvReflectResult ParseStaticallyUsedResources(
+ Parser* p_parser,
+ SpvReflectShaderModule* p_module,
+ SpvReflectEntryPoint* p_entry,
+ size_t uniform_count,
+ uint32_t* uniforms,
+ size_t push_constant_count,
+ uint32_t* push_constants
+)
+{
+ // Find function with the right id
+ Function* p_func = NULL;
+ for (size_t i = 0; i < p_parser->function_count; ++i) {
+ if (p_parser->functions[i].id == p_entry->id) {
+ p_func = &(p_parser->functions[i]);
+ break;
+ }
+ }
+ if (p_func == NULL) {
+ return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE;
+ }
+
+ size_t called_function_count = 0;
+ SpvReflectResult result = TraverseCallGraph(
+ p_parser,
+ p_func,
+ &called_function_count,
+ NULL,
+ 0);
+ if (result != SPV_REFLECT_RESULT_SUCCESS) {
+ return result;
+ }
+
+ uint32_t* p_called_functions = NULL;
+ if (called_function_count > 0) {
+ p_called_functions = (uint32_t*)calloc(called_function_count, sizeof(*p_called_functions));
+ if (IsNull(p_called_functions)) {
+ return SPV_REFLECT_RESULT_ERROR_ALLOC_FAILED;
+ }
+ }
+
+ called_function_count = 0;
+ result = TraverseCallGraph(
+ p_parser,
+ p_func,
+ &called_function_count,
+ p_called_functions,
+ 0);
+ if (result != SPV_REFLECT_RESULT_SUCCESS) {
+ return result;
+ }
+
+ if (called_function_count > 0) {
+ qsort(
+ p_called_functions,
+ called_function_count,
+ sizeof(*p_called_functions),
+ SortCompareUint32);
+ }
+ called_function_count = DedupSortedUint32(p_called_functions, called_function_count);
+
+ uint32_t used_variable_count = 0;
+ for (size_t i = 0, j = 0; i < called_function_count; ++i) {
+ // No need to bounds check j because a missing ID issue would have been
+ // found during TraverseCallGraph
+ while (p_parser->functions[j].id != p_called_functions[i]) {
+ ++j;
+ }
+ used_variable_count += p_parser->functions[j].accessed_ptr_count;
+ }
+ uint32_t* used_variables = NULL;
+ if (used_variable_count > 0) {
+ used_variables = (uint32_t*)calloc(used_variable_count,
+ sizeof(*used_variables));
+ if (IsNull(used_variables)) {
+ SafeFree(p_called_functions);
+ return SPV_REFLECT_RESULT_ERROR_ALLOC_FAILED;
+ }
+ }
+ used_variable_count = 0;
+ for (size_t i = 0, j = 0; i < called_function_count; ++i) {
+ while (p_parser->functions[j].id != p_called_functions[i]) {
+ ++j;
+ }
+
+ memcpy(&used_variables[used_variable_count],
+ p_parser->functions[j].accessed_ptrs,
+ p_parser->functions[j].accessed_ptr_count * sizeof(*used_variables));
+ used_variable_count += p_parser->functions[j].accessed_ptr_count;
+ }
+ SafeFree(p_called_functions);
+
+ if (used_variable_count > 0) {
+ qsort(used_variables, used_variable_count, sizeof(*used_variables),
+ SortCompareUint32);
+ }
+ used_variable_count = (uint32_t)DedupSortedUint32(used_variables,
+ used_variable_count);
+
+ // Do set intersection to find the used uniform and push constants
+ size_t used_uniform_count = 0;
+ //
+ SpvReflectResult result0 = IntersectSortedUint32(
+ used_variables,
+ used_variable_count,
+ uniforms,
+ uniform_count,
+ &p_entry->used_uniforms,
+ &used_uniform_count);
+
+ size_t used_push_constant_count = 0;
+ //
+ SpvReflectResult result1 = IntersectSortedUint32(
+ used_variables,
+ used_variable_count,
+ push_constants,
+ push_constant_count,
+ &p_entry->used_push_constants,
+ &used_push_constant_count);
+
+ for (uint32_t j = 0; j < p_module->descriptor_binding_count; ++j) {
+ SpvReflectDescriptorBinding* p_binding = &p_module->descriptor_bindings[j];
+ bool found = SearchSortedUint32(
+ used_variables,
+ used_variable_count,
+ p_binding->spirv_id);
+ if (found) {
+ p_binding->accessed = 1;
+ }
+ }
+
+ SafeFree(used_variables);
+ if (result0 != SPV_REFLECT_RESULT_SUCCESS) {
+ return result0;
+ }
+ if (result1 != SPV_REFLECT_RESULT_SUCCESS) {
+ return result1;
+ }
+
+ p_entry->used_uniform_count = (uint32_t)used_uniform_count;
+ p_entry->used_push_constant_count = (uint32_t)used_push_constant_count;
+
+ return SPV_REFLECT_RESULT_SUCCESS;
+}
+
+static SpvReflectResult ParseEntryPoints(Parser* p_parser, SpvReflectShaderModule* p_module)
+{
+ if (p_parser->entry_point_count == 0) {
+ return SPV_REFLECT_RESULT_SUCCESS;
+ }
+
+ p_module->entry_point_count = p_parser->entry_point_count;
+ p_module->entry_points = (SpvReflectEntryPoint*)calloc(p_module->entry_point_count,
+ sizeof(*(p_module->entry_points)));
+ if (IsNull(p_module->entry_points)) {
+ return SPV_REFLECT_RESULT_ERROR_ALLOC_FAILED;
+ }
+
+ SpvReflectResult result;
+ size_t uniform_count = 0;
+ uint32_t* uniforms = NULL;
+ if ((result = EnumerateAllUniforms(p_module, &uniform_count, &uniforms)) !=
+ SPV_REFLECT_RESULT_SUCCESS) {
+ return result;
+ }
+ size_t push_constant_count = 0;
+ uint32_t* push_constants = NULL;
+ if ((result = EnumerateAllPushConstants(p_module, &push_constant_count, &push_constants)) !=
+ SPV_REFLECT_RESULT_SUCCESS) {
+ return result;
+ }
+
+ size_t entry_point_index = 0;
+ for (size_t i = 0; entry_point_index < p_parser->entry_point_count && i < p_parser->node_count; ++i) {
+ Node* p_node = &(p_parser->nodes[i]);
+ if (p_node->op != SpvOpEntryPoint) {
+ continue;
+ }
+
+ SpvReflectEntryPoint* p_entry_point = &(p_module->entry_points[entry_point_index]);
+ CHECKED_READU32_CAST(p_parser, p_node->word_offset + 1, SpvExecutionModel, p_entry_point->spirv_execution_model);
+ CHECKED_READU32(p_parser, p_node->word_offset + 2, p_entry_point->id);
+
+ switch (p_entry_point->spirv_execution_model) {
+ default: break;
+ case SpvExecutionModelVertex : p_entry_point->shader_stage = SPV_REFLECT_SHADER_STAGE_VERTEX_BIT; break;
+ case SpvExecutionModelTessellationControl : p_entry_point->shader_stage = SPV_REFLECT_SHADER_STAGE_TESSELLATION_CONTROL_BIT; break;
+ case SpvExecutionModelTessellationEvaluation : p_entry_point->shader_stage = SPV_REFLECT_SHADER_STAGE_TESSELLATION_EVALUATION_BIT; break;
+ case SpvExecutionModelGeometry : p_entry_point->shader_stage = SPV_REFLECT_SHADER_STAGE_GEOMETRY_BIT; break;
+ case SpvExecutionModelFragment : p_entry_point->shader_stage = SPV_REFLECT_SHADER_STAGE_FRAGMENT_BIT; break;
+ case SpvExecutionModelGLCompute : p_entry_point->shader_stage = SPV_REFLECT_SHADER_STAGE_COMPUTE_BIT; break;
+ }
+
+ ++entry_point_index;
+
+ // Name length is required to calculate next operand
+ uint32_t name_start_word_offset = 3;
+ uint32_t name_length_with_terminator = 0;
+ result = ReadStr(p_parser, p_node->word_offset + name_start_word_offset, 0, p_node->word_count, &name_length_with_terminator, NULL);
+ if (result != SPV_REFLECT_RESULT_SUCCESS) {
+ return result;
+ }
+ p_entry_point->name = (const char*)(p_parser->spirv_code + p_node->word_offset + name_start_word_offset);
+
+ uint32_t name_word_count = RoundUp(name_length_with_terminator, SPIRV_WORD_SIZE) / SPIRV_WORD_SIZE;
+ size_t interface_variable_count = (p_node->word_count - (name_start_word_offset + name_word_count));
+ uint32_t* interface_variables = NULL;
+ if (interface_variable_count > 0) {
+ interface_variables = (uint32_t*)calloc(interface_variable_count, sizeof(*(interface_variables)));
+ if (IsNull(interface_variables)) {
+ return SPV_REFLECT_RESULT_ERROR_ALLOC_FAILED;
+ }
+ }
+
+ for (uint32_t var_index = 0; var_index < interface_variable_count; ++var_index) {
+ uint32_t var_result_id = (uint32_t)INVALID_VALUE;
+ uint32_t offset = name_start_word_offset + name_word_count + var_index;
+ CHECKED_READU32(p_parser, p_node->word_offset + offset, var_result_id);
+ interface_variables[var_index] = var_result_id;
+ }
+
+ result = ParseInterfaceVariables(
+ p_parser,
+ p_module,
+ p_entry_point,
+ interface_variable_count,
+ interface_variables);
+ if (result != SPV_REFLECT_RESULT_SUCCESS) {
+ return result;
+ }
+ SafeFree(interface_variables);
+
+ result = ParseStaticallyUsedResources(
+ p_parser,
+ p_module,
+ p_entry_point,
+ uniform_count,
+ uniforms,
+ push_constant_count,
+ push_constants);
+ if (result != SPV_REFLECT_RESULT_SUCCESS) {
+ return result;
+ }
+ }
+
+ SafeFree(uniforms);
+ SafeFree(push_constants);
+
+ return SPV_REFLECT_RESULT_SUCCESS;
+}
+
+static SpvReflectResult ParsePushConstantBlocks(Parser* p_parser, SpvReflectShaderModule* p_module)
+{
+ for (size_t i = 0; i < p_parser->node_count; ++i) {
+ Node* p_node = &(p_parser->nodes[i]);
+ if ((p_node->op != SpvOpVariable) || (p_node->storage_class != SpvStorageClassPushConstant)) {
+ continue;
+ }
+
+ p_module->push_constant_block_count += 1;
+ }
+
+ if (p_module->push_constant_block_count == 0) {
+ return SPV_REFLECT_RESULT_SUCCESS;
+ }
+
+ p_module->push_constant_blocks = (SpvReflectBlockVariable*)calloc(p_module->push_constant_block_count, sizeof(*p_module->push_constant_blocks));
+ if (IsNull(p_module->push_constant_blocks)) {
+ return SPV_REFLECT_RESULT_ERROR_ALLOC_FAILED;
+ }
+
+ uint32_t push_constant_index = 0;
+ for (size_t i = 0; i < p_parser->node_count; ++i) {
+ Node* p_node = &(p_parser->nodes[i]);
+ if ((p_node->op != SpvOpVariable) || (p_node->storage_class != SpvStorageClassPushConstant)) {
+ continue;
+ }
+
+ SpvReflectTypeDescription* p_type = FindType(p_module, p_node->type_id);
+ if (IsNull(p_node)) {
+ return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE;
+ }
+ // If the type is a pointer, resolve it
+ if (p_type->op == SpvOpTypePointer) {
+ // Find the type's node
+ Node* p_type_node = FindNode(p_parser, p_type->id);
+ if (IsNull(p_type_node)) {
+ return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE;
+ }
+ // Should be the resolved type
+ p_type = FindType(p_module, p_type_node->type_id);
+ if (IsNull(p_type)) {
+ return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE;
+ }
+ }
+
+ Node* p_type_node = FindNode(p_parser, p_type->id);
+ if (IsNull(p_type_node)) {
+ return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE;
+ }
+
+ SpvReflectBlockVariable* p_push_constant = &p_module->push_constant_blocks[push_constant_index];
+ p_push_constant->spirv_id = p_node->result_id;
+ SpvReflectResult result = ParseDescriptorBlockVariable(p_parser, p_module, p_type, p_push_constant);
+ if (result != SPV_REFLECT_RESULT_SUCCESS) {
+ return result;
+ }
+ result = ParseDescriptorBlockVariableSizes(p_parser, p_module, true, false, false, p_push_constant);
+ if (result != SPV_REFLECT_RESULT_SUCCESS) {
+ return result;
+ }
+
+ ++push_constant_index;
+ }
+
+ return SPV_REFLECT_RESULT_SUCCESS;
+}
+
+static int SortCompareDescriptorSet(const void* a, const void* b)
+{
+ const SpvReflectDescriptorSet* p_elem_a = (const SpvReflectDescriptorSet*)a;
+ const SpvReflectDescriptorSet* p_elem_b = (const SpvReflectDescriptorSet*)b;
+ int value = (int)(p_elem_a->set) - (int)(p_elem_b->set);
+ // We should never see duplicate descriptor set numbers in a shader; if so, a tiebreaker
+ // would be needed here.
+ assert(value != 0);
+ return value;
+}
+
+static SpvReflectResult ParseEntrypointDescriptorSets(SpvReflectShaderModule* p_module) {
+ // Update the entry point's sets
+ for (uint32_t i = 0; i < p_module->entry_point_count; ++i) {
+ SpvReflectEntryPoint* p_entry = &p_module->entry_points[i];
+ for (uint32_t j = 0; j < p_entry->descriptor_set_count; ++j) {
+ SafeFree(p_entry->descriptor_sets[j].bindings);
+ }
+ SafeFree(p_entry->descriptor_sets);
+ p_entry->descriptor_set_count = 0;
+ for (uint32_t j = 0; j < p_module->descriptor_set_count; ++j) {
+ const SpvReflectDescriptorSet* p_set = &p_module->descriptor_sets[j];
+ for (uint32_t k = 0; k < p_set->binding_count; ++k) {
+ bool found = SearchSortedUint32(
+ p_entry->used_uniforms,
+ p_entry->used_uniform_count,
+ p_set->bindings[k]->spirv_id);
+ if (found) {
+ ++p_entry->descriptor_set_count;
+ break;
+ }
+ }
+ }
+
+ p_entry->descriptor_sets = NULL;
+ if (p_entry->descriptor_set_count > 0) {
+ p_entry->descriptor_sets = (SpvReflectDescriptorSet*)calloc(p_entry->descriptor_set_count,
+ sizeof(*p_entry->descriptor_sets));
+ if (IsNull(p_entry->descriptor_sets)) {
+ return SPV_REFLECT_RESULT_ERROR_ALLOC_FAILED;
+ }
+ }
+ p_entry->descriptor_set_count = 0;
+ for (uint32_t j = 0; j < p_module->descriptor_set_count; ++j) {
+ const SpvReflectDescriptorSet* p_set = &p_module->descriptor_sets[j];
+ uint32_t count = 0;
+ for (uint32_t k = 0; k < p_set->binding_count; ++k) {
+ bool found = SearchSortedUint32(
+ p_entry->used_uniforms,
+ p_entry->used_uniform_count,
+ p_set->bindings[k]->spirv_id);
+ if (found) {
+ ++count;
+ }
+ }
+ if (count == 0) {
+ continue;
+ }
+ SpvReflectDescriptorSet* p_entry_set = &p_entry->descriptor_sets[
+ p_entry->descriptor_set_count++];
+ p_entry_set->set = p_set->set;
+ p_entry_set->bindings = (SpvReflectDescriptorBinding**)calloc(count,
+ sizeof(*p_entry_set->bindings));
+ if (IsNull(p_entry_set->bindings)) {
+ return SPV_REFLECT_RESULT_ERROR_ALLOC_FAILED;
+ }
+ for (uint32_t k = 0; k < p_set->binding_count; ++k) {
+ bool found = SearchSortedUint32(
+ p_entry->used_uniforms,
+ p_entry->used_uniform_count,
+ p_set->bindings[k]->spirv_id);
+ if (found) {
+ p_entry_set->bindings[p_entry_set->binding_count++] = p_set->bindings[k];
+ }
+ }
+ }
+ }
+
+ return SPV_REFLECT_RESULT_SUCCESS;
+}
+
+static SpvReflectResult ParseDescriptorSets(SpvReflectShaderModule* p_module)
+{
+ // Count the descriptors in each set
+ for (uint32_t i = 0; i < p_module->descriptor_binding_count; ++i) {
+ SpvReflectDescriptorBinding* p_descriptor = &(p_module->descriptor_bindings[i]);
+
+ // Look for a target set using the descriptor's set number
+ SpvReflectDescriptorSet* p_target_set = NULL;
+ for (uint32_t j = 0; j < SPV_REFLECT_MAX_DESCRIPTOR_SETS; ++j) {
+ SpvReflectDescriptorSet* p_set = &p_module->descriptor_sets[j];
+ if (p_set->set == p_descriptor->set) {
+ p_target_set = p_set;
+ break;
+ }
+ }
+
+ // If a target set isn't found, find the first available one.
+ if (IsNull(p_target_set)) {
+ for (uint32_t j = 0; j < SPV_REFLECT_MAX_DESCRIPTOR_SETS; ++j) {
+ SpvReflectDescriptorSet* p_set = &p_module->descriptor_sets[j];
+ if (p_set->set == (uint32_t)INVALID_VALUE) {
+ p_target_set = p_set;
+ p_target_set->set = p_descriptor->set;
+ break;
+ }
+ }
+ }
+
+ if (IsNull(p_target_set)) {
+ return SPV_REFLECT_RESULT_ERROR_INTERNAL_ERROR;
+ }
+
+ p_target_set->binding_count += 1;
+ }
+
+ // Count the descriptor sets
+ for (uint32_t i = 0; i < SPV_REFLECT_MAX_DESCRIPTOR_SETS; ++i) {
+ const SpvReflectDescriptorSet* p_set = &p_module->descriptor_sets[i];
+ if (p_set->set != (uint32_t)INVALID_VALUE) {
+ p_module->descriptor_set_count += 1;
+ }
+ }
+
+ // Sort the descriptor sets based on numbers
+ if (p_module->descriptor_set_count > 0) {
+ qsort(p_module->descriptor_sets,
+ p_module->descriptor_set_count,
+ sizeof(*(p_module->descriptor_sets)),
+ SortCompareDescriptorSet);
+ }
+
+ // Build descriptor pointer array
+ for (uint32_t i = 0; i <p_module->descriptor_set_count; ++i) {
+ SpvReflectDescriptorSet* p_set = &(p_module->descriptor_sets[i]);
+ p_set->bindings = (SpvReflectDescriptorBinding **)calloc(p_set->binding_count, sizeof(*(p_set->bindings)));
+
+ uint32_t descriptor_index = 0;
+ for (uint32_t j = 0; j < p_module->descriptor_binding_count; ++j) {
+ SpvReflectDescriptorBinding* p_descriptor = &(p_module->descriptor_bindings[j]);
+ if (p_descriptor->set == p_set->set) {
+ assert(descriptor_index < p_set->binding_count);
+ p_set->bindings[descriptor_index] = p_descriptor;
+ ++descriptor_index;
+ }
+ }
+ }
+
+ return ParseEntrypointDescriptorSets(p_module);
+}
+
+static SpvReflectResult DisambiguateStorageBufferSrvUav(SpvReflectShaderModule* p_module)
+{
+ if (p_module->descriptor_binding_count == 0) {
+ return SPV_REFLECT_RESULT_SUCCESS;
+ }
+
+ for (uint32_t descriptor_index = 0; descriptor_index < p_module->descriptor_binding_count; ++descriptor_index) {
+ SpvReflectDescriptorBinding* p_descriptor = &(p_module->descriptor_bindings[descriptor_index]);
+ // Skip everything that isn't a STORAGE_BUFFER descriptor
+ if (p_descriptor->descriptor_type != SPV_REFLECT_DESCRIPTOR_TYPE_STORAGE_BUFFER) {
+ continue;
+ }
+
+ //
+ // Vulkan doesn't disambiguate between SRVs and UAVs so they
+ // come back as STORAGE_BUFFER. The block parsing process will
+ // mark a block as non-writable should any member of the block
+ // or its descendants are non-writable.
+ //
+ if (p_descriptor->block.decoration_flags & SPV_REFLECT_DECORATION_NON_WRITABLE) {
+ p_descriptor->resource_type = SPV_REFLECT_RESOURCE_FLAG_SRV;
+ }
+ }
+
+ return SPV_REFLECT_RESULT_SUCCESS;
+}
+
+static SpvReflectResult SynchronizeDescriptorSets(SpvReflectShaderModule* p_module)
+{
+ // Free and reset all descriptor set numbers
+ for (uint32_t i = 0; i < SPV_REFLECT_MAX_DESCRIPTOR_SETS; ++i) {
+ SpvReflectDescriptorSet* p_set = &p_module->descriptor_sets[i];
+ SafeFree(p_set->bindings);
+ p_set->binding_count = 0;
+ p_set->set = (uint32_t)INVALID_VALUE;
+ }
+ // Set descriptor set count to zero
+ p_module->descriptor_set_count = 0;
+
+ SpvReflectResult result = ParseDescriptorSets(p_module);
+ return result;
+}
+
+SpvReflectResult spvReflectGetShaderModule(
+ size_t size,
+ const void* p_code,
+ SpvReflectShaderModule* p_module
+)
+{
+ return spvReflectCreateShaderModule(size, p_code, p_module);
+}
+
+SpvReflectResult spvReflectCreateShaderModule(
+ size_t size,
+ const void* p_code,
+ SpvReflectShaderModule* p_module
+)
+{
+ // Initialize all module fields to zero
+ memset(p_module, 0, sizeof(*p_module));
+
+ // Allocate module internals
+#ifdef __cplusplus
+ p_module->_internal = (SpvReflectShaderModule::Internal*)calloc(1, sizeof(*(p_module->_internal)));
+#else
+ p_module->_internal = calloc(1, sizeof(*(p_module->_internal)));
+#endif
+ if (IsNull(p_module->_internal)) {
+ return SPV_REFLECT_RESULT_ERROR_ALLOC_FAILED;
+ }
+ // Allocate SPIR-V code storage
+ p_module->_internal->spirv_size = size;
+ p_module->_internal->spirv_code = (uint32_t*)calloc(1, p_module->_internal->spirv_size);
+ p_module->_internal->spirv_word_count = (uint32_t)(size / SPIRV_WORD_SIZE);
+ if (IsNull(p_module->_internal->spirv_code)) {
+ SafeFree(p_module->_internal);
+ return SPV_REFLECT_RESULT_ERROR_ALLOC_FAILED;
+ }
+ memcpy(p_module->_internal->spirv_code, p_code, size);
+
+ Parser parser = { 0 };
+ SpvReflectResult result = CreateParser(p_module->_internal->spirv_size,
+ p_module->_internal->spirv_code,
+ &parser);
+
+ // Generator
+ {
+ const uint32_t* p_ptr = (const uint32_t*)p_module->_internal->spirv_code;
+ p_module->generator = (SpvReflectGenerator)((*(p_ptr + 2) & 0xFFFF0000) >> 16);
+ }
+
+ if (result == SPV_REFLECT_RESULT_SUCCESS) {
+ result = ParseNodes(&parser);
+ }
+ if (result == SPV_REFLECT_RESULT_SUCCESS) {
+ result = ParseStrings(&parser);
+ }
+ if (result == SPV_REFLECT_RESULT_SUCCESS) {
+ result = ParseSource(&parser, p_module);
+ }
+ if (result == SPV_REFLECT_RESULT_SUCCESS) {
+ result = ParseFunctions(&parser);
+ }
+ if (result == SPV_REFLECT_RESULT_SUCCESS) {
+ result = ParseMemberCounts(&parser);
+ }
+ if (result == SPV_REFLECT_RESULT_SUCCESS) {
+ result = ParseNames(&parser);
+ }
+ if (result == SPV_REFLECT_RESULT_SUCCESS) {
+ result = ParseDecorations(&parser);
+ }
+
+ // Start of reflection data parsing
+ if (result == SPV_REFLECT_RESULT_SUCCESS) {
+ p_module->source_language = parser.source_language;
+ p_module->source_language_version = parser.source_language_version;
+
+ // Zero out descriptor set data
+ p_module->descriptor_set_count = 0;
+ memset(p_module->descriptor_sets, 0, SPV_REFLECT_MAX_DESCRIPTOR_SETS * sizeof(*p_module->descriptor_sets));
+ // Initialize descriptor set numbers
+ for (uint32_t set_number = 0; set_number < SPV_REFLECT_MAX_DESCRIPTOR_SETS; ++set_number) {
+ p_module->descriptor_sets[set_number].set = (uint32_t)INVALID_VALUE;
+ }
+ }
+ if (result == SPV_REFLECT_RESULT_SUCCESS) {
+ result = ParseTypes(&parser, p_module);
+ }
+ if (result == SPV_REFLECT_RESULT_SUCCESS) {
+ result = ParseDescriptorBindings(&parser, p_module);
+ }
+ if (result == SPV_REFLECT_RESULT_SUCCESS) {
+ result = ParseDescriptorType(p_module);
+ }
+ if (result == SPV_REFLECT_RESULT_SUCCESS) {
+ result = ParseUAVCounterBindings(p_module);
+ }
+ if (result == SPV_REFLECT_RESULT_SUCCESS) {
+ result = ParseDescriptorBlocks(&parser, p_module);
+ }
+ if (result == SPV_REFLECT_RESULT_SUCCESS) {
+ result = ParsePushConstantBlocks(&parser, p_module);
+ }
+ if (result == SPV_REFLECT_RESULT_SUCCESS) {
+ result = ParseEntryPoints(&parser, p_module);
+ }
+ if (result == SPV_REFLECT_RESULT_SUCCESS && p_module->entry_point_count > 0) {
+ SpvReflectEntryPoint* p_entry = &(p_module->entry_points[0]);
+ p_module->entry_point_name = p_entry->name;
+ p_module->entry_point_id = p_entry->id;
+ p_module->spirv_execution_model = p_entry->spirv_execution_model;
+ p_module->shader_stage = p_entry->shader_stage;
+ p_module->input_variable_count = p_entry->input_variable_count;
+ p_module->input_variables = p_entry->input_variables;
+ p_module->output_variable_count = p_entry->output_variable_count;
+ p_module->output_variables = p_entry->output_variables;
+ }
+ if (result == SPV_REFLECT_RESULT_SUCCESS) {
+ result = DisambiguateStorageBufferSrvUav(p_module);
+ }
+ if (result == SPV_REFLECT_RESULT_SUCCESS) {
+ result = SynchronizeDescriptorSets(p_module);
+ }
+
+ // Destroy module if parse was not successful
+ if (result != SPV_REFLECT_RESULT_SUCCESS) {
+ spvReflectDestroyShaderModule(p_module);
+ }
+
+ DestroyParser(&parser);
+
+ return result;
+}
+
+static void SafeFreeTypes(SpvReflectTypeDescription* p_type)
+{
+ if (IsNull(p_type)) {
+ return;
+ }
+
+ if (IsNotNull(p_type->members)) {
+ for (size_t i = 0; i < p_type->member_count; ++i) {
+ SpvReflectTypeDescription* p_member = &p_type->members[i];
+ SafeFreeTypes(p_member);
+ }
+
+ SafeFree(p_type->members);
+ p_type->members = NULL;
+ }
+}
+
+static void SafeFreeBlockVariables(SpvReflectBlockVariable* p_block)
+{
+ if (IsNull(p_block)) {
+ return;
+ }
+
+ if (IsNotNull(p_block->members)) {
+ for (size_t i = 0; i < p_block->member_count; ++i) {
+ SpvReflectBlockVariable* p_member = &p_block->members[i];
+ SafeFreeBlockVariables(p_member);
+ }
+
+ SafeFree(p_block->members);
+ p_block->members = NULL;
+ }
+}
+
+static void SafeFreeInterfaceVariable(SpvReflectInterfaceVariable* p_interface)
+{
+ if (IsNull(p_interface)) {
+ return;
+ }
+
+ if (IsNotNull(p_interface->members)) {
+ for (size_t i = 0; i < p_interface->member_count; ++i) {
+ SpvReflectInterfaceVariable* p_member = &p_interface->members[i];
+ SafeFreeInterfaceVariable(p_member);
+ }
+
+ SafeFree(p_interface->members);
+ p_interface->members = NULL;
+ }
+}
+
+void spvReflectDestroyShaderModule(SpvReflectShaderModule* p_module)
+{
+ if (IsNull(p_module->_internal)) {
+ return;
+ }
+
+ // Descriptor set bindings
+ for (size_t i = 0; i < p_module->descriptor_set_count; ++i) {
+ SpvReflectDescriptorSet* p_set = &p_module->descriptor_sets[i];
+ free(p_set->bindings);
+ }
+
+ // Descriptor binding blocks
+ for (size_t i = 0; i < p_module->descriptor_binding_count; ++i) {
+ SpvReflectDescriptorBinding* p_descriptor = &p_module->descriptor_bindings[i];
+ SafeFreeBlockVariables(&p_descriptor->block);
+ }
+ SafeFree(p_module->descriptor_bindings);
+
+ // Entry points
+ for (size_t i = 0; i < p_module->entry_point_count; ++i) {
+ SpvReflectEntryPoint* p_entry = &p_module->entry_points[i];
+ for (size_t j = 0; j < p_entry->input_variable_count; j++) {
+ SafeFreeInterfaceVariable(&p_entry->input_variables[j]);
+ }
+ for (size_t j = 0; j < p_entry->output_variable_count; j++) {
+ SafeFreeInterfaceVariable(&p_entry->output_variables[j]);
+ }
+ for (uint32_t j = 0; j < p_entry->descriptor_set_count; ++j) {
+ SafeFree(p_entry->descriptor_sets[j].bindings);
+ }
+ SafeFree(p_entry->descriptor_sets);
+ SafeFree(p_entry->input_variables);
+ SafeFree(p_entry->output_variables);
+ SafeFree(p_entry->used_uniforms);
+ SafeFree(p_entry->used_push_constants);
+ }
+ SafeFree(p_module->entry_points);
+
+ // Push constants
+ for (size_t i = 0; i < p_module->push_constant_block_count; ++i) {
+ SafeFreeBlockVariables(&p_module->push_constant_blocks[i]);
+ }
+ SafeFree(p_module->push_constant_blocks);
+
+ // Type infos
+ for (size_t i = 0; i < p_module->_internal->type_description_count; ++i) {
+ SpvReflectTypeDescription* p_type = &p_module->_internal->type_descriptions[i];
+ if (IsNotNull(p_type->members)) {
+ SafeFreeTypes(p_type);
+ }
+ SafeFree(p_type->members);
+ }
+ SafeFree(p_module->_internal->type_descriptions);
+
+ // Free SPIR-V code
+ SafeFree(p_module->_internal->spirv_code);
+ // Free internal
+ SafeFree(p_module->_internal);
+}
+
+uint32_t spvReflectGetCodeSize(const SpvReflectShaderModule* p_module)
+{
+ if (IsNull(p_module)) {
+ return 0;
+ }
+
+ return (uint32_t)(p_module->_internal->spirv_size);
+}
+
+const uint32_t* spvReflectGetCode(const SpvReflectShaderModule* p_module)
+{
+ if (IsNull(p_module)) {
+ return NULL;
+ }
+
+ return p_module->_internal->spirv_code;
+}
+
+const SpvReflectEntryPoint* spvReflectGetEntryPoint(
+ const SpvReflectShaderModule* p_module,
+ const char* entry_point
+) {
+ if (IsNull(p_module) || IsNull(entry_point)) {
+ return NULL;
+ }
+
+ for (uint32_t i = 0; i < p_module->entry_point_count; ++i) {
+ if (strcmp(p_module->entry_points[i].name, entry_point) == 0) {
+ return &p_module->entry_points[i];
+ }
+ }
+ return NULL;
+}
+
+SpvReflectResult spvReflectEnumerateDescriptorBindings(
+ const SpvReflectShaderModule* p_module,
+ uint32_t* p_count,
+ SpvReflectDescriptorBinding** pp_bindings
+)
+{
+ if (IsNull(p_module)) {
+ return SPV_REFLECT_RESULT_ERROR_NULL_POINTER;
+ }
+ if (IsNull(p_count)) {
+ return SPV_REFLECT_RESULT_ERROR_NULL_POINTER;
+ }
+
+ if (IsNotNull(pp_bindings)) {
+ if (*p_count != p_module->descriptor_binding_count) {
+ return SPV_REFLECT_RESULT_ERROR_COUNT_MISMATCH;
+ }
+
+ for (uint32_t index = 0; index < *p_count; ++index) {
+ SpvReflectDescriptorBinding* p_bindings = (SpvReflectDescriptorBinding*)&p_module->descriptor_bindings[index];
+ pp_bindings[index] = p_bindings;
+ }
+ }
+ else {
+ *p_count = p_module->descriptor_binding_count;
+ }
+
+ return SPV_REFLECT_RESULT_SUCCESS;
+}
+
+SpvReflectResult spvReflectEnumerateEntryPointDescriptorBindings(
+ const SpvReflectShaderModule* p_module,
+ const char* entry_point,
+ uint32_t* p_count,
+ SpvReflectDescriptorBinding** pp_bindings
+)
+{
+ if (IsNull(p_module)) {
+ return SPV_REFLECT_RESULT_ERROR_NULL_POINTER;
+ }
+ if (IsNull(p_count)) {
+ return SPV_REFLECT_RESULT_ERROR_NULL_POINTER;
+ }
+
+ const SpvReflectEntryPoint* p_entry =
+ spvReflectGetEntryPoint(p_module, entry_point);
+ if (IsNull(p_entry)) {
+ return SPV_REFLECT_RESULT_ERROR_ELEMENT_NOT_FOUND;
+ }
+
+ uint32_t count = 0;
+ for (uint32_t i = 0; i < p_module->descriptor_binding_count; ++i) {
+ bool found = SearchSortedUint32(
+ p_entry->used_uniforms,
+ p_entry->used_uniform_count,
+ p_module->descriptor_bindings[i].spirv_id);
+ if (found) {
+ if (IsNotNull(pp_bindings)) {
+ if (count >= *p_count) {
+ return SPV_REFLECT_RESULT_ERROR_COUNT_MISMATCH;
+ }
+ pp_bindings[count++] = (SpvReflectDescriptorBinding*)&p_module->descriptor_bindings[i];
+ } else {
+ ++count;
+ }
+ }
+ }
+ if (IsNotNull(pp_bindings)) {
+ if (count != *p_count) {
+ return SPV_REFLECT_RESULT_ERROR_COUNT_MISMATCH;
+ }
+ } else {
+ *p_count = count;
+ }
+ return SPV_REFLECT_RESULT_SUCCESS;
+}
+
+SpvReflectResult spvReflectEnumerateDescriptorSets(
+ const SpvReflectShaderModule* p_module,
+ uint32_t* p_count,
+ SpvReflectDescriptorSet** pp_sets
+)
+{
+ if (IsNull(p_module)) {
+ return SPV_REFLECT_RESULT_ERROR_NULL_POINTER;
+ }
+ if (IsNull(p_count)) {
+ return SPV_REFLECT_RESULT_ERROR_NULL_POINTER;
+ }
+
+ if (IsNotNull(pp_sets)) {
+ if (*p_count != p_module->descriptor_set_count) {
+ return SPV_REFLECT_RESULT_ERROR_COUNT_MISMATCH;
+ }
+
+ for (uint32_t index = 0; index < *p_count; ++index) {
+ SpvReflectDescriptorSet* p_set = (SpvReflectDescriptorSet*)&p_module->descriptor_sets[index];
+ pp_sets[index] = p_set;
+ }
+ }
+ else {
+ *p_count = p_module->descriptor_set_count;
+ }
+
+ return SPV_REFLECT_RESULT_SUCCESS;
+}
+
+SpvReflectResult spvReflectEnumerateEntryPointDescriptorSets(
+ const SpvReflectShaderModule* p_module,
+ const char* entry_point,
+ uint32_t* p_count,
+ SpvReflectDescriptorSet** pp_sets
+)
+{
+ if (IsNull(p_module)) {
+ return SPV_REFLECT_RESULT_ERROR_NULL_POINTER;
+ }
+ if (IsNull(p_count)) {
+ return SPV_REFLECT_RESULT_ERROR_NULL_POINTER;
+ }
+
+ const SpvReflectEntryPoint* p_entry =
+ spvReflectGetEntryPoint(p_module, entry_point);
+ if (IsNull(p_entry)) {
+ return SPV_REFLECT_RESULT_ERROR_ELEMENT_NOT_FOUND;
+ }
+
+ if (IsNotNull(pp_sets)) {
+ if (*p_count != p_entry->descriptor_set_count) {
+ return SPV_REFLECT_RESULT_ERROR_COUNT_MISMATCH;
+ }
+
+ for (uint32_t index = 0; index < *p_count; ++index) {
+ SpvReflectDescriptorSet* p_set = (SpvReflectDescriptorSet*)&p_entry->descriptor_sets[index];
+ pp_sets[index] = p_set;
+ }
+ }
+ else {
+ *p_count = p_entry->descriptor_set_count;
+ }
+
+ return SPV_REFLECT_RESULT_SUCCESS;
+}
+
+SpvReflectResult spvReflectEnumerateInputVariables(
+ const SpvReflectShaderModule* p_module,
+ uint32_t* p_count,
+ SpvReflectInterfaceVariable** pp_variables
+)
+{
+ if (IsNull(p_module)) {
+ return SPV_REFLECT_RESULT_ERROR_NULL_POINTER;
+ }
+ if (IsNull(p_count)) {
+ return SPV_REFLECT_RESULT_ERROR_NULL_POINTER;
+ }
+
+ if (IsNotNull(pp_variables)) {
+ if (*p_count != p_module->input_variable_count) {
+ return SPV_REFLECT_RESULT_ERROR_COUNT_MISMATCH;
+ }
+
+ for (uint32_t index = 0; index < *p_count; ++index) {
+ SpvReflectInterfaceVariable* p_var = (SpvReflectInterfaceVariable*)&p_module->input_variables[index];
+ pp_variables[index] = p_var;
+ }
+ }
+ else {
+ *p_count = p_module->input_variable_count;
+ }
+
+ return SPV_REFLECT_RESULT_SUCCESS;
+}
+
+SpvReflectResult spvReflectEnumerateEntryPointInputVariables(
+ const SpvReflectShaderModule* p_module,
+ const char* entry_point,
+ uint32_t* p_count,
+ SpvReflectInterfaceVariable** pp_variables
+)
+{
+ if (IsNull(p_module)) {
+ return SPV_REFLECT_RESULT_ERROR_NULL_POINTER;
+ }
+ if (IsNull(p_count)) {
+ return SPV_REFLECT_RESULT_ERROR_NULL_POINTER;
+ }
+
+ const SpvReflectEntryPoint* p_entry =
+ spvReflectGetEntryPoint(p_module, entry_point);
+ if (IsNull(p_entry)) {
+ return SPV_REFLECT_RESULT_ERROR_ELEMENT_NOT_FOUND;
+ }
+
+ if (IsNotNull(pp_variables)) {
+ if (*p_count != p_entry->input_variable_count) {
+ return SPV_REFLECT_RESULT_ERROR_COUNT_MISMATCH;
+ }
+
+ for (uint32_t index = 0; index < *p_count; ++index) {
+ SpvReflectInterfaceVariable* p_var = (SpvReflectInterfaceVariable*)&p_entry->input_variables[index];
+ pp_variables[index] = p_var;
+ }
+ }
+ else {
+ *p_count = p_entry->input_variable_count;
+ }
+
+ return SPV_REFLECT_RESULT_SUCCESS;
+}
+
+SpvReflectResult spvReflectEnumerateOutputVariables(
+ const SpvReflectShaderModule* p_module,
+ uint32_t* p_count,
+ SpvReflectInterfaceVariable** pp_variables
+)
+{
+ if (IsNull(p_module)) {
+ return SPV_REFLECT_RESULT_ERROR_NULL_POINTER;
+ }
+ if (IsNull(p_count)) {
+ return SPV_REFLECT_RESULT_ERROR_NULL_POINTER;
+ }
+
+ if (IsNotNull(pp_variables)) {
+ if (*p_count != p_module->output_variable_count) {
+ return SPV_REFLECT_RESULT_ERROR_COUNT_MISMATCH;
+ }
+
+ for (uint32_t index = 0; index < *p_count; ++index) {
+ SpvReflectInterfaceVariable* p_var = (SpvReflectInterfaceVariable*)&p_module->output_variables[index];
+ pp_variables[index] = p_var;
+ }
+ }
+ else {
+ *p_count = p_module->output_variable_count;
+ }
+
+ return SPV_REFLECT_RESULT_SUCCESS;
+}
+
+SpvReflectResult spvReflectEnumerateEntryPointOutputVariables(
+ const SpvReflectShaderModule* p_module,
+ const char* entry_point,
+ uint32_t* p_count,
+ SpvReflectInterfaceVariable** pp_variables
+)
+{
+ if (IsNull(p_module)) {
+ return SPV_REFLECT_RESULT_ERROR_NULL_POINTER;
+ }
+ if (IsNull(p_count)) {
+ return SPV_REFLECT_RESULT_ERROR_NULL_POINTER;
+ }
+
+ const SpvReflectEntryPoint* p_entry =
+ spvReflectGetEntryPoint(p_module, entry_point);
+ if (IsNull(p_entry)) {
+ return SPV_REFLECT_RESULT_ERROR_ELEMENT_NOT_FOUND;
+ }
+
+ if (IsNotNull(pp_variables)) {
+ if (*p_count != p_entry->output_variable_count) {
+ return SPV_REFLECT_RESULT_ERROR_COUNT_MISMATCH;
+ }
+
+ for (uint32_t index = 0; index < *p_count; ++index) {
+ SpvReflectInterfaceVariable* p_var = (SpvReflectInterfaceVariable*)&p_entry->output_variables[index];
+ pp_variables[index] = p_var;
+ }
+ }
+ else {
+ *p_count = p_entry->output_variable_count;
+ }
+
+ return SPV_REFLECT_RESULT_SUCCESS;
+}
+
+SpvReflectResult spvReflectEnumeratePushConstantBlocks(
+ const SpvReflectShaderModule* p_module,
+ uint32_t* p_count,
+ SpvReflectBlockVariable** pp_blocks
+)
+{
+ if (IsNull(p_module)) {
+ return SPV_REFLECT_RESULT_ERROR_NULL_POINTER;
+ }
+ if (IsNull(p_count)) {
+ return SPV_REFLECT_RESULT_ERROR_NULL_POINTER;
+ }
+
+ if (pp_blocks != NULL) {
+ if (*p_count != p_module->push_constant_block_count) {
+ return SPV_REFLECT_RESULT_ERROR_COUNT_MISMATCH;
+ }
+
+ for (uint32_t index = 0; index < *p_count; ++index) {
+ SpvReflectBlockVariable* p_push_constant_blocks = (SpvReflectBlockVariable*)&p_module->push_constant_blocks[index];
+ pp_blocks[index] = p_push_constant_blocks;
+ }
+ }
+ else {
+ *p_count = p_module->push_constant_block_count;
+ }
+
+ return SPV_REFLECT_RESULT_SUCCESS;
+}
+SpvReflectResult spvReflectEnumeratePushConstants(
+ const SpvReflectShaderModule* p_module,
+ uint32_t* p_count,
+ SpvReflectBlockVariable** pp_blocks
+)
+{
+ return spvReflectEnumeratePushConstantBlocks(p_module, p_count, pp_blocks);
+}
+
+SpvReflectResult spvReflectEnumerateEntryPointPushConstantBlocks(
+ const SpvReflectShaderModule* p_module,
+ const char* entry_point,
+ uint32_t* p_count,
+ SpvReflectBlockVariable** pp_blocks
+)
+{
+ if (IsNull(p_module)) {
+ return SPV_REFLECT_RESULT_ERROR_NULL_POINTER;
+ }
+ if (IsNull(p_count)) {
+ return SPV_REFLECT_RESULT_ERROR_NULL_POINTER;
+ }
+
+
+ const SpvReflectEntryPoint* p_entry =
+ spvReflectGetEntryPoint(p_module, entry_point);
+ if (IsNull(p_entry)) {
+ return SPV_REFLECT_RESULT_ERROR_ELEMENT_NOT_FOUND;
+ }
+
+ uint32_t count = 0;
+ for (uint32_t i = 0; i < p_module->push_constant_block_count; ++i) {
+ bool found = SearchSortedUint32(p_entry->used_push_constants,
+ p_entry->used_push_constant_count,
+ p_module->push_constant_blocks[i].spirv_id);
+ if (found) {
+ if (IsNotNull(pp_blocks)) {
+ if (count >= *p_count) {
+ return SPV_REFLECT_RESULT_ERROR_COUNT_MISMATCH;
+ }
+ pp_blocks[count++] = (SpvReflectBlockVariable*)&p_module->push_constant_blocks[i];
+ } else {
+ ++count;
+ }
+ }
+ }
+ if (IsNotNull(pp_blocks)) {
+ if (count != *p_count) {
+ return SPV_REFLECT_RESULT_ERROR_COUNT_MISMATCH;
+ }
+ } else {
+ *p_count = count;
+ }
+ return SPV_REFLECT_RESULT_SUCCESS;
+}
+
+const SpvReflectDescriptorBinding* spvReflectGetDescriptorBinding(
+ const SpvReflectShaderModule* p_module,
+ uint32_t binding_number,
+ uint32_t set_number,
+ SpvReflectResult* p_result
+)
+{
+ const SpvReflectDescriptorBinding* p_descriptor = NULL;
+ if (IsNotNull(p_module)) {
+ for (uint32_t index = 0; index < p_module->descriptor_binding_count; ++index) {
+ const SpvReflectDescriptorBinding* p_potential = &p_module->descriptor_bindings[index];
+ if ((p_potential->binding == binding_number) && (p_potential->set == set_number)) {
+ p_descriptor = p_potential;
+ break;
+ }
+ }
+ }
+ if (IsNotNull(p_result)) {
+ *p_result = IsNotNull(p_descriptor)
+ ? SPV_REFLECT_RESULT_SUCCESS
+ : (IsNull(p_module) ? SPV_REFLECT_RESULT_ERROR_NULL_POINTER
+ : SPV_REFLECT_RESULT_ERROR_ELEMENT_NOT_FOUND);
+ }
+ return p_descriptor;
+}
+
+const SpvReflectDescriptorBinding* spvReflectGetEntryPointDescriptorBinding(
+ const SpvReflectShaderModule* p_module,
+ const char* entry_point,
+ uint32_t binding_number,
+ uint32_t set_number,
+ SpvReflectResult* p_result
+)
+{
+ const SpvReflectEntryPoint* p_entry =
+ spvReflectGetEntryPoint(p_module, entry_point);
+ if (IsNull(p_entry)) {
+ if (IsNotNull(p_result)) {
+ *p_result = SPV_REFLECT_RESULT_ERROR_ELEMENT_NOT_FOUND;
+ }
+ return NULL;
+ }
+ const SpvReflectDescriptorBinding* p_descriptor = NULL;
+ if (IsNotNull(p_module)) {
+ for (uint32_t index = 0; index < p_module->descriptor_binding_count; ++index) {
+ const SpvReflectDescriptorBinding* p_potential = &p_module->descriptor_bindings[index];
+ bool found = SearchSortedUint32(
+ p_entry->used_uniforms,
+ p_entry->used_uniform_count,
+ p_potential->spirv_id);
+ if ((p_potential->binding == binding_number) && (p_potential->set == set_number) && found) {
+ p_descriptor = p_potential;
+ break;
+ }
+ }
+ }
+ if (IsNotNull(p_result)) {
+ *p_result = IsNotNull(p_descriptor)
+ ? SPV_REFLECT_RESULT_SUCCESS
+ : (IsNull(p_module) ? SPV_REFLECT_RESULT_ERROR_NULL_POINTER
+ : SPV_REFLECT_RESULT_ERROR_ELEMENT_NOT_FOUND);
+ }
+ return p_descriptor;
+}
+
+const SpvReflectDescriptorSet* spvReflectGetDescriptorSet(
+ const SpvReflectShaderModule* p_module,
+ uint32_t set_number,
+ SpvReflectResult* p_result
+)
+{
+ const SpvReflectDescriptorSet* p_set = NULL;
+ if (IsNotNull(p_module)) {
+ for (uint32_t index = 0; index < p_module->descriptor_set_count; ++index) {
+ const SpvReflectDescriptorSet* p_potential = &p_module->descriptor_sets[index];
+ if (p_potential->set == set_number) {
+ p_set = p_potential;
+ }
+ }
+ }
+ if (IsNotNull(p_result)) {
+ *p_result = IsNotNull(p_set)
+ ? SPV_REFLECT_RESULT_SUCCESS
+ : (IsNull(p_module) ? SPV_REFLECT_RESULT_ERROR_NULL_POINTER
+ : SPV_REFLECT_RESULT_ERROR_ELEMENT_NOT_FOUND);
+ }
+ return p_set;
+}
+
+const SpvReflectDescriptorSet* spvReflectGetEntryPointDescriptorSet(
+ const SpvReflectShaderModule* p_module,
+ const char* entry_point,
+ uint32_t set_number,
+ SpvReflectResult* p_result)
+{
+ const SpvReflectDescriptorSet* p_set = NULL;
+ if (IsNotNull(p_module)) {
+ const SpvReflectEntryPoint* p_entry = spvReflectGetEntryPoint(p_module, entry_point);
+ if (IsNull(p_entry)) {
+ if (IsNotNull(p_result)) {
+ *p_result = SPV_REFLECT_RESULT_ERROR_ELEMENT_NOT_FOUND;
+ }
+ return NULL;
+ }
+ for (uint32_t index = 0; index < p_entry->descriptor_set_count; ++index) {
+ const SpvReflectDescriptorSet* p_potential = &p_entry->descriptor_sets[index];
+ if (p_potential->set == set_number) {
+ p_set = p_potential;
+ }
+ }
+ }
+ if (IsNotNull(p_result)) {
+ *p_result = IsNotNull(p_set)
+ ? SPV_REFLECT_RESULT_SUCCESS
+ : (IsNull(p_module) ? SPV_REFLECT_RESULT_ERROR_NULL_POINTER
+ : SPV_REFLECT_RESULT_ERROR_ELEMENT_NOT_FOUND);
+ }
+ return p_set;
+}
+
+
+const SpvReflectInterfaceVariable* spvReflectGetInputVariableByLocation(
+ const SpvReflectShaderModule* p_module,
+ uint32_t location,
+ SpvReflectResult* p_result
+)
+{
+ if (location == INVALID_VALUE) {
+ if (IsNotNull(p_result)) {
+ *p_result = SPV_REFLECT_RESULT_ERROR_ELEMENT_NOT_FOUND;
+ }
+ return NULL;
+ }
+ const SpvReflectInterfaceVariable* p_var = NULL;
+ if (IsNotNull(p_module)) {
+ for (uint32_t index = 0; index < p_module->input_variable_count; ++index) {
+ const SpvReflectInterfaceVariable* p_potential = &p_module->input_variables[index];
+ if (p_potential->location == location) {
+ p_var = p_potential;
+ }
+ }
+ }
+ if (IsNotNull(p_result)) {
+ *p_result = IsNotNull(p_var)
+ ? SPV_REFLECT_RESULT_SUCCESS
+ : (IsNull(p_module) ? SPV_REFLECT_RESULT_ERROR_NULL_POINTER
+ : SPV_REFLECT_RESULT_ERROR_ELEMENT_NOT_FOUND);
+ }
+ return p_var;
+}
+const SpvReflectInterfaceVariable* spvReflectGetInputVariable(
+ const SpvReflectShaderModule* p_module,
+ uint32_t location,
+ SpvReflectResult* p_result
+)
+{
+ return spvReflectGetInputVariableByLocation(p_module, location, p_result);
+}
+
+const SpvReflectInterfaceVariable* spvReflectGetEntryPointInputVariableByLocation(
+ const SpvReflectShaderModule* p_module,
+ const char* entry_point,
+ uint32_t location,
+ SpvReflectResult* p_result
+)
+{
+ if (location == INVALID_VALUE) {
+ if (IsNotNull(p_result)) {
+ *p_result = SPV_REFLECT_RESULT_ERROR_ELEMENT_NOT_FOUND;
+ }
+ return NULL;
+ }
+
+ const SpvReflectInterfaceVariable* p_var = NULL;
+ if (IsNotNull(p_module)) {
+ const SpvReflectEntryPoint* p_entry =
+ spvReflectGetEntryPoint(p_module, entry_point);
+ if (IsNull(p_entry)) {
+ if (IsNotNull(p_result)) {
+ *p_result = SPV_REFLECT_RESULT_ERROR_ELEMENT_NOT_FOUND;
+ }
+ return NULL;
+ }
+ for (uint32_t index = 0; index < p_entry->input_variable_count; ++index) {
+ const SpvReflectInterfaceVariable* p_potential = &p_entry->input_variables[index];
+ if (p_potential->location == location) {
+ p_var = p_potential;
+ }
+ }
+ }
+ if (IsNotNull(p_result)) {
+ *p_result = IsNotNull(p_var)
+ ? SPV_REFLECT_RESULT_SUCCESS
+ : (IsNull(p_module) ? SPV_REFLECT_RESULT_ERROR_NULL_POINTER
+ : SPV_REFLECT_RESULT_ERROR_ELEMENT_NOT_FOUND);
+ }
+ return p_var;
+}
+
+const SpvReflectInterfaceVariable* spvReflectGetInputVariableBySemantic(
+ const SpvReflectShaderModule* p_module,
+ const char* semantic,
+ SpvReflectResult* p_result
+)
+{
+ if (IsNull(semantic)) {
+ if (IsNotNull(p_result)) {
+ *p_result = SPV_REFLECT_RESULT_ERROR_NULL_POINTER;
+ }
+ return NULL;
+ }
+ if (semantic[0] == '\0') {
+ if (IsNotNull(p_result)) {
+ *p_result = SPV_REFLECT_RESULT_ERROR_ELEMENT_NOT_FOUND;
+ }
+ return NULL;
+ }
+ const SpvReflectInterfaceVariable* p_var = NULL;
+ if (IsNotNull(p_module)) {
+ for (uint32_t index = 0; index < p_module->input_variable_count; ++index) {
+ const SpvReflectInterfaceVariable* p_potential = &p_module->input_variables[index];
+ if (p_potential->semantic != NULL && strcmp(p_potential->semantic, semantic) == 0) {
+ p_var = p_potential;
+ }
+ }
+ }
+ if (IsNotNull(p_result)) {
+ *p_result = IsNotNull(p_var)
+ ? SPV_REFLECT_RESULT_SUCCESS
+ : (IsNull(p_module) ? SPV_REFLECT_RESULT_ERROR_NULL_POINTER
+ : SPV_REFLECT_RESULT_ERROR_ELEMENT_NOT_FOUND);
+ }
+ return p_var;
+}
+
+const SpvReflectInterfaceVariable* spvReflectGetEntryPointInputVariableBySemantic(
+ const SpvReflectShaderModule* p_module,
+ const char* entry_point,
+ const char* semantic,
+ SpvReflectResult* p_result
+)
+{
+ if (IsNull(semantic)) {
+ if (IsNotNull(p_result)) {
+ *p_result = SPV_REFLECT_RESULT_ERROR_NULL_POINTER;
+ }
+ return NULL;
+ }
+ if (semantic[0] == '\0') {
+ if (IsNotNull(p_result)) {
+ *p_result = SPV_REFLECT_RESULT_ERROR_ELEMENT_NOT_FOUND;
+ }
+ return NULL;
+ }
+ const SpvReflectInterfaceVariable* p_var = NULL;
+ if (IsNotNull(p_module)) {
+ const SpvReflectEntryPoint* p_entry = spvReflectGetEntryPoint(p_module, entry_point);
+ if (IsNull(p_entry)) {
+ if (IsNotNull(p_result)) {
+ *p_result = SPV_REFLECT_RESULT_ERROR_ELEMENT_NOT_FOUND;
+ }
+ return NULL;
+ }
+ for (uint32_t index = 0; index < p_entry->input_variable_count; ++index) {
+ const SpvReflectInterfaceVariable* p_potential = &p_entry->input_variables[index];
+ if (p_potential->semantic != NULL && strcmp(p_potential->semantic, semantic) == 0) {
+ p_var = p_potential;
+ }
+ }
+ }
+ if (IsNotNull(p_result)) {
+ *p_result = IsNotNull(p_var)
+ ? SPV_REFLECT_RESULT_SUCCESS
+ : (IsNull(p_module) ? SPV_REFLECT_RESULT_ERROR_NULL_POINTER
+ : SPV_REFLECT_RESULT_ERROR_ELEMENT_NOT_FOUND);
+ }
+ return p_var;
+}
+
+const SpvReflectInterfaceVariable* spvReflectGetOutputVariableByLocation(
+ const SpvReflectShaderModule* p_module,
+ uint32_t location,
+ SpvReflectResult* p_result
+)
+{
+ if (location == INVALID_VALUE) {
+ if (IsNotNull(p_result)) {
+ *p_result = SPV_REFLECT_RESULT_ERROR_ELEMENT_NOT_FOUND;
+ }
+ return NULL;
+ }
+ const SpvReflectInterfaceVariable* p_var = NULL;
+ if (IsNotNull(p_module)) {
+ for (uint32_t index = 0; index < p_module->output_variable_count; ++index) {
+ const SpvReflectInterfaceVariable* p_potential = &p_module->output_variables[index];
+ if (p_potential->location == location) {
+ p_var = p_potential;
+ }
+ }
+ }
+ if (IsNotNull(p_result)) {
+ *p_result = IsNotNull(p_var)
+ ? SPV_REFLECT_RESULT_SUCCESS
+ : (IsNull(p_module) ? SPV_REFLECT_RESULT_ERROR_NULL_POINTER
+ : SPV_REFLECT_RESULT_ERROR_ELEMENT_NOT_FOUND);
+ }
+ return p_var;
+}
+const SpvReflectInterfaceVariable* spvReflectGetOutputVariable(
+ const SpvReflectShaderModule* p_module,
+ uint32_t location,
+ SpvReflectResult* p_result
+)
+{
+ return spvReflectGetOutputVariableByLocation(p_module, location, p_result);
+}
+
+const SpvReflectInterfaceVariable* spvReflectGetEntryPointOutputVariableByLocation(
+ const SpvReflectShaderModule* p_module,
+ const char* entry_point,
+ uint32_t location,
+ SpvReflectResult* p_result
+)
+{
+ if (location == INVALID_VALUE) {
+ if (IsNotNull(p_result)) {
+ *p_result = SPV_REFLECT_RESULT_ERROR_ELEMENT_NOT_FOUND;
+ }
+ return NULL;
+ }
+
+ const SpvReflectInterfaceVariable* p_var = NULL;
+ if (IsNotNull(p_module)) {
+ const SpvReflectEntryPoint* p_entry = spvReflectGetEntryPoint(p_module, entry_point);
+ if (IsNull(p_entry)) {
+ if (IsNotNull(p_result)) {
+ *p_result = SPV_REFLECT_RESULT_ERROR_ELEMENT_NOT_FOUND;
+ }
+ return NULL;
+ }
+ for (uint32_t index = 0; index < p_entry->output_variable_count; ++index) {
+ const SpvReflectInterfaceVariable* p_potential = &p_entry->output_variables[index];
+ if (p_potential->location == location) {
+ p_var = p_potential;
+ }
+ }
+ }
+ if (IsNotNull(p_result)) {
+ *p_result = IsNotNull(p_var)
+ ? SPV_REFLECT_RESULT_SUCCESS
+ : (IsNull(p_module) ? SPV_REFLECT_RESULT_ERROR_NULL_POINTER
+ : SPV_REFLECT_RESULT_ERROR_ELEMENT_NOT_FOUND);
+ }
+ return p_var;
+}
+
+const SpvReflectInterfaceVariable* spvReflectGetOutputVariableBySemantic(
+ const SpvReflectShaderModule* p_module,
+ const char* semantic,
+ SpvReflectResult* p_result
+)
+{
+ if (IsNull(semantic)) {
+ if (IsNotNull(p_result)) {
+ *p_result = SPV_REFLECT_RESULT_ERROR_NULL_POINTER;
+ }
+ return NULL;
+ }
+ if (semantic[0] == '\0') {
+ if (IsNotNull(p_result)) {
+ *p_result = SPV_REFLECT_RESULT_ERROR_ELEMENT_NOT_FOUND;
+ }
+ return NULL;
+ }
+ const SpvReflectInterfaceVariable* p_var = NULL;
+ if (IsNotNull(p_module)) {
+ for (uint32_t index = 0; index < p_module->output_variable_count; ++index) {
+ const SpvReflectInterfaceVariable* p_potential = &p_module->output_variables[index];
+ if (p_potential->semantic != NULL && strcmp(p_potential->semantic, semantic) == 0) {
+ p_var = p_potential;
+ }
+ }
+ }
+ if (IsNotNull(p_result)) {
+ *p_result = IsNotNull(p_var)
+ ? SPV_REFLECT_RESULT_SUCCESS
+ : (IsNull(p_module) ? SPV_REFLECT_RESULT_ERROR_NULL_POINTER
+ : SPV_REFLECT_RESULT_ERROR_ELEMENT_NOT_FOUND);
+ }
+ return p_var;
+}
+
+const SpvReflectInterfaceVariable* spvReflectGetEntryPointOutputVariableBySemantic(
+ const SpvReflectShaderModule* p_module,
+ const char* entry_point,
+ const char* semantic,
+ SpvReflectResult* p_result)
+{
+ if (IsNull(semantic)) {
+ if (IsNotNull(p_result)) {
+ *p_result = SPV_REFLECT_RESULT_ERROR_NULL_POINTER;
+ }
+ return NULL;
+ }
+ if (semantic[0] == '\0') {
+ if (IsNotNull(p_result)) {
+ *p_result = SPV_REFLECT_RESULT_ERROR_ELEMENT_NOT_FOUND;
+ }
+ return NULL;
+ }
+ const SpvReflectInterfaceVariable* p_var = NULL;
+ if (IsNotNull(p_module)) {
+ const SpvReflectEntryPoint* p_entry = spvReflectGetEntryPoint(p_module, entry_point);
+ if (IsNull(p_entry)) {
+ if (IsNotNull(p_result)) {
+ *p_result = SPV_REFLECT_RESULT_ERROR_ELEMENT_NOT_FOUND;
+ }
+ return NULL;
+ }
+ for (uint32_t index = 0; index < p_entry->output_variable_count; ++index) {
+ const SpvReflectInterfaceVariable* p_potential = &p_entry->output_variables[index];
+ if (p_potential->semantic != NULL && strcmp(p_potential->semantic, semantic) == 0) {
+ p_var = p_potential;
+ }
+ }
+ }
+ if (IsNotNull(p_result)) {
+ *p_result = IsNotNull(p_var)
+ ? SPV_REFLECT_RESULT_SUCCESS
+ : (IsNull(p_module) ? SPV_REFLECT_RESULT_ERROR_NULL_POINTER
+ : SPV_REFLECT_RESULT_ERROR_ELEMENT_NOT_FOUND);
+ }
+ return p_var;
+}
+
+const SpvReflectBlockVariable* spvReflectGetPushConstantBlock(
+ const SpvReflectShaderModule* p_module,
+ uint32_t index,
+ SpvReflectResult* p_result
+)
+{
+ const SpvReflectBlockVariable* p_push_constant = NULL;
+ if (IsNotNull(p_module)) {
+ if (index < p_module->push_constant_block_count) {
+ p_push_constant = &p_module->push_constant_blocks[index];
+ }
+ }
+ if (IsNotNull(p_result)) {
+ *p_result = IsNotNull(p_push_constant)
+ ? SPV_REFLECT_RESULT_SUCCESS
+ : (IsNull(p_module) ? SPV_REFLECT_RESULT_ERROR_NULL_POINTER
+ : SPV_REFLECT_RESULT_ERROR_ELEMENT_NOT_FOUND);
+ }
+ return p_push_constant;
+}
+const SpvReflectBlockVariable* spvReflectGetPushConstant(
+ const SpvReflectShaderModule* p_module,
+ uint32_t index,
+ SpvReflectResult* p_result
+)
+{
+ return spvReflectGetPushConstantBlock(p_module, index, p_result);
+}
+
+const SpvReflectBlockVariable* spvReflectGetEntryPointPushConstantBlock(
+ const SpvReflectShaderModule* p_module,
+ const char* entry_point,
+ SpvReflectResult* p_result)
+{
+ const SpvReflectBlockVariable* p_push_constant = NULL;
+ if (IsNotNull(p_module)) {
+ const SpvReflectEntryPoint* p_entry =
+ spvReflectGetEntryPoint(p_module, entry_point);
+ if (IsNull(p_entry)) {
+ if (IsNotNull(p_result)) {
+ *p_result = SPV_REFLECT_RESULT_ERROR_ELEMENT_NOT_FOUND;
+ }
+ return NULL;
+ }
+ for (uint32_t i = 0; i < p_module->push_constant_block_count; ++i) {
+ bool found = SearchSortedUint32(
+ p_entry->used_push_constants,
+ p_entry->used_push_constant_count,
+ p_module->push_constant_blocks[i].spirv_id);
+ if (found) {
+ p_push_constant = &p_module->push_constant_blocks[i];
+ break;
+ }
+ }
+ }
+ if (IsNotNull(p_result)) {
+ *p_result = IsNotNull(p_push_constant)
+ ? SPV_REFLECT_RESULT_SUCCESS
+ : (IsNull(p_module) ? SPV_REFLECT_RESULT_ERROR_NULL_POINTER
+ : SPV_REFLECT_RESULT_ERROR_ELEMENT_NOT_FOUND);
+ }
+ return p_push_constant;
+}
+
+SpvReflectResult spvReflectChangeDescriptorBindingNumbers(
+ SpvReflectShaderModule* p_module,
+ const SpvReflectDescriptorBinding* p_binding,
+ uint32_t new_binding_number,
+ uint32_t new_set_binding
+)
+{
+ if (IsNull(p_module)) {
+ return SPV_REFLECT_RESULT_ERROR_NULL_POINTER;
+ }
+ if (IsNull(p_binding)) {
+ return SPV_REFLECT_RESULT_ERROR_NULL_POINTER;
+ }
+
+ SpvReflectDescriptorBinding* p_target_descriptor = NULL;
+ for (uint32_t index = 0; index < p_module->descriptor_binding_count; ++index) {
+ if(&p_module->descriptor_bindings[index] == p_binding) {
+ p_target_descriptor = &p_module->descriptor_bindings[index];
+ break;
+ }
+ }
+
+ if (IsNotNull(p_target_descriptor)) {
+ if (p_target_descriptor->word_offset.binding > (p_module->_internal->spirv_word_count - 1)) {
+ return SPV_REFLECT_RESULT_ERROR_RANGE_EXCEEDED;
+ }
+ // Binding number
+ if (new_binding_number != SPV_REFLECT_BINDING_NUMBER_DONT_CHANGE) {
+ uint32_t* p_code = p_module->_internal->spirv_code + p_target_descriptor->word_offset.binding;
+ *p_code = new_binding_number;
+ p_target_descriptor->binding = new_binding_number;
+ }
+ // Set number
+ if (new_set_binding != SPV_REFLECT_SET_NUMBER_DONT_CHANGE) {
+ uint32_t* p_code = p_module->_internal->spirv_code + p_target_descriptor->word_offset.set;
+ *p_code = new_set_binding;
+ p_target_descriptor->set = new_set_binding;
+ }
+ }
+
+ SpvReflectResult result = SPV_REFLECT_RESULT_SUCCESS;
+ if (new_set_binding != SPV_REFLECT_SET_NUMBER_DONT_CHANGE) {
+ result = SynchronizeDescriptorSets(p_module);
+ }
+ return result;
+}
+SpvReflectResult spvReflectChangeDescriptorBindingNumber(
+ SpvReflectShaderModule* p_module,
+ const SpvReflectDescriptorBinding* p_descriptor_binding,
+ uint32_t new_binding_number,
+ uint32_t optional_new_set_number
+)
+{
+ return spvReflectChangeDescriptorBindingNumbers(
+ p_module,p_descriptor_binding,
+ new_binding_number,
+ optional_new_set_number);
+}
+
+SpvReflectResult spvReflectChangeDescriptorSetNumber(
+ SpvReflectShaderModule* p_module,
+ const SpvReflectDescriptorSet* p_set,
+ uint32_t new_set_number
+)
+{
+ if (IsNull(p_module)) {
+ return SPV_REFLECT_RESULT_ERROR_NULL_POINTER;
+ }
+ if (IsNull(p_set)) {
+ return SPV_REFLECT_RESULT_ERROR_NULL_POINTER;
+ }
+ SpvReflectDescriptorSet* p_target_set = NULL;
+ for (uint32_t index = 0; index < SPV_REFLECT_MAX_DESCRIPTOR_SETS; ++index) {
+ // The descriptor sets for specific entry points might not be in this set,
+ // so just match on set index.
+ if (p_module->descriptor_sets[index].set == p_set->set) {
+ p_target_set = (SpvReflectDescriptorSet*)p_set;
+ break;
+ }
+ }
+
+ SpvReflectResult result = SPV_REFLECT_RESULT_SUCCESS;
+ if (IsNotNull(p_target_set) && new_set_number != SPV_REFLECT_SET_NUMBER_DONT_CHANGE) {
+ for (uint32_t index = 0; index < p_target_set->binding_count; ++index) {
+ SpvReflectDescriptorBinding* p_descriptor = p_target_set->bindings[index];
+ if (p_descriptor->word_offset.set > (p_module->_internal->spirv_word_count - 1)) {
+ return SPV_REFLECT_RESULT_ERROR_RANGE_EXCEEDED;
+ }
+
+ uint32_t* p_code = p_module->_internal->spirv_code + p_descriptor->word_offset.set;
+ *p_code = new_set_number;
+ p_descriptor->set = new_set_number;
+ }
+
+ result = SynchronizeDescriptorSets(p_module);
+ }
+
+ return result;
+}
+
+static SpvReflectResult ChangeVariableLocation(
+ SpvReflectShaderModule* p_module,
+ SpvReflectInterfaceVariable* p_variable,
+ uint32_t new_location
+)
+{
+ if (p_variable->word_offset.location > (p_module->_internal->spirv_word_count - 1)) {
+ return SPV_REFLECT_RESULT_ERROR_RANGE_EXCEEDED;
+ }
+ uint32_t* p_code = p_module->_internal->spirv_code + p_variable->word_offset.location;
+ *p_code = new_location;
+ p_variable->location = new_location;
+ return SPV_REFLECT_RESULT_SUCCESS;
+}
+
+SpvReflectResult spvReflectChangeInputVariableLocation(
+ SpvReflectShaderModule* p_module,
+ const SpvReflectInterfaceVariable* p_input_variable,
+ uint32_t new_location
+)
+{
+ if (IsNull(p_module)) {
+ return SPV_REFLECT_RESULT_ERROR_NULL_POINTER;
+ }
+ if (IsNull(p_input_variable)) {
+ return SPV_REFLECT_RESULT_ERROR_NULL_POINTER;
+ }
+ for (uint32_t index = 0; index < p_module->input_variable_count; ++index) {
+ if(&p_module->input_variables[index] == p_input_variable) {
+ return ChangeVariableLocation(p_module, &p_module->input_variables[index], new_location);
+ }
+ }
+ return SPV_REFLECT_RESULT_ERROR_ELEMENT_NOT_FOUND;
+}
+
+SpvReflectResult spvReflectChangeOutputVariableLocation(
+ SpvReflectShaderModule* p_module,
+ const SpvReflectInterfaceVariable* p_output_variable,
+ uint32_t new_location
+)
+{
+ if (IsNull(p_module)) {
+ return SPV_REFLECT_RESULT_ERROR_NULL_POINTER;
+ }
+ if (IsNull(p_output_variable)) {
+ return SPV_REFLECT_RESULT_ERROR_NULL_POINTER;
+ }
+ for (uint32_t index = 0; index < p_module->output_variable_count; ++index) {
+ if(&p_module->output_variables[index] == p_output_variable) {
+ return ChangeVariableLocation(p_module, &p_module->output_variables[index], new_location);
+ }
+ }
+ return SPV_REFLECT_RESULT_ERROR_ELEMENT_NOT_FOUND;
+}
+
+const char* spvReflectSourceLanguage(SpvSourceLanguage source_lang)
+{
+ switch (source_lang) {
+ case SpvSourceLanguageUnknown : return "Unknown";
+ case SpvSourceLanguageESSL : return "ESSL";
+ case SpvSourceLanguageGLSL : return "GLSL";
+ case SpvSourceLanguageOpenCL_C : return "OpenCL_C";
+ case SpvSourceLanguageOpenCL_CPP : return "OpenCL_CPP";
+ case SpvSourceLanguageHLSL : return "HLSL";
+
+ case SpvSourceLanguageMax:
+ break;
+ }
+ return "";
+}
diff --git a/thirdparty/spirv-reflect/spirv_reflect.h b/thirdparty/spirv-reflect/spirv_reflect.h
new file mode 100644
index 0000000000..6554aaa2cf
--- /dev/null
+++ b/thirdparty/spirv-reflect/spirv_reflect.h
@@ -0,0 +1,2045 @@
+/*
+ Copyright 2017-2018 Google Inc.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+/*
+
+VERSION HISTORY
+
+ 1.0 (2018-03-27) Initial public release
+
+*/
+
+/*!
+
+ @file spirv_reflect.h
+
+*/
+#ifndef SPIRV_REFLECT_H
+#define SPIRV_REFLECT_H
+
+#include "./include/spirv/unified1/spirv.h"
+
+#include <stdint.h>
+#include <string.h>
+
+#ifdef _MSC_VER
+ #define SPV_REFLECT_DEPRECATED(msg_str) __declspec(deprecated("This symbol is deprecated. Details: " msg_str))
+#elif defined(__clang__)
+ #define SPV_REFLECT_DEPRECATED(msg_str) __attribute__((deprecated(msg_str)))
+#elif defined(__GNUC__)
+ #if GCC_VERSION >= 40500
+ #define SPV_REFLECT_DEPRECATED(msg_str) __attribute__((deprecated(msg_str)))
+ #else
+ #define SPV_REFLECT_DEPRECATED(msg_str) __attribute__((deprecated))
+ #endif
+#else
+ #define SPV_REFLECT_DEPRECATED(msg_str)
+#endif
+
+/*! @enum SpvReflectResult
+
+*/
+typedef enum SpvReflectResult {
+ SPV_REFLECT_RESULT_SUCCESS,
+ SPV_REFLECT_RESULT_NOT_READY,
+ SPV_REFLECT_RESULT_ERROR_PARSE_FAILED,
+ SPV_REFLECT_RESULT_ERROR_ALLOC_FAILED,
+ SPV_REFLECT_RESULT_ERROR_RANGE_EXCEEDED,
+ SPV_REFLECT_RESULT_ERROR_NULL_POINTER,
+ SPV_REFLECT_RESULT_ERROR_INTERNAL_ERROR,
+ SPV_REFLECT_RESULT_ERROR_COUNT_MISMATCH,
+ SPV_REFLECT_RESULT_ERROR_ELEMENT_NOT_FOUND,
+ SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_CODE_SIZE,
+ SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_MAGIC_NUMBER,
+ SPV_REFLECT_RESULT_ERROR_SPIRV_UNEXPECTED_EOF,
+ SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE,
+ SPV_REFLECT_RESULT_ERROR_SPIRV_SET_NUMBER_OVERFLOW,
+ SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_STORAGE_CLASS,
+ SPV_REFLECT_RESULT_ERROR_SPIRV_RECURSION,
+ SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_INSTRUCTION,
+ SPV_REFLECT_RESULT_ERROR_SPIRV_UNEXPECTED_BLOCK_DATA,
+ SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_BLOCK_MEMBER_REFERENCE,
+} SpvReflectResult;
+
+/*! @enum SpvReflectTypeFlagBits
+
+*/
+typedef enum SpvReflectTypeFlagBits {
+ SPV_REFLECT_TYPE_FLAG_UNDEFINED = 0x00000000,
+ SPV_REFLECT_TYPE_FLAG_VOID = 0x00000001,
+ SPV_REFLECT_TYPE_FLAG_BOOL = 0x00000002,
+ SPV_REFLECT_TYPE_FLAG_INT = 0x00000004,
+ SPV_REFLECT_TYPE_FLAG_FLOAT = 0x00000008,
+ SPV_REFLECT_TYPE_FLAG_VECTOR = 0x00000100,
+ SPV_REFLECT_TYPE_FLAG_MATRIX = 0x00000200,
+ SPV_REFLECT_TYPE_FLAG_EXTERNAL_IMAGE = 0x00010000,
+ SPV_REFLECT_TYPE_FLAG_EXTERNAL_SAMPLER = 0x00020000,
+ SPV_REFLECT_TYPE_FLAG_EXTERNAL_SAMPLED_IMAGE = 0x00040000,
+ SPV_REFLECT_TYPE_FLAG_EXTERNAL_BLOCK = 0x00080000,
+ SPV_REFLECT_TYPE_FLAG_EXTERNAL_MASK = 0x000F0000,
+ SPV_REFLECT_TYPE_FLAG_STRUCT = 0x10000000,
+ SPV_REFLECT_TYPE_FLAG_ARRAY = 0x20000000,
+} SpvReflectTypeFlagBits;
+
+typedef uint32_t SpvReflectTypeFlags;
+
+/*! @enum SpvReflectDecorationBits
+
+*/
+typedef enum SpvReflectDecorationFlagBits {
+ SPV_REFLECT_DECORATION_NONE = 0x00000000,
+ SPV_REFLECT_DECORATION_BLOCK = 0x00000001,
+ SPV_REFLECT_DECORATION_BUFFER_BLOCK = 0x00000002,
+ SPV_REFLECT_DECORATION_ROW_MAJOR = 0x00000004,
+ SPV_REFLECT_DECORATION_COLUMN_MAJOR = 0x00000008,
+ SPV_REFLECT_DECORATION_BUILT_IN = 0x00000010,
+ SPV_REFLECT_DECORATION_NOPERSPECTIVE = 0x00000020,
+ SPV_REFLECT_DECORATION_FLAT = 0x00000040,
+ SPV_REFLECT_DECORATION_NON_WRITABLE = 0x00000080,
+} SpvReflectDecorationFlagBits;
+
+typedef uint32_t SpvReflectDecorationFlags;
+
+/*! @enum SpvReflectResourceType
+
+*/
+typedef enum SpvReflectResourceType {
+ SPV_REFLECT_RESOURCE_FLAG_UNDEFINED = 0x00000000,
+ SPV_REFLECT_RESOURCE_FLAG_SAMPLER = 0x00000001,
+ SPV_REFLECT_RESOURCE_FLAG_CBV = 0x00000002,
+ SPV_REFLECT_RESOURCE_FLAG_SRV = 0x00000004,
+ SPV_REFLECT_RESOURCE_FLAG_UAV = 0x00000008,
+} SpvReflectResourceType;
+
+/*! @enum SpvReflectFormat
+
+*/
+typedef enum SpvReflectFormat {
+ SPV_REFLECT_FORMAT_UNDEFINED = 0, // = VK_FORMAT_UNDEFINED
+ SPV_REFLECT_FORMAT_R32_UINT = 98, // = VK_FORMAT_R32_UINT
+ SPV_REFLECT_FORMAT_R32_SINT = 99, // = VK_FORMAT_R32_SINT
+ SPV_REFLECT_FORMAT_R32_SFLOAT = 100, // = VK_FORMAT_R32_SFLOAT
+ SPV_REFLECT_FORMAT_R32G32_UINT = 101, // = VK_FORMAT_R32G32_UINT
+ SPV_REFLECT_FORMAT_R32G32_SINT = 102, // = VK_FORMAT_R32G32_SINT
+ SPV_REFLECT_FORMAT_R32G32_SFLOAT = 103, // = VK_FORMAT_R32G32_SFLOAT
+ SPV_REFLECT_FORMAT_R32G32B32_UINT = 104, // = VK_FORMAT_R32G32B32_UINT
+ SPV_REFLECT_FORMAT_R32G32B32_SINT = 105, // = VK_FORMAT_R32G32B32_SINT
+ SPV_REFLECT_FORMAT_R32G32B32_SFLOAT = 106, // = VK_FORMAT_R32G32B32_SFLOAT
+ SPV_REFLECT_FORMAT_R32G32B32A32_UINT = 107, // = VK_FORMAT_R32G32B32A32_UINT
+ SPV_REFLECT_FORMAT_R32G32B32A32_SINT = 108, // = VK_FORMAT_R32G32B32A32_SINT
+ SPV_REFLECT_FORMAT_R32G32B32A32_SFLOAT = 109, // = VK_FORMAT_R32G32B32A32_SFLOAT
+} SpvReflectFormat;
+
+/*! @enum SpvReflectVariableFlagBits
+
+*/
+enum SpvReflectVariableFlagBits{
+ SPV_REFLECT_VARIABLE_FLAGS_NONE = 0x00000000,
+ SPV_REFLECT_VARIABLE_FLAGS_UNUSED = 0x00000001,
+};
+
+typedef uint32_t SpvReflectVariableFlags;
+
+/*! @enum SpvReflectDescriptorType
+
+*/
+typedef enum SpvReflectDescriptorType {
+ SPV_REFLECT_DESCRIPTOR_TYPE_SAMPLER = 0, // = VK_DESCRIPTOR_TYPE_SAMPLER
+ SPV_REFLECT_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER = 1, // = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER
+ SPV_REFLECT_DESCRIPTOR_TYPE_SAMPLED_IMAGE = 2, // = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE
+ SPV_REFLECT_DESCRIPTOR_TYPE_STORAGE_IMAGE = 3, // = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE
+ SPV_REFLECT_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER = 4, // = VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER
+ SPV_REFLECT_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER = 5, // = VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER
+ SPV_REFLECT_DESCRIPTOR_TYPE_UNIFORM_BUFFER = 6, // = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER
+ SPV_REFLECT_DESCRIPTOR_TYPE_STORAGE_BUFFER = 7, // = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER
+ SPV_REFLECT_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC = 8, // = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC
+ SPV_REFLECT_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC = 9, // = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC
+ SPV_REFLECT_DESCRIPTOR_TYPE_INPUT_ATTACHMENT = 10, // = VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT
+} SpvReflectDescriptorType;
+
+/*! @enum SpvReflectShaderStageFlagBits
+
+*/
+typedef enum SpvReflectShaderStageFlagBits {
+ SPV_REFLECT_SHADER_STAGE_VERTEX_BIT = 0x00000001, // = VK_SHADER_STAGE_VERTEX_BIT
+ SPV_REFLECT_SHADER_STAGE_TESSELLATION_CONTROL_BIT = 0x00000002, // = VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT
+ SPV_REFLECT_SHADER_STAGE_TESSELLATION_EVALUATION_BIT = 0x00000004, // = VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT
+ SPV_REFLECT_SHADER_STAGE_GEOMETRY_BIT = 0x00000008, // = VK_SHADER_STAGE_GEOMETRY_BIT
+ SPV_REFLECT_SHADER_STAGE_FRAGMENT_BIT = 0x00000010, // = VK_SHADER_STAGE_FRAGMENT_BIT
+ SPV_REFLECT_SHADER_STAGE_COMPUTE_BIT = 0x00000020, // = VK_SHADER_STAGE_COMPUTE_BIT
+} SpvReflectShaderStageFlagBits;
+
+/*! @enum SpvReflectGenerator
+
+*/
+typedef enum SpvReflectGenerator {
+ SPV_REFLECT_GENERATOR_KHRONOS_LLVM_SPIRV_TRANSLATOR = 6,
+ SPV_REFLECT_GENERATOR_KHRONOS_SPIRV_TOOLS_ASSEMBLER = 7,
+ SPV_REFLECT_GENERATOR_KHRONOS_GLSLANG_REFERENCE_FRONT_END = 8,
+ SPV_REFLECT_GENERATOR_GOOGLE_SHADERC_OVER_GLSLANG = 13,
+ SPV_REFLECT_GENERATOR_GOOGLE_SPIREGG = 14,
+ SPV_REFLECT_GENERATOR_GOOGLE_RSPIRV = 15,
+ SPV_REFLECT_GENERATOR_X_LEGEND_MESA_MESAIR_SPIRV_TRANSLATOR = 16,
+ SPV_REFLECT_GENERATOR_KHRONOS_SPIRV_TOOLS_LINKER = 17,
+ SPV_REFLECT_GENERATOR_WINE_VKD3D_SHADER_COMPILER = 18,
+ SPV_REFLECT_GENERATOR_CLAY_CLAY_SHADER_COMPILER = 19,
+} SpvReflectGenerator;
+
+enum {
+ SPV_REFLECT_MAX_ARRAY_DIMS = 32,
+ SPV_REFLECT_MAX_DESCRIPTOR_SETS = 64,
+};
+
+enum {
+ SPV_REFLECT_BINDING_NUMBER_DONT_CHANGE = ~0,
+ SPV_REFLECT_SET_NUMBER_DONT_CHANGE = ~0
+};
+
+typedef struct SpvReflectNumericTraits {
+ struct Scalar {
+ uint32_t width;
+ uint32_t signedness;
+ } scalar;
+
+ struct Vector {
+ uint32_t component_count;
+ } vector;
+
+ struct Matrix {
+ uint32_t column_count;
+ uint32_t row_count;
+ uint32_t stride; // Measured in bytes
+ } matrix;
+} SpvReflectNumericTraits;
+
+typedef struct SpvReflectImageTraits {
+ SpvDim dim;
+ uint32_t depth;
+ uint32_t arrayed;
+ uint32_t ms; // 0: single-sampled; 1: multisampled
+ uint32_t sampled;
+ SpvImageFormat image_format;
+} SpvReflectImageTraits;
+
+typedef struct SpvReflectArrayTraits {
+ uint32_t dims_count;
+ uint32_t dims[SPV_REFLECT_MAX_ARRAY_DIMS];
+ uint32_t stride; // Measured in bytes
+} SpvReflectArrayTraits;
+
+typedef struct SpvReflectBindingArrayTraits {
+ uint32_t dims_count;
+ uint32_t dims[SPV_REFLECT_MAX_ARRAY_DIMS];
+} SpvReflectBindingArrayTraits;
+
+/*! @struct SpvReflectTypeDescription
+
+*/
+typedef struct SpvReflectTypeDescription {
+ uint32_t id;
+ SpvOp op;
+ const char* type_name;
+ const char* struct_member_name;
+ SpvStorageClass storage_class;
+ SpvReflectTypeFlags type_flags;
+ SpvReflectDecorationFlags decoration_flags;
+
+ struct Traits {
+ SpvReflectNumericTraits numeric;
+ SpvReflectImageTraits image;
+ SpvReflectArrayTraits array;
+ } traits;
+
+ uint32_t member_count;
+ struct SpvReflectTypeDescription* members;
+} SpvReflectTypeDescription;
+
+
+/*! @struct SpvReflectInterfaceVariable
+
+*/
+typedef struct SpvReflectInterfaceVariable {
+ uint32_t spirv_id;
+ const char* name;
+ uint32_t location;
+ SpvStorageClass storage_class;
+ const char* semantic;
+ SpvReflectDecorationFlags decoration_flags;
+ SpvBuiltIn built_in;
+ SpvReflectNumericTraits numeric;
+ SpvReflectArrayTraits array;
+
+ uint32_t member_count;
+ struct SpvReflectInterfaceVariable* members;
+
+ SpvReflectFormat format;
+
+ // NOTE: SPIR-V shares type references for variables
+ // that have the same underlying type. This means
+ // that the same type name will appear for multiple
+ // variables.
+ SpvReflectTypeDescription* type_description;
+
+ struct {
+ uint32_t location;
+ } word_offset;
+} SpvReflectInterfaceVariable;
+
+/*! @struct SpvReflectBlockVariable
+
+*/
+typedef struct SpvReflectBlockVariable {
+ uint32_t spirv_id;
+ const char* name;
+ uint32_t offset; // Measured in bytes
+ uint32_t absolute_offset; // Measured in bytes
+ uint32_t size; // Measured in bytes
+ uint32_t padded_size; // Measured in bytes
+ SpvReflectDecorationFlags decoration_flags;
+ SpvReflectNumericTraits numeric;
+ SpvReflectArrayTraits array;
+ SpvReflectVariableFlags flags;
+
+ uint32_t member_count;
+ struct SpvReflectBlockVariable* members;
+
+ SpvReflectTypeDescription* type_description;
+} SpvReflectBlockVariable;
+
+/*! @struct SpvReflectDescriptorBinding
+
+*/
+typedef struct SpvReflectDescriptorBinding {
+ uint32_t spirv_id;
+ const char* name;
+ uint32_t binding;
+ uint32_t input_attachment_index;
+ uint32_t set;
+ SpvReflectDescriptorType descriptor_type;
+ SpvReflectResourceType resource_type;
+ SpvReflectImageTraits image;
+ SpvReflectBlockVariable block;
+ SpvReflectBindingArrayTraits array;
+ uint32_t count;
+ uint32_t accessed;
+ uint32_t uav_counter_id;
+ struct SpvReflectDescriptorBinding* uav_counter_binding;
+
+ SpvReflectTypeDescription* type_description;
+
+ struct {
+ uint32_t binding;
+ uint32_t set;
+ } word_offset;
+} SpvReflectDescriptorBinding;
+
+/*! @struct SpvReflectDescriptorSet
+
+*/
+typedef struct SpvReflectDescriptorSet {
+ uint32_t set;
+ uint32_t binding_count;
+ SpvReflectDescriptorBinding** bindings;
+} SpvReflectDescriptorSet;
+
+/*! @struct SpvReflectEntryPoint
+
+ */
+typedef struct SpvReflectEntryPoint {
+ const char* name;
+ uint32_t id;
+
+ SpvExecutionModel spirv_execution_model;
+ SpvReflectShaderStageFlagBits shader_stage;
+
+ uint32_t input_variable_count;
+ SpvReflectInterfaceVariable* input_variables;
+ uint32_t output_variable_count;
+ SpvReflectInterfaceVariable* output_variables;
+
+ uint32_t descriptor_set_count;
+ SpvReflectDescriptorSet* descriptor_sets;
+
+ uint32_t used_uniform_count;
+ uint32_t* used_uniforms;
+ uint32_t used_push_constant_count;
+ uint32_t* used_push_constants;
+} SpvReflectEntryPoint;
+
+/*! @struct SpvReflectShaderModule
+
+*/
+typedef struct SpvReflectShaderModule {
+ SpvReflectGenerator generator;
+ const char* entry_point_name;
+ uint32_t entry_point_id;
+ uint32_t entry_point_count;
+ SpvReflectEntryPoint* entry_points;
+ SpvSourceLanguage source_language;
+ uint32_t source_language_version;
+ const char* source_file;
+ const char* source_source;
+ SpvExecutionModel spirv_execution_model;
+ SpvReflectShaderStageFlagBits shader_stage;
+ uint32_t descriptor_binding_count;
+ SpvReflectDescriptorBinding* descriptor_bindings;
+ uint32_t descriptor_set_count;
+ SpvReflectDescriptorSet descriptor_sets[SPV_REFLECT_MAX_DESCRIPTOR_SETS];
+ uint32_t input_variable_count;
+ SpvReflectInterfaceVariable* input_variables;
+ uint32_t output_variable_count;
+ SpvReflectInterfaceVariable* output_variables;
+ uint32_t push_constant_block_count;
+ SpvReflectBlockVariable* push_constant_blocks;
+
+ struct Internal {
+ size_t spirv_size;
+ uint32_t* spirv_code;
+ uint32_t spirv_word_count;
+
+ size_t type_description_count;
+ SpvReflectTypeDescription* type_descriptions;
+ } * _internal;
+
+} SpvReflectShaderModule;
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/*! @fn spvReflectCreateShaderModule
+
+ @param size Size in bytes of SPIR-V code.
+ @param p_code Pointer to SPIR-V code.
+ @param p_module Pointer to an instance of SpvReflectShaderModule.
+ @return SPV_REFLECT_RESULT_SUCCESS on success.
+
+*/
+SpvReflectResult spvReflectCreateShaderModule(
+ size_t size,
+ const void* p_code,
+ SpvReflectShaderModule* p_module
+);
+
+SPV_REFLECT_DEPRECATED("renamed to spvReflectCreateShaderModule")
+SpvReflectResult spvReflectGetShaderModule(
+ size_t size,
+ const void* p_code,
+ SpvReflectShaderModule* p_module
+);
+
+
+/*! @fn spvReflectDestroyShaderModule
+
+ @param p_module Pointer to an instance of SpvReflectShaderModule.
+
+*/
+void spvReflectDestroyShaderModule(SpvReflectShaderModule* p_module);
+
+
+/*! @fn spvReflectGetCodeSize
+
+ @param p_module Pointer to an instance of SpvReflectShaderModule.
+ @return Returns the size of the SPIR-V in bytes
+
+*/
+uint32_t spvReflectGetCodeSize(const SpvReflectShaderModule* p_module);
+
+
+/*! @fn spvReflectGetCode
+
+ @param p_module Pointer to an instance of SpvReflectShaderModule.
+ @return Returns a const pointer to the compiled SPIR-V bytecode.
+
+*/
+const uint32_t* spvReflectGetCode(const SpvReflectShaderModule* p_module);
+
+/*! @fn spvReflectGetEntryPoint
+
+ @param p_module Pointer to an instance of SpvReflectShaderModule.
+ @param entry_point Name of the requested entry point.
+ @return Returns a const pointer to the requested entry point,
+ or NULL if it's not found.
+*/
+const SpvReflectEntryPoint* spvReflectGetEntryPoint(
+ const SpvReflectShaderModule* p_module,
+ const char* entry_point
+);
+
+/*! @fn spvReflectEnumerateDescriptorBindings
+
+ @param p_module Pointer to an instance of SpvReflectShaderModule.
+ @param p_count If pp_bindings is NULL, the module's descriptor binding
+ count (across all descriptor sets) will be stored here.
+ If pp_bindings is not NULL, *p_count must contain the
+ module's descriptor binding count.
+ @param pp_bindings If NULL, the module's total descriptor binding count
+ will be written to *p_count.
+ If non-NULL, pp_bindings must point to an array with
+ *p_count entries, where pointers to the module's
+ descriptor bindings will be written. The caller must not
+ free the binding pointers written to this array.
+ @return If successful, returns SPV_REFLECT_RESULT_SUCCESS.
+ Otherwise, the error code indicates the cause of the
+ failure.
+
+*/
+SpvReflectResult spvReflectEnumerateDescriptorBindings(
+ const SpvReflectShaderModule* p_module,
+ uint32_t* p_count,
+ SpvReflectDescriptorBinding** pp_bindings
+);
+
+/*! @fn spvReflectEnumerateEntryPointDescriptorBindings
+ @brief Creates a listing of all descriptor bindings that are used in the
+ static call tree of the given entry point.
+ @param p_module Pointer to an instance of SpvReflectShaderModule.
+ @param entry_point The name of the entry point to get the descriptor bindings for.
+ @param p_count If pp_bindings is NULL, the entry point's descriptor binding
+ count (across all descriptor sets) will be stored here.
+ If pp_bindings is not NULL, *p_count must contain the
+ entry points's descriptor binding count.
+ @param pp_bindings If NULL, the entry point's total descriptor binding count
+ will be written to *p_count.
+ If non-NULL, pp_bindings must point to an array with
+ *p_count entries, where pointers to the entry point's
+ descriptor bindings will be written. The caller must not
+ free the binding pointers written to this array.
+ @return If successful, returns SPV_REFLECT_RESULT_SUCCESS.
+ Otherwise, the error code indicates the cause of the
+ failure.
+
+*/
+SpvReflectResult spvReflectEnumerateEntryPointDescriptorBindings(
+ const SpvReflectShaderModule* p_module,
+ const char* entry_point,
+ uint32_t* p_count,
+ SpvReflectDescriptorBinding** pp_bindings
+);
+
+/*! @fn spvReflectEnumerateDescriptorSets
+
+ @param p_module Pointer to an instance of SpvReflectShaderModule.
+ @param p_count If pp_sets is NULL, the module's descriptor set
+ count will be stored here.
+ If pp_sets is not NULL, *p_count must contain the
+ module's descriptor set count.
+ @param pp_sets If NULL, the module's total descriptor set count
+ will be written to *p_count.
+ If non-NULL, pp_sets must point to an array with
+ *p_count entries, where pointers to the module's
+ descriptor sets will be written. The caller must not
+ free the descriptor set pointers written to this array.
+ @return If successful, returns SPV_REFLECT_RESULT_SUCCESS.
+ Otherwise, the error code indicates the cause of the
+ failure.
+
+*/
+SpvReflectResult spvReflectEnumerateDescriptorSets(
+ const SpvReflectShaderModule* p_module,
+ uint32_t* p_count,
+ SpvReflectDescriptorSet** pp_sets
+);
+
+/*! @fn spvReflectEnumerateEntryPointDescriptorSets
+ @brief Creates a listing of all descriptor sets and their bindings that are
+ used in the static call tree of a given entry point.
+ @param p_module Pointer to an instance of SpvReflectShaderModule.
+ @param entry_point The name of the entry point to get the descriptor bindings for.
+ @param p_count If pp_sets is NULL, the module's descriptor set
+ count will be stored here.
+ If pp_sets is not NULL, *p_count must contain the
+ module's descriptor set count.
+ @param pp_sets If NULL, the module's total descriptor set count
+ will be written to *p_count.
+ If non-NULL, pp_sets must point to an array with
+ *p_count entries, where pointers to the module's
+ descriptor sets will be written. The caller must not
+ free the descriptor set pointers written to this array.
+ @return If successful, returns SPV_REFLECT_RESULT_SUCCESS.
+ Otherwise, the error code indicates the cause of the
+ failure.
+
+*/
+SpvReflectResult spvReflectEnumerateEntryPointDescriptorSets(
+ const SpvReflectShaderModule* p_module,
+ const char* entry_point,
+ uint32_t* p_count,
+ SpvReflectDescriptorSet** pp_sets
+);
+
+
+/*! @fn spvReflectEnumerateInputVariables
+ @brief If the module contains multiple entry points, this will only get
+ the input variables for the first one.
+ @param p_module Pointer to an instance of SpvReflectShaderModule.
+ @param p_count If pp_variables is NULL, the module's input variable
+ count will be stored here.
+ If pp_variables is not NULL, *p_count must contain
+ the module's input variable count.
+ @param pp_variables If NULL, the module's input variable count will be
+ written to *p_count.
+ If non-NULL, pp_variables must point to an array with
+ *p_count entries, where pointers to the module's
+ input variables will be written. The caller must not
+ free the interface variables written to this array.
+ @return If successful, returns SPV_REFLECT_RESULT_SUCCESS.
+ Otherwise, the error code indicates the cause of the
+ failure.
+
+*/
+SpvReflectResult spvReflectEnumerateInputVariables(
+ const SpvReflectShaderModule* p_module,
+ uint32_t* p_count,
+ SpvReflectInterfaceVariable** pp_variables
+);
+
+/*! @fn spvReflectEnumerateEntryPointInputVariables
+ @brief Enumerate the input variables for a given entry point.
+ @param entry_point The name of the entry point to get the input variables for.
+ @param p_module Pointer to an instance of SpvReflectShaderModule.
+ @param p_count If pp_variables is NULL, the entry point's input variable
+ count will be stored here.
+ If pp_variables is not NULL, *p_count must contain
+ the entry point's input variable count.
+ @param pp_variables If NULL, the entry point's input variable count will be
+ written to *p_count.
+ If non-NULL, pp_variables must point to an array with
+ *p_count entries, where pointers to the entry point's
+ input variables will be written. The caller must not
+ free the interface variables written to this array.
+ @return If successful, returns SPV_REFLECT_RESULT_SUCCESS.
+ Otherwise, the error code indicates the cause of the
+ failure.
+
+*/
+SpvReflectResult spvReflectEnumerateEntryPointInputVariables(
+ const SpvReflectShaderModule* p_module,
+ const char* entry_point,
+ uint32_t* p_count,
+ SpvReflectInterfaceVariable** pp_variables
+);
+
+
+/*! @fn spvReflectEnumerateOutputVariables
+ @brief Note: If the module contains multiple entry points, this will only get
+ the output variables for the first one.
+ @param p_module Pointer to an instance of SpvReflectShaderModule.
+ @param p_count If pp_variables is NULL, the module's output variable
+ count will be stored here.
+ If pp_variables is not NULL, *p_count must contain
+ the module's output variable count.
+ @param pp_variables If NULL, the module's output variable count will be
+ written to *p_count.
+ If non-NULL, pp_variables must point to an array with
+ *p_count entries, where pointers to the module's
+ output variables will be written. The caller must not
+ free the interface variables written to this array.
+ @return If successful, returns SPV_REFLECT_RESULT_SUCCESS.
+ Otherwise, the error code indicates the cause of the
+ failure.
+
+*/
+SpvReflectResult spvReflectEnumerateOutputVariables(
+ const SpvReflectShaderModule* p_module,
+ uint32_t* p_count,
+ SpvReflectInterfaceVariable** pp_variables
+);
+
+/*! @fn spvReflectEnumerateEntryPointOutputVariables
+ @brief Enumerate the output variables for a given entry point.
+ @param p_module Pointer to an instance of SpvReflectShaderModule.
+ @param entry_point The name of the entry point to get the output variables for.
+ @param p_count If pp_variables is NULL, the entry point's output variable
+ count will be stored here.
+ If pp_variables is not NULL, *p_count must contain
+ the entry point's output variable count.
+ @param pp_variables If NULL, the entry point's output variable count will be
+ written to *p_count.
+ If non-NULL, pp_variables must point to an array with
+ *p_count entries, where pointers to the entry point's
+ output variables will be written. The caller must not
+ free the interface variables written to this array.
+ @return If successful, returns SPV_REFLECT_RESULT_SUCCESS.
+ Otherwise, the error code indicates the cause of the
+ failure.
+
+*/
+SpvReflectResult spvReflectEnumerateEntryPointOutputVariables(
+ const SpvReflectShaderModule* p_module,
+ const char* entry_point,
+ uint32_t* p_count,
+ SpvReflectInterfaceVariable** pp_variables
+);
+
+
+/*! @fn spvReflectEnumeratePushConstantBlocks
+ @brief Note: If the module contains multiple entry points, this will only get
+ the push constant blocks for the first one.
+ @param p_module Pointer to an instance of SpvReflectShaderModule.
+ @param p_count If pp_blocks is NULL, the module's push constant
+ block count will be stored here.
+ If pp_blocks is not NULL, *p_count must
+ contain the module's push constant block count.
+ @param pp_blocks If NULL, the module's push constant block count
+ will be written to *p_count.
+ If non-NULL, pp_blocks must point to an
+ array with *p_count entries, where pointers to
+ the module's push constant blocks will be written.
+ The caller must not free the block variables written
+ to this array.
+ @return If successful, returns SPV_REFLECT_RESULT_SUCCESS.
+ Otherwise, the error code indicates the cause of the
+ failure.
+
+*/
+SpvReflectResult spvReflectEnumeratePushConstantBlocks(
+ const SpvReflectShaderModule* p_module,
+ uint32_t* p_count,
+ SpvReflectBlockVariable** pp_blocks
+);
+SPV_REFLECT_DEPRECATED("renamed to spvReflectEnumeratePushConstantBlocks")
+SpvReflectResult spvReflectEnumeratePushConstants(
+ const SpvReflectShaderModule* p_module,
+ uint32_t* p_count,
+ SpvReflectBlockVariable** pp_blocks
+);
+
+/*! @fn spvReflectEnumerateEntryPointPushConstantBlocks
+ @brief Enumerate the push constant blocks used in the static call tree of a
+ given entry point.
+ @param p_module Pointer to an instance of SpvReflectShaderModule.
+ @param p_count If pp_blocks is NULL, the entry point's push constant
+ block count will be stored here.
+ If pp_blocks is not NULL, *p_count must
+ contain the entry point's push constant block count.
+ @param pp_blocks If NULL, the entry point's push constant block count
+ will be written to *p_count.
+ If non-NULL, pp_blocks must point to an
+ array with *p_count entries, where pointers to
+ the entry point's push constant blocks will be written.
+ The caller must not free the block variables written
+ to this array.
+ @return If successful, returns SPV_REFLECT_RESULT_SUCCESS.
+ Otherwise, the error code indicates the cause of the
+ failure.
+
+*/
+SpvReflectResult spvReflectEnumerateEntryPointPushConstantBlocks(
+ const SpvReflectShaderModule* p_module,
+ const char* entry_point,
+ uint32_t* p_count,
+ SpvReflectBlockVariable** pp_blocks
+);
+
+
+/*! @fn spvReflectGetDescriptorBinding
+
+ @param p_module Pointer to an instance of SpvReflectShaderModule.
+ @param binding_number The "binding" value of the requested descriptor
+ binding.
+ @param set_number The "set" value of the requested descriptor binding.
+ @param p_result If successful, SPV_REFLECT_RESULT_SUCCESS will be
+ written to *p_result. Otherwise, a error code
+ indicating the cause of the failure will be stored
+ here.
+ @return If the module contains a descriptor binding that
+ matches the provided [binding_number, set_number]
+ values, a pointer to that binding is returned. The
+ caller must not free this pointer.
+ If no match can be found, or if an unrelated error
+ occurs, the return value will be NULL. Detailed
+ error results are written to *pResult.
+@note If the module contains multiple desriptor bindings
+ with the same set and binding numbers, there are
+ no guarantees about which binding will be returned.
+
+*/
+const SpvReflectDescriptorBinding* spvReflectGetDescriptorBinding(
+ const SpvReflectShaderModule* p_module,
+ uint32_t binding_number,
+ uint32_t set_number,
+ SpvReflectResult* p_result
+);
+
+/*! @fn spvReflectGetEntryPointDescriptorBinding
+ @brief Get the descriptor binding with the given binding number and set
+ number that is used in the static call tree of a certain entry
+ point.
+ @param p_module Pointer to an instance of SpvReflectShaderModule.
+ @param entry_point The entry point to get the binding from.
+ @param binding_number The "binding" value of the requested descriptor
+ binding.
+ @param set_number The "set" value of the requested descriptor binding.
+ @param p_result If successful, SPV_REFLECT_RESULT_SUCCESS will be
+ written to *p_result. Otherwise, a error code
+ indicating the cause of the failure will be stored
+ here.
+ @return If the entry point contains a descriptor binding that
+ matches the provided [binding_number, set_number]
+ values, a pointer to that binding is returned. The
+ caller must not free this pointer.
+ If no match can be found, or if an unrelated error
+ occurs, the return value will be NULL. Detailed
+ error results are written to *pResult.
+@note If the entry point contains multiple desriptor bindings
+ with the same set and binding numbers, there are
+ no guarantees about which binding will be returned.
+
+*/
+const SpvReflectDescriptorBinding* spvReflectGetEntryPointDescriptorBinding(
+ const SpvReflectShaderModule* p_module,
+ const char* entry_point,
+ uint32_t binding_number,
+ uint32_t set_number,
+ SpvReflectResult* p_result
+);
+
+
+/*! @fn spvReflectGetDescriptorSet
+
+ @param p_module Pointer to an instance of SpvReflectShaderModule.
+ @param set_number The "set" value of the requested descriptor set.
+ @param p_result If successful, SPV_REFLECT_RESULT_SUCCESS will be
+ written to *p_result. Otherwise, a error code
+ indicating the cause of the failure will be stored
+ here.
+ @return If the module contains a descriptor set with the
+ provided set_number, a pointer to that set is
+ returned. The caller must not free this pointer.
+ If no match can be found, or if an unrelated error
+ occurs, the return value will be NULL. Detailed
+ error results are written to *pResult.
+
+*/
+const SpvReflectDescriptorSet* spvReflectGetDescriptorSet(
+ const SpvReflectShaderModule* p_module,
+ uint32_t set_number,
+ SpvReflectResult* p_result
+);
+
+/*! @fn spvReflectGetEntryPointDescriptorSet
+
+ @param p_module Pointer to an instance of SpvReflectShaderModule.
+ @param entry_point The entry point to get the descriptor set from.
+ @param set_number The "set" value of the requested descriptor set.
+ @param p_result If successful, SPV_REFLECT_RESULT_SUCCESS will be
+ written to *p_result. Otherwise, a error code
+ indicating the cause of the failure will be stored
+ here.
+ @return If the entry point contains a descriptor set with the
+ provided set_number, a pointer to that set is
+ returned. The caller must not free this pointer.
+ If no match can be found, or if an unrelated error
+ occurs, the return value will be NULL. Detailed
+ error results are written to *pResult.
+
+*/
+const SpvReflectDescriptorSet* spvReflectGetEntryPointDescriptorSet(
+ const SpvReflectShaderModule* p_module,
+ const char* entry_point,
+ uint32_t set_number,
+ SpvReflectResult* p_result
+);
+
+
+/* @fn spvReflectGetInputVariableByLocation
+
+ @param p_module Pointer to an instance of SpvReflectShaderModule.
+ @param location The "location" value of the requested input variable.
+ A location of 0xFFFFFFFF will always return NULL
+ with *p_result == ELEMENT_NOT_FOUND.
+ @param p_result If successful, SPV_REFLECT_RESULT_SUCCESS will be
+ written to *p_result. Otherwise, a error code
+ indicating the cause of the failure will be stored
+ here.
+ @return If the module contains an input interface variable
+ with the provided location value, a pointer to that
+ variable is returned. The caller must not free this
+ pointer.
+ If no match can be found, or if an unrelated error
+ occurs, the return value will be NULL. Detailed
+ error results are written to *pResult.
+@note
+
+*/
+const SpvReflectInterfaceVariable* spvReflectGetInputVariableByLocation(
+ const SpvReflectShaderModule* p_module,
+ uint32_t location,
+ SpvReflectResult* p_result
+);
+SPV_REFLECT_DEPRECATED("renamed to spvReflectGetInputVariableByLocation")
+const SpvReflectInterfaceVariable* spvReflectGetInputVariable(
+ const SpvReflectShaderModule* p_module,
+ uint32_t location,
+ SpvReflectResult* p_result
+);
+
+/* @fn spvReflectGetEntryPointInputVariableByLocation
+
+ @param p_module Pointer to an instance of SpvReflectShaderModule.
+ @param entry_point The entry point to get the input variable from.
+ @param location The "location" value of the requested input variable.
+ A location of 0xFFFFFFFF will always return NULL
+ with *p_result == ELEMENT_NOT_FOUND.
+ @param p_result If successful, SPV_REFLECT_RESULT_SUCCESS will be
+ written to *p_result. Otherwise, a error code
+ indicating the cause of the failure will be stored
+ here.
+ @return If the entry point contains an input interface variable
+ with the provided location value, a pointer to that
+ variable is returned. The caller must not free this
+ pointer.
+ If no match can be found, or if an unrelated error
+ occurs, the return value will be NULL. Detailed
+ error results are written to *pResult.
+@note
+
+*/
+const SpvReflectInterfaceVariable* spvReflectGetEntryPointInputVariableByLocation(
+ const SpvReflectShaderModule* p_module,
+ const char* entry_point,
+ uint32_t location,
+ SpvReflectResult* p_result
+);
+
+/* @fn spvReflectGetInputVariableBySemantic
+
+ @param p_module Pointer to an instance of SpvReflectShaderModule.
+ @param semantic The "semantic" value of the requested input variable.
+ A semantic of NULL will return NULL.
+ A semantic of "" will always return NULL with
+ *p_result == ELEMENT_NOT_FOUND.
+ @param p_result If successful, SPV_REFLECT_RESULT_SUCCESS will be
+ written to *p_result. Otherwise, a error code
+ indicating the cause of the failure will be stored
+ here.
+ @return If the module contains an input interface variable
+ with the provided semantic, a pointer to that
+ variable is returned. The caller must not free this
+ pointer.
+ If no match can be found, or if an unrelated error
+ occurs, the return value will be NULL. Detailed
+ error results are written to *pResult.
+@note
+
+*/
+const SpvReflectInterfaceVariable* spvReflectGetInputVariableBySemantic(
+ const SpvReflectShaderModule* p_module,
+ const char* semantic,
+ SpvReflectResult* p_result
+);
+
+/* @fn spvReflectGetEntryPointInputVariableBySemantic
+
+ @param p_module Pointer to an instance of SpvReflectShaderModule.
+ @param entry_point The entry point to get the input variable from.
+ @param semantic The "semantic" value of the requested input variable.
+ A semantic of NULL will return NULL.
+ A semantic of "" will always return NULL with
+ *p_result == ELEMENT_NOT_FOUND.
+ @param p_result If successful, SPV_REFLECT_RESULT_SUCCESS will be
+ written to *p_result. Otherwise, a error code
+ indicating the cause of the failure will be stored
+ here.
+ @return If the entry point contains an input interface variable
+ with the provided semantic, a pointer to that
+ variable is returned. The caller must not free this
+ pointer.
+ If no match can be found, or if an unrelated error
+ occurs, the return value will be NULL. Detailed
+ error results are written to *pResult.
+@note
+
+*/
+const SpvReflectInterfaceVariable* spvReflectGetEntryPointInputVariableBySemantic(
+ const SpvReflectShaderModule* p_module,
+ const char* entry_point,
+ const char* semantic,
+ SpvReflectResult* p_result
+);
+
+/* @fn spvReflectGetOutputVariableByLocation
+
+ @param p_module Pointer to an instance of SpvReflectShaderModule.
+ @param location The "location" value of the requested output variable.
+ A location of 0xFFFFFFFF will always return NULL
+ with *p_result == ELEMENT_NOT_FOUND.
+ @param p_result If successful, SPV_REFLECT_RESULT_SUCCESS will be
+ written to *p_result. Otherwise, a error code
+ indicating the cause of the failure will be stored
+ here.
+ @return If the module contains an output interface variable
+ with the provided location value, a pointer to that
+ variable is returned. The caller must not free this
+ pointer.
+ If no match can be found, or if an unrelated error
+ occurs, the return value will be NULL. Detailed
+ error results are written to *pResult.
+@note
+
+*/
+const SpvReflectInterfaceVariable* spvReflectGetOutputVariableByLocation(
+ const SpvReflectShaderModule* p_module,
+ uint32_t location,
+ SpvReflectResult* p_result
+);
+SPV_REFLECT_DEPRECATED("renamed to spvReflectGetOutputVariableByLocation")
+const SpvReflectInterfaceVariable* spvReflectGetOutputVariable(
+ const SpvReflectShaderModule* p_module,
+ uint32_t location,
+ SpvReflectResult* p_result
+);
+
+/* @fn spvReflectGetEntryPointOutputVariableByLocation
+
+ @param p_module Pointer to an instance of SpvReflectShaderModule.
+ @param entry_point The entry point to get the output variable from.
+ @param location The "location" value of the requested output variable.
+ A location of 0xFFFFFFFF will always return NULL
+ with *p_result == ELEMENT_NOT_FOUND.
+ @param p_result If successful, SPV_REFLECT_RESULT_SUCCESS will be
+ written to *p_result. Otherwise, a error code
+ indicating the cause of the failure will be stored
+ here.
+ @return If the entry point contains an output interface variable
+ with the provided location value, a pointer to that
+ variable is returned. The caller must not free this
+ pointer.
+ If no match can be found, or if an unrelated error
+ occurs, the return value will be NULL. Detailed
+ error results are written to *pResult.
+@note
+
+*/
+const SpvReflectInterfaceVariable* spvReflectGetEntryPointOutputVariableByLocation(
+ const SpvReflectShaderModule* p_module,
+ const char* entry_point,
+ uint32_t location,
+ SpvReflectResult* p_result
+);
+
+/* @fn spvReflectGetOutputVariableBySemantic
+
+ @param p_module Pointer to an instance of SpvReflectShaderModule.
+ @param semantic The "semantic" value of the requested output variable.
+ A semantic of NULL will return NULL.
+ A semantic of "" will always return NULL with
+ *p_result == ELEMENT_NOT_FOUND.
+ @param p_result If successful, SPV_REFLECT_RESULT_SUCCESS will be
+ written to *p_result. Otherwise, a error code
+ indicating the cause of the failure will be stored
+ here.
+ @return If the module contains an output interface variable
+ with the provided semantic, a pointer to that
+ variable is returned. The caller must not free this
+ pointer.
+ If no match can be found, or if an unrelated error
+ occurs, the return value will be NULL. Detailed
+ error results are written to *pResult.
+@note
+
+*/
+const SpvReflectInterfaceVariable* spvReflectGetOutputVariableBySemantic(
+ const SpvReflectShaderModule* p_module,
+ const char* semantic,
+ SpvReflectResult* p_result
+);
+
+/* @fn spvReflectGetEntryPointOutputVariableBySemantic
+
+ @param p_module Pointer to an instance of SpvReflectShaderModule.
+ @param entry_point The entry point to get the output variable from.
+ @param semantic The "semantic" value of the requested output variable.
+ A semantic of NULL will return NULL.
+ A semantic of "" will always return NULL with
+ *p_result == ELEMENT_NOT_FOUND.
+ @param p_result If successful, SPV_REFLECT_RESULT_SUCCESS will be
+ written to *p_result. Otherwise, a error code
+ indicating the cause of the failure will be stored
+ here.
+ @return If the entry point contains an output interface variable
+ with the provided semantic, a pointer to that
+ variable is returned. The caller must not free this
+ pointer.
+ If no match can be found, or if an unrelated error
+ occurs, the return value will be NULL. Detailed
+ error results are written to *pResult.
+@note
+
+*/
+const SpvReflectInterfaceVariable* spvReflectGetEntryPointOutputVariableBySemantic(
+ const SpvReflectShaderModule* p_module,
+ const char* entry_point,
+ const char* semantic,
+ SpvReflectResult* p_result
+);
+
+/*! @fn spvReflectGetPushConstantBlock
+
+ @param p_module Pointer to an instance of SpvReflectShaderModule.
+ @param index The index of the desired block within the module's
+ array of push constant blocks.
+ @param p_result If successful, SPV_REFLECT_RESULT_SUCCESS will be
+ written to *p_result. Otherwise, a error code
+ indicating the cause of the failure will be stored
+ here.
+ @return If the provided index is within range, a pointer to
+ the corresponding push constant block is returned.
+ The caller must not free this pointer.
+ If no match can be found, or if an unrelated error
+ occurs, the return value will be NULL. Detailed
+ error results are written to *pResult.
+
+*/
+const SpvReflectBlockVariable* spvReflectGetPushConstantBlock(
+ const SpvReflectShaderModule* p_module,
+ uint32_t index,
+ SpvReflectResult* p_result
+);
+SPV_REFLECT_DEPRECATED("renamed to spvReflectGetPushConstantBlock")
+const SpvReflectBlockVariable* spvReflectGetPushConstant(
+ const SpvReflectShaderModule* p_module,
+ uint32_t index,
+ SpvReflectResult* p_result
+);
+
+/*! @fn spvReflectGetEntryPointPushConstantBlock
+ @brief Get the push constant block corresponding to the given entry point.
+ As by the Vulkan specification there can be no more than one push
+ constant block used by a given entry point, so if there is one it will
+ be returned, otherwise NULL will be returned.
+ @param p_module Pointer to an instance of SpvReflectShaderModule.
+ @param entry_point The entry point to get the push constant block from.
+ @param p_result If successful, SPV_REFLECT_RESULT_SUCCESS will be
+ written to *p_result. Otherwise, a error code
+ indicating the cause of the failure will be stored
+ here.
+ @return If the provided index is within range, a pointer to
+ the corresponding push constant block is returned.
+ The caller must not free this pointer.
+ If no match can be found, or if an unrelated error
+ occurs, the return value will be NULL. Detailed
+ error results are written to *pResult.
+
+*/
+const SpvReflectBlockVariable* spvReflectGetEntryPointPushConstantBlock(
+ const SpvReflectShaderModule* p_module,
+ const char* entry_point,
+ SpvReflectResult* p_result
+);
+
+
+/*! @fn spvReflectChangeDescriptorBindingNumbers
+ @brief Assign new set and/or binding numbers to a descriptor binding.
+ In addition to updating the reflection data, this function modifies
+ the underlying SPIR-V bytecode. The updated code can be retrieved
+ with spvReflectGetCode(). If the binding is used in multiple
+ entry points within the module, it will be changed in all of them.
+ @param p_module Pointer to an instance of SpvReflectShaderModule.
+ @param p_binding Pointer to the descriptor binding to modify.
+ @param new_binding_number The new binding number to assign to the
+ provided descriptor binding.
+ To leave the binding number unchanged, pass
+ SPV_REFLECT_BINDING_NUMBER_DONT_CHANGE.
+ @param new_set_number The new set number to assign to the
+ provided descriptor binding. Successfully changing
+ a descriptor binding's set number invalidates all
+ existing SpvReflectDescriptorBinding and
+ SpvReflectDescriptorSet pointers from this module.
+ To leave the set number unchanged, pass
+ SPV_REFLECT_SET_NUMBER_DONT_CHANGE.
+ @return If successful, returns SPV_REFLECT_RESULT_SUCCESS.
+ Otherwise, the error code indicates the cause of
+ the failure.
+*/
+SpvReflectResult spvReflectChangeDescriptorBindingNumbers(
+ SpvReflectShaderModule* p_module,
+ const SpvReflectDescriptorBinding* p_binding,
+ uint32_t new_binding_number,
+ uint32_t new_set_number
+);
+SPV_REFLECT_DEPRECATED("Renamed to spvReflectChangeDescriptorBindingNumbers")
+SpvReflectResult spvReflectChangeDescriptorBindingNumber(
+ SpvReflectShaderModule* p_module,
+ const SpvReflectDescriptorBinding* p_descriptor_binding,
+ uint32_t new_binding_number,
+ uint32_t optional_new_set_number
+);
+
+/*! @fn spvReflectChangeDescriptorSetNumber
+ @brief Assign a new set number to an entire descriptor set (including
+ all descriptor bindings in that set).
+ In addition to updating the reflection data, this function modifies
+ the underlying SPIR-V bytecode. The updated code can be retrieved
+ with spvReflectGetCode(). If the descriptor set is used in
+ multiple entry points within the module, it will be modified in all
+ of them.
+ @param p_module Pointer to an instance of SpvReflectShaderModule.
+ @param p_set Pointer to the descriptor binding to modify.
+ @param new_set_number The new set number to assign to the
+ provided descriptor set, and all its descriptor
+ bindings. Successfully changing a descriptor
+ binding's set number invalidates all existing
+ SpvReflectDescriptorBinding and
+ SpvReflectDescriptorSet pointers from this module.
+ To leave the set number unchanged, pass
+ SPV_REFLECT_SET_NUMBER_DONT_CHANGE.
+ @return If successful, returns SPV_REFLECT_RESULT_SUCCESS.
+ Otherwise, the error code indicates the cause of
+ the failure.
+*/
+SpvReflectResult spvReflectChangeDescriptorSetNumber(
+ SpvReflectShaderModule* p_module,
+ const SpvReflectDescriptorSet* p_set,
+ uint32_t new_set_number
+);
+
+/*! @fn spvReflectChangeInputVariableLocation
+ @brief Assign a new location to an input interface variable.
+ In addition to updating the reflection data, this function modifies
+ the underlying SPIR-V bytecode. The updated code can be retrieved
+ with spvReflectGetCode().
+ It is the caller's responsibility to avoid assigning the same
+ location to multiple input variables. If the input variable is used
+ by multiple entry points in the module, it will be changed in all of
+ them.
+ @param p_module Pointer to an instance of SpvReflectShaderModule.
+ @param p_input_variable Pointer to the input variable to update.
+ @param new_location The new location to assign to p_input_variable.
+ @return If successful, returns SPV_REFLECT_RESULT_SUCCESS.
+ Otherwise, the error code indicates the cause of
+ the failure.
+
+*/
+SpvReflectResult spvReflectChangeInputVariableLocation(
+ SpvReflectShaderModule* p_module,
+ const SpvReflectInterfaceVariable* p_input_variable,
+ uint32_t new_location
+);
+
+
+/*! @fn spvReflectChangeOutputVariableLocation
+ @brief Assign a new location to an output interface variable.
+ In addition to updating the reflection data, this function modifies
+ the underlying SPIR-V bytecode. The updated code can be retrieved
+ with spvReflectGetCode().
+ It is the caller's responsibility to avoid assigning the same
+ location to multiple output variables. If the output variable is used
+ by multiple entry points in the module, it will be changed in all of
+ them.
+ @param p_module Pointer to an instance of SpvReflectShaderModule.
+ @param p_output_variable Pointer to the output variable to update.
+ @param new_location The new location to assign to p_output_variable.
+ @return If successful, returns SPV_REFLECT_RESULT_SUCCESS.
+ Otherwise, the error code indicates the cause of
+ the failure.
+
+*/
+SpvReflectResult spvReflectChangeOutputVariableLocation(
+ SpvReflectShaderModule* p_module,
+ const SpvReflectInterfaceVariable* p_output_variable,
+ uint32_t new_location
+);
+
+
+/*! @fn spvReflectSourceLanguage
+
+ @param source_lang The source language code.
+ @return Returns string of source language specified in \a source_lang.
+ The caller must not free the memory associated with this string.
+*/
+const char* spvReflectSourceLanguage(SpvSourceLanguage source_lang);
+
+#if defined(__cplusplus)
+};
+#endif
+
+#if defined(__cplusplus)
+#include <cstdlib>
+#include <string>
+#include <vector>
+
+namespace spv_reflect {
+
+/*! \class ShaderModule
+
+*/
+class ShaderModule {
+public:
+ ShaderModule();
+ ShaderModule(size_t size, const void* p_code);
+ ShaderModule(const std::vector<uint8_t>& code);
+ ShaderModule(const std::vector<uint32_t>& code);
+ ~ShaderModule();
+
+ SpvReflectResult GetResult() const;
+
+ const SpvReflectShaderModule& GetShaderModule() const;
+
+ uint32_t GetCodeSize() const;
+ const uint32_t* GetCode() const;
+
+ const char* GetEntryPointName() const;
+
+ const char* GetSourceFile() const;
+
+ uint32_t GetEntryPointCount() const;
+ const char* GetEntryPointName(uint32_t index) const;
+
+ SpvReflectShaderStageFlagBits GetShaderStage() const;
+ SPV_REFLECT_DEPRECATED("Renamed to GetShaderStage")
+ SpvReflectShaderStageFlagBits GetVulkanShaderStage() const {
+ return GetShaderStage();
+ }
+
+ SpvReflectResult EnumerateDescriptorBindings(uint32_t* p_count, SpvReflectDescriptorBinding** pp_bindings) const;
+ SpvReflectResult EnumerateEntryPointDescriptorBindings(const char* entry_point, uint32_t* p_count, SpvReflectDescriptorBinding** pp_bindings) const;
+ SpvReflectResult EnumerateDescriptorSets( uint32_t* p_count, SpvReflectDescriptorSet** pp_sets) const ;
+ SpvReflectResult EnumerateEntryPointDescriptorSets(const char* entry_point, uint32_t* p_count, SpvReflectDescriptorSet** pp_sets) const ;
+ SpvReflectResult EnumerateInputVariables(uint32_t* p_count,SpvReflectInterfaceVariable** pp_variables) const;
+ SpvReflectResult EnumerateEntryPointInputVariables(const char* entry_point, uint32_t* p_count,SpvReflectInterfaceVariable** pp_variables) const;
+ SpvReflectResult EnumerateOutputVariables(uint32_t* p_count,SpvReflectInterfaceVariable** pp_variables) const;
+ SpvReflectResult EnumerateEntryPointOutputVariables(const char* entry_point, uint32_t* p_count,SpvReflectInterfaceVariable** pp_variables) const;
+ SpvReflectResult EnumeratePushConstantBlocks(uint32_t* p_count, SpvReflectBlockVariable** pp_blocks) const;
+ SpvReflectResult EnumerateEntryPointPushConstantBlocks(const char* entry_point, uint32_t* p_count, SpvReflectBlockVariable** pp_blocks) const;
+ SPV_REFLECT_DEPRECATED("Renamed to EnumeratePushConstantBlocks")
+ SpvReflectResult EnumeratePushConstants(uint32_t* p_count, SpvReflectBlockVariable** pp_blocks) const {
+ return EnumeratePushConstantBlocks(p_count, pp_blocks);
+ }
+
+ const SpvReflectDescriptorBinding* GetDescriptorBinding(uint32_t binding_number, uint32_t set_number, SpvReflectResult* p_result = nullptr) const;
+ const SpvReflectDescriptorBinding* GetEntryPointDescriptorBinding(const char* entry_point, uint32_t binding_number, uint32_t set_number, SpvReflectResult* p_result = nullptr) const;
+ const SpvReflectDescriptorSet* GetDescriptorSet(uint32_t set_number, SpvReflectResult* p_result = nullptr) const;
+ const SpvReflectDescriptorSet* GetEntryPointDescriptorSet(const char* entry_point, uint32_t set_number, SpvReflectResult* p_result = nullptr) const;
+ const SpvReflectInterfaceVariable* GetInputVariableByLocation(uint32_t location, SpvReflectResult* p_result = nullptr) const;
+ SPV_REFLECT_DEPRECATED("Renamed to GetInputVariableByLocation")
+ const SpvReflectInterfaceVariable* GetInputVariable(uint32_t location, SpvReflectResult* p_result = nullptr) const {
+ return GetInputVariableByLocation(location, p_result);
+ }
+ const SpvReflectInterfaceVariable* GetEntryPointInputVariableByLocation(const char* entry_point, uint32_t location, SpvReflectResult* p_result = nullptr) const;
+ const SpvReflectInterfaceVariable* GetInputVariableBySemantic(const char* semantic, SpvReflectResult* p_result = nullptr) const;
+ const SpvReflectInterfaceVariable* GetEntryPointInputVariableBySemantic(const char* entry_point, const char* semantic, SpvReflectResult* p_result = nullptr) const;
+ const SpvReflectInterfaceVariable* GetOutputVariableByLocation(uint32_t location, SpvReflectResult* p_result = nullptr) const;
+ SPV_REFLECT_DEPRECATED("Renamed to GetOutputVariableByLocation")
+ const SpvReflectInterfaceVariable* GetOutputVariable(uint32_t location, SpvReflectResult* p_result = nullptr) const {
+ return GetOutputVariableByLocation(location, p_result);
+ }
+ const SpvReflectInterfaceVariable* GetEntryPointOutputVariableByLocation(const char* entry_point, uint32_t location, SpvReflectResult* p_result = nullptr) const;
+ const SpvReflectInterfaceVariable* GetOutputVariableBySemantic(const char* semantic, SpvReflectResult* p_result = nullptr) const;
+ const SpvReflectInterfaceVariable* GetEntryPointOutputVariableBySemantic(const char* entry_point, const char* semantic, SpvReflectResult* p_result = nullptr) const;
+ const SpvReflectBlockVariable* GetPushConstantBlock(uint32_t index, SpvReflectResult* p_result = nullptr) const;
+ SPV_REFLECT_DEPRECATED("Renamed to GetPushConstantBlock")
+ const SpvReflectBlockVariable* GetPushConstant(uint32_t index, SpvReflectResult* p_result = nullptr) const {
+ return GetPushConstantBlock(index, p_result);
+ }
+ const SpvReflectBlockVariable* GetEntryPointPushConstantBlock(const char* entry_point, SpvReflectResult* p_result = nullptr) const;
+
+ SpvReflectResult ChangeDescriptorBindingNumbers(const SpvReflectDescriptorBinding* p_binding,
+ uint32_t new_binding_number = SPV_REFLECT_BINDING_NUMBER_DONT_CHANGE,
+ uint32_t optional_new_set_number = SPV_REFLECT_SET_NUMBER_DONT_CHANGE);
+ SPV_REFLECT_DEPRECATED("Renamed to ChangeDescriptorBindingNumbers")
+ SpvReflectResult ChangeDescriptorBindingNumber(const SpvReflectDescriptorBinding* p_binding, uint32_t new_binding_number = SPV_REFLECT_BINDING_NUMBER_DONT_CHANGE,
+ uint32_t new_set_number = SPV_REFLECT_SET_NUMBER_DONT_CHANGE) {
+ return ChangeDescriptorBindingNumbers(p_binding, new_binding_number, new_set_number);
+ }
+ SpvReflectResult ChangeDescriptorSetNumber(const SpvReflectDescriptorSet* p_set, uint32_t new_set_number = SPV_REFLECT_SET_NUMBER_DONT_CHANGE);
+ SpvReflectResult ChangeInputVariableLocation(const SpvReflectInterfaceVariable* p_input_variable, uint32_t new_location);
+ SpvReflectResult ChangeOutputVariableLocation(const SpvReflectInterfaceVariable* p_output_variable, uint32_t new_location);
+
+private:
+ mutable SpvReflectResult m_result = SPV_REFLECT_RESULT_NOT_READY;
+ SpvReflectShaderModule m_module = {};
+};
+
+
+// =================================================================================================
+// ShaderModule
+// =================================================================================================
+
+/*! @fn ShaderModule
+
+*/
+inline ShaderModule::ShaderModule() {}
+
+
+/*! @fn ShaderModule
+
+ @param size
+ @param p_code
+
+*/
+inline ShaderModule::ShaderModule(size_t size, const void* p_code) {
+ m_result = spvReflectCreateShaderModule(
+ size,
+ p_code,
+ &m_module);
+}
+
+/*! @fn ShaderModule
+
+ @param code
+
+*/
+inline ShaderModule::ShaderModule(const std::vector<uint8_t>& code) {
+ m_result = spvReflectCreateShaderModule(
+ code.size(),
+ code.data(),
+ &m_module);
+}
+
+/*! @fn ShaderModule
+
+ @param code
+
+*/
+inline ShaderModule::ShaderModule(const std::vector<uint32_t>& code) {
+ m_result = spvReflectCreateShaderModule(
+ code.size() * sizeof(uint32_t),
+ code.data(),
+ &m_module);
+}
+
+/*! @fn ~ShaderModule
+
+*/
+inline ShaderModule::~ShaderModule() {
+ spvReflectDestroyShaderModule(&m_module);
+}
+
+
+/*! @fn GetResult
+
+ @return
+
+*/
+inline SpvReflectResult ShaderModule::GetResult() const {
+ return m_result;
+}
+
+
+/*! @fn GetShaderModule
+
+ @return
+
+*/
+inline const SpvReflectShaderModule& ShaderModule::GetShaderModule() const {
+ return m_module;
+}
+
+
+/*! @fn GetCodeSize
+
+ @return
+
+ */
+inline uint32_t ShaderModule::GetCodeSize() const {
+ return spvReflectGetCodeSize(&m_module);
+}
+
+
+/*! @fn GetCode
+
+ @return
+
+*/
+inline const uint32_t* ShaderModule::GetCode() const {
+ return spvReflectGetCode(&m_module);
+}
+
+
+/*! @fn GetEntryPoint
+
+ @return Returns entry point
+
+*/
+inline const char* ShaderModule::GetEntryPointName() const {
+ return this->GetEntryPointName(0);
+}
+
+/*! @fn GetEntryPoint
+
+ @return Returns entry point
+
+*/
+inline const char* ShaderModule::GetSourceFile() const {
+ return m_module.source_file;
+}
+
+/*! @fn GetEntryPointCount
+
+ @param
+ @return
+*/
+inline uint32_t ShaderModule::GetEntryPointCount() const {
+ return m_module.entry_point_count;
+}
+
+/*! @fn GetEntryPointName
+
+ @param index
+ @return
+*/
+inline const char* ShaderModule::GetEntryPointName(uint32_t index) const {
+ return m_module.entry_points[index].name;
+}
+
+/*! @fn GetShaderStage
+
+ @return Returns Vulkan shader stage
+
+*/
+inline SpvReflectShaderStageFlagBits ShaderModule::GetShaderStage() const {
+ return m_module.shader_stage;
+}
+
+/*! @fn EnumerateDescriptorBindings
+
+ @param count
+ @param p_binding_numbers
+ @param pp_bindings
+ @return
+
+*/
+inline SpvReflectResult ShaderModule::EnumerateDescriptorBindings(
+ uint32_t* p_count,
+ SpvReflectDescriptorBinding** pp_bindings
+) const
+{
+ m_result = spvReflectEnumerateDescriptorBindings(
+ &m_module,
+ p_count,
+ pp_bindings);
+ return m_result;
+}
+
+/*! @fn EnumerateEntryPointDescriptorBindings
+
+ @param entry_point
+ @param count
+ @param pp_bindings
+ @return
+
+*/
+inline SpvReflectResult ShaderModule::EnumerateEntryPointDescriptorBindings(
+ const char* entry_point,
+ uint32_t* p_count,
+ SpvReflectDescriptorBinding** pp_bindings
+) const
+{
+ m_result = spvReflectEnumerateEntryPointDescriptorBindings(
+ &m_module,
+ entry_point,
+ p_count,
+ pp_bindings);
+ return m_result;
+}
+
+
+/*! @fn EnumerateDescriptorSets
+
+ @param count
+ @param pp_sets
+ @return
+
+*/
+inline SpvReflectResult ShaderModule::EnumerateDescriptorSets(
+ uint32_t* p_count,
+ SpvReflectDescriptorSet** pp_sets
+) const
+{
+ m_result = spvReflectEnumerateDescriptorSets(
+ &m_module,
+ p_count,
+ pp_sets);
+ return m_result;
+}
+
+/*! @fn EnumerateEntryPointDescriptorSets
+
+ @param entry_point
+ @param count
+ @param pp_sets
+ @return
+
+*/
+inline SpvReflectResult ShaderModule::EnumerateEntryPointDescriptorSets(
+ const char* entry_point,
+ uint32_t* p_count,
+ SpvReflectDescriptorSet** pp_sets
+) const
+{
+ m_result = spvReflectEnumerateEntryPointDescriptorSets(
+ &m_module,
+ entry_point,
+ p_count,
+ pp_sets);
+ return m_result;
+}
+
+
+/*! @fn EnumerateInputVariables
+
+ @param count
+ @param pp_variables
+ @return
+
+*/
+inline SpvReflectResult ShaderModule::EnumerateInputVariables(
+ uint32_t* p_count,
+ SpvReflectInterfaceVariable** pp_variables
+) const
+{
+ m_result = spvReflectEnumerateInputVariables(
+ &m_module,
+ p_count,
+ pp_variables);
+ return m_result;
+}
+
+/*! @fn EnumerateEntryPointInputVariables
+
+ @param entry_point
+ @param count
+ @param pp_variables
+ @return
+
+*/
+inline SpvReflectResult ShaderModule::EnumerateEntryPointInputVariables(
+ const char* entry_point,
+ uint32_t* p_count,
+ SpvReflectInterfaceVariable** pp_variables
+) const
+{
+ m_result = spvReflectEnumerateEntryPointInputVariables(
+ &m_module,
+ entry_point,
+ p_count,
+ pp_variables);
+ return m_result;
+}
+
+
+/*! @fn EnumerateOutputVariables
+
+ @param count
+ @param pp_variables
+ @return
+
+*/
+inline SpvReflectResult ShaderModule::EnumerateOutputVariables(
+ uint32_t* p_count,
+ SpvReflectInterfaceVariable** pp_variables
+) const
+{
+ m_result = spvReflectEnumerateOutputVariables(
+ &m_module,
+ p_count,
+ pp_variables);
+ return m_result;
+}
+
+/*! @fn EnumerateEntryPointOutputVariables
+
+ @param entry_point
+ @param count
+ @param pp_variables
+ @return
+
+*/
+inline SpvReflectResult ShaderModule::EnumerateEntryPointOutputVariables(
+ const char* entry_point,
+ uint32_t* p_count,
+ SpvReflectInterfaceVariable** pp_variables
+) const
+{
+ m_result = spvReflectEnumerateEntryPointOutputVariables(
+ &m_module,
+ entry_point,
+ p_count,
+ pp_variables);
+ return m_result;
+}
+
+
+/*! @fn EnumeratePushConstantBlocks
+
+ @param count
+ @param pp_blocks
+ @return
+
+*/
+inline SpvReflectResult ShaderModule::EnumeratePushConstantBlocks(
+ uint32_t* p_count,
+ SpvReflectBlockVariable** pp_blocks
+) const
+{
+ m_result = spvReflectEnumeratePushConstantBlocks(
+ &m_module,
+ p_count,
+ pp_blocks);
+ return m_result;
+}
+
+/*! @fn EnumerateEntryPointPushConstantBlocks
+
+ @param entry_point
+ @param count
+ @param pp_blocks
+ @return
+
+*/
+inline SpvReflectResult ShaderModule::EnumerateEntryPointPushConstantBlocks(
+ const char* entry_point,
+ uint32_t* p_count,
+ SpvReflectBlockVariable** pp_blocks
+) const
+{
+ m_result = spvReflectEnumerateEntryPointPushConstantBlocks(
+ &m_module,
+ entry_point,
+ p_count,
+ pp_blocks);
+ return m_result;
+}
+
+
+/*! @fn GetDescriptorBinding
+
+ @param binding_number
+ @param set_number
+ @param p_result
+ @return
+
+*/
+inline const SpvReflectDescriptorBinding* ShaderModule::GetDescriptorBinding(
+ uint32_t binding_number,
+ uint32_t set_number,
+ SpvReflectResult* p_result
+) const
+{
+ return spvReflectGetDescriptorBinding(
+ &m_module,
+ binding_number,
+ set_number,
+ p_result);
+}
+
+/*! @fn GetEntryPointDescriptorBinding
+
+ @param entry_point
+ @param binding_number
+ @param set_number
+ @param p_result
+ @return
+
+*/
+inline const SpvReflectDescriptorBinding* ShaderModule::GetEntryPointDescriptorBinding(
+ const char* entry_point,
+ uint32_t binding_number,
+ uint32_t set_number,
+ SpvReflectResult* p_result
+) const
+{
+ return spvReflectGetEntryPointDescriptorBinding(
+ &m_module,
+ entry_point,
+ binding_number,
+ set_number,
+ p_result);
+}
+
+
+/*! @fn GetDescriptorSet
+
+ @param set_number
+ @param p_result
+ @return
+
+*/
+inline const SpvReflectDescriptorSet* ShaderModule::GetDescriptorSet(
+ uint32_t set_number,
+ SpvReflectResult* p_result
+) const
+{
+ return spvReflectGetDescriptorSet(
+ &m_module,
+ set_number,
+ p_result);
+}
+
+/*! @fn GetEntryPointDescriptorSet
+
+ @param entry_point
+ @param set_number
+ @param p_result
+ @return
+
+*/
+inline const SpvReflectDescriptorSet* ShaderModule::GetEntryPointDescriptorSet(
+ const char* entry_point,
+ uint32_t set_number,
+ SpvReflectResult* p_result
+) const
+{
+ return spvReflectGetEntryPointDescriptorSet(
+ &m_module,
+ entry_point,
+ set_number,
+ p_result);
+}
+
+
+/*! @fn GetInputVariable
+
+ @param location
+ @param p_result
+ @return
+
+*/
+inline const SpvReflectInterfaceVariable* ShaderModule::GetInputVariableByLocation(
+ uint32_t location,
+ SpvReflectResult* p_result
+) const
+{
+ return spvReflectGetInputVariableByLocation(
+ &m_module,
+ location,
+ p_result);
+}
+inline const SpvReflectInterfaceVariable* ShaderModule::GetInputVariableBySemantic(
+ const char* semantic,
+ SpvReflectResult* p_result
+) const
+{
+ return spvReflectGetInputVariableBySemantic(
+ &m_module,
+ semantic,
+ p_result);
+}
+
+/*! @fn GetEntryPointInputVariable
+
+ @param entry_point
+ @param location
+ @param p_result
+ @return
+
+*/
+inline const SpvReflectInterfaceVariable* ShaderModule::GetEntryPointInputVariableByLocation(
+ const char* entry_point,
+ uint32_t location,
+ SpvReflectResult* p_result
+) const
+{
+ return spvReflectGetEntryPointInputVariableByLocation(
+ &m_module,
+ entry_point,
+ location,
+ p_result);
+}
+inline const SpvReflectInterfaceVariable* ShaderModule::GetEntryPointInputVariableBySemantic(
+ const char* entry_point,
+ const char* semantic,
+ SpvReflectResult* p_result
+) const
+{
+ return spvReflectGetEntryPointInputVariableBySemantic(
+ &m_module,
+ entry_point,
+ semantic,
+ p_result);
+}
+
+
+/*! @fn GetOutputVariable
+
+ @param location
+ @param p_result
+ @return
+
+*/
+inline const SpvReflectInterfaceVariable* ShaderModule::GetOutputVariableByLocation(
+ uint32_t location,
+ SpvReflectResult* p_result
+) const
+{
+ return spvReflectGetOutputVariableByLocation(
+ &m_module,
+ location,
+ p_result);
+}
+inline const SpvReflectInterfaceVariable* ShaderModule::GetOutputVariableBySemantic(
+ const char* semantic,
+ SpvReflectResult* p_result
+) const
+{
+ return spvReflectGetOutputVariableBySemantic(&m_module,
+ semantic,
+ p_result);
+}
+
+/*! @fn GetEntryPointOutputVariable
+
+ @param entry_point
+ @param location
+ @param p_result
+ @return
+
+*/
+inline const SpvReflectInterfaceVariable* ShaderModule::GetEntryPointOutputVariableByLocation(
+ const char* entry_point,
+ uint32_t location,
+ SpvReflectResult* p_result
+) const
+{
+ return spvReflectGetEntryPointOutputVariableByLocation(
+ &m_module,
+ entry_point,
+ location,
+ p_result);
+}
+inline const SpvReflectInterfaceVariable* ShaderModule::GetEntryPointOutputVariableBySemantic(
+ const char* entry_point,
+ const char* semantic,
+ SpvReflectResult* p_result
+) const
+{
+ return spvReflectGetEntryPointOutputVariableBySemantic(
+ &m_module,
+ entry_point,
+ semantic,
+ p_result);
+}
+
+
+/*! @fn GetPushConstant
+
+ @param index
+ @param p_result
+ @return
+
+*/
+inline const SpvReflectBlockVariable* ShaderModule::GetPushConstantBlock(
+ uint32_t index,
+ SpvReflectResult* p_result
+) const
+{
+ return spvReflectGetPushConstantBlock(
+ &m_module,
+ index,
+ p_result);
+}
+
+/*! @fn GetEntryPointPushConstant
+
+ @param entry_point
+ @param index
+ @param p_result
+ @return
+
+*/
+inline const SpvReflectBlockVariable* ShaderModule::GetEntryPointPushConstantBlock(
+ const char* entry_point,
+ SpvReflectResult* p_result
+) const
+{
+ return spvReflectGetEntryPointPushConstantBlock(
+ &m_module,
+ entry_point,
+ p_result);
+}
+
+
+/*! @fn ChangeDescriptorBindingNumbers
+
+ @param p_binding
+ @param new_binding_number
+ @param new_set_number
+ @return
+
+*/
+inline SpvReflectResult ShaderModule::ChangeDescriptorBindingNumbers(
+ const SpvReflectDescriptorBinding* p_binding,
+ uint32_t new_binding_number,
+ uint32_t new_set_number
+)
+{
+ return spvReflectChangeDescriptorBindingNumbers(
+ &m_module,
+ p_binding,
+ new_binding_number,
+ new_set_number);
+}
+
+
+/*! @fn ChangeDescriptorSetNumber
+
+ @param p_set
+ @param new_set_number
+ @return
+
+*/
+inline SpvReflectResult ShaderModule::ChangeDescriptorSetNumber(
+ const SpvReflectDescriptorSet* p_set,
+ uint32_t new_set_number
+)
+{
+ return spvReflectChangeDescriptorSetNumber(
+ &m_module,
+ p_set,
+ new_set_number);
+}
+
+
+/*! @fn ChangeInputVariableLocation
+
+ @param p_input_variable
+ @param new_location
+ @return
+
+*/
+inline SpvReflectResult ShaderModule::ChangeInputVariableLocation(
+ const SpvReflectInterfaceVariable* p_input_variable,
+ uint32_t new_location)
+{
+ return spvReflectChangeInputVariableLocation(
+ &m_module,
+ p_input_variable,
+ new_location);
+}
+
+
+/*! @fn ChangeOutputVariableLocation
+
+ @param p_input_variable
+ @param new_location
+ @return
+
+*/
+inline SpvReflectResult ShaderModule::ChangeOutputVariableLocation(
+ const SpvReflectInterfaceVariable* p_output_variable,
+ uint32_t new_location)
+{
+ return spvReflectChangeOutputVariableLocation(
+ &m_module,
+ p_output_variable,
+ new_location);
+}
+
+} // namespace spv_reflect
+#endif // defined(__cplusplus)
+#endif // SPIRV_REFLECT_H