浏览代码

Replaced GLSLang reflection by SPIRV-Reflect, eventually allowing to move GLSLang out.

Juan Linietsky 6 年之前
父节点
当前提交
60c7498cee

+ 1 - 0
drivers/SCsub

@@ -33,6 +33,7 @@ else:
 
 
 # Core dependencies
 # Core dependencies
 SConscript("png/SCsub")
 SConscript("png/SCsub")
+SConscript("spirv-reflect/SCsub")
 
 
 if env['vsproj']:
 if env['vsproj']:
     import os
     import os

+ 16 - 0
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')

+ 246 - 9
drivers/vulkan/rendering_device_vulkan.cpp

@@ -1,10 +1,11 @@
 #include "rendering_device_vulkan.h"
 #include "rendering_device_vulkan.h"
-#include "drivers/vulkan/vulkan_context.h"
-
 #include "core/hashfuncs.h"
 #include "core/hashfuncs.h"
+#include "core/os/file_access.h"
 #include "core/project_settings.h"
 #include "core/project_settings.h"
+#include "drivers/vulkan/vulkan_context.h"
 #include "thirdparty/glslang/SPIRV/GlslangToSpv.h"
 #include "thirdparty/glslang/SPIRV/GlslangToSpv.h"
 #include "thirdparty/glslang/glslang/Include/Types.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) {
 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;
 				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);
 				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;
 	glslang::TShader::ForbidIncluder includer;
 
 
 	//descriptor layouts
 	//descriptor layouts
-	Vector<Vector<VkDescriptorSetLayoutBinding> > bindings;
+	Vector<Vector<VkDescriptorSetLayoutBinding> > set_bindings;
 	Vector<Vector<UniformInfo> > uniform_info;
 	Vector<Vector<UniformInfo> > uniform_info;
 	Shader::PushConstant push_constant;
 	Shader::PushConstant push_constant;
 	push_constant.push_constant_size = 0;
 	push_constant.push_constant_size = 0;
@@ -3652,11 +3652,27 @@ RID RenderingDeviceVulkan::shader_create_from_source(const Vector<ShaderStageSou
 			return RID();
 			return RID();
 		}
 		}
 
 
+#if 0
 		//obtain bindings for descriptor layout
 		//obtain bindings for descriptor layout
 		program.mapIO();
 		program.mapIO();
 		program.buildReflection(EShReflectionAllBlockVariables);
 		program.buildReflection(EShReflectionAllBlockVariables);
 		//program.dumpReflection();
 		//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++) {
 		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)) {
 			if (!_uniform_add_binding(bindings, uniform_info, program.getUniform(j), p_stages[i].shader_stage, push_constant, r_error)) {
 				return RID();
 				return RID();
@@ -3698,11 +3714,233 @@ RID RenderingDeviceVulkan::shader_create_from_source(const Vector<ShaderStageSou
 			fragment_outputs = program.getNumPipeOutputs();
 			fragment_outputs = program.getNumPipeOutputs();
 		}
 		}
 
 
+#endif
 		std::vector<uint32_t> SpirV;
 		std::vector<uint32_t> SpirV;
 		spv::SpvBuildLogger logger;
 		spv::SpvBuildLogger logger;
 		glslang::SpvOptions spvOptions;
 		glslang::SpvOptions spvOptions;
 		glslang::GlslangToSpv(*program.getIntermediate(stages[p_stages[i].shader_stage]), SpirV, &logger, &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);
 		spirv_code.push_back(SpirV);
 
 
 		stages_processed |= (1 << p_stages[i].shader_stage);
 		stages_processed |= (1 << p_stages[i].shader_stage);
@@ -3758,15 +3996,15 @@ RID RenderingDeviceVulkan::shader_create_from_source(const Vector<ShaderStageSou
 
 
 	if (success) {
 	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)
 			//empty ones are fine if they were not used according to spec (binding count will be 0)
 			VkDescriptorSetLayoutCreateInfo layout_create_info;
 			VkDescriptorSetLayoutCreateInfo layout_create_info;
 			layout_create_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
 			layout_create_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
 			layout_create_info.pNext = NULL;
 			layout_create_info.pNext = NULL;
 			layout_create_info.flags = 0;
 			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;
 			VkDescriptorSetLayout layout;
 			VkResult res = vkCreateDescriptorSetLayout(device, &layout_create_info, NULL, &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];
 		const Uniform &uniform = uniforms[uniform_idx];
 
 
 		ERR_FAIL_COND_V_MSG(uniform.type != set_uniform.type, RID(),
 		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
 		VkWriteDescriptorSet write; //common header
 		write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
 		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 = 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);
 	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
 	frames_drawn = frame_count; //start from frame count, so everything else is immediately old
 
 

+ 1 - 1
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;
 			r_gen_code.uniform_total_size = offset;
 			print_line("uniform total: " + itos(r_gen_code.uniform_total_size));
 			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
 			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
 #else
 			// add up
 			// add up

+ 1077 - 0
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
+

+ 4442 - 0
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 "";
+}

+ 2045 - 0
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