${adaptor_graphics_vulkan_src_files}
${adaptor_graphics_vulkan_x11_src_files}
${adaptor_imaging_ubuntu_x11_vulkan_src_files}
+ ${adaptor_libraries_spirv_reflect_src_files}
)
ELSE()
SET(SOURCES ${SOURCES}
${adaptor_graphics_dir}/vulkan-impl/vulkan-program.cpp
${adaptor_graphics_dir}/vulkan-impl/vulkan-program-impl.cpp
${adaptor_graphics_dir}/vulkan-impl/vulkan-queue-impl.cpp
+ ${adaptor_graphics_dir}/vulkan-impl/vulkan-reflection.cpp
${adaptor_graphics_dir}/vulkan-impl/vulkan-render-pass.cpp
${adaptor_graphics_dir}/vulkan-impl/vulkan-render-pass-impl.cpp
${adaptor_graphics_dir}/vulkan-impl/vulkan-render-target.cpp
#include <dali/integration-api/debug.h>
#include <dali/internal/graphics/common/shader-parser.h>
#include <dali/internal/graphics/vulkan-impl/vulkan-graphics-controller.h>
+#include <dali/internal/graphics/vulkan-impl/vulkan-reflection.h>
#include <dali/internal/graphics/vulkan-impl/vulkan-shader-impl.h>
#include <dali/internal/graphics/vulkan-impl/vulkan-shader.h>
ProgramCreateInfo createInfo;
std::string name;
uint32_t refCount{0u};
+
+ std::unique_ptr<Vulkan::Reflection> reflection{nullptr};
};
ProgramImpl::ProgramImpl(const Graphics::ProgramCreateInfo& createInfo, VulkanGraphicsController& controller)
if(!shaderImpl->Compile())
{
DALI_LOG_ERROR("SPIRV Compilation failed!\n");
+ success = false;
}
}
}
+
+ if(success)
+ {
+ // Build reflection
+ mImpl->reflection = std::make_unique<Vulkan::Reflection>(*this, controller);
+ }
}
ProgramImpl::~ProgramImpl() = default;
return mImpl->refCount;
}
+const Vulkan::Reflection& ProgramImpl::GetReflection() const
+{
+ return *mImpl->reflection;
+}
+
bool ProgramImpl::GetParameter(uint32_t parameterId, void* out)
{
return false;
namespace Dali::Graphics::Vulkan
{
+class Reflection;
+
/**
* @brief Program implementation
*
*/
[[nodiscard]] uint32_t GetRefCount() const;
+ /**
+ * @brief Returns reflection
+ *
+ * @return Valid reflection associated with the Program
+ */
+ [[nodiscard]] const Vulkan::Reflection& GetReflection() const;
+
/**
* @brief Returns controller
*
const Vulkan::Reflection& Program::GetReflection() const
{
- // TODO: Implement reflection
- return *reinterpret_cast<Vulkan::Reflection*>(0u);
+ return mProgram->GetReflection();
}
VulkanGraphicsController& Program::GetController() const
--- /dev/null
+/*
+ * Copyright (c) 2024 Samsung Electronics Co., Ltd.
+ *
+ * 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.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/graphics/vulkan-impl/vulkan-reflection.h>
+
+// INTERNAL INCLUDES
+#include <dali/integration-api/debug.h>
+#include <dali/internal/graphics/vulkan-impl/vulkan-graphics-controller.h>
+#include <dali/internal/graphics/vulkan-impl/vulkan-program-impl.h>
+#include <dali/internal/graphics/vulkan-impl/vulkan-shader-impl.h>
+#include <dali/internal/graphics/vulkan-impl/vulkan-shader.h>
+#include <dali/public-api/common/vector-wrapper.h>
+
+// EXTERNAL INCLUDES
+#include <third-party/SPIRV-Reflect/spirv_reflect.h>
+#include <vulkan/vulkan.hpp>
+
+namespace
+{
+#if defined(DEBUG_ENABLED)
+Debug::Filter* gGraphicsReflectionLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_GRAPHICS_REFLECTION");
+#endif
+
+} // namespace
+namespace Dali::Graphics::Vulkan
+{
+inline VertexInputAttributeFormat ToVertexInputAttributeFormat(SpvReflectFormat spvFormat)
+{
+ // only supported types (we need to verify)
+ switch(spvFormat)
+ {
+ case SPV_REFLECT_FORMAT_R32_SINT:
+ {
+ return VertexInputAttributeFormat::INTEGER;
+ }
+ case SPV_REFLECT_FORMAT_R32_SFLOAT:
+ {
+ return VertexInputAttributeFormat::FLOAT;
+ }
+ //case SPV_REFLECT_FORMAT_R32G32_SINT:{
+ // return VertexInputAttributeFormat::VEC2
+ //}
+ case SPV_REFLECT_FORMAT_R32G32_SFLOAT:
+ {
+ return VertexInputAttributeFormat::VEC2;
+ }
+ //case SPV_REFLECT_FORMAT_R32G32B32_SINT:{}
+ case SPV_REFLECT_FORMAT_R32G32B32_SFLOAT:
+ {
+ return VertexInputAttributeFormat::VEC3;
+ }
+ //case SPV_REFLECT_FORMAT_R32G32B32A32_SINT:{};
+ case SPV_REFLECT_FORMAT_R32G32B32A32_SFLOAT:
+ {
+ return VertexInputAttributeFormat::VEC4;
+ }
+ default:
+ {
+ return VertexInputAttributeFormat::UNDEFINED;
+ }
+ }
+}
+
+Reflection::Reflection(Vulkan::ProgramImpl& program, VulkanGraphicsController& controller)
+: Graphics::Reflection(),
+ mController(controller),
+ mProgram(program)
+{
+ BuildReflection();
+}
+
+Reflection::~Reflection() = default;
+
+template<typename FN, typename OUT>
+void SPIRVEnumerate(FN& proc, SpvReflectShaderModule* module, std::vector<OUT*>& out)
+{
+ uint32_t var_count = 0;
+ proc(module, &var_count, nullptr);
+ out.resize(var_count);
+ auto ptr = out.data();
+ proc(module, &var_count, reinterpret_cast<OUT**>(ptr));
+}
+
+void Reflection::BuildReflection()
+{
+ // LIMITATION: only one shader module per stage is allowed. Vulkan supports linking multiple
+ // modules per stage but at this moment we won't support it (because we don't have a use case)
+ bool vertexShaderDone = false;
+ bool fragmentShaderDone = false;
+ enum class StageCheckResult
+ {
+ INVALID = -1,
+ ALREADY_DONE = 1,
+ OK = 0
+ };
+
+ // initialize uniform block data
+ mUniformBlocks.clear();
+ mUniformBlocks.resize(1); // index 0 is standalone block which isn't in use by Vulkan but must be there
+
+ // initialize list of samplers
+ // NOTE: We support only COMBINED_IMAGE_SAMPLER type currently (regular sampler on the GLES side)
+ std::vector<UniformInfo> samplers;
+
+ // build descriptor set layout (currently, we support only one set!)
+ std::vector<vk::DescriptorSetLayoutCreateInfo> dsLayoutInfos;
+
+ for(auto& state : (*mProgram.GetCreateInfo().shaderState))
+ {
+ auto impl = static_cast<const Vulkan::Shader*>(state.shader)->GetImplementation();
+ auto spirvBinary = impl->GetCreateInfo().sourceData;
+ auto spirvLength = impl->GetCreateInfo().sourceSize;
+ auto stage = state.pipelineStage;
+ SpvReflectShaderModule module;
+ SpvReflectResult result = spvReflectCreateShaderModule(spirvLength, spirvBinary, &module);
+
+ if(result != SPV_REFLECT_RESULT_SUCCESS)
+ {
+ DALI_LOG_ERROR("Can't reflect SPIRV module! err = %d\n", int(result));
+ continue;
+ }
+
+ // helper lambda if we need to check more types of pipeline stages in the future
+ auto CheckStageIfDone = [stage](auto expectedStage, auto& variable, const char* stageName) -> StageCheckResult {
+ if(stage == expectedStage)
+ {
+ if(!variable)
+ {
+ variable = true;
+ }
+ else
+ {
+ DALI_LOG_ERROR("Can't reflect SPIRV module! Only one module per %s is allowed!\n", stageName);
+ return StageCheckResult::ALREADY_DONE; // return true if stage already done
+ }
+ }
+ else
+ {
+ return StageCheckResult::INVALID; // not stage
+ }
+ return StageCheckResult::OK;
+ };
+
+ // Process only one module per stage
+ if(CheckStageIfDone(PipelineStage::VERTEX_SHADER, vertexShaderDone, "VERTEX_STAGE") == StageCheckResult::ALREADY_DONE)
+ {
+ continue;
+ }
+ if(CheckStageIfDone(PipelineStage::FRAGMENT_SHADER, fragmentShaderDone, "FRAGMENT_STAGE") == StageCheckResult::ALREADY_DONE)
+ {
+ continue;
+ }
+
+ // Process vertex shader attributes
+ if(stage == PipelineStage::VERTEX_SHADER)
+ {
+ BuildVertexAttributeReflection(&module);
+
+ // build vertex input layouts for Vulkan
+ }
+
+ // Prepare descriptor set layout allocation
+ std::vector<SpvReflectDescriptorSet*> dsSets;
+ SPIRVEnumerate(spvReflectEnumerateDescriptorSets, &module, dsSets);
+
+ // Per each descriptor set
+ for(auto& dsSet : dsSets)
+ {
+ if(dsSet->set >= mVkDescriptorSetLayoutCreateInfoList.size())
+ {
+ mVkDescriptorSetLayoutCreateInfoList.resize(dsSet->set + 1);
+ mVkDescriptorSetLayoutBindingList.resize(dsSet->set + 1);
+ }
+
+ // per each set preallocate bindings
+ std::vector<vk::DescriptorSetLayoutBinding> bindings;
+ bindings.resize(dsSet->binding_count);
+ for(auto i = 0u; i < dsSet->binding_count; ++i)
+ {
+ auto& bind = bindings[i];
+ auto& ref = *dsSet->bindings[i];
+ bind.setBinding(ref.binding);
+ bind.setDescriptorCount(ref.count);
+ bind.setDescriptorType(vk::DescriptorType(ref.descriptor_type));
+ bind.setStageFlags(
+ stage == PipelineStage::VERTEX_SHADER ? vk::ShaderStageFlagBits::eVertex : vk::ShaderStageFlagBits::eFragment);
+ }
+
+ auto& dsSetCreateInfo = mVkDescriptorSetLayoutCreateInfoList[dsSet->set];
+
+ auto& bindingList = mVkDescriptorSetLayoutBindingList[dsSet->set];
+ bindingList.insert(bindingList.end(), bindings.begin(), bindings.end());
+ dsSetCreateInfo.setBindings(bindingList);
+ dsSetCreateInfo.setBindingCount(bindingList.size());
+ }
+
+ // process uniform buffer bindings and samplers (opaque uniforms)
+ std::vector<SpvReflectDescriptorBinding*> dsBindings;
+ SPIRVEnumerate(spvReflectEnumerateDescriptorBindings, &module, dsBindings);
+
+ uint32_t blockIndex = 1u;
+ for([[maybe_unused]] auto& binding : dsBindings)
+ {
+ // process uniform buffer
+ if(binding->descriptor_type == SPV_REFLECT_DESCRIPTOR_TYPE_UNIFORM_BUFFER)
+ {
+ auto memberCount = binding->block.member_count;
+ auto members = binding->block.members;
+ mUniformBlocks.emplace_back();
+ auto& block = mUniformBlocks.back();
+ block.binding = binding->binding;
+ block.name = binding->name;
+ block.descriptorSet = binding->set;
+ block.size = 0; // to be updated with members
+
+ block.members.resize(memberCount);
+ for(auto i = 0u; i < memberCount; ++i)
+ {
+ auto& out = block.members[i];
+ auto& memb = members[i];
+ out.name = memb.name;
+ out.location = 0;
+ out.offset = memb.offset;
+ out.elementStride = memb.array.dims_count ? memb.array.stride : 0;
+ out.elementCount = memb.array.dims[0]; // will be zero for non-array
+ out.uniformClass = UniformClass::UNIFORM_BUFFER;
+ out.bufferIndex = blockIndex++; // TODO: do we need this for Vulkan?
+ block.size += memb.padded_size;
+ }
+ }
+ else if(binding->descriptor_type == SPV_REFLECT_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER)
+ {
+ samplers.emplace_back();
+ auto uniformInfo = &samplers.back();
+ uniformInfo->uniformClass = UniformClass::COMBINED_IMAGE_SAMPLER;
+ uniformInfo->name = binding->name;
+ uniformInfo->offset = 0;
+ uniformInfo->location = 0; // location is in the order of bidings
+ uniformInfo->binding = binding->binding;
+ }
+ }
+
+ if(!samplers.empty())
+ {
+ mUniformOpaques.insert(samplers.begin(), samplers.end(), mUniformOpaques.end());
+ // sort samplers by bindings
+ std::sort(mUniformOpaques.begin(), mUniformOpaques.end(), [](auto& lhs, auto& rhs) { return lhs.binding < rhs.binding; });
+ for(auto i = 0u; i < mUniformOpaques.size(); ++i)
+ {
+ mUniformOpaques[i].location = i;
+ }
+ }
+
+ spvReflectDestroyShaderModule(&module);
+ }
+}
+
+void Reflection::BuildVertexAttributeReflection(SpvReflectShaderModule* spvModule)
+{
+ std::vector<SpvReflectInterfaceVariable*> attrs;
+ SPIRVEnumerate(spvReflectEnumerateInputVariables, &*spvModule, attrs);
+ mVertexInputAttributes.clear();
+ mVertexInputAttributes.resize(attrs.size());
+ int maximumLocation = int(attrs.size()) - 1;
+ for(auto& attr : attrs)
+ {
+ // SPIRV contains builtin attributes that are added with locations
+ // at the end of 32bit range. To skip it we assume some 'healthy' top range
+ // for locations that we are unlikely to exceed. max of unsigned 16bit number (65535)
+ // should be more than enough.
+ // TODO: consider an usecase we may want to use built-in inputs?
+ if(attr->location > std::numeric_limits<uint16_t>::max())
+ {
+ continue;
+ }
+
+ AttributeInfo attributeInfo;
+ attributeInfo.location = attr->location;
+ attributeInfo.name = attr->name;
+ attributeInfo.format = ToVertexInputAttributeFormat(attr->format);
+
+ if(attributeInfo.location >= 0)
+ {
+ if(maximumLocation < int(attributeInfo.location))
+ {
+ maximumLocation = int(attributeInfo.location);
+ // Increase container size s.t. we can use maximumLocation as index.
+ mVertexInputAttributes.resize(maximumLocation + 1u);
+ }
+
+ mVertexInputAttributes[attributeInfo.location] = std::move(attributeInfo);
+ }
+ }
+}
+
+uint32_t Reflection::GetVertexAttributeLocation(const std::string& name) const
+{
+ DALI_LOG_INFO(gGraphicsReflectionLogFilter, Debug::Verbose, "name : %s\n", name.c_str());
+ for(auto&& attr : mVertexInputAttributes)
+ {
+ if(attr.name == name)
+ {
+ return attr.location;
+ }
+ }
+ return ERROR_ATTRIBUTE_NOT_FOUND;
+}
+
+Dali::Graphics::VertexInputAttributeFormat Reflection::GetVertexAttributeFormat(uint32_t location) const
+{
+ DALI_LOG_INFO(gGraphicsReflectionLogFilter, Debug::Verbose, "location : %u\n", location);
+ if(location >= mVertexInputAttributes.size())
+ {
+ return Dali::Graphics::VertexInputAttributeFormat::UNDEFINED;
+ }
+
+ return mVertexInputAttributes[location].format;
+}
+
+std::string Reflection::GetVertexAttributeName(uint32_t location) const
+{
+ DALI_LOG_INFO(gGraphicsReflectionLogFilter, Debug::Verbose, "location : %u\n", location);
+ if(location >= mVertexInputAttributes.size())
+ {
+ return {};
+ }
+
+ return mVertexInputAttributes[location].name;
+}
+
+std::vector<uint32_t> Reflection::GetVertexAttributeLocations() const
+{
+ std::vector<uint32_t> locations;
+ for(auto&& attr : mVertexInputAttributes)
+ {
+ if(attr.format != Dali::Graphics::VertexInputAttributeFormat::UNDEFINED)
+ {
+ locations.push_back(attr.location);
+ }
+ }
+
+ return locations;
+}
+
+uint32_t Reflection::GetUniformBlockCount() const
+{
+ return mUniformBlocks.size();
+}
+
+uint32_t Reflection::GetUniformBlockBinding(uint32_t index) const
+{
+ return index < mUniformBlocks.size() ? mUniformBlocks[index].binding : 0u;
+}
+
+uint32_t Reflection::GetUniformBlockSize(uint32_t index) const
+{
+ return index < mUniformBlocks.size() ? mUniformBlocks[index].size : 0u;
+}
+
+bool Reflection::GetUniformBlock(uint32_t index, Dali::Graphics::UniformBlockInfo& out) const
+{
+ if(index >= mUniformBlocks.size())
+ {
+ return false;
+ }
+
+ const auto& block = mUniformBlocks[index];
+
+ out.name = block.name;
+ out.binding = block.binding;
+ out.descriptorSet = block.descriptorSet;
+ auto membersSize = block.members.size();
+ out.members.resize(membersSize);
+ out.size = block.size;
+ for(auto i = 0u; i < out.members.size(); ++i)
+ {
+ const auto& memberUniform = block.members[i];
+ out.members[i].name = memberUniform.name;
+ out.members[i].binding = block.binding;
+ out.members[i].uniformClass = Graphics::UniformClass::UNIFORM;
+ out.members[i].offset = memberUniform.offset;
+ out.members[i].location = memberUniform.location;
+ out.members[i].elementCount = memberUniform.elementCount;
+ out.members[i].elementStride = memberUniform.elementStride;
+ }
+
+ return true;
+}
+
+std::vector<uint32_t> Reflection::GetUniformBlockLocations() const
+{
+ std::vector<uint32_t> retval{};
+ for(auto&& ubo : mUniformBlocks)
+ {
+ retval.emplace_back(ubo.binding);
+ }
+ return retval;
+}
+
+std::string Reflection::GetUniformBlockName(uint32_t blockIndex) const
+{
+ if(blockIndex < mUniformBlocks.size())
+ {
+ return mUniformBlocks[blockIndex].name;
+ }
+ else
+ {
+ return {};
+ }
+}
+
+uint32_t Reflection::GetUniformBlockMemberCount(uint32_t blockIndex) const
+{
+ if(blockIndex < mUniformBlocks.size())
+ {
+ return static_cast<uint32_t>(mUniformBlocks[blockIndex].members.size());
+ }
+ else
+ {
+ return 0u;
+ }
+}
+
+std::string Reflection::GetUniformBlockMemberName(uint32_t blockIndex, uint32_t memberLocation) const
+{
+ if(blockIndex < mUniformBlocks.size() && memberLocation < mUniformBlocks[blockIndex].members.size())
+ {
+ return mUniformBlocks[blockIndex].members[memberLocation].name;
+ }
+ else
+ {
+ return {};
+ }
+}
+
+uint32_t Reflection::GetUniformBlockMemberOffset(uint32_t blockIndex, uint32_t memberLocation) const
+{
+ if(blockIndex < mUniformBlocks.size() && memberLocation < mUniformBlocks[blockIndex].members.size())
+ {
+ return mUniformBlocks[blockIndex].members[memberLocation].offset;
+ }
+ else
+ {
+ return 0u;
+ }
+}
+
+bool Reflection::GetNamedUniform(const std::string& name, Dali::Graphics::UniformInfo& out) const
+{
+ auto index = 0u;
+ for(auto&& ubo : mUniformBlocks)
+ {
+ for(auto&& member : ubo.members)
+ {
+ if(name == member.name || name == (ubo.name + "." + member.name))
+ {
+ out.name = name;
+ out.location = member.location;
+ out.binding = ubo.binding;
+ out.bufferIndex = index;
+ out.offset = member.offset;
+ out.uniformClass = Graphics::UniformClass::UNIFORM;
+ return true;
+ }
+ }
+ ++index;
+ }
+
+ // check samplers
+ index = 0u;
+ for(auto&& uniform : mUniformOpaques)
+ {
+ if(uniform.name == name)
+ {
+ out.uniformClass = Graphics::UniformClass::COMBINED_IMAGE_SAMPLER;
+ out.binding = 0;
+ out.name = name;
+ out.offset = index; // lexical location in shader
+ out.location = uniform.location; // uniform location mapping
+ return true;
+ }
+ ++index;
+ }
+
+ return false;
+}
+
+const std::vector<Dali::Graphics::UniformInfo>& Reflection::GetSamplers() const
+{
+ return mUniformOpaques;
+}
+
+Graphics::ShaderLanguage Reflection::GetLanguage() const
+{
+ return ShaderLanguage::SPIRV_1_0;
+}
+
+} // namespace Dali::Graphics::Vulkan
--- /dev/null
+#ifndef DALI_GRAPHICS_VULKAN_REFLECTION_H
+#define DALI_GRAPHICS_VULKAN_REFLECTION_H
+
+/*
+ * Copyright (c) 2024 Samsung Electronics Co., Ltd.
+ *
+ * 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.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/graphics-api/graphics-reflection.h>
+
+// INTERNAL INCLUDES
+#include <dali/graphics-api/graphics-types.h>
+
+// EXTERNAL_INCLUDES
+#include <unordered_set>
+#include <vulkan/vulkan.hpp>
+
+struct SpvReflectShaderModule;
+namespace Dali::Graphics
+{
+namespace Vulkan
+{
+class ProgramImpl;
+constexpr uint32_t ERROR_ATTRIBUTE_NOT_FOUND(-1u);
+class VulkanGraphicsController;
+
+/**
+ * Reflection object represents a single full graphics reflection state.
+ *
+ * The state involves compiled and linked shaders as well as state parameters
+ * like blending, stencil, scissors, viewport etc.
+ *
+ * Some of the parameters can be modified by issuing commands but
+ * the Reflection must mark those states
+ * as dynamic.
+ *
+ */
+class Reflection : public Dali::Graphics::Reflection
+{
+public:
+ explicit Reflection(Vulkan::ProgramImpl& program, VulkanGraphicsController& controller);
+
+ ~Reflection() override;
+
+ // not copyable
+ Reflection(const Reflection&) = delete;
+ Reflection& operator=(const Reflection&) = delete;
+
+ /**
+ * @brief Gets the location of a vertex attribute.
+ *
+ * @param [in] name The name of vertex attribute
+ * @return The index of the vertex attribute in the shader
+ */
+ [[nodiscard]] uint32_t GetVertexAttributeLocation(const std::string& name) const override;
+
+ /**
+ * @brief Gets the format of a vertex attribute.
+ *
+ * @param [in] location The location of vertex attribute
+ * @return The format of a vertex attribute
+ */
+ [[nodiscard]] Dali::Graphics::VertexInputAttributeFormat GetVertexAttributeFormat(uint32_t location) const override;
+
+ /**
+ * @brief Gets the name of a vertex attribute.
+ *
+ * @param [in] location The location of vertex attribute
+ * @return The name of the vertex attribute
+ */
+ [[nodiscard]] std::string GetVertexAttributeName(uint32_t location) const override;
+
+ /**
+ * @brief Gets the locations of all the vertex attribute in the shader.
+ *
+ * @return A vector of the locations of all the vertex attributes in the shader
+ */
+ [[nodiscard]] std::vector<uint32_t> GetVertexAttributeLocations() const override;
+
+ // Uniform blocks
+
+ /**
+ * @brief Gets the number of uniform blocks in the shader
+ *
+ * @return The number of uniform blocks
+ */
+ [[nodiscard]] uint32_t GetUniformBlockCount() const override;
+
+ /**
+ * @brief Gets the binding point to which the uniform block with the given index is binded.
+ *
+ * @param [in] index The index of the uniform block
+ * @return The binding point
+ */
+ [[nodiscard]] uint32_t GetUniformBlockBinding(uint32_t index) const override;
+
+ /**
+ * @brief Gets the size of the uniform block with the given index.
+ *
+ * @param [in] index The index of the uniform block
+ * @return The size of the uniform block
+ */
+ [[nodiscard]] uint32_t GetUniformBlockSize(uint32_t index) const override;
+
+ /**
+ * @brief Retrieves the information of the uniform block with the given index.
+ *
+ * The information includes the name, binding point, size, uniforms inside the uniform block, etc.
+ *
+ * @param [in] index The index of the uniform block
+ * @param [out] out A structure that contains the information of the uniform block
+ * @return Whether the uniform block exists or not
+ */
+ bool GetUniformBlock(uint32_t index, Dali::Graphics::UniformBlockInfo& out) const override;
+
+ /**
+ * @brief Gets the binding points of all the uniform blocks in the shader.
+ *
+ * @return A vector of binding points
+ */
+ [[nodiscard]] std::vector<uint32_t> GetUniformBlockLocations() const override;
+
+ /**
+ * @brief Gets the name of uniform block with the given index.
+ *
+ * @param [in] blockIndex The index of the uniform block
+ * @return The name of the uniform block
+ */
+ [[nodiscard]] std::string GetUniformBlockName(uint32_t blockIndex) const override;
+
+ /**
+ * @brief Gets the number of uniforms in the uniform block with the given index.
+ *
+ * @param [in] blockIndex The index of the uniform block
+ * @return The number of uniforms in the uniform block
+ */
+ [[nodiscard]] uint32_t GetUniformBlockMemberCount(uint32_t blockIndex) const override;
+
+ /**
+ * @brief Gets the name of the uniform in the given location within the uniform block.
+ *
+ * @param [in] blockIndex The index of the uniform block
+ * @param [in] memberLocation The location of the uniform within the uniform block
+ * @return The name of the uniform
+ */
+ [[nodiscard]] std::string GetUniformBlockMemberName(uint32_t blockIndex, uint32_t memberLocation) const override;
+
+ /**
+ * @brief Gets the byte offset of the uniform in the given location within the uniform block.
+ *
+ * @param [in] blockIndex The index of the uniform block
+ * @param [in] memberLocation The location of the uniform within the uniform block
+ * @return The byte offset of the uniform
+ */
+ [[nodiscard]] uint32_t GetUniformBlockMemberOffset(uint32_t blockIndex, uint32_t memberLocation) const override;
+
+ // Named uniforms
+
+ /**
+ * @brief Gets the information of the uniform by its name.
+ *
+ * @param [in] name The name of the uniform
+ * @param [out] out The information of the uniform
+ * @return Whether the uniform exists or not
+ */
+ [[nodiscard]] bool GetNamedUniform(const std::string& name, Dali::Graphics::UniformInfo& out) const override;
+
+ // Sampler
+
+ /**
+ * @brief Gets all the sampler uniforms
+ *
+ * @return A vector of the sampler uniforms
+ */
+ [[nodiscard]] const std::vector<Dali::Graphics::UniformInfo>& GetSamplers() const override;
+
+ // Language
+
+ /**
+ * @brief Retrieves the language of the shader
+ *
+ * @return The language of the shader
+ */
+ [[nodiscard]] Graphics::ShaderLanguage GetLanguage() const override;
+
+public:
+ /**
+ * @brief Build the reflection of vertex attributes
+ */
+ void BuildVertexAttributeReflection(SpvReflectShaderModule* spvModule);
+
+ void BuildReflection();
+
+protected:
+ Reflection(Reflection&&) = default;
+ Reflection& operator=(Reflection&&) = default;
+
+private:
+ VulkanGraphicsController& mController; ///< The Graphics controller
+ Vulkan::ProgramImpl& mProgram; ///< The Program object
+
+ struct AttributeInfo
+ {
+ uint32_t location{ERROR_ATTRIBUTE_NOT_FOUND};
+ std::string name{};
+ Dali::Graphics::VertexInputAttributeFormat format{};
+ };
+
+ std::vector<AttributeInfo> mVertexInputAttributes; ///< List of vertex attributes
+ std::vector<Graphics::UniformInfo> mUniformOpaques{}; ///< List of opaque uniforms (i.e. samplers)
+ std::vector<Graphics::UniformBlockInfo> mUniformBlocks{}; ///< List of uniform blocks (First is for standalone uniforms)
+
+ // Vulkan data
+ std::vector<vk::DescriptorSetLayoutCreateInfo> mVkDescriptorSetLayoutCreateInfoList; ///< List of DSlayout create structures
+ std::vector<std::vector<vk::DescriptorSetLayoutBinding>> mVkDescriptorSetLayoutBindingList;
+};
+
+} // namespace Vulkan
+} // namespace Dali::Graphics
+
+#endif // DALI_GRAPHICS_VULKAN_REFLECTION_H
--- /dev/null
+#include "output_stream.h"
+
+#include <algorithm>
+#include <cassert>
+#include <iomanip>
+#include <sstream>
+#include <string>
+#include <unordered_set>
+#include <vector>
+
+enum TextLineType {
+ TEXT_LINE_TYPE_BLOCK_BEGIN = 0x01,
+ TEXT_LINE_TYPE_BLOCK_END = 0x02,
+ TEXT_LINE_TYPE_STRUCT_BEGIN = 0x04,
+ TEXT_LINE_TYPE_STRUCT_END = 0x08,
+ TEXT_LINE_TYPE_REF_BEGIN = 0x10,
+ TEXT_LINE_TYPE_REF_END = 0x20,
+ TEXT_LINE_TYPE_LINES = 0x40,
+};
+
+struct TextLine {
+ std::string indent;
+ std::string modifier;
+ std::string type_name;
+ std::string name;
+ uint32_t absolute_offset;
+ uint32_t relative_offset;
+ uint32_t size;
+ uint32_t padded_size;
+ uint32_t array_stride;
+ uint32_t block_variable_flags;
+ std::vector<uint32_t> array_dims;
+ // Text Data
+ uint32_t text_line_flags;
+ std::vector<TextLine> lines;
+ std::string formatted_line;
+ std::string formatted_absolute_offset;
+ std::string formatted_relative_offset;
+ std::string formatted_size;
+ std::string formatted_padded_size;
+ std::string formatted_array_stride;
+ std::string formatted_block_variable_flags;
+};
+
+static std::string AsHexString(uint32_t n) {
+ // std::iomanip can die in a fire.
+ char out_word[11];
+ int len = snprintf(out_word, 11, "0x%08X", n);
+ assert(len == 10);
+ (void)len;
+ return std::string(out_word);
+}
+
+std::string ToStringGenerator(SpvReflectGenerator generator) {
+ switch (generator) {
+ case SPV_REFLECT_GENERATOR_KHRONOS_LLVM_SPIRV_TRANSLATOR:
+ return "Khronos LLVM/SPIR-V Translator";
+ break;
+ case SPV_REFLECT_GENERATOR_KHRONOS_SPIRV_TOOLS_ASSEMBLER:
+ return "Khronos SPIR-V Tools Assembler";
+ break;
+ case SPV_REFLECT_GENERATOR_KHRONOS_GLSLANG_REFERENCE_FRONT_END:
+ return "Khronos Glslang Reference Front End";
+ break;
+ case SPV_REFLECT_GENERATOR_GOOGLE_SHADERC_OVER_GLSLANG:
+ return "Google Shaderc over Glslang";
+ break;
+ case SPV_REFLECT_GENERATOR_GOOGLE_SPIREGG:
+ return "Google spiregg";
+ break;
+ case SPV_REFLECT_GENERATOR_GOOGLE_RSPIRV:
+ return "Google rspirv";
+ break;
+ case SPV_REFLECT_GENERATOR_X_LEGEND_MESA_MESAIR_SPIRV_TRANSLATOR:
+ return "X-LEGEND Mesa-IR/SPIR-V Translator";
+ break;
+ case SPV_REFLECT_GENERATOR_KHRONOS_SPIRV_TOOLS_LINKER:
+ return "Khronos SPIR-V Tools Linker";
+ break;
+ case SPV_REFLECT_GENERATOR_WINE_VKD3D_SHADER_COMPILER:
+ return "Wine VKD3D Shader Compiler";
+ break;
+ case SPV_REFLECT_GENERATOR_CLAY_CLAY_SHADER_COMPILER:
+ return "Clay Clay Shader Compiler";
+ break;
+ }
+ // unhandled SpvReflectGenerator enum value
+ return "???";
+}
+
+std::string ToStringSpvSourceLanguage(SpvSourceLanguage lang) {
+ switch (lang) {
+ 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 SpvSourceLanguageCPP_for_OpenCL:
+ return "CPP_for_OpenCL";
+ case SpvSourceLanguageSYCL:
+ return "SYCL";
+ case SpvSourceLanguageHERO_C:
+ return "Hero C";
+ case SpvSourceLanguageNZSL:
+ return "NZSL";
+
+ default:
+ break;
+ }
+ // SpvSourceLanguageUnknown, SpvSourceLanguageMax, or another value that does
+ // not correspond to a known language.
+ return "Unknown";
+}
+
+std::string ToStringSpvExecutionModel(SpvExecutionModel model) {
+ switch (model) {
+ case SpvExecutionModelVertex:
+ return "Vertex";
+ case SpvExecutionModelTessellationControl:
+ return "TessellationControl";
+ case SpvExecutionModelTessellationEvaluation:
+ return "TessellationEvaluation";
+ case SpvExecutionModelGeometry:
+ return "Geometry";
+ case SpvExecutionModelFragment:
+ return "Fragment";
+ case SpvExecutionModelGLCompute:
+ return "GLCompute";
+ case SpvExecutionModelKernel:
+ return "Kernel";
+ case SpvExecutionModelTaskNV:
+ return "TaskNV";
+ case SpvExecutionModelMeshNV:
+ return "MeshNV";
+ case SpvExecutionModelTaskEXT:
+ return "TaskEXT";
+ case SpvExecutionModelMeshEXT:
+ return "MeshEXT";
+ case SpvExecutionModelRayGenerationKHR:
+ return "RayGenerationKHR";
+ case SpvExecutionModelIntersectionKHR:
+ return "IntersectionKHR";
+ case SpvExecutionModelAnyHitKHR:
+ return "AnyHitKHR";
+ case SpvExecutionModelClosestHitKHR:
+ return "ClosestHitKHR";
+ case SpvExecutionModelMissKHR:
+ return "MissKHR";
+ case SpvExecutionModelCallableKHR:
+ return "CallableKHR";
+
+ case SpvExecutionModelMax:
+ break;
+
+ default:
+ break;
+ }
+
+ // unhandled SpvExecutionModel enum value
+ return "???";
+}
+
+std::string ToStringShaderStage(SpvReflectShaderStageFlagBits stage) {
+ switch (stage) {
+ case SPV_REFLECT_SHADER_STAGE_VERTEX_BIT:
+ return "VS";
+ case SPV_REFLECT_SHADER_STAGE_TESSELLATION_CONTROL_BIT:
+ return "HS";
+ case SPV_REFLECT_SHADER_STAGE_TESSELLATION_EVALUATION_BIT:
+ return "DS";
+ case SPV_REFLECT_SHADER_STAGE_GEOMETRY_BIT:
+ return "GS";
+ case SPV_REFLECT_SHADER_STAGE_FRAGMENT_BIT:
+ return "PS";
+ case SPV_REFLECT_SHADER_STAGE_COMPUTE_BIT:
+ return "CS";
+ case SPV_REFLECT_SHADER_STAGE_TASK_BIT_NV:
+ return "TASK";
+ case SPV_REFLECT_SHADER_STAGE_MESH_BIT_NV:
+ return "MESH";
+ case SPV_REFLECT_SHADER_STAGE_RAYGEN_BIT_KHR:
+ return "RAYGEN";
+ case SPV_REFLECT_SHADER_STAGE_ANY_HIT_BIT_KHR:
+ return "ANY_HIT";
+ case SPV_REFLECT_SHADER_STAGE_CLOSEST_HIT_BIT_KHR:
+ return "CLOSEST_HIT";
+ case SPV_REFLECT_SHADER_STAGE_MISS_BIT_KHR:
+ return "MISS";
+ case SPV_REFLECT_SHADER_STAGE_INTERSECTION_BIT_KHR:
+ return "INTERSECTION";
+ case SPV_REFLECT_SHADER_STAGE_CALLABLE_BIT_KHR:
+ return "CALLABLE";
+
+ default:
+ break;
+ }
+
+ // Unhandled SpvReflectShaderStageFlagBits enum value
+ return "???";
+}
+
+std::string ToStringSpvStorageClass(SpvStorageClass storage_class) {
+ switch (storage_class) {
+ case SpvStorageClassUniformConstant:
+ return "UniformConstant";
+ case SpvStorageClassInput:
+ return "Input";
+ case SpvStorageClassUniform:
+ return "Uniform";
+ case SpvStorageClassOutput:
+ return "Output";
+ case SpvStorageClassWorkgroup:
+ return "Workgroup";
+ case SpvStorageClassCrossWorkgroup:
+ return "CrossWorkgroup";
+ case SpvStorageClassPrivate:
+ return "Private";
+ case SpvStorageClassFunction:
+ return "Function";
+ case SpvStorageClassGeneric:
+ return "Generic";
+ case SpvStorageClassPushConstant:
+ return "PushConstant";
+ case SpvStorageClassAtomicCounter:
+ return "AtomicCounter";
+ case SpvStorageClassImage:
+ return "Image";
+ case SpvStorageClassStorageBuffer:
+ return "StorageBuffer";
+ case SpvStorageClassCallableDataKHR:
+ return "CallableDataKHR";
+ case SpvStorageClassIncomingCallableDataKHR:
+ return "IncomingCallableDataKHR";
+ case SpvStorageClassRayPayloadKHR:
+ return "RayPayloadKHR";
+ case SpvStorageClassHitAttributeKHR:
+ return "HitAttributeKHR";
+ case SpvStorageClassIncomingRayPayloadKHR:
+ return "IncomingRayPayloadKHR";
+ case SpvStorageClassShaderRecordBufferKHR:
+ return "ShaderRecordBufferKHR";
+ case SpvStorageClassPhysicalStorageBuffer:
+ return "PhysicalStorageBuffer";
+ case SpvStorageClassCodeSectionINTEL:
+ return "CodeSectionINTEL";
+ case SpvStorageClassDeviceOnlyINTEL:
+ return "DeviceOnlyINTEL";
+ case SpvStorageClassHostOnlyINTEL:
+ return "HostOnlyINTEL";
+ case SpvStorageClassMax:
+ break;
+
+ default:
+ break;
+ }
+
+ // Special case: this specific "unhandled" value does actually seem to show
+ // up.
+ if (storage_class == (SpvStorageClass)-1) {
+ return "NOT APPLICABLE";
+ }
+
+ // unhandled SpvStorageClass enum value
+ return "???";
+}
+
+std::string ToStringSpvDim(SpvDim dim) {
+ switch (dim) {
+ case SpvDim1D:
+ return "1D";
+ case SpvDim2D:
+ return "2D";
+ case SpvDim3D:
+ return "3D";
+ case SpvDimCube:
+ return "Cube";
+ case SpvDimRect:
+ return "Rect";
+ case SpvDimBuffer:
+ return "Buffer";
+ case SpvDimSubpassData:
+ return "SubpassData";
+ case SpvDimTileImageDataEXT:
+ return "DimTileImageDataEXT";
+
+ case SpvDimMax:
+ break;
+ }
+ // unhandled SpvDim enum value
+ return "???";
+}
+
+std::string ToStringResourceType(SpvReflectResourceType res_type) {
+ switch (res_type) {
+ case SPV_REFLECT_RESOURCE_FLAG_UNDEFINED:
+ return "UNDEFINED";
+ case SPV_REFLECT_RESOURCE_FLAG_SAMPLER:
+ return "SAMPLER";
+ case SPV_REFLECT_RESOURCE_FLAG_CBV:
+ return "CBV";
+ case SPV_REFLECT_RESOURCE_FLAG_SRV:
+ return "SRV";
+ case SPV_REFLECT_RESOURCE_FLAG_UAV:
+ return "UAV";
+ }
+ // unhandled SpvReflectResourceType enum value
+ return "???";
+}
+
+std::string ToStringDescriptorType(SpvReflectDescriptorType value) {
+ switch (value) {
+ case SPV_REFLECT_DESCRIPTOR_TYPE_SAMPLER:
+ return "VK_DESCRIPTOR_TYPE_SAMPLER";
+ case SPV_REFLECT_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
+ return "VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER";
+ case SPV_REFLECT_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
+ return "VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE";
+ case SPV_REFLECT_DESCRIPTOR_TYPE_STORAGE_IMAGE:
+ return "VK_DESCRIPTOR_TYPE_STORAGE_IMAGE";
+ case SPV_REFLECT_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
+ return "VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER";
+ case SPV_REFLECT_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
+ return "VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER";
+ case SPV_REFLECT_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
+ return "VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER";
+ case SPV_REFLECT_DESCRIPTOR_TYPE_STORAGE_BUFFER:
+ return "VK_DESCRIPTOR_TYPE_STORAGE_BUFFER";
+ case SPV_REFLECT_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
+ return "VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC";
+ case SPV_REFLECT_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC:
+ return "VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC";
+ case SPV_REFLECT_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
+ return "VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT";
+ case SPV_REFLECT_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR:
+ return "VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR";
+ }
+ // unhandled SpvReflectDescriptorType enum value
+ return "VK_DESCRIPTOR_TYPE_???";
+}
+
+static std::string ToStringSpvBuiltIn(SpvBuiltIn built_in) {
+ switch (built_in) {
+ case SpvBuiltInPosition:
+ return "Position";
+ case SpvBuiltInPointSize:
+ return "PointSize";
+ case SpvBuiltInClipDistance:
+ return "ClipDistance";
+ case SpvBuiltInCullDistance:
+ return "CullDistance";
+ case SpvBuiltInVertexId:
+ return "VertexId";
+ case SpvBuiltInInstanceId:
+ return "InstanceId";
+ case SpvBuiltInPrimitiveId:
+ return "PrimitiveId";
+ case SpvBuiltInInvocationId:
+ return "InvocationId";
+ case SpvBuiltInLayer:
+ return "Layer";
+ case SpvBuiltInViewportIndex:
+ return "ViewportIndex";
+ case SpvBuiltInTessLevelOuter:
+ return "TessLevelOuter";
+ case SpvBuiltInTessLevelInner:
+ return "TessLevelInner";
+ case SpvBuiltInTessCoord:
+ return "TessCoord";
+ case SpvBuiltInPatchVertices:
+ return "PatchVertices";
+ case SpvBuiltInFragCoord:
+ return "FragCoord";
+ case SpvBuiltInPointCoord:
+ return "PointCoord";
+ case SpvBuiltInFrontFacing:
+ return "FrontFacing";
+ case SpvBuiltInSampleId:
+ return "SampleId";
+ case SpvBuiltInSamplePosition:
+ return "SamplePosition";
+ case SpvBuiltInSampleMask:
+ return "SampleMask";
+ case SpvBuiltInFragDepth:
+ return "FragDepth";
+ case SpvBuiltInHelperInvocation:
+ return "HelperInvocation";
+ case SpvBuiltInNumWorkgroups:
+ return "NumWorkgroups";
+ case SpvBuiltInWorkgroupSize:
+ return "WorkgroupSize";
+ case SpvBuiltInWorkgroupId:
+ return "WorkgroupId";
+ case SpvBuiltInLocalInvocationId:
+ return "LocalInvocationId";
+ case SpvBuiltInGlobalInvocationId:
+ return "GlobalInvocationId";
+ case SpvBuiltInLocalInvocationIndex:
+ return "LocalInvocationIndex";
+ case SpvBuiltInWorkDim:
+ return "WorkDim";
+ case SpvBuiltInGlobalSize:
+ return "GlobalSize";
+ case SpvBuiltInEnqueuedWorkgroupSize:
+ return "EnqueuedWorkgroupSize";
+ case SpvBuiltInGlobalOffset:
+ return "GlobalOffset";
+ case SpvBuiltInGlobalLinearId:
+ return "GlobalLinearId";
+ case SpvBuiltInSubgroupSize:
+ return "SubgroupSize";
+ case SpvBuiltInSubgroupMaxSize:
+ return "SubgroupMaxSize";
+ case SpvBuiltInNumSubgroups:
+ return "NumSubgroups";
+ case SpvBuiltInNumEnqueuedSubgroups:
+ return "NumEnqueuedSubgroups";
+ case SpvBuiltInSubgroupId:
+ return "SubgroupId";
+ case SpvBuiltInSubgroupLocalInvocationId:
+ return "SubgroupLocalInvocationId";
+ case SpvBuiltInVertexIndex:
+ return "VertexIndex";
+ case SpvBuiltInInstanceIndex:
+ return "InstanceIndex";
+ case SpvBuiltInSubgroupEqMaskKHR:
+ return "SubgroupEqMaskKHR";
+ case SpvBuiltInSubgroupGeMaskKHR:
+ return "SubgroupGeMaskKHR";
+ case SpvBuiltInSubgroupGtMaskKHR:
+ return "SubgroupGtMaskKHR";
+ case SpvBuiltInSubgroupLeMaskKHR:
+ return "SubgroupLeMaskKHR";
+ case SpvBuiltInSubgroupLtMaskKHR:
+ return "SubgroupLtMaskKHR";
+ case SpvBuiltInBaseVertex:
+ return "BaseVertex";
+ case SpvBuiltInBaseInstance:
+ return "BaseInstance";
+ case SpvBuiltInDrawIndex:
+ return "DrawIndex";
+ case SpvBuiltInDeviceIndex:
+ return "DeviceIndex";
+ case SpvBuiltInViewIndex:
+ return "ViewIndex";
+ case SpvBuiltInBaryCoordNoPerspAMD:
+ return "BaryCoordNoPerspAMD";
+ case SpvBuiltInBaryCoordNoPerspCentroidAMD:
+ return "BaryCoordNoPerspCentroidAMD";
+ case SpvBuiltInBaryCoordNoPerspSampleAMD:
+ return "BaryCoordNoPerspSampleAMD";
+ case SpvBuiltInBaryCoordSmoothAMD:
+ return "BaryCoordSmoothAMD";
+ case SpvBuiltInBaryCoordSmoothCentroidAMD:
+ return "BaryCoordSmoothCentroidAMD";
+ case SpvBuiltInBaryCoordSmoothSampleAMD:
+ return "BaryCoordSmoothSampleAMD";
+ case SpvBuiltInBaryCoordPullModelAMD:
+ return "BaryCoordPullModelAMD";
+ case SpvBuiltInFragStencilRefEXT:
+ return "FragStencilRefEXT";
+ case SpvBuiltInViewportMaskNV:
+ return "ViewportMaskNV";
+ case SpvBuiltInSecondaryPositionNV:
+ return "SecondaryPositionNV";
+ case SpvBuiltInSecondaryViewportMaskNV:
+ return "SecondaryViewportMaskNV";
+ case SpvBuiltInPositionPerViewNV:
+ return "PositionPerViewNV";
+ case SpvBuiltInViewportMaskPerViewNV:
+ return "ViewportMaskPerViewNV";
+ case SpvBuiltInLaunchIdKHR:
+ return "InLaunchIdKHR";
+ case SpvBuiltInLaunchSizeKHR:
+ return "InLaunchSizeKHR";
+ case SpvBuiltInWorldRayOriginKHR:
+ return "InWorldRayOriginKHR";
+ case SpvBuiltInWorldRayDirectionKHR:
+ return "InWorldRayDirectionKHR";
+ case SpvBuiltInObjectRayOriginKHR:
+ return "InObjectRayOriginKHR";
+ case SpvBuiltInObjectRayDirectionKHR:
+ return "InObjectRayDirectionKHR";
+ case SpvBuiltInRayTminKHR:
+ return "InRayTminKHR";
+ case SpvBuiltInRayTmaxKHR:
+ return "InRayTmaxKHR";
+ case SpvBuiltInInstanceCustomIndexKHR:
+ return "InInstanceCustomIndexKHR";
+ case SpvBuiltInObjectToWorldKHR:
+ return "InObjectToWorldKHR";
+ case SpvBuiltInWorldToObjectKHR:
+ return "InWorldToObjectKHR";
+ case SpvBuiltInHitTNV:
+ return "InHitTNV";
+ case SpvBuiltInHitKindKHR:
+ return "InHitKindKHR";
+ case SpvBuiltInIncomingRayFlagsKHR:
+ return "InIncomingRayFlagsKHR";
+ case SpvBuiltInRayGeometryIndexKHR:
+ return "InRayGeometryIndexKHR";
+
+ case SpvBuiltInMax:
+ default:
+ break;
+ }
+ // unhandled SpvBuiltIn enum value
+ std::stringstream ss;
+ ss << "??? (" << built_in << ")";
+ return ss.str();
+}
+
+std::string ToStringSpvBuiltIn(const SpvReflectInterfaceVariable& variable, bool preface) {
+ std::stringstream ss;
+ if (variable.decoration_flags & SPV_REFLECT_DECORATION_BLOCK) {
+ if (preface) {
+ ss << "(built-in block) ";
+ }
+ ss << "[";
+ for (uint32_t i = 0; i < variable.member_count; i++) {
+ ss << ToStringSpvBuiltIn(variable.members[i].built_in);
+ if (i < (variable.member_count - 1)) {
+ ss << ", ";
+ }
+ }
+ ss << "]";
+ } else {
+ if (preface) {
+ ss << "(built-in) ";
+ }
+ ss << ToStringSpvBuiltIn(variable.built_in);
+ }
+ return ss.str();
+}
+
+std::string ToStringSpvImageFormat(SpvImageFormat fmt) {
+ switch (fmt) {
+ case SpvImageFormatUnknown:
+ return "Unknown";
+ case SpvImageFormatRgba32f:
+ return "Rgba32f";
+ case SpvImageFormatRgba16f:
+ return "Rgba16f";
+ case SpvImageFormatR32f:
+ return "R32f";
+ case SpvImageFormatRgba8:
+ return "Rgba8";
+ case SpvImageFormatRgba8Snorm:
+ return "Rgba8Snorm";
+ case SpvImageFormatRg32f:
+ return "Rg32f";
+ case SpvImageFormatRg16f:
+ return "Rg16f";
+ case SpvImageFormatR11fG11fB10f:
+ return "R11fG11fB10f";
+ case SpvImageFormatR16f:
+ return "R16f";
+ case SpvImageFormatRgba16:
+ return "Rgba16";
+ case SpvImageFormatRgb10A2:
+ return "Rgb10A2";
+ case SpvImageFormatRg16:
+ return "Rg16";
+ case SpvImageFormatRg8:
+ return "Rg8";
+ case SpvImageFormatR16:
+ return "R16";
+ case SpvImageFormatR8:
+ return "R8";
+ case SpvImageFormatRgba16Snorm:
+ return "Rgba16Snorm";
+ case SpvImageFormatRg16Snorm:
+ return "Rg16Snorm";
+ case SpvImageFormatRg8Snorm:
+ return "Rg8Snorm";
+ case SpvImageFormatR16Snorm:
+ return "R16Snorm";
+ case SpvImageFormatR8Snorm:
+ return "R8Snorm";
+ case SpvImageFormatRgba32i:
+ return "Rgba32i";
+ case SpvImageFormatRgba16i:
+ return "Rgba16i";
+ case SpvImageFormatRgba8i:
+ return "Rgba8i";
+ case SpvImageFormatR32i:
+ return "R32i";
+ case SpvImageFormatRg32i:
+ return "Rg32i";
+ case SpvImageFormatRg16i:
+ return "Rg16i";
+ case SpvImageFormatRg8i:
+ return "Rg8i";
+ case SpvImageFormatR16i:
+ return "R16i";
+ case SpvImageFormatR8i:
+ return "R8i";
+ case SpvImageFormatRgba32ui:
+ return "Rgba32ui";
+ case SpvImageFormatRgba16ui:
+ return "Rgba16ui";
+ case SpvImageFormatRgba8ui:
+ return "Rgba8ui";
+ case SpvImageFormatR32ui:
+ return "R32ui";
+ case SpvImageFormatRgb10a2ui:
+ return "Rgb10a2ui";
+ case SpvImageFormatRg32ui:
+ return "Rg32ui";
+ case SpvImageFormatRg16ui:
+ return "Rg16ui";
+ case SpvImageFormatRg8ui:
+ return "Rg8ui";
+ case SpvImageFormatR16ui:
+ return "R16ui";
+ case SpvImageFormatR8ui:
+ return "R8ui";
+ case SpvImageFormatR64ui:
+ return "R64ui";
+ case SpvImageFormatR64i:
+ return "R64i";
+
+ case SpvImageFormatMax:
+ break;
+ }
+ // unhandled SpvImageFormat enum value
+ return "???";
+}
+
+std::string ToStringUserType(SpvReflectUserType user_type) {
+ switch (user_type) {
+ case SPV_REFLECT_USER_TYPE_CBUFFER:
+ return "cbuffer";
+ case SPV_REFLECT_USER_TYPE_TBUFFER:
+ return "tbuffer";
+ case SPV_REFLECT_USER_TYPE_APPEND_STRUCTURED_BUFFER:
+ return "AppendStructuredBuffer";
+ case SPV_REFLECT_USER_TYPE_BUFFER:
+ return "Buffer";
+ case SPV_REFLECT_USER_TYPE_BYTE_ADDRESS_BUFFER:
+ return "ByteAddressBuffer";
+ case SPV_REFLECT_USER_TYPE_CONSTANT_BUFFER:
+ return "ConstantBuffer";
+ case SPV_REFLECT_USER_TYPE_CONSUME_STRUCTURED_BUFFER:
+ return "ConsumeStructuredBuffer";
+ case SPV_REFLECT_USER_TYPE_INPUT_PATCH:
+ return "InputPatch";
+ case SPV_REFLECT_USER_TYPE_OUTPUT_PATCH:
+ return "OutputPatch";
+ case SPV_REFLECT_USER_TYPE_RASTERIZER_ORDERED_BUFFER:
+ return "RasterizerOrderedBuffer";
+ case SPV_REFLECT_USER_TYPE_RASTERIZER_ORDERED_BYTE_ADDRESS_BUFFER:
+ return "RasterizerOrderedByteAddressBuffer";
+ case SPV_REFLECT_USER_TYPE_RASTERIZER_ORDERED_STRUCTURED_BUFFER:
+ return "RasterizerOrderedStructuredBuffer";
+ case SPV_REFLECT_USER_TYPE_RASTERIZER_ORDERED_TEXTURE_1D:
+ return "RasterizerOrderedTexture1D";
+ case SPV_REFLECT_USER_TYPE_RASTERIZER_ORDERED_TEXTURE_1D_ARRAY:
+ return "RasterizerOrderedTexture1DArray";
+ case SPV_REFLECT_USER_TYPE_RASTERIZER_ORDERED_TEXTURE_2D:
+ return "RasterizerOrderedTexture2D";
+ case SPV_REFLECT_USER_TYPE_RASTERIZER_ORDERED_TEXTURE_2D_ARRAY:
+ return "RasterizerOrderedTexture2DArray";
+ case SPV_REFLECT_USER_TYPE_RASTERIZER_ORDERED_TEXTURE_3D:
+ return "RasterizerOrderedTexture3D";
+ case SPV_REFLECT_USER_TYPE_RAYTRACING_ACCELERATION_STRUCTURE:
+ return "RaytracingAccelerationStructure";
+ case SPV_REFLECT_USER_TYPE_RW_BUFFER:
+ return "RWBuffer";
+ case SPV_REFLECT_USER_TYPE_RW_BYTE_ADDRESS_BUFFER:
+ return "RWByteAddressBuffer";
+ case SPV_REFLECT_USER_TYPE_RW_STRUCTURED_BUFFER:
+ return "RWStructuredBuffer";
+ case SPV_REFLECT_USER_TYPE_RW_TEXTURE_1D:
+ return "RWTexture1D";
+ case SPV_REFLECT_USER_TYPE_RW_TEXTURE_1D_ARRAY:
+ return "RWTexture1DArray";
+ case SPV_REFLECT_USER_TYPE_RW_TEXTURE_2D:
+ return "RWTexture2D";
+ case SPV_REFLECT_USER_TYPE_RW_TEXTURE_2D_ARRAY:
+ return "RWTexture2DArray";
+ case SPV_REFLECT_USER_TYPE_RW_TEXTURE_3D:
+ return "RWTexture3D";
+ case SPV_REFLECT_USER_TYPE_STRUCTURED_BUFFER:
+ return "StructuredBuffer";
+ case SPV_REFLECT_USER_TYPE_SUBPASS_INPUT:
+ return "SubpassInput";
+ case SPV_REFLECT_USER_TYPE_SUBPASS_INPUT_MS:
+ return "SubpassInputMS";
+ case SPV_REFLECT_USER_TYPE_TEXTURE_1D:
+ return "Texture1D";
+ case SPV_REFLECT_USER_TYPE_TEXTURE_1D_ARRAY:
+ return "Texture1DArray";
+ case SPV_REFLECT_USER_TYPE_TEXTURE_2D:
+ return "Texture2D";
+ case SPV_REFLECT_USER_TYPE_TEXTURE_2D_ARRAY:
+ return "Texture2DArray";
+ case SPV_REFLECT_USER_TYPE_TEXTURE_2DMS:
+ return "Texture2DMS";
+ case SPV_REFLECT_USER_TYPE_TEXTURE_2DMS_ARRAY:
+ return "Texture2DMSArray";
+ case SPV_REFLECT_USER_TYPE_TEXTURE_3D:
+ return "Texture3D";
+ case SPV_REFLECT_USER_TYPE_TEXTURE_BUFFER:
+ return "TextureBuffer";
+ case SPV_REFLECT_USER_TYPE_TEXTURE_CUBE:
+ return "TextureCube";
+ case SPV_REFLECT_USER_TYPE_TEXTURE_CUBE_ARRAY:
+ return "TextureCubeArray";
+ default:
+ return "???";
+ }
+}
+
+std::string ToStringTypeFlags(SpvReflectTypeFlags type_flags) {
+ if (type_flags == SPV_REFLECT_TYPE_FLAG_UNDEFINED) {
+ return "UNDEFINED";
+ }
+
+#define PRINT_AND_CLEAR_TYPE_FLAG(stream, flags, bit) \
+ if (((flags) & (SPV_REFLECT_TYPE_FLAG_##bit)) == (SPV_REFLECT_TYPE_FLAG_##bit)) { \
+ stream << #bit << " "; \
+ flags ^= SPV_REFLECT_TYPE_FLAG_##bit; \
+ }
+ std::stringstream sstream;
+ PRINT_AND_CLEAR_TYPE_FLAG(sstream, type_flags, ARRAY);
+ PRINT_AND_CLEAR_TYPE_FLAG(sstream, type_flags, STRUCT);
+ PRINT_AND_CLEAR_TYPE_FLAG(sstream, type_flags, REF);
+ PRINT_AND_CLEAR_TYPE_FLAG(sstream, type_flags, EXTERNAL_MASK);
+ PRINT_AND_CLEAR_TYPE_FLAG(sstream, type_flags, EXTERNAL_BLOCK);
+ PRINT_AND_CLEAR_TYPE_FLAG(sstream, type_flags, EXTERNAL_SAMPLED_IMAGE);
+ PRINT_AND_CLEAR_TYPE_FLAG(sstream, type_flags, EXTERNAL_SAMPLER);
+ PRINT_AND_CLEAR_TYPE_FLAG(sstream, type_flags, EXTERNAL_IMAGE);
+ PRINT_AND_CLEAR_TYPE_FLAG(sstream, type_flags, MATRIX);
+ PRINT_AND_CLEAR_TYPE_FLAG(sstream, type_flags, VECTOR);
+ PRINT_AND_CLEAR_TYPE_FLAG(sstream, type_flags, FLOAT);
+ PRINT_AND_CLEAR_TYPE_FLAG(sstream, type_flags, INT);
+ PRINT_AND_CLEAR_TYPE_FLAG(sstream, type_flags, BOOL);
+ PRINT_AND_CLEAR_TYPE_FLAG(sstream, type_flags, VOID);
+#undef PRINT_AND_CLEAR_TYPE_FLAG
+ if (type_flags != 0) {
+ // Unhandled SpvReflectTypeFlags bit
+ sstream << "???";
+ }
+ return sstream.str();
+}
+
+std::string ToStringDecorationFlags(SpvReflectDecorationFlags decoration_flags) {
+ if (decoration_flags == SPV_REFLECT_DECORATION_NONE) {
+ return "NONE";
+ }
+
+#define PRINT_AND_CLEAR_DECORATION_FLAG(stream, flags, bit) \
+ if (((flags) & (SPV_REFLECT_DECORATION_##bit)) == (SPV_REFLECT_DECORATION_##bit)) { \
+ stream << #bit << " "; \
+ flags ^= SPV_REFLECT_DECORATION_##bit; \
+ }
+ std::stringstream sstream;
+ PRINT_AND_CLEAR_DECORATION_FLAG(sstream, decoration_flags, NON_WRITABLE);
+ PRINT_AND_CLEAR_DECORATION_FLAG(sstream, decoration_flags, NON_READABLE);
+ PRINT_AND_CLEAR_DECORATION_FLAG(sstream, decoration_flags, FLAT);
+ PRINT_AND_CLEAR_DECORATION_FLAG(sstream, decoration_flags, NOPERSPECTIVE);
+ PRINT_AND_CLEAR_DECORATION_FLAG(sstream, decoration_flags, BUILT_IN);
+ PRINT_AND_CLEAR_DECORATION_FLAG(sstream, decoration_flags, COLUMN_MAJOR);
+ PRINT_AND_CLEAR_DECORATION_FLAG(sstream, decoration_flags, ROW_MAJOR);
+ PRINT_AND_CLEAR_DECORATION_FLAG(sstream, decoration_flags, BUFFER_BLOCK);
+ PRINT_AND_CLEAR_DECORATION_FLAG(sstream, decoration_flags, BLOCK);
+ PRINT_AND_CLEAR_DECORATION_FLAG(sstream, decoration_flags, PATCH);
+ PRINT_AND_CLEAR_DECORATION_FLAG(sstream, decoration_flags, PER_VERTEX);
+ PRINT_AND_CLEAR_DECORATION_FLAG(sstream, decoration_flags, PER_TASK);
+#undef PRINT_AND_CLEAR_DECORATION_FLAG
+ if (decoration_flags != 0) {
+ // Unhandled SpvReflectDecorationFlags bit
+ sstream << "???";
+ }
+ return sstream.str();
+}
+
+std::string ToStringFormat(SpvReflectFormat fmt) {
+ switch (fmt) {
+ case SPV_REFLECT_FORMAT_UNDEFINED:
+ return "VK_FORMAT_UNDEFINED";
+ case SPV_REFLECT_FORMAT_R16_UINT:
+ return "VK_FORMAT_R16_UINT";
+ case SPV_REFLECT_FORMAT_R16_SINT:
+ return "VK_FORMAT_R16_SINT";
+ case SPV_REFLECT_FORMAT_R16_SFLOAT:
+ return "VK_FORMAT_R16_SFLOAT";
+ case SPV_REFLECT_FORMAT_R16G16_UINT:
+ return "VK_FORMAT_R16G16_UINT";
+ case SPV_REFLECT_FORMAT_R16G16_SINT:
+ return "VK_FORMAT_R16G16_SINT";
+ case SPV_REFLECT_FORMAT_R16G16_SFLOAT:
+ return "VK_FORMAT_R16G16_SFLOAT";
+ case SPV_REFLECT_FORMAT_R16G16B16_UINT:
+ return "VK_FORMAT_R16G16B16_UINT";
+ case SPV_REFLECT_FORMAT_R16G16B16_SINT:
+ return "VK_FORMAT_R16G16B16_SINT";
+ case SPV_REFLECT_FORMAT_R16G16B16_SFLOAT:
+ return "VK_FORMAT_R16G16B16_SFLOAT";
+ case SPV_REFLECT_FORMAT_R16G16B16A16_UINT:
+ return "VK_FORMAT_R16G16B16A16_UINT";
+ case SPV_REFLECT_FORMAT_R16G16B16A16_SINT:
+ return "VK_FORMAT_R16G16B16A16_SINT";
+ case SPV_REFLECT_FORMAT_R16G16B16A16_SFLOAT:
+ return "VK_FORMAT_R16G16B16A16_SFLOAT";
+ case SPV_REFLECT_FORMAT_R32_UINT:
+ return "VK_FORMAT_R32_UINT";
+ case SPV_REFLECT_FORMAT_R32_SINT:
+ return "VK_FORMAT_R32_SINT";
+ case SPV_REFLECT_FORMAT_R32_SFLOAT:
+ return "VK_FORMAT_R32_SFLOAT";
+ case SPV_REFLECT_FORMAT_R32G32_UINT:
+ return "VK_FORMAT_R32G32_UINT";
+ case SPV_REFLECT_FORMAT_R32G32_SINT:
+ return "VK_FORMAT_R32G32_SINT";
+ case SPV_REFLECT_FORMAT_R32G32_SFLOAT:
+ return "VK_FORMAT_R32G32_SFLOAT";
+ case SPV_REFLECT_FORMAT_R32G32B32_UINT:
+ return "VK_FORMAT_R32G32B32_UINT";
+ case SPV_REFLECT_FORMAT_R32G32B32_SINT:
+ return "VK_FORMAT_R32G32B32_SINT";
+ case SPV_REFLECT_FORMAT_R32G32B32_SFLOAT:
+ return "VK_FORMAT_R32G32B32_SFLOAT";
+ case SPV_REFLECT_FORMAT_R32G32B32A32_UINT:
+ return "VK_FORMAT_R32G32B32A32_UINT";
+ case SPV_REFLECT_FORMAT_R32G32B32A32_SINT:
+ return "VK_FORMAT_R32G32B32A32_SINT";
+ case SPV_REFLECT_FORMAT_R32G32B32A32_SFLOAT:
+ return "VK_FORMAT_R32G32B32A32_SFLOAT";
+ case SPV_REFLECT_FORMAT_R64_UINT:
+ return "VK_FORMAT_R64_UINT";
+ case SPV_REFLECT_FORMAT_R64_SINT:
+ return "VK_FORMAT_R64_SINT";
+ case SPV_REFLECT_FORMAT_R64_SFLOAT:
+ return "VK_FORMAT_R64_SFLOAT";
+ case SPV_REFLECT_FORMAT_R64G64_UINT:
+ return "VK_FORMAT_R64G64_UINT";
+ case SPV_REFLECT_FORMAT_R64G64_SINT:
+ return "VK_FORMAT_R64G64_SINT";
+ case SPV_REFLECT_FORMAT_R64G64_SFLOAT:
+ return "VK_FORMAT_R64G64_SFLOAT";
+ case SPV_REFLECT_FORMAT_R64G64B64_UINT:
+ return "VK_FORMAT_R64G64B64_UINT";
+ case SPV_REFLECT_FORMAT_R64G64B64_SINT:
+ return "VK_FORMAT_R64G64B64_SINT";
+ case SPV_REFLECT_FORMAT_R64G64B64_SFLOAT:
+ return "VK_FORMAT_R64G64B64_SFLOAT";
+ case SPV_REFLECT_FORMAT_R64G64B64A64_UINT:
+ return "VK_FORMAT_R64G64B64A64_UINT";
+ case SPV_REFLECT_FORMAT_R64G64B64A64_SINT:
+ return "VK_FORMAT_R64G64B64A64_SINT";
+ case SPV_REFLECT_FORMAT_R64G64B64A64_SFLOAT:
+ return "VK_FORMAT_R64G64B64A64_SFLOAT";
+ }
+ // unhandled SpvReflectFormat enum value
+ return "VK_FORMAT_???";
+}
+
+static std::string ToStringScalarType(const SpvReflectTypeDescription& type) {
+ switch (type.op) {
+ case SpvOpTypeVoid: {
+ return "void";
+ break;
+ }
+ case SpvOpTypeBool: {
+ return "bool";
+ break;
+ }
+ case SpvOpTypeInt: {
+ if (type.traits.numeric.scalar.signedness)
+ return "int";
+ else
+ return "uint";
+ }
+ case SpvOpTypeFloat: {
+ switch (type.traits.numeric.scalar.width) {
+ case 32:
+ return "float";
+ case 64:
+ return "double";
+ default:
+ break;
+ }
+ break;
+ }
+ case SpvOpTypeStruct: {
+ return "struct";
+ }
+ case SpvOpTypePointer: {
+ return "ptr";
+ }
+ default: {
+ break;
+ }
+ }
+ return "";
+}
+
+static std::string ToStringGlslType(const SpvReflectTypeDescription& type) {
+ switch (type.op) {
+ case SpvOpTypeVector: {
+ switch (type.traits.numeric.scalar.width) {
+ case 32: {
+ switch (type.traits.numeric.vector.component_count) {
+ case 2:
+ return "vec2";
+ case 3:
+ return "vec3";
+ case 4:
+ return "vec4";
+ }
+ } break;
+
+ case 64: {
+ switch (type.traits.numeric.vector.component_count) {
+ case 2:
+ return "dvec2";
+ case 3:
+ return "dvec3";
+ case 4:
+ return "dvec4";
+ }
+ } break;
+ }
+ } break;
+ default:
+ break;
+ }
+ return ToStringScalarType(type);
+}
+
+static std::string ToStringHlslType(const SpvReflectTypeDescription& type) {
+ switch (type.op) {
+ case SpvOpTypeVector: {
+ switch (type.traits.numeric.scalar.width) {
+ case 32: {
+ switch (type.traits.numeric.vector.component_count) {
+ case 2:
+ return "float2";
+ case 3:
+ return "float3";
+ case 4:
+ return "float4";
+ }
+ } break;
+
+ case 64: {
+ switch (type.traits.numeric.vector.component_count) {
+ case 2:
+ return "double2";
+ case 3:
+ return "double3";
+ case 4:
+ return "double4";
+ }
+ } break;
+ }
+ } break;
+
+ default:
+ break;
+ }
+ return ToStringScalarType(type);
+}
+
+std::string ToStringType(SpvSourceLanguage src_lang, const SpvReflectTypeDescription& type) {
+ if (src_lang == SpvSourceLanguageHLSL) {
+ return ToStringHlslType(type);
+ }
+
+ return ToStringGlslType(type);
+}
+
+std::string ToStringComponentType(const SpvReflectTypeDescription& type, uint32_t member_decoration_flags) {
+ uint32_t masked_type = type.type_flags & 0xF;
+ if (masked_type == 0) {
+ return "";
+ }
+
+ std::stringstream ss;
+
+ if (type.type_flags & SPV_REFLECT_TYPE_FLAG_MATRIX) {
+ if (member_decoration_flags & SPV_REFLECT_DECORATION_COLUMN_MAJOR) {
+ ss << "column_major"
+ << " ";
+ } else if (member_decoration_flags & SPV_REFLECT_DECORATION_ROW_MAJOR) {
+ ss << "row_major"
+ << " ";
+ }
+ }
+
+ switch (masked_type) {
+ default:
+ assert(false && "unsupported component type");
+ break;
+ case SPV_REFLECT_TYPE_FLAG_BOOL:
+ ss << "bool";
+ break;
+ case SPV_REFLECT_TYPE_FLAG_INT:
+ ss << (type.traits.numeric.scalar.signedness ? "int" : "uint");
+ break;
+ case SPV_REFLECT_TYPE_FLAG_FLOAT:
+ ss << "float";
+ break;
+ }
+
+ if (type.type_flags & SPV_REFLECT_TYPE_FLAG_MATRIX) {
+ ss << type.traits.numeric.matrix.row_count;
+ ss << "x";
+ ss << type.traits.numeric.matrix.column_count;
+ } else if (type.type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) {
+ ss << type.traits.numeric.vector.component_count;
+ }
+
+ return ss.str();
+}
+
+void ParseBlockMembersToTextLines(const char* indent, int indent_depth, bool flatten_cbuffers, const std::string& parent_name,
+ uint32_t member_count, const SpvReflectBlockVariable* p_members,
+ std::vector<TextLine>* p_text_lines, std::unordered_set<uint32_t>& physical_pointer_spirv_id) {
+ const char* t = indent;
+ for (uint32_t member_index = 0; member_index < member_count; ++member_index) {
+ indent_depth = flatten_cbuffers ? 2 : indent_depth;
+ std::stringstream ss_indent;
+ for (int indent_count = 0; indent_count < indent_depth; ++indent_count) {
+ ss_indent << t;
+ }
+ std::string expanded_indent = ss_indent.str();
+
+ const auto& member = p_members[member_index];
+ if (!member.type_description) {
+ // TODO 212 - If a buffer ref has an array of itself, all members are null
+ continue;
+ }
+
+ bool is_struct = ((member.type_description->type_flags & static_cast<SpvReflectTypeFlags>(SPV_REFLECT_TYPE_FLAG_STRUCT)) != 0);
+ bool is_ref = ((member.type_description->type_flags & static_cast<SpvReflectTypeFlags>(SPV_REFLECT_TYPE_FLAG_REF)) != 0);
+ bool is_array = ((member.type_description->type_flags & static_cast<SpvReflectTypeFlags>(SPV_REFLECT_TYPE_FLAG_ARRAY)) != 0);
+ if (is_struct) {
+ const std::string name = (member.name == nullptr ? "" : member.name);
+
+ // Begin struct
+ TextLine tl = {};
+ tl.indent = expanded_indent;
+ tl.type_name = (member.type_description->type_name == nullptr ? "" : member.type_description->type_name);
+ tl.absolute_offset = member.absolute_offset;
+ tl.relative_offset = member.offset;
+ tl.size = member.size;
+ tl.padded_size = member.padded_size;
+ tl.array_stride = member.array.stride;
+ tl.block_variable_flags = member.flags;
+ tl.text_line_flags = is_ref ? TEXT_LINE_TYPE_REF_BEGIN : TEXT_LINE_TYPE_STRUCT_BEGIN;
+ if (!flatten_cbuffers) {
+ p_text_lines->push_back(tl);
+ }
+
+ const bool array_of_structs = is_array && member.type_description->struct_type_description;
+ const uint32_t struct_id =
+ array_of_structs ? member.type_description->struct_type_description->id : member.type_description->id;
+
+ if (physical_pointer_spirv_id.count(struct_id) == 0) {
+ physical_pointer_spirv_id.insert(member.type_description->id);
+ if (array_of_structs) {
+ physical_pointer_spirv_id.insert(member.type_description->struct_type_description->id);
+ }
+
+ // Members
+ tl = {};
+ std::string current_parent_name;
+ if (flatten_cbuffers) {
+ current_parent_name = parent_name.empty() ? name : (parent_name + "." + name);
+ }
+ std::vector<TextLine>* p_target_text_line = flatten_cbuffers ? p_text_lines : &tl.lines;
+ ParseBlockMembersToTextLines(t, indent_depth + 1, flatten_cbuffers, current_parent_name, member.member_count,
+ member.members, p_target_text_line, physical_pointer_spirv_id);
+ tl.text_line_flags = TEXT_LINE_TYPE_LINES;
+ p_text_lines->push_back(tl);
+ }
+ physical_pointer_spirv_id.erase(member.type_description->id);
+
+ // End struct
+ tl = {};
+ tl.indent = expanded_indent;
+ tl.name = name;
+ if ((member.array.dims_count > 0) || (member.type_description->traits.array.dims[0] > 0)) {
+ const SpvReflectArrayTraits* p_array_info = (member.array.dims_count > 0) ? &member.array : nullptr;
+ if (p_array_info == nullptr) {
+ //
+ // glslang based compilers stores array information in the type and
+ // not the variable
+ //
+ p_array_info = (member.type_description->traits.array.dims[0] > 0) ? &member.type_description->traits.array : nullptr;
+ }
+ if (p_array_info != nullptr) {
+ std::stringstream ss_array;
+ for (uint32_t array_dim_index = 0; array_dim_index < p_array_info->dims_count; ++array_dim_index) {
+ uint32_t dim = p_array_info->dims[array_dim_index];
+ //
+ // dim = 0 means it's an unbounded array
+ //
+ if (dim > 0) {
+ ss_array << "[" << dim << "]";
+ } else {
+ ss_array << "[]";
+ }
+ }
+ tl.name += ss_array.str();
+ }
+ }
+ tl.absolute_offset = member.absolute_offset;
+ tl.relative_offset = member.offset;
+ tl.size = member.size;
+ tl.padded_size = member.padded_size;
+ tl.array_stride = member.array.stride;
+ tl.block_variable_flags = member.flags;
+ tl.text_line_flags = is_ref ? TEXT_LINE_TYPE_REF_END : TEXT_LINE_TYPE_STRUCT_END;
+ if (!flatten_cbuffers) {
+ p_text_lines->push_back(tl);
+ }
+ } else {
+ std::string name = (member.name == nullptr ? "" : member.name);
+ if (flatten_cbuffers) {
+ if (!parent_name.empty()) {
+ name = parent_name + "." + name;
+ }
+ }
+
+ TextLine tl = {};
+ tl.indent = expanded_indent;
+ tl.type_name = ToStringComponentType(*member.type_description, member.decoration_flags);
+ tl.name = name;
+ if (member.array.dims_count > 0) {
+ std::stringstream ss_array;
+ for (uint32_t array_dim_index = 0; array_dim_index < member.array.dims_count; ++array_dim_index) {
+ uint32_t dim = member.array.dims[array_dim_index];
+ ss_array << "[" << dim << "]";
+ }
+ tl.name += ss_array.str();
+ }
+ tl.absolute_offset = member.absolute_offset;
+ tl.relative_offset = member.offset;
+ tl.size = member.size;
+ tl.padded_size = member.padded_size;
+ tl.array_stride = member.array.stride;
+ tl.block_variable_flags = member.flags;
+ p_text_lines->push_back(tl);
+ }
+ }
+}
+
+void ParseBlockVariableToTextLines(const char* indent, bool flatten_cbuffers, const SpvReflectBlockVariable& block_var,
+ std::vector<TextLine>* p_text_lines) {
+ // Begin block
+ TextLine tl = {};
+ tl.indent = indent;
+ tl.type_name = (block_var.type_description->type_name != nullptr) ? block_var.type_description->type_name : "<unnamed>";
+ tl.size = block_var.size;
+ tl.padded_size = block_var.padded_size;
+ tl.text_line_flags = TEXT_LINE_TYPE_BLOCK_BEGIN;
+ p_text_lines->push_back(tl);
+
+ // Members
+ tl = {};
+ std::unordered_set<uint32_t> physical_pointer_spirv_id;
+ ParseBlockMembersToTextLines(indent, 2, flatten_cbuffers, "", block_var.member_count, block_var.members, &tl.lines,
+ physical_pointer_spirv_id);
+ tl.text_line_flags = TEXT_LINE_TYPE_LINES;
+ p_text_lines->push_back(tl);
+
+ // End block
+ tl = {};
+ tl.indent = indent;
+ tl.name = (block_var.name != nullptr) ? block_var.name : "<unnamed>";
+ tl.absolute_offset = 0;
+ tl.relative_offset = 0;
+ tl.size = block_var.size;
+ tl.padded_size = block_var.padded_size;
+ tl.text_line_flags = TEXT_LINE_TYPE_BLOCK_END;
+ p_text_lines->push_back(tl);
+}
+
+void FormatTextLines(const std::vector<TextLine>& text_lines, const char* indent, std::vector<TextLine>* p_formatted_lines) {
+ size_t modifier_width = 0;
+ size_t type_name_width = 0;
+ size_t name_width = 0;
+
+ // Widths
+ for (auto& tl : text_lines) {
+ if (tl.text_line_flags != 0) {
+ continue;
+ }
+ modifier_width = std::max<size_t>(modifier_width, tl.modifier.length());
+ type_name_width = std::max<size_t>(type_name_width, tl.type_name.length());
+ name_width = std::max<size_t>(name_width, tl.name.length());
+ }
+
+ // Output
+ size_t n = text_lines.size();
+ for (size_t i = 0; i < n; ++i) {
+ auto& tl = text_lines[i];
+
+ std::stringstream ss;
+ if ((tl.text_line_flags == TEXT_LINE_TYPE_BLOCK_BEGIN) || (tl.text_line_flags == TEXT_LINE_TYPE_STRUCT_BEGIN) ||
+ (tl.text_line_flags == TEXT_LINE_TYPE_REF_BEGIN)) {
+ ss << indent;
+ ss << tl.indent;
+ if (tl.text_line_flags == TEXT_LINE_TYPE_REF_BEGIN) ss << "ref ";
+ ss << "struct ";
+ ss << tl.type_name;
+ ss << " {";
+ } else if ((tl.text_line_flags == TEXT_LINE_TYPE_BLOCK_END) || (tl.text_line_flags == TEXT_LINE_TYPE_STRUCT_END) ||
+ (tl.text_line_flags == TEXT_LINE_TYPE_REF_END)) {
+ ss << indent;
+ ss << tl.indent;
+ ss << "} ";
+ ss << tl.name;
+ ss << ";";
+ } else if (tl.text_line_flags == TEXT_LINE_TYPE_LINES) {
+ FormatTextLines(tl.lines, indent, p_formatted_lines);
+ } else {
+ ss << indent;
+ ss << tl.indent;
+ if (modifier_width > 0) {
+ ss << std::setw(modifier_width) << std::left << tl.modifier;
+ ss << " ";
+ }
+ ss << std::setw(type_name_width) << std::left << tl.type_name;
+ ss << " ";
+ ss << std::setw(name_width) << (tl.name + ";");
+ }
+
+ // Reuse the various strings to store the formatted texts
+ TextLine out_tl = {};
+ out_tl.formatted_line = ss.str();
+ if (out_tl.formatted_line.length() > 0) {
+ out_tl.array_stride = tl.array_stride;
+ out_tl.text_line_flags = tl.text_line_flags;
+ out_tl.formatted_absolute_offset = std::to_string(tl.absolute_offset);
+ out_tl.formatted_relative_offset = std::to_string(tl.relative_offset);
+ out_tl.formatted_size = std::to_string(tl.size);
+ out_tl.formatted_padded_size = std::to_string(tl.padded_size);
+ out_tl.formatted_array_stride = std::to_string(tl.array_stride);
+ // Block variable flags
+ if (tl.block_variable_flags != 0) {
+ std::stringstream ss_flags;
+ if (tl.block_variable_flags & SPV_REFLECT_VARIABLE_FLAGS_UNUSED) {
+ ss_flags << "UNUSED";
+ }
+ out_tl.formatted_block_variable_flags = ss_flags.str();
+ }
+ p_formatted_lines->push_back(out_tl);
+ }
+ }
+}
+
+void StreamWriteTextLines(std::ostream& os, const char* indent, bool flatten_cbuffers, const std::vector<TextLine>& text_lines) {
+ std::vector<TextLine> formatted_lines;
+ FormatTextLines(text_lines, indent, &formatted_lines);
+
+ size_t line_width = 0;
+ size_t offset_width = 0;
+ size_t absolute_offset_width = 0;
+ size_t size_width = 0;
+ size_t padded_size_width = 0;
+ size_t array_stride_width = 0;
+
+ // Width
+ for (auto& tl : formatted_lines) {
+ if (tl.text_line_flags != 0) {
+ continue;
+ }
+ line_width = std::max<size_t>(line_width, tl.formatted_line.length());
+ absolute_offset_width = std::max<size_t>(absolute_offset_width, tl.formatted_absolute_offset.length());
+ offset_width = std::max<size_t>(offset_width, tl.formatted_relative_offset.length());
+ size_width = std::max<size_t>(size_width, tl.formatted_size.length());
+ padded_size_width = std::max<size_t>(padded_size_width, tl.formatted_padded_size.length());
+ array_stride_width = std::max<size_t>(array_stride_width, tl.formatted_array_stride.length());
+ }
+
+ size_t n = formatted_lines.size();
+ for (size_t i = 0; i < n; ++i) {
+ auto& tl = formatted_lines[i];
+
+ if (tl.text_line_flags == TEXT_LINE_TYPE_BLOCK_BEGIN) {
+ if (i > 0) {
+ os << "\n";
+ }
+
+ size_t pos = tl.formatted_line.find_first_not_of(' ');
+ if (pos != std::string::npos) {
+ std::string s(pos, ' ');
+ os << s << "//"
+ << " ";
+ os << "size = " << tl.formatted_size << ", ";
+ os << "padded size = " << tl.formatted_padded_size;
+ os << "\n";
+ }
+
+ os << std::setw(line_width) << std::left << tl.formatted_line;
+ } else if (tl.text_line_flags == TEXT_LINE_TYPE_BLOCK_END) {
+ os << std::setw(line_width) << std::left << tl.formatted_line;
+ if (i < (n - 1)) {
+ os << "\n";
+ }
+ } else if (tl.text_line_flags == TEXT_LINE_TYPE_STRUCT_BEGIN || tl.text_line_flags == TEXT_LINE_TYPE_REF_BEGIN) {
+ if (!flatten_cbuffers) {
+ if (i > 0) {
+ os << "\n";
+ }
+
+ size_t pos = tl.formatted_line.find_first_not_of(' ');
+ if (pos != std::string::npos) {
+ std::string s(pos, ' ');
+ os << s << "//"
+ << " ";
+ os << "abs offset = " << tl.formatted_absolute_offset << ", ";
+ os << "rel offset = " << tl.formatted_relative_offset << ", ";
+ os << "size = " << tl.formatted_size << ", ";
+ os << "padded size = " << tl.formatted_padded_size;
+ if (tl.array_stride > 0) {
+ os << ", ";
+ os << "array stride = " << tl.formatted_array_stride;
+ }
+ if (!tl.formatted_block_variable_flags.empty()) {
+ os << " ";
+ os << tl.formatted_block_variable_flags;
+ }
+ os << "\n";
+ }
+
+ os << std::setw(line_width) << std::left << tl.formatted_line;
+ }
+ } else if (tl.text_line_flags == TEXT_LINE_TYPE_STRUCT_END || tl.text_line_flags == TEXT_LINE_TYPE_REF_END) {
+ if (!flatten_cbuffers) {
+ os << std::setw(line_width) << std::left << tl.formatted_line;
+ if (i < (n - 1)) {
+ os << "\n";
+ }
+ }
+ } else {
+ os << std::setw(line_width) << std::left << tl.formatted_line;
+ os << " "
+ << "//"
+ << " ";
+ os << "abs offset = " << std::setw(absolute_offset_width) << std::right << tl.formatted_absolute_offset << ", ";
+ if (!flatten_cbuffers) {
+ os << "rel offset = " << std::setw(offset_width) << std::right << tl.formatted_relative_offset << ", ";
+ }
+ os << "size = " << std::setw(size_width) << std::right << tl.formatted_size << ", ";
+ os << "padded size = " << std::setw(padded_size_width) << std::right << tl.formatted_padded_size;
+ if (tl.array_stride > 0) {
+ os << ", ";
+ os << "array stride = " << std::setw(array_stride_width) << tl.formatted_array_stride;
+ }
+ if (!tl.formatted_block_variable_flags.empty()) {
+ os << " ";
+ os << tl.formatted_block_variable_flags;
+ }
+ }
+
+ if (i < (n - 1)) {
+ os << "\n";
+ }
+ }
+}
+
+void StreamWritePushConstantsBlock(std::ostream& os, const SpvReflectBlockVariable& obj, bool flatten_cbuffers,
+ const char* indent) {
+ const char* t = indent;
+ os << t << "spirv id : " << obj.spirv_id << "\n";
+
+ os << t << "name : " << ((obj.name != nullptr) ? obj.name : "<unnamed>");
+ if ((obj.type_description->type_name != nullptr) && (strlen(obj.type_description->type_name) > 0)) {
+ os << " "
+ << "(" << obj.type_description->type_name << ")";
+ }
+
+ std::vector<TextLine> text_lines;
+ ParseBlockVariableToTextLines(" ", flatten_cbuffers, obj, &text_lines);
+ if (!text_lines.empty()) {
+ os << "\n";
+ StreamWriteTextLines(os, t, flatten_cbuffers, text_lines);
+ os << "\n";
+ }
+}
+
+void StreamWriteDescriptorBinding(std::ostream& os, const SpvReflectDescriptorBinding& obj, bool write_set, bool flatten_cbuffers,
+ const char* indent) {
+ const char* t = indent;
+ os << t << "spirv id : " << obj.spirv_id << "\n";
+ if (write_set) {
+ os << t << "set : " << obj.set << "\n";
+ }
+ os << t << "binding : " << obj.binding << "\n";
+ os << t << "type : " << ToStringDescriptorType(obj.descriptor_type);
+ os << " "
+ << "(" << ToStringResourceType(obj.resource_type) << ")"
+ << "\n";
+
+ // count
+ os << t << "count : " << obj.count << "\n";
+
+ // array
+ if (obj.array.dims_count > 0) {
+ os << t << "array : ";
+ for (uint32_t dim_index = 0; dim_index < obj.array.dims_count; ++dim_index) {
+ os << "[" << obj.array.dims[dim_index] << "]";
+ }
+ os << "\n";
+ }
+
+ // counter
+ if (obj.uav_counter_binding != nullptr) {
+ os << t << "counter : ";
+ os << "(";
+ os << "set=" << obj.uav_counter_binding->set << ", ";
+ os << "binding=" << obj.uav_counter_binding->binding << ", ";
+ os << "name=" << obj.uav_counter_binding->name;
+ os << ");";
+ os << "\n";
+ }
+
+ // accessed
+ os << t << "accessed : " << (obj.accessed ? "true" : "false") << "\n";
+
+ os << t << "name : " << ((obj.name != nullptr) ? obj.name : "<unnamed>");
+ if ((obj.type_description->type_name != nullptr) && (strlen(obj.type_description->type_name) > 0)) {
+ os << " "
+ << "(" << obj.type_description->type_name << ")";
+ }
+
+ if (obj.descriptor_type == SPV_REFLECT_DESCRIPTOR_TYPE_UNIFORM_BUFFER ||
+ obj.descriptor_type == SPV_REFLECT_DESCRIPTOR_TYPE_STORAGE_BUFFER) {
+ std::vector<TextLine> text_lines;
+ ParseBlockVariableToTextLines(" ", flatten_cbuffers, obj.block, &text_lines);
+ if (!text_lines.empty()) {
+ os << "\n";
+ StreamWriteTextLines(os, t, flatten_cbuffers, text_lines);
+ os << "\n";
+ }
+ }
+}
+
+void StreamWriteInterfaceVariable(std::ostream& os, const SpvReflectInterfaceVariable& obj, const char* indent) {
+ const char* t = indent;
+ os << t << "spirv id : " << obj.spirv_id << "\n";
+ os << t << "location : ";
+ if (obj.decoration_flags & SPV_REFLECT_DECORATION_BUILT_IN) {
+ os << ToStringSpvBuiltIn(obj, true);
+ } else {
+ os << obj.location;
+ }
+ os << "\n";
+ os << t << "type : " << ToStringComponentType(*obj.type_description, 0) << "\n";
+
+ // array
+ if (obj.array.dims_count > 0) {
+ os << t << "array : ";
+ for (uint32_t dim_index = 0; dim_index < obj.array.dims_count; ++dim_index) {
+ os << "[" << obj.array.dims[dim_index] << "]";
+ }
+ os << "\n";
+ }
+
+ os << t << "semantic : " << (obj.semantic != NULL ? obj.semantic : "") << "\n";
+ os << t << "name : " << (obj.name != NULL ? obj.name : "");
+ if ((obj.type_description->type_name != nullptr) && (strlen(obj.type_description->type_name) > 0)) {
+ os << " "
+ << "(" << obj.type_description->type_name << ")";
+ }
+ os << "\n";
+ os << t << "qualifier : ";
+ if (obj.decoration_flags & SPV_REFLECT_DECORATION_FLAT) {
+ os << "flat";
+ } else if (obj.decoration_flags & SPV_REFLECT_DECORATION_NOPERSPECTIVE) {
+ os << "noperspective";
+ }
+}
+
+void StreamWriteEntryPoint(std::ostream& os, const SpvReflectEntryPoint& obj, const char* indent) {
+ os << indent << "entry point : " << obj.name;
+ os << " (stage=" << ToStringShaderStage(obj.shader_stage) << ")";
+ if (obj.shader_stage == SPV_REFLECT_SHADER_STAGE_COMPUTE_BIT) {
+ os << "\n";
+ os << "local size : "
+ << "(" << (obj.local_size.x == SPV_REFLECT_EXECUTION_MODE_SPEC_CONSTANT ? "Spec Constant" : std::to_string(obj.local_size.x))
+ << ", "
+ << (obj.local_size.y == SPV_REFLECT_EXECUTION_MODE_SPEC_CONSTANT ? "Spec Constant" : std::to_string(obj.local_size.y))
+ << ", "
+ << (obj.local_size.z == SPV_REFLECT_EXECUTION_MODE_SPEC_CONSTANT ? "Spec Constant" : std::to_string(obj.local_size.z))
+ << ")";
+ }
+}
+
+void StreamWriteShaderModule(std::ostream& os, const SpvReflectShaderModule& obj, const char* indent) {
+ (void)indent;
+ os << "generator : " << ToStringGenerator(obj.generator) << "\n";
+ os << "source lang : " << spvReflectSourceLanguage(obj.source_language) << "\n";
+ os << "source lang ver : " << obj.source_language_version << "\n";
+ os << "source file : " << (obj.source_file != NULL ? obj.source_file : "") << "\n";
+ // os << "shader stage : " << ToStringShaderStage(obj.shader_stage) <<
+ // "\n";
+
+ for (uint32_t i = 0; i < obj.entry_point_count; ++i) {
+ StreamWriteEntryPoint(os, obj.entry_points[i], "");
+ if (i < (obj.entry_point_count - 1)) {
+ os << "\n";
+ }
+ }
+}
+
+// Avoid unused variable warning/error on Linux
+#ifndef NDEBUG
+#define USE_ASSERT(x) assert(x)
+#else
+#define USE_ASSERT(x) ((void)(x))
+#endif
+
+void WriteReflection(const spv_reflect::ShaderModule& obj, bool flatten_cbuffers, std::ostream& os) {
+ const char* t = " ";
+ const char* tt = " ";
+ const char* ttt = " ";
+
+ StreamWriteShaderModule(os, obj.GetShaderModule(), "");
+
+ uint32_t count = 0;
+ std::vector<SpvReflectInterfaceVariable*> variables;
+ std::vector<SpvReflectDescriptorBinding*> bindings;
+ std::vector<SpvReflectDescriptorSet*> sets;
+ std::vector<SpvReflectBlockVariable*> push_constant_bocks;
+
+ count = 0;
+ SpvReflectResult result = obj.EnumerateInputVariables(&count, nullptr);
+ USE_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS);
+ variables.resize(count);
+ result = obj.EnumerateInputVariables(&count, variables.data());
+ USE_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS);
+ if (count > 0) {
+ os << "\n";
+ os << "\n";
+ os << "\n";
+ os << t << "Input variables: " << count << "\n\n";
+ for (size_t i = 0; i < variables.size(); ++i) {
+ auto p_var = variables[i];
+ USE_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS);
+ os << tt << i << ":"
+ << "\n";
+ StreamWriteInterfaceVariable(os, *p_var, ttt);
+ if (i < (count - 1)) {
+ os << "\n";
+ }
+ }
+ }
+
+ count = 0;
+ result = obj.EnumerateOutputVariables(&count, nullptr);
+ USE_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS);
+ variables.resize(count);
+ result = obj.EnumerateOutputVariables(&count, variables.data());
+ USE_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS);
+ if (count > 0) {
+ os << "\n";
+ os << "\n";
+ os << "\n";
+ os << t << "Output variables: " << count << "\n\n";
+ for (size_t i = 0; i < variables.size(); ++i) {
+ auto p_var = variables[i];
+ USE_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS);
+ os << tt << i << ":"
+ << "\n";
+ StreamWriteInterfaceVariable(os, *p_var, ttt);
+ if (i < (count - 1)) {
+ os << "\n";
+ }
+ }
+ }
+
+ count = 0;
+ result = obj.EnumeratePushConstantBlocks(&count, nullptr);
+ USE_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS);
+ push_constant_bocks.resize(count);
+ result = obj.EnumeratePushConstantBlocks(&count, push_constant_bocks.data());
+ USE_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS);
+ if (count > 0) {
+ os << "\n";
+ os << "\n";
+ os << "\n";
+ os << t << "Push constant blocks: " << count << "\n\n";
+ for (size_t i = 0; i < push_constant_bocks.size(); ++i) {
+ auto p_block = push_constant_bocks[i];
+ os << tt << i << ":"
+ << "\n";
+ StreamWritePushConstantsBlock(os, *p_block, flatten_cbuffers, ttt);
+ }
+ }
+
+ count = 0;
+ result = obj.EnumerateDescriptorBindings(&count, nullptr);
+ USE_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS);
+ bindings.resize(count);
+ result = obj.EnumerateDescriptorBindings(&count, bindings.data());
+ USE_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS);
+ std::sort(std::begin(bindings), std::end(bindings), [](SpvReflectDescriptorBinding* a, SpvReflectDescriptorBinding* b) -> bool {
+ if (a->set != b->set) {
+ return a->set < b->set;
+ }
+ return a->binding < b->binding;
+ });
+ if (count > 0) {
+ os << "\n";
+ os << "\n";
+ os << "\n";
+ os << t << "Descriptor bindings: " << count << "\n\n";
+ for (size_t i = 0; i < bindings.size(); ++i) {
+ auto p_binding = bindings[i];
+ USE_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS);
+ os << tt << "Binding"
+ << " " << p_binding->set << "." << p_binding->binding << ""
+ << "\n";
+ StreamWriteDescriptorBinding(os, *p_binding, true, flatten_cbuffers, ttt);
+ if (i < (count - 1)) {
+ os << "\n\n";
+ }
+ }
+ }
+}
+
+//////////////////////////////////
+
+SpvReflectToYaml::SpvReflectToYaml(const SpvReflectShaderModule& shader_module, uint32_t verbosity)
+ : sm_(shader_module), verbosity_(verbosity) {}
+
+void SpvReflectToYaml::WriteTypeDescription(std::ostream& os, const SpvReflectTypeDescription& td, uint32_t indent_level) {
+ // YAML anchors can only refer to points earlier in the doc, so child type
+ // descriptions must be processed before the parent.
+ if (!td.copied) {
+ for (uint32_t i = 0; i < td.member_count; ++i) {
+ WriteTypeDescription(os, td.members[i], indent_level);
+ }
+ }
+ const std::string t0 = Indent(indent_level);
+ const std::string t1 = Indent(indent_level + 1);
+ const std::string t2 = Indent(indent_level + 2);
+ const std::string t3 = Indent(indent_level + 3);
+ const std::string t4 = Indent(indent_level + 4);
+
+ // Determine the index of this type within the shader module's list.
+ uint32_t type_description_index = static_cast<uint32_t>(type_description_to_index_.size());
+ type_description_to_index_[&td] = type_description_index;
+
+ os << t0 << "- &td" << type_description_index << std::endl;
+ // typedef struct SpvReflectTypeDescription {
+ // uint32_t id;
+ os << t1 << "id: " << td.id << std::endl;
+ // SpvOp op;
+ os << t1 << "op: " << td.op << std::endl;
+ // const char* type_name;
+ os << t1 << "type_name: " << SafeString(td.type_name) << std::endl;
+ // const char* struct_member_name;
+ os << t1 << "struct_member_name: " << SafeString(td.struct_member_name) << std::endl;
+ // SpvStorageClass storage_class;
+ os << t1 << "storage_class: " << td.storage_class << " # " << ToStringSpvStorageClass(td.storage_class) << std::endl;
+ // SpvReflectTypeFlags type_flags;
+ os << t1 << "type_flags: " << AsHexString(td.type_flags) << " # " << ToStringTypeFlags(td.type_flags) << std::endl;
+ // SpvReflectDecorationFlags decoration_flags;
+ os << t1 << "decoration_flags: " << AsHexString(td.decoration_flags) << " # " << ToStringDecorationFlags(td.decoration_flags)
+ << std::endl;
+ // struct Traits {
+ os << t1 << "traits:" << std::endl;
+ // SpvReflectNumericTraits numeric;
+ // typedef struct SpvReflectNumericTraits {
+ os << t2 << "numeric:" << std::endl;
+ // struct Scalar {
+ // uint32_t width;
+ // uint32_t signedness;
+ // } scalar;
+ os << t3 << "scalar: { ";
+ os << "width: " << td.traits.numeric.scalar.width << ", ";
+ os << "signedness: " << td.traits.numeric.scalar.signedness;
+ os << " }" << std::endl;
+ // struct Vector {
+ // uint32_t component_count;
+ // } vector;
+ os << t3 << "vector: { ";
+ os << "component_count: " << td.traits.numeric.vector.component_count;
+ os << " }" << std::endl;
+ // struct Matrix {
+ // uint32_t column_count;
+ // uint32_t row_count;
+ // uint32_t stride; // Measured in bytes
+ // } matrix;
+ os << t3 << "matrix: { ";
+ os << "column_count: " << td.traits.numeric.matrix.column_count << ", ";
+ os << "row_count: " << td.traits.numeric.matrix.row_count << ", ";
+ ;
+ os << "stride: " << td.traits.numeric.matrix.stride;
+ os << " }" << std::endl;
+ // } SpvReflectNumericTraits;
+
+ // SpvReflectImageTraits image;
+ os << t2 << "image: { ";
+ // typedef struct SpvReflectImageTraits {
+ // SpvDim dim;
+ os << "dim: " << td.traits.image.dim << ", ";
+ // uint32_t depth;
+ os << "depth: " << td.traits.image.depth << ", ";
+ // uint32_t arrayed;
+ os << "arrayed: " << td.traits.image.arrayed << ", ";
+ // uint32_t ms;
+ os << "ms: " << td.traits.image.ms << ", ";
+ // uint32_t sampled;
+ os << "sampled: " << td.traits.image.sampled << ", ";
+ // SpvImageFormat image_format;
+ os << "image_format: " << td.traits.image.image_format;
+ // } SpvReflectImageTraits;
+ os << " }"
+ << " # dim=" << ToStringSpvDim(td.traits.image.dim) << " image_format=" << ToStringSpvImageFormat(td.traits.image.image_format)
+ << std::endl;
+
+ // SpvReflectArrayTraits array;
+ os << t2 << "array: { ";
+ // typedef struct SpvReflectArrayTraits {
+ // uint32_t dims_count;
+ os << "dims_count: " << td.traits.array.dims_count << ", ";
+ // uint32_t dims[SPV_REFLECT_MAX_ARRAY_DIMS];
+ os << "dims: [";
+ for (uint32_t i_dim = 0; i_dim < td.traits.array.dims_count; ++i_dim) {
+ os << td.traits.array.dims[i_dim] << ",";
+ }
+ os << "], ";
+ // uint32_t stride; // Measured in bytes
+ os << "stride: " << td.traits.array.stride;
+ // } SpvReflectArrayTraits;
+ os << " }" << std::endl;
+ // } traits;
+
+ // uint32_t member_count;
+ os << t1 << "member_count: " << td.member_count << std::endl;
+ // struct SpvReflectTypeDescription* members;
+ os << t1 << "members:" << std::endl;
+ if (td.copied) {
+ os << t1 << "- [forward pointer]" << std::endl;
+ } else {
+ for (uint32_t i_member = 0; i_member < td.member_count; ++i_member) {
+ os << t2 << "- *td" << type_description_to_index_[&(td.members[i_member])] << std::endl;
+ }
+ }
+ // } SpvReflectTypeDescription;
+}
+
+void SpvReflectToYaml::WriteBlockVariable(std::ostream& os, const SpvReflectBlockVariable& bv, uint32_t indent_level) {
+ if ((bv.flags & SPV_REFLECT_VARIABLE_FLAGS_PHYSICAL_POINTER_COPY)) {
+ return; // catches recursive buffer references
+ }
+
+ for (uint32_t i = 0; i < bv.member_count; ++i) {
+ WriteBlockVariable(os, bv.members[i], indent_level);
+ }
+
+ const std::string t0 = Indent(indent_level);
+ const std::string t1 = Indent(indent_level + 1);
+ const std::string t2 = Indent(indent_level + 2);
+ const std::string t3 = Indent(indent_level + 3);
+
+ assert(block_variable_to_index_.find(&bv) == block_variable_to_index_.end());
+ uint32_t block_variable_index = static_cast<uint32_t>(block_variable_to_index_.size());
+ block_variable_to_index_[&bv] = block_variable_index;
+
+ os << t0 << "- &bv" << block_variable_index << std::endl;
+ // typedef struct SpvReflectBlockVariable {
+ // const char* name;
+ os << t1 << "name: " << SafeString(bv.name) << std::endl;
+ // uint32_t offset; // Measured in bytes
+ os << t1 << "offset: " << bv.offset << std::endl;
+ // uint32_t absolute_offset; // Measured in bytes
+ os << t1 << "absolute_offset: " << bv.absolute_offset << std::endl;
+ // uint32_t size; // Measured in bytes
+ os << t1 << "size: " << bv.size << std::endl;
+ // uint32_t padded_size; // Measured in bytes
+ os << t1 << "padded_size: " << bv.padded_size << std::endl;
+ // SpvReflectDecorationFlags decoration_flags;
+ os << t1 << "decorations: " << AsHexString(bv.decoration_flags) << " # " << ToStringDecorationFlags(bv.decoration_flags)
+ << std::endl;
+ // SpvReflectNumericTraits numeric;
+ // typedef struct SpvReflectNumericTraits {
+ os << t1 << "numeric:" << std::endl;
+ // struct Scalar {
+ // uint32_t width;
+ // uint32_t signedness;
+ // } scalar;
+ os << t2 << "scalar: { ";
+ os << "width: " << bv.numeric.scalar.width << ", ";
+ os << "signedness: " << bv.numeric.scalar.signedness << " }" << std::endl;
+ // struct Vector {
+ // uint32_t component_count;
+ // } vector;
+ os << t2 << "vector: { ";
+ os << "component_count: " << bv.numeric.vector.component_count << " }" << std::endl;
+ // struct Matrix {
+ // uint32_t column_count;
+ // uint32_t row_count;
+ // uint32_t stride; // Measured in bytes
+ // } matrix;
+ os << t2 << "matrix: { ";
+ os << "column_count: " << bv.numeric.matrix.column_count << ", ";
+ os << "row_count: " << bv.numeric.matrix.row_count << ", ";
+ os << "stride: " << bv.numeric.matrix.stride << " }" << std::endl;
+ // } SpvReflectNumericTraits;
+
+ // SpvReflectArrayTraits array;
+ os << t1 << "array: { ";
+ // typedef struct SpvReflectArrayTraits {
+ // uint32_t dims_count;
+ os << "dims_count: " << bv.array.dims_count << ", ";
+ // uint32_t dims[SPV_REFLECT_MAX_ARRAY_DIMS];
+ os << "dims: [";
+ for (uint32_t i_dim = 0; i_dim < bv.array.dims_count; ++i_dim) {
+ os << bv.array.dims[i_dim] << ",";
+ }
+ os << "], ";
+ // uint32_t stride; // Measured in bytes
+ os << "stride: " << bv.array.stride;
+ // } SpvReflectArrayTraits;
+ os << " }" << std::endl;
+
+ // uint32_t member_count;
+ os << t1 << "member_count: " << bv.member_count << std::endl;
+ // struct SpvReflectBlockVariable* members;
+ os << t1 << "members:" << std::endl;
+ for (uint32_t i = 0; i < bv.member_count; ++i) {
+ auto itor = block_variable_to_index_.find(&bv.members[i]);
+ if (itor != block_variable_to_index_.end()) {
+ os << t2 << "- *bv" << itor->second << std::endl;
+ } else {
+ os << t2 << "- [recursive]" << std::endl;
+ }
+ }
+ if (verbosity_ >= 1) {
+ // SpvReflectTypeDescription* type_description;
+ if (bv.type_description == nullptr) {
+ os << t1 << "type_description:" << std::endl;
+ } else {
+ auto itor = type_description_to_index_.find(bv.type_description);
+ assert(itor != type_description_to_index_.end());
+ os << t1 << "type_description: *td" << itor->second << std::endl;
+ }
+ }
+ // } SpvReflectBlockVariable;
+}
+
+void SpvReflectToYaml::WriteDescriptorBinding(std::ostream& os, const SpvReflectDescriptorBinding& db, uint32_t indent_level) {
+ if (db.uav_counter_binding != nullptr) {
+ auto itor = descriptor_binding_to_index_.find(db.uav_counter_binding);
+ if (itor == descriptor_binding_to_index_.end()) {
+ WriteDescriptorBinding(os, *(db.uav_counter_binding), indent_level);
+ }
+ }
+
+ const std::string t0 = Indent(indent_level);
+ const std::string t1 = Indent(indent_level + 1);
+ const std::string t2 = Indent(indent_level + 2);
+ const std::string t3 = Indent(indent_level + 3);
+
+ // A binding's UAV binding later may appear later in the table than the
+ // binding itself, in which case we've already output entries for both
+ // bindings, and can just write another reference here.
+ {
+ auto itor = descriptor_binding_to_index_.find(&db);
+ if (itor != descriptor_binding_to_index_.end()) {
+ os << t0 << "- *db" << itor->second << std::endl;
+ return;
+ }
+ }
+
+ uint32_t descriptor_binding_index = static_cast<uint32_t>(descriptor_binding_to_index_.size());
+ descriptor_binding_to_index_[&db] = descriptor_binding_index;
+
+ os << t0 << "- &db" << descriptor_binding_index << std::endl;
+ // typedef struct SpvReflectDescriptorBinding {
+ // uint32_t spirv_id;
+ os << t1 << "spirv_id: " << db.spirv_id << std::endl;
+ // const char* name;
+ os << t1 << "name: " << SafeString(db.name) << std::endl;
+ // uint32_t binding;
+ os << t1 << "binding: " << db.binding << std::endl;
+ // uint32_t input_attachment_index;
+ os << t1 << "input_attachment_index: " << db.input_attachment_index << std::endl;
+ // uint32_t set;
+ os << t1 << "set: " << db.set << std::endl;
+ // SpvReflectDecorationFlags decoration_flags;
+ os << t1 << "decoration_flags: " << AsHexString(db.decoration_flags) << " # " << ToStringDecorationFlags(db.decoration_flags)
+ << std::endl;
+ // SpvReflectDescriptorType descriptor_type;
+ os << t1 << "descriptor_type: " << db.descriptor_type << " # " << ToStringDescriptorType(db.descriptor_type) << std::endl;
+ // SpvReflectResourceType resource_type;
+ os << t1 << "resource_type: " << db.resource_type << " # " << ToStringResourceType(db.resource_type) << std::endl;
+ // SpvReflectImageTraits image;
+ os << t1 << "image: { ";
+ // typedef struct SpvReflectImageTraits {
+ // SpvDim dim;
+ os << "dim: " << db.image.dim << ", ";
+ // uint32_t depth;
+ os << "depth: " << db.image.depth << ", ";
+ // uint32_t arrayed;
+ os << "arrayed: " << db.image.arrayed << ", ";
+ // uint32_t ms;
+ os << "ms: " << db.image.ms << ", ";
+ // uint32_t sampled;
+ os << "sampled: " << db.image.sampled << ", ";
+ // SpvImageFormat image_format;
+ os << "image_format: " << db.image.image_format;
+ // } SpvReflectImageTraits;
+ os << " }"
+ << " # dim=" << ToStringSpvDim(db.image.dim) << " image_format=" << ToStringSpvImageFormat(db.image.image_format) << std::endl;
+
+ // SpvReflectBlockVariable block;
+ {
+ auto itor = block_variable_to_index_.find(&db.block);
+ assert(itor != block_variable_to_index_.end());
+ os << t1 << "block: *bv" << itor->second << " # " << SafeString(db.block.name) << std::endl;
+ }
+ // SpvReflectBindingArrayTraits array;
+ os << t1 << "array: { ";
+ // typedef struct SpvReflectBindingArrayTraits {
+ // uint32_t dims_count;
+ os << "dims_count: " << db.array.dims_count << ", ";
+ // uint32_t dims[SPV_REFLECT_MAX_ARRAY_DIMS];
+ os << "dims: [";
+ for (uint32_t i_dim = 0; i_dim < db.array.dims_count; ++i_dim) {
+ os << db.array.dims[i_dim] << ",";
+ }
+ // } SpvReflectBindingArrayTraits;
+ os << "] }" << std::endl;
+
+ // uint32_t accessed;
+ os << t1 << "accessed: " << db.accessed << std::endl;
+
+ // uint32_t uav_counter_id;
+ os << t1 << "uav_counter_id: " << db.uav_counter_id << std::endl;
+ // struct SpvReflectDescriptorBinding* uav_counter_binding;
+ if (db.uav_counter_binding == nullptr) {
+ os << t1 << "uav_counter_binding:" << std::endl;
+ } else {
+ auto itor = descriptor_binding_to_index_.find(db.uav_counter_binding);
+ assert(itor != descriptor_binding_to_index_.end());
+ os << t1 << "uav_counter_binding: *db" << itor->second << " # " << SafeString(db.uav_counter_binding->name) << std::endl;
+ }
+
+ if (db.byte_address_buffer_offset_count > 0) {
+ os << t1 << "ByteAddressBuffer offsets: [";
+ for (uint32_t i = 0; i < db.byte_address_buffer_offset_count; i++) {
+ os << db.byte_address_buffer_offsets[i];
+ if (i < (db.byte_address_buffer_offset_count - 1)) {
+ os << ", ";
+ }
+ }
+ os << "]\n";
+ }
+
+ if (verbosity_ >= 1) {
+ // SpvReflectTypeDescription* type_description;
+ if (db.type_description == nullptr) {
+ os << t1 << "type_description:" << std::endl;
+ } else {
+ auto itor = type_description_to_index_.find(db.type_description);
+ assert(itor != type_description_to_index_.end());
+ os << t1 << "type_description: *td" << itor->second << std::endl;
+ }
+ }
+ // struct {
+ // uint32_t binding;
+ // uint32_t set;
+ // } word_offset;
+ os << t1 << "word_offset: { binding: " << db.word_offset.binding;
+ os << ", set: " << db.word_offset.set << " }" << std::endl;
+
+ if (db.user_type != SPV_REFLECT_USER_TYPE_INVALID) {
+ os << t1 << "user_type: " << ToStringUserType(db.user_type) << std::endl;
+ }
+ // } SpvReflectDescriptorBinding;
+}
+
+void SpvReflectToYaml::WriteInterfaceVariable(std::ostream& os, const SpvReflectInterfaceVariable& iv, uint32_t indent_level) {
+ for (uint32_t i = 0; i < iv.member_count; ++i) {
+ assert(interface_variable_to_index_.find(&iv.members[i]) == interface_variable_to_index_.end());
+ WriteInterfaceVariable(os, iv.members[i], indent_level);
+ }
+
+ const std::string t0 = Indent(indent_level);
+ const std::string t1 = Indent(indent_level + 1);
+ const std::string t2 = Indent(indent_level + 2);
+ const std::string t3 = Indent(indent_level + 3);
+
+ uint32_t interface_variable_index = static_cast<uint32_t>(interface_variable_to_index_.size());
+ interface_variable_to_index_[&iv] = interface_variable_index;
+
+ // typedef struct SpvReflectInterfaceVariable {
+ os << t0 << "- &iv" << interface_variable_index << std::endl;
+ // uint32_t spirv_id;
+ os << t1 << "spirv_id: " << iv.spirv_id << std::endl;
+ // const char* name;
+ os << t1 << "name: " << SafeString(iv.name) << std::endl;
+ // uint32_t location;
+ os << t1 << "location: " << iv.location << std::endl;
+ // SpvStorageClass storage_class;
+ os << t1 << "storage_class: " << iv.storage_class << " # " << ToStringSpvStorageClass(iv.storage_class) << std::endl;
+ // const char* semantic;
+ os << t1 << "semantic: " << SafeString(iv.semantic) << std::endl;
+ // SpvReflectDecorationFlags decoration_flags;
+ os << t1 << "decoration_flags: " << AsHexString(iv.decoration_flags) << " # " << ToStringDecorationFlags(iv.decoration_flags)
+ << std::endl;
+ // SpvBuiltIn built_in;
+ os << t1 << "built_in: ";
+ if (iv.decoration_flags & SPV_REFLECT_DECORATION_BLOCK) {
+ for (uint32_t i = 0; i < iv.member_count; i++) {
+ os << iv.members[i].built_in;
+ if (i < (iv.member_count - 1)) {
+ os << ", ";
+ }
+ }
+ } else {
+ os << iv.built_in;
+ }
+ os << " # " << ToStringSpvBuiltIn(iv, false) << std::endl;
+ // SpvReflectNumericTraits numeric;
+ // typedef struct SpvReflectNumericTraits {
+ os << t1 << "numeric:" << std::endl;
+ // struct Scalar {
+ // uint32_t width;
+ // uint32_t signedness;
+ // } scalar;
+ os << t2 << "scalar: { ";
+ os << "width: " << iv.numeric.scalar.width << ", ";
+ os << "signedness: " << iv.numeric.scalar.signedness << " }" << std::endl;
+ // struct Vector {
+ // uint32_t component_count;
+ // } vector;
+ os << t2 << "vector: { ";
+ os << "component_count: " << iv.numeric.vector.component_count << " }" << std::endl;
+ // struct Matrix {
+ // uint32_t column_count;
+ // uint32_t row_count;
+ // uint32_t stride; // Measured in bytes
+ // } matrix;
+ os << t2 << "matrix: { ";
+ os << "column_count: " << iv.numeric.matrix.column_count << ", ";
+ os << "row_count: " << iv.numeric.matrix.row_count << ", ";
+ os << "stride: " << iv.numeric.matrix.stride << " }" << std::endl;
+ // } SpvReflectNumericTraits;
+
+ // SpvReflectArrayTraits array;
+ os << t1 << "array: { ";
+ // typedef struct SpvReflectArrayTraits {
+ // uint32_t dims_count;
+ os << "dims_count: " << iv.array.dims_count << ", ";
+ // uint32_t dims[SPV_REFLECT_MAX_ARRAY_DIMS];
+ os << "dims: [";
+ for (uint32_t i_dim = 0; i_dim < iv.array.dims_count; ++i_dim) {
+ os << iv.array.dims[i_dim] << ",";
+ }
+ os << "], ";
+ // uint32_t stride; // Measured in bytes
+ os << "stride: " << iv.array.stride;
+ // } SpvReflectArrayTraits;
+ os << " }" << std::endl;
+
+ // uint32_t member_count;
+ os << t1 << "member_count: " << iv.member_count << std::endl;
+ // struct SpvReflectInterfaceVariable* members;
+ os << t1 << "members:" << std::endl;
+ for (uint32_t i = 0; i < iv.member_count; ++i) {
+ auto itor = interface_variable_to_index_.find(&iv.members[i]);
+ assert(itor != interface_variable_to_index_.end());
+ os << t2 << "- *iv" << itor->second << " # " << SafeString(iv.members[i].name) << std::endl;
+ }
+
+ // SpvReflectFormat format;
+ os << t1 << "format: " << iv.format << " # " << ToStringFormat(iv.format) << std::endl;
+
+ if (verbosity_ >= 1) {
+ // SpvReflectTypeDescription* type_description;
+ if (!iv.type_description) {
+ os << t1 << "type_description:" << std::endl;
+ } else {
+ auto itor = type_description_to_index_.find(iv.type_description);
+ assert(itor != type_description_to_index_.end());
+ os << t1 << "type_description: *td" << itor->second << std::endl;
+ }
+ }
+
+ // struct {
+ // uint32_t location;
+ // } word_offset;
+ os << t1 << "word_offset: { location: " << iv.word_offset.location << " }" << std::endl;
+
+ // } SpvReflectInterfaceVariable;
+}
+
+void SpvReflectToYaml::WriteBlockVariableTypes(std::ostream& os, const SpvReflectBlockVariable& bv, uint32_t indent_level) {
+ const auto* td = bv.type_description;
+ if (td && type_description_to_index_.find(td) == type_description_to_index_.end()) {
+ WriteTypeDescription(os, *td, indent_level);
+ }
+
+ if (bv.flags & SPV_REFLECT_VARIABLE_FLAGS_PHYSICAL_POINTER_COPY) {
+ return;
+ }
+ for (uint32_t i = 0; i < bv.member_count; ++i) {
+ WriteBlockVariableTypes(os, bv.members[i], indent_level);
+ }
+}
+void SpvReflectToYaml::WriteDescriptorBindingTypes(std::ostream& os, const SpvReflectDescriptorBinding& db, uint32_t indent_level) {
+ WriteBlockVariableTypes(os, db.block, indent_level);
+
+ if (db.uav_counter_binding) {
+ WriteDescriptorBindingTypes(os, *(db.uav_counter_binding), indent_level);
+ }
+
+ const auto* td = db.type_description;
+ if (td && type_description_to_index_.find(td) == type_description_to_index_.end()) {
+ WriteTypeDescription(os, *td, indent_level);
+ }
+}
+void SpvReflectToYaml::WriteInterfaceVariableTypes(std::ostream& os, const SpvReflectInterfaceVariable& iv, uint32_t indent_level) {
+ const auto* td = iv.type_description;
+ if (td && type_description_to_index_.find(td) == type_description_to_index_.end()) {
+ WriteTypeDescription(os, *td, indent_level);
+ }
+
+ for (uint32_t i = 0; i < iv.member_count; ++i) {
+ WriteInterfaceVariableTypes(os, iv.members[i], indent_level);
+ }
+}
+
+void SpvReflectToYaml::Write(std::ostream& os) {
+ if (!sm_._internal) {
+ return;
+ }
+
+ uint32_t indent_level = 0;
+ const std::string t0 = Indent(indent_level);
+ const std::string t1 = Indent(indent_level + 1);
+ const std::string t2 = Indent(indent_level + 2);
+ const std::string t3 = Indent(indent_level + 3);
+
+ os << "%YAML 1.0" << std::endl;
+ os << "---" << std::endl;
+
+ type_description_to_index_.clear();
+ if (verbosity_ >= 2) {
+ os << t0 << "all_type_descriptions:" << std::endl;
+ // Write the entire internal type_description table; all type descriptions
+ // are reachable from there, though most of them are purely internal & not
+ // referenced by any of the public-facing structures.
+ for (size_t i = 0; i < sm_._internal->type_description_count; ++i) {
+ WriteTypeDescription(os, sm_._internal->type_descriptions[i], indent_level + 1);
+ }
+ } else if (verbosity_ >= 1) {
+ os << t0 << "all_type_descriptions:" << std::endl;
+ // Iterate through all public-facing structures and write any type
+ // descriptions we find (and their children).
+ for (uint32_t i = 0; i < sm_.descriptor_binding_count; ++i) {
+ WriteDescriptorBindingTypes(os, sm_.descriptor_bindings[i], indent_level + 1);
+ }
+ for (uint32_t i = 0; i < sm_.push_constant_block_count; ++i) {
+ WriteBlockVariableTypes(os, sm_.push_constant_blocks[i], indent_level + 1);
+ }
+ for (uint32_t i = 0; i < sm_.input_variable_count; ++i) {
+ WriteInterfaceVariableTypes(os, *sm_.input_variables[i], indent_level + 1);
+ }
+ for (uint32_t i = 0; i < sm_.output_variable_count; ++i) {
+ WriteInterfaceVariableTypes(os, *sm_.output_variables[i], indent_level + 1);
+ }
+ }
+
+ block_variable_to_index_.clear();
+ os << t0 << "all_block_variables:" << std::endl;
+ for (uint32_t i = 0; i < sm_.descriptor_binding_count; ++i) {
+ WriteBlockVariable(os, sm_.descriptor_bindings[i].block, indent_level + 1);
+ }
+ for (uint32_t i = 0; i < sm_.push_constant_block_count; ++i) {
+ WriteBlockVariable(os, sm_.push_constant_blocks[i], indent_level + 1);
+ }
+
+ descriptor_binding_to_index_.clear();
+ os << t0 << "all_descriptor_bindings:" << std::endl;
+ for (uint32_t i = 0; i < sm_.descriptor_binding_count; ++i) {
+ WriteDescriptorBinding(os, sm_.descriptor_bindings[i], indent_level + 1);
+ }
+
+ interface_variable_to_index_.clear();
+ os << t0 << "all_interface_variables:" << std::endl;
+ for (uint32_t i = 0; i < sm_.input_variable_count; ++i) {
+ WriteInterfaceVariable(os, *sm_.input_variables[i], indent_level + 1);
+ }
+ for (uint32_t i = 0; i < sm_.output_variable_count; ++i) {
+ WriteInterfaceVariable(os, *sm_.output_variables[i], indent_level + 1);
+ }
+
+ // struct SpvReflectShaderModule {
+ os << t0 << "module:" << std::endl;
+ // uint16_t generator;
+ os << t1 << "generator: " << sm_.generator << " # " << ToStringGenerator(sm_.generator) << std::endl;
+ // const char* entry_point_name;
+ os << t1 << "entry_point_name: " << SafeString(sm_.entry_point_name) << std::endl;
+ // uint32_t entry_point_id;
+ os << t1 << "entry_point_id: " << sm_.entry_point_id << std::endl;
+ // SpvSourceLanguage source_language;
+ os << t1 << "source_language: " << sm_.source_language << " # " << ToStringSpvSourceLanguage(sm_.source_language) << std::endl;
+ // uint32_t source_language_version;
+ os << t1 << "source_language_version: " << sm_.source_language_version << std::endl;
+ // SpvExecutionModel spirv_execution_model;
+ os << t1 << "spirv_execution_model: " << sm_.spirv_execution_model << " # "
+ << ToStringSpvExecutionModel(sm_.spirv_execution_model) << std::endl;
+ // SpvShaderStageFlagBits shader_stage;
+ os << t1 << "shader_stage: " << AsHexString(sm_.shader_stage) << " # " << ToStringShaderStage(sm_.shader_stage) << std::endl;
+ // uint32_t descriptor_binding_count;
+ os << t1 << "descriptor_binding_count: " << sm_.descriptor_binding_count << std::endl;
+ // SpvReflectDescriptorBinding* descriptor_bindings;
+ os << t1 << "descriptor_bindings:" << std::endl;
+ for (uint32_t i = 0; i < sm_.descriptor_binding_count; ++i) {
+ auto itor = descriptor_binding_to_index_.find(&sm_.descriptor_bindings[i]);
+ assert(itor != descriptor_binding_to_index_.end());
+ os << t2 << "- *db" << itor->second << " # " << SafeString(sm_.descriptor_bindings[i].name) << std::endl;
+ }
+ // uint32_t descriptor_set_count;
+ os << t1 << "descriptor_set_count: " << sm_.descriptor_set_count << std::endl;
+ // SpvReflectDescriptorSet descriptor_sets[SPV_REFLECT_MAX_DESCRIPTOR_SETS];
+ os << t1 << "descriptor_sets:" << std::endl;
+ for (uint32_t i_set = 0; i_set < sm_.descriptor_set_count; ++i_set) {
+ // typedef struct SpvReflectDescriptorSet {
+ const auto& dset = sm_.descriptor_sets[i_set];
+ // uint32_t set;
+ os << t1 << "- "
+ << "set: " << dset.set << std::endl;
+ // uint32_t binding_count;
+ os << t2 << "binding_count: " << dset.binding_count << std::endl;
+ // SpvReflectDescriptorBinding** bindings;
+ os << t2 << "bindings:" << std::endl;
+ for (uint32_t i_binding = 0; i_binding < dset.binding_count; ++i_binding) {
+ auto itor = descriptor_binding_to_index_.find(dset.bindings[i_binding]);
+ assert(itor != descriptor_binding_to_index_.end());
+ os << t3 << "- *db" << itor->second << " # " << SafeString(dset.bindings[i_binding]->name) << std::endl;
+ }
+ // } SpvReflectDescriptorSet;
+ }
+ // uint32_t input_variable_count;
+ os << t1 << "input_variable_count: " << sm_.input_variable_count << ",\n";
+ // SpvReflectInterfaceVariable* input_variables;
+ os << t1 << "input_variables:" << std::endl;
+ for (uint32_t i = 0; i < sm_.input_variable_count; ++i) {
+ auto itor = interface_variable_to_index_.find(sm_.input_variables[i]);
+ assert(itor != interface_variable_to_index_.end());
+ os << t2 << "- *iv" << itor->second << " # " << SafeString(sm_.input_variables[i]->name) << std::endl;
+ }
+ // uint32_t output_variable_count;
+ os << t1 << "output_variable_count: " << sm_.output_variable_count << ",\n";
+ // SpvReflectInterfaceVariable* output_variables;
+ os << t1 << "output_variables:" << std::endl;
+ for (uint32_t i = 0; i < sm_.output_variable_count; ++i) {
+ auto itor = interface_variable_to_index_.find(sm_.output_variables[i]);
+ assert(itor != interface_variable_to_index_.end());
+ os << t2 << "- *iv" << itor->second << " # " << SafeString(sm_.output_variables[i]->name) << std::endl;
+ }
+ // uint32_t push_constant_count;
+ os << t1 << "push_constant_count: " << sm_.push_constant_block_count << ",\n";
+ // SpvReflectBlockVariable* push_constants;
+ os << t1 << "push_constants:" << std::endl;
+ for (uint32_t i = 0; i < sm_.push_constant_block_count; ++i) {
+ auto itor = block_variable_to_index_.find(&sm_.push_constant_blocks[i]);
+ assert(itor != block_variable_to_index_.end());
+ os << t2 << "- *bv" << itor->second << " # " << SafeString(sm_.push_constant_blocks[i].name) << std::endl;
+ }
+
+ // uint32_t spec_constant_count;
+ os << t1 << "specialization_constant_count: " << sm_.spec_constant_count << ",\n";
+ // SpvReflectSpecializationConstant* spec_constants;
+ os << t1 << "specialization_constants:" << std::endl;
+ for (uint32_t i = 0; i < sm_.spec_constant_count; ++i) {
+ os << t3 << "- name: " << SafeString(sm_.spec_constants[i].name) << std::endl;
+ os << t3 << " spirv_id: " << sm_.spec_constants[i].spirv_id << std::endl;
+ os << t3 << " constant_id: " << sm_.spec_constants[i].constant_id << std::endl;
+ }
+
+ if (verbosity_ >= 2) {
+ // struct Internal {
+ os << t1 << "_internal:" << std::endl;
+ if (sm_._internal) {
+ // size_t spirv_size;
+ os << t2 << "spirv_size: " << sm_._internal->spirv_size << std::endl;
+ // uint32_t* spirv_code;
+ os << t2 << "spirv_code: [";
+ for (size_t i = 0; i < sm_._internal->spirv_word_count; ++i) {
+ if ((i % 6) == 0) {
+ os << std::endl << t3;
+ }
+ os << AsHexString(sm_._internal->spirv_code[i]) << ",";
+ }
+ os << "]" << std::endl;
+ // uint32_t spirv_word_count;
+ os << t2 << "spirv_word_count: " << sm_._internal->spirv_word_count << std::endl;
+ // size_t type_description_count;
+ os << t2 << "type_description_count: " << sm_._internal->type_description_count << std::endl;
+ // SpvReflectTypeDescription* type_descriptions;
+ os << t2 << "type_descriptions:" << std::endl;
+ for (uint32_t i = 0; i < sm_._internal->type_description_count; ++i) {
+ auto itor = type_description_to_index_.find(&sm_._internal->type_descriptions[i]);
+ assert(itor != type_description_to_index_.end());
+ os << t3 << "- *td" << itor->second << std::endl;
+ }
+ }
+ // } * _internal;
+ }
+
+ os << "..." << std::endl;
+}
--- /dev/null
+#ifndef SPIRV_REFLECT_OUTPUT_STREAM_H
+#define SPIRV_REFLECT_OUTPUT_STREAM_H
+
+#include <map>
+#include <ostream>
+#include <string>
+
+#include "spirv_reflect.h"
+
+std::string ToStringSpvSourceLanguage(SpvSourceLanguage lang);
+std::string ToStringSpvExecutionModel(SpvExecutionModel model);
+std::string ToStringSpvStorageClass(SpvStorageClass storage_class);
+std::string ToStringSpvDim(SpvDim dim);
+std::string ToStringSpvBuiltIn(const SpvReflectInterfaceVariable& variable, bool preface);
+std::string ToStringSpvImageFormat(SpvImageFormat fmt);
+
+std::string ToStringGenerator(SpvReflectGenerator generator);
+std::string ToStringShaderStage(SpvReflectShaderStageFlagBits stage);
+std::string ToStringResourceType(SpvReflectResourceType type);
+std::string ToStringDescriptorType(SpvReflectDescriptorType value);
+std::string ToStringTypeFlags(SpvReflectTypeFlags type_flags);
+std::string ToStringDecorationFlags(SpvReflectDecorationFlags decoration_flags);
+std::string ToStringDescriptorType(SpvReflectDescriptorType value);
+std::string ToStringFormat(SpvReflectFormat fmt);
+std::string ToStringComponentType(const SpvReflectTypeDescription& type, uint32_t member_decoration_flags);
+std::string ToStringType(SpvSourceLanguage src_lang, const SpvReflectTypeDescription& type);
+
+// std::ostream& operator<<(std::ostream& os, const spv_reflect::ShaderModule& obj);
+void WriteReflection(const spv_reflect::ShaderModule& obj, bool flatten_cbuffers, std::ostream& os);
+
+class SpvReflectToYaml {
+ public:
+ // verbosity = 0: top-level tables only (module, block variables, interface variables, descriptor bindings).
+ // verbosity = 1: everything above, plus type description tables for all public objects.
+ // verbosity = 2: everything above, plus SPIRV bytecode and full type description table. HUGE.
+ explicit SpvReflectToYaml(const SpvReflectShaderModule& shader_module, uint32_t verbosity = 0);
+
+ friend std::ostream& operator<<(std::ostream& os, SpvReflectToYaml& to_yaml) {
+ to_yaml.Write(os);
+ return os;
+ }
+
+ private:
+ void Write(std::ostream& os);
+
+ SpvReflectToYaml(const SpvReflectToYaml&) = delete;
+ SpvReflectToYaml(const SpvReflectToYaml&&) = delete;
+ static std::string Indent(uint32_t level) { return std::string(2 * level, ' '); }
+ static std::string SafeString(const char* str) { return str ? (std::string("\"") + str + "\"") : ""; }
+ void WriteTypeDescription(std::ostream& os, const SpvReflectTypeDescription& td, uint32_t indent_level);
+ void WriteBlockVariable(std::ostream& os, const SpvReflectBlockVariable& bv, uint32_t indent_level);
+ void WriteDescriptorBinding(std::ostream& os, const SpvReflectDescriptorBinding& db, uint32_t indent_level);
+ void WriteInterfaceVariable(std::ostream& os, const SpvReflectInterfaceVariable& iv, uint32_t indent_level);
+
+ // Write all SpvReflectTypeDescription objects reachable from the specified objects, if they haven't been
+ // written already.
+ void WriteBlockVariableTypes(std::ostream& os, const SpvReflectBlockVariable& bv, uint32_t indent_level);
+ void WriteDescriptorBindingTypes(std::ostream& os, const SpvReflectDescriptorBinding& db, uint32_t indent_level);
+ void WriteInterfaceVariableTypes(std::ostream& os, const SpvReflectInterfaceVariable& iv, uint32_t indent_level);
+
+ const SpvReflectShaderModule& sm_;
+ uint32_t verbosity_ = 0;
+ std::map<const SpvReflectTypeDescription*, uint32_t> type_description_to_index_;
+ std::map<const SpvReflectBlockVariable*, uint32_t> block_variable_to_index_;
+ std::map<const SpvReflectDescriptorBinding*, uint32_t> descriptor_binding_to_index_;
+ std::map<const SpvReflectInterfaceVariable*, uint32_t> interface_variable_to_index_;
+};
+
+#endif
\ No newline at end of file
--- /dev/null
+/*
+** Copyright (c) 2014-2020 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#, D, Beef
+**
+** - 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']
+** - C# will use enum classes in the Specification class located in the "Spv"
+*namespace,
+** e.g.: Spv.Specification.SourceLanguage.GLSL
+** - D will have tokens under the "spv" module, e.g: spv.SourceLanguage.GLSL
+** - Beef will use enum classes in the Specification class located in the "Spv"
+*namespace,
+** e.g.: Spv.Specification.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 0x10600
+#define SPV_REVISION 1
+
+static const unsigned int SpvMagicNumber = 0x07230203;
+static const unsigned int SpvVersion = 0x00010600;
+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,
+ SpvSourceLanguageCPP_for_OpenCL = 6,
+ SpvSourceLanguageSYCL = 7,
+ SpvSourceLanguageHERO_C = 8,
+ SpvSourceLanguageNZSL = 9,
+ SpvSourceLanguageMax = 0x7fffffff,
+} SpvSourceLanguage;
+
+typedef enum SpvExecutionModel_ {
+ SpvExecutionModelVertex = 0,
+ SpvExecutionModelTessellationControl = 1,
+ SpvExecutionModelTessellationEvaluation = 2,
+ SpvExecutionModelGeometry = 3,
+ SpvExecutionModelFragment = 4,
+ SpvExecutionModelGLCompute = 5,
+ SpvExecutionModelKernel = 6,
+ SpvExecutionModelTaskNV = 5267,
+ SpvExecutionModelMeshNV = 5268,
+ SpvExecutionModelRayGenerationKHR = 5313,
+ SpvExecutionModelRayGenerationNV = 5313,
+ SpvExecutionModelIntersectionKHR = 5314,
+ SpvExecutionModelIntersectionNV = 5314,
+ SpvExecutionModelAnyHitKHR = 5315,
+ SpvExecutionModelAnyHitNV = 5315,
+ SpvExecutionModelClosestHitKHR = 5316,
+ SpvExecutionModelClosestHitNV = 5316,
+ SpvExecutionModelMissKHR = 5317,
+ SpvExecutionModelMissNV = 5317,
+ SpvExecutionModelCallableKHR = 5318,
+ SpvExecutionModelCallableNV = 5318,
+ SpvExecutionModelTaskEXT = 5364,
+ SpvExecutionModelMeshEXT = 5365,
+ SpvExecutionModelMax = 0x7fffffff,
+} SpvExecutionModel;
+
+typedef enum SpvAddressingModel_ {
+ SpvAddressingModelLogical = 0,
+ SpvAddressingModelPhysical32 = 1,
+ SpvAddressingModelPhysical64 = 2,
+ SpvAddressingModelPhysicalStorageBuffer64 = 5348,
+ SpvAddressingModelPhysicalStorageBuffer64EXT = 5348,
+ SpvAddressingModelMax = 0x7fffffff,
+} SpvAddressingModel;
+
+typedef enum SpvMemoryModel_ {
+ SpvMemoryModelSimple = 0,
+ SpvMemoryModelGLSL450 = 1,
+ SpvMemoryModelOpenCL = 2,
+ SpvMemoryModelVulkan = 3,
+ SpvMemoryModelVulkanKHR = 3,
+ 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,
+ SpvExecutionModeNonCoherentColorAttachmentReadEXT = 4169,
+ SpvExecutionModeNonCoherentDepthAttachmentReadEXT = 4170,
+ SpvExecutionModeNonCoherentStencilAttachmentReadEXT = 4171,
+ SpvExecutionModeSubgroupUniformControlFlowKHR = 4421,
+ SpvExecutionModePostDepthCoverage = 4446,
+ SpvExecutionModeDenormPreserve = 4459,
+ SpvExecutionModeDenormFlushToZero = 4460,
+ SpvExecutionModeSignedZeroInfNanPreserve = 4461,
+ SpvExecutionModeRoundingModeRTE = 4462,
+ SpvExecutionModeRoundingModeRTZ = 4463,
+ SpvExecutionModeEarlyAndLateFragmentTestsAMD = 5017,
+ SpvExecutionModeStencilRefReplacingEXT = 5027,
+ SpvExecutionModeStencilRefUnchangedFrontAMD = 5079,
+ SpvExecutionModeStencilRefGreaterFrontAMD = 5080,
+ SpvExecutionModeStencilRefLessFrontAMD = 5081,
+ SpvExecutionModeStencilRefUnchangedBackAMD = 5082,
+ SpvExecutionModeStencilRefGreaterBackAMD = 5083,
+ SpvExecutionModeStencilRefLessBackAMD = 5084,
+ SpvExecutionModeOutputLinesEXT = 5269,
+ SpvExecutionModeOutputLinesNV = 5269,
+ SpvExecutionModeOutputPrimitivesEXT = 5270,
+ SpvExecutionModeOutputPrimitivesNV = 5270,
+ SpvExecutionModeDerivativeGroupQuadsNV = 5289,
+ SpvExecutionModeDerivativeGroupLinearNV = 5290,
+ SpvExecutionModeOutputTrianglesEXT = 5298,
+ SpvExecutionModeOutputTrianglesNV = 5298,
+ SpvExecutionModePixelInterlockOrderedEXT = 5366,
+ SpvExecutionModePixelInterlockUnorderedEXT = 5367,
+ SpvExecutionModeSampleInterlockOrderedEXT = 5368,
+ SpvExecutionModeSampleInterlockUnorderedEXT = 5369,
+ SpvExecutionModeShadingRateInterlockOrderedEXT = 5370,
+ SpvExecutionModeShadingRateInterlockUnorderedEXT = 5371,
+ SpvExecutionModeSharedLocalMemorySizeINTEL = 5618,
+ SpvExecutionModeRoundingModeRTPINTEL = 5620,
+ SpvExecutionModeRoundingModeRTNINTEL = 5621,
+ SpvExecutionModeFloatingPointModeALTINTEL = 5622,
+ SpvExecutionModeFloatingPointModeIEEEINTEL = 5623,
+ SpvExecutionModeMaxWorkgroupSizeINTEL = 5893,
+ SpvExecutionModeMaxWorkDimINTEL = 5894,
+ SpvExecutionModeNoGlobalOffsetINTEL = 5895,
+ SpvExecutionModeNumSIMDWorkitemsINTEL = 5896,
+ SpvExecutionModeSchedulerTargetFmaxMhzINTEL = 5903,
+ SpvExecutionModeStreamingInterfaceINTEL = 6154,
+ SpvExecutionModeRegisterMapInterfaceINTEL = 6160,
+ SpvExecutionModeNamedBarrierCountINTEL = 6417,
+ 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,
+ SpvStorageClassTileImageEXT = 4172,
+ SpvStorageClassCallableDataKHR = 5328,
+ SpvStorageClassCallableDataNV = 5328,
+ SpvStorageClassIncomingCallableDataKHR = 5329,
+ SpvStorageClassIncomingCallableDataNV = 5329,
+ SpvStorageClassRayPayloadKHR = 5338,
+ SpvStorageClassRayPayloadNV = 5338,
+ SpvStorageClassHitAttributeKHR = 5339,
+ SpvStorageClassHitAttributeNV = 5339,
+ SpvStorageClassIncomingRayPayloadKHR = 5342,
+ SpvStorageClassIncomingRayPayloadNV = 5342,
+ SpvStorageClassShaderRecordBufferKHR = 5343,
+ SpvStorageClassShaderRecordBufferNV = 5343,
+ SpvStorageClassPhysicalStorageBuffer = 5349,
+ SpvStorageClassPhysicalStorageBufferEXT = 5349,
+ SpvStorageClassHitObjectAttributeNV = 5385,
+ SpvStorageClassTaskPayloadWorkgroupEXT = 5402,
+ SpvStorageClassCodeSectionINTEL = 5605,
+ SpvStorageClassDeviceOnlyINTEL = 5936,
+ SpvStorageClassHostOnlyINTEL = 5937,
+ SpvStorageClassMax = 0x7fffffff,
+} SpvStorageClass;
+
+typedef enum SpvDim_ {
+ SpvDim1D = 0,
+ SpvDim2D = 1,
+ SpvDim3D = 2,
+ SpvDimCube = 3,
+ SpvDimRect = 4,
+ SpvDimBuffer = 5,
+ SpvDimSubpassData = 6,
+ SpvDimTileImageDataEXT = 4173,
+ 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,
+ SpvImageFormatR64ui = 40,
+ SpvImageFormatR64i = 41,
+ 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,
+ SpvImageChannelDataTypeUnsignedIntRaw10EXT = 19,
+ SpvImageChannelDataTypeUnsignedIntRaw12EXT = 20,
+ SpvImageChannelDataTypeMax = 0x7fffffff,
+} SpvImageChannelDataType;
+
+typedef enum SpvImageOperandsShift_ {
+ SpvImageOperandsBiasShift = 0,
+ SpvImageOperandsLodShift = 1,
+ SpvImageOperandsGradShift = 2,
+ SpvImageOperandsConstOffsetShift = 3,
+ SpvImageOperandsOffsetShift = 4,
+ SpvImageOperandsConstOffsetsShift = 5,
+ SpvImageOperandsSampleShift = 6,
+ SpvImageOperandsMinLodShift = 7,
+ SpvImageOperandsMakeTexelAvailableShift = 8,
+ SpvImageOperandsMakeTexelAvailableKHRShift = 8,
+ SpvImageOperandsMakeTexelVisibleShift = 9,
+ SpvImageOperandsMakeTexelVisibleKHRShift = 9,
+ SpvImageOperandsNonPrivateTexelShift = 10,
+ SpvImageOperandsNonPrivateTexelKHRShift = 10,
+ SpvImageOperandsVolatileTexelShift = 11,
+ SpvImageOperandsVolatileTexelKHRShift = 11,
+ SpvImageOperandsSignExtendShift = 12,
+ SpvImageOperandsZeroExtendShift = 13,
+ SpvImageOperandsNontemporalShift = 14,
+ SpvImageOperandsOffsetsShift = 16,
+ SpvImageOperandsMax = 0x7fffffff,
+} SpvImageOperandsShift;
+
+typedef enum SpvImageOperandsMask_ {
+ SpvImageOperandsMaskNone = 0,
+ SpvImageOperandsBiasMask = 0x00000001,
+ SpvImageOperandsLodMask = 0x00000002,
+ SpvImageOperandsGradMask = 0x00000004,
+ SpvImageOperandsConstOffsetMask = 0x00000008,
+ SpvImageOperandsOffsetMask = 0x00000010,
+ SpvImageOperandsConstOffsetsMask = 0x00000020,
+ SpvImageOperandsSampleMask = 0x00000040,
+ SpvImageOperandsMinLodMask = 0x00000080,
+ SpvImageOperandsMakeTexelAvailableMask = 0x00000100,
+ SpvImageOperandsMakeTexelAvailableKHRMask = 0x00000100,
+ SpvImageOperandsMakeTexelVisibleMask = 0x00000200,
+ SpvImageOperandsMakeTexelVisibleKHRMask = 0x00000200,
+ SpvImageOperandsNonPrivateTexelMask = 0x00000400,
+ SpvImageOperandsNonPrivateTexelKHRMask = 0x00000400,
+ SpvImageOperandsVolatileTexelMask = 0x00000800,
+ SpvImageOperandsVolatileTexelKHRMask = 0x00000800,
+ SpvImageOperandsSignExtendMask = 0x00001000,
+ SpvImageOperandsZeroExtendMask = 0x00002000,
+ SpvImageOperandsNontemporalMask = 0x00004000,
+ SpvImageOperandsOffsetsMask = 0x00010000,
+} SpvImageOperandsMask;
+
+typedef enum SpvFPFastMathModeShift_ {
+ SpvFPFastMathModeNotNaNShift = 0,
+ SpvFPFastMathModeNotInfShift = 1,
+ SpvFPFastMathModeNSZShift = 2,
+ SpvFPFastMathModeAllowRecipShift = 3,
+ SpvFPFastMathModeFastShift = 4,
+ SpvFPFastMathModeAllowContractFastINTELShift = 16,
+ SpvFPFastMathModeAllowReassocINTELShift = 17,
+ SpvFPFastMathModeMax = 0x7fffffff,
+} SpvFPFastMathModeShift;
+
+typedef enum SpvFPFastMathModeMask_ {
+ SpvFPFastMathModeMaskNone = 0,
+ SpvFPFastMathModeNotNaNMask = 0x00000001,
+ SpvFPFastMathModeNotInfMask = 0x00000002,
+ SpvFPFastMathModeNSZMask = 0x00000004,
+ SpvFPFastMathModeAllowRecipMask = 0x00000008,
+ SpvFPFastMathModeFastMask = 0x00000010,
+ SpvFPFastMathModeAllowContractFastINTELMask = 0x00010000,
+ SpvFPFastMathModeAllowReassocINTELMask = 0x00020000,
+} SpvFPFastMathModeMask;
+
+typedef enum SpvFPRoundingMode_ {
+ SpvFPRoundingModeRTE = 0,
+ SpvFPRoundingModeRTZ = 1,
+ SpvFPRoundingModeRTP = 2,
+ SpvFPRoundingModeRTN = 3,
+ SpvFPRoundingModeMax = 0x7fffffff,
+} SpvFPRoundingMode;
+
+typedef enum SpvLinkageType_ {
+ SpvLinkageTypeExport = 0,
+ SpvLinkageTypeImport = 1,
+ SpvLinkageTypeLinkOnceODR = 2,
+ 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,
+ SpvFunctionParameterAttributeRuntimeAlignedINTEL = 5940,
+ 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,
+ SpvDecorationUniformId = 27,
+ 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,
+ SpvDecorationNoSignedWrap = 4469,
+ SpvDecorationNoUnsignedWrap = 4470,
+ SpvDecorationWeightTextureQCOM = 4487,
+ SpvDecorationBlockMatchTextureQCOM = 4488,
+ SpvDecorationExplicitInterpAMD = 4999,
+ SpvDecorationOverrideCoverageNV = 5248,
+ SpvDecorationPassthroughNV = 5250,
+ SpvDecorationViewportRelativeNV = 5252,
+ SpvDecorationSecondaryViewportRelativeNV = 5256,
+ SpvDecorationPerPrimitiveEXT = 5271,
+ SpvDecorationPerPrimitiveNV = 5271,
+ SpvDecorationPerViewNV = 5272,
+ SpvDecorationPerTaskNV = 5273,
+ SpvDecorationPerVertexKHR = 5285,
+ SpvDecorationPerVertexNV = 5285,
+ SpvDecorationNonUniform = 5300,
+ SpvDecorationNonUniformEXT = 5300,
+ SpvDecorationRestrictPointer = 5355,
+ SpvDecorationRestrictPointerEXT = 5355,
+ SpvDecorationAliasedPointer = 5356,
+ SpvDecorationAliasedPointerEXT = 5356,
+ SpvDecorationHitObjectShaderRecordBufferNV = 5386,
+ SpvDecorationBindlessSamplerNV = 5398,
+ SpvDecorationBindlessImageNV = 5399,
+ SpvDecorationBoundSamplerNV = 5400,
+ SpvDecorationBoundImageNV = 5401,
+ SpvDecorationSIMTCallINTEL = 5599,
+ SpvDecorationReferencedIndirectlyINTEL = 5602,
+ SpvDecorationClobberINTEL = 5607,
+ SpvDecorationSideEffectsINTEL = 5608,
+ SpvDecorationVectorComputeVariableINTEL = 5624,
+ SpvDecorationFuncParamIOKindINTEL = 5625,
+ SpvDecorationVectorComputeFunctionINTEL = 5626,
+ SpvDecorationStackCallINTEL = 5627,
+ SpvDecorationGlobalVariableOffsetINTEL = 5628,
+ SpvDecorationCounterBuffer = 5634,
+ SpvDecorationHlslCounterBufferGOOGLE = 5634,
+ SpvDecorationHlslSemanticGOOGLE = 5635,
+ SpvDecorationUserSemantic = 5635,
+ SpvDecorationUserTypeGOOGLE = 5636,
+ SpvDecorationFunctionRoundingModeINTEL = 5822,
+ SpvDecorationFunctionDenormModeINTEL = 5823,
+ SpvDecorationRegisterINTEL = 5825,
+ SpvDecorationMemoryINTEL = 5826,
+ SpvDecorationNumbanksINTEL = 5827,
+ SpvDecorationBankwidthINTEL = 5828,
+ SpvDecorationMaxPrivateCopiesINTEL = 5829,
+ SpvDecorationSinglepumpINTEL = 5830,
+ SpvDecorationDoublepumpINTEL = 5831,
+ SpvDecorationMaxReplicatesINTEL = 5832,
+ SpvDecorationSimpleDualPortINTEL = 5833,
+ SpvDecorationMergeINTEL = 5834,
+ SpvDecorationBankBitsINTEL = 5835,
+ SpvDecorationForcePow2DepthINTEL = 5836,
+ SpvDecorationBurstCoalesceINTEL = 5899,
+ SpvDecorationCacheSizeINTEL = 5900,
+ SpvDecorationDontStaticallyCoalesceINTEL = 5901,
+ SpvDecorationPrefetchINTEL = 5902,
+ SpvDecorationStallEnableINTEL = 5905,
+ SpvDecorationFuseLoopsInFunctionINTEL = 5907,
+ SpvDecorationMathOpDSPModeINTEL = 5909,
+ SpvDecorationAliasScopeINTEL = 5914,
+ SpvDecorationNoAliasINTEL = 5915,
+ SpvDecorationInitiationIntervalINTEL = 5917,
+ SpvDecorationMaxConcurrencyINTEL = 5918,
+ SpvDecorationPipelineEnableINTEL = 5919,
+ SpvDecorationBufferLocationINTEL = 5921,
+ SpvDecorationIOPipeStorageINTEL = 5944,
+ SpvDecorationFunctionFloatingPointModeINTEL = 6080,
+ SpvDecorationSingleElementVectorINTEL = 6085,
+ SpvDecorationVectorComputeCallableFunctionINTEL = 6087,
+ SpvDecorationMediaBlockIOINTEL = 6140,
+ SpvDecorationLatencyControlLabelINTEL = 6172,
+ SpvDecorationLatencyControlConstraintINTEL = 6173,
+ SpvDecorationConduitKernelArgumentINTEL = 6175,
+ SpvDecorationRegisterMapKernelArgumentINTEL = 6176,
+ SpvDecorationMMHostInterfaceAddressWidthINTEL = 6177,
+ SpvDecorationMMHostInterfaceDataWidthINTEL = 6178,
+ SpvDecorationMMHostInterfaceLatencyINTEL = 6179,
+ SpvDecorationMMHostInterfaceReadWriteModeINTEL = 6180,
+ SpvDecorationMMHostInterfaceMaxBurstINTEL = 6181,
+ SpvDecorationMMHostInterfaceWaitRequestINTEL = 6182,
+ SpvDecorationStableKernelArgumentINTEL = 6183,
+ 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,
+ SpvBuiltInCoreIDARM = 4160,
+ SpvBuiltInCoreCountARM = 4161,
+ SpvBuiltInCoreMaxIDARM = 4162,
+ SpvBuiltInWarpIDARM = 4163,
+ SpvBuiltInWarpMaxIDARM = 4164,
+ 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,
+ SpvBuiltInPrimitiveShadingRateKHR = 4432,
+ SpvBuiltInDeviceIndex = 4438,
+ SpvBuiltInViewIndex = 4440,
+ SpvBuiltInShadingRateKHR = 4444,
+ 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,
+ SpvBuiltInTaskCountNV = 5274,
+ SpvBuiltInPrimitiveCountNV = 5275,
+ SpvBuiltInPrimitiveIndicesNV = 5276,
+ SpvBuiltInClipDistancePerViewNV = 5277,
+ SpvBuiltInCullDistancePerViewNV = 5278,
+ SpvBuiltInLayerPerViewNV = 5279,
+ SpvBuiltInMeshViewCountNV = 5280,
+ SpvBuiltInMeshViewIndicesNV = 5281,
+ SpvBuiltInBaryCoordKHR = 5286,
+ SpvBuiltInBaryCoordNV = 5286,
+ SpvBuiltInBaryCoordNoPerspKHR = 5287,
+ SpvBuiltInBaryCoordNoPerspNV = 5287,
+ SpvBuiltInFragSizeEXT = 5292,
+ SpvBuiltInFragmentSizeNV = 5292,
+ SpvBuiltInFragInvocationCountEXT = 5293,
+ SpvBuiltInInvocationsPerPixelNV = 5293,
+ SpvBuiltInPrimitivePointIndicesEXT = 5294,
+ SpvBuiltInPrimitiveLineIndicesEXT = 5295,
+ SpvBuiltInPrimitiveTriangleIndicesEXT = 5296,
+ SpvBuiltInCullPrimitiveEXT = 5299,
+ SpvBuiltInLaunchIdKHR = 5319,
+ SpvBuiltInLaunchIdNV = 5319,
+ SpvBuiltInLaunchSizeKHR = 5320,
+ SpvBuiltInLaunchSizeNV = 5320,
+ SpvBuiltInWorldRayOriginKHR = 5321,
+ SpvBuiltInWorldRayOriginNV = 5321,
+ SpvBuiltInWorldRayDirectionKHR = 5322,
+ SpvBuiltInWorldRayDirectionNV = 5322,
+ SpvBuiltInObjectRayOriginKHR = 5323,
+ SpvBuiltInObjectRayOriginNV = 5323,
+ SpvBuiltInObjectRayDirectionKHR = 5324,
+ SpvBuiltInObjectRayDirectionNV = 5324,
+ SpvBuiltInRayTminKHR = 5325,
+ SpvBuiltInRayTminNV = 5325,
+ SpvBuiltInRayTmaxKHR = 5326,
+ SpvBuiltInRayTmaxNV = 5326,
+ SpvBuiltInInstanceCustomIndexKHR = 5327,
+ SpvBuiltInInstanceCustomIndexNV = 5327,
+ SpvBuiltInObjectToWorldKHR = 5330,
+ SpvBuiltInObjectToWorldNV = 5330,
+ SpvBuiltInWorldToObjectKHR = 5331,
+ SpvBuiltInWorldToObjectNV = 5331,
+ SpvBuiltInHitTNV = 5332,
+ SpvBuiltInHitKindKHR = 5333,
+ SpvBuiltInHitKindNV = 5333,
+ SpvBuiltInCurrentRayTimeNV = 5334,
+ SpvBuiltInHitTriangleVertexPositionsKHR = 5335,
+ SpvBuiltInIncomingRayFlagsKHR = 5351,
+ SpvBuiltInIncomingRayFlagsNV = 5351,
+ SpvBuiltInRayGeometryIndexKHR = 5352,
+ SpvBuiltInWarpsPerSMNV = 5374,
+ SpvBuiltInSMCountNV = 5375,
+ SpvBuiltInWarpIDNV = 5376,
+ SpvBuiltInSMIDNV = 5377,
+ SpvBuiltInCullMaskKHR = 6021,
+ 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,
+ SpvLoopControlMinIterationsShift = 4,
+ SpvLoopControlMaxIterationsShift = 5,
+ SpvLoopControlIterationMultipleShift = 6,
+ SpvLoopControlPeelCountShift = 7,
+ SpvLoopControlPartialCountShift = 8,
+ SpvLoopControlInitiationIntervalINTELShift = 16,
+ SpvLoopControlMaxConcurrencyINTELShift = 17,
+ SpvLoopControlDependencyArrayINTELShift = 18,
+ SpvLoopControlPipelineEnableINTELShift = 19,
+ SpvLoopControlLoopCoalesceINTELShift = 20,
+ SpvLoopControlMaxInterleavingINTELShift = 21,
+ SpvLoopControlSpeculatedIterationsINTELShift = 22,
+ SpvLoopControlNoFusionINTELShift = 23,
+ SpvLoopControlLoopCountINTELShift = 24,
+ SpvLoopControlMaxReinvocationDelayINTELShift = 25,
+ SpvLoopControlMax = 0x7fffffff,
+} SpvLoopControlShift;
+
+typedef enum SpvLoopControlMask_ {
+ SpvLoopControlMaskNone = 0,
+ SpvLoopControlUnrollMask = 0x00000001,
+ SpvLoopControlDontUnrollMask = 0x00000002,
+ SpvLoopControlDependencyInfiniteMask = 0x00000004,
+ SpvLoopControlDependencyLengthMask = 0x00000008,
+ SpvLoopControlMinIterationsMask = 0x00000010,
+ SpvLoopControlMaxIterationsMask = 0x00000020,
+ SpvLoopControlIterationMultipleMask = 0x00000040,
+ SpvLoopControlPeelCountMask = 0x00000080,
+ SpvLoopControlPartialCountMask = 0x00000100,
+ SpvLoopControlInitiationIntervalINTELMask = 0x00010000,
+ SpvLoopControlMaxConcurrencyINTELMask = 0x00020000,
+ SpvLoopControlDependencyArrayINTELMask = 0x00040000,
+ SpvLoopControlPipelineEnableINTELMask = 0x00080000,
+ SpvLoopControlLoopCoalesceINTELMask = 0x00100000,
+ SpvLoopControlMaxInterleavingINTELMask = 0x00200000,
+ SpvLoopControlSpeculatedIterationsINTELMask = 0x00400000,
+ SpvLoopControlNoFusionINTELMask = 0x00800000,
+ SpvLoopControlLoopCountINTELMask = 0x01000000,
+ SpvLoopControlMaxReinvocationDelayINTELMask = 0x02000000,
+} SpvLoopControlMask;
+
+typedef enum SpvFunctionControlShift_ {
+ SpvFunctionControlInlineShift = 0,
+ SpvFunctionControlDontInlineShift = 1,
+ SpvFunctionControlPureShift = 2,
+ SpvFunctionControlConstShift = 3,
+ SpvFunctionControlOptNoneINTELShift = 16,
+ SpvFunctionControlMax = 0x7fffffff,
+} SpvFunctionControlShift;
+
+typedef enum SpvFunctionControlMask_ {
+ SpvFunctionControlMaskNone = 0,
+ SpvFunctionControlInlineMask = 0x00000001,
+ SpvFunctionControlDontInlineMask = 0x00000002,
+ SpvFunctionControlPureMask = 0x00000004,
+ SpvFunctionControlConstMask = 0x00000008,
+ SpvFunctionControlOptNoneINTELMask = 0x00010000,
+} SpvFunctionControlMask;
+
+typedef enum SpvMemorySemanticsShift_ {
+ SpvMemorySemanticsAcquireShift = 1,
+ SpvMemorySemanticsReleaseShift = 2,
+ SpvMemorySemanticsAcquireReleaseShift = 3,
+ SpvMemorySemanticsSequentiallyConsistentShift = 4,
+ SpvMemorySemanticsUniformMemoryShift = 6,
+ SpvMemorySemanticsSubgroupMemoryShift = 7,
+ SpvMemorySemanticsWorkgroupMemoryShift = 8,
+ SpvMemorySemanticsCrossWorkgroupMemoryShift = 9,
+ SpvMemorySemanticsAtomicCounterMemoryShift = 10,
+ SpvMemorySemanticsImageMemoryShift = 11,
+ SpvMemorySemanticsOutputMemoryShift = 12,
+ SpvMemorySemanticsOutputMemoryKHRShift = 12,
+ SpvMemorySemanticsMakeAvailableShift = 13,
+ SpvMemorySemanticsMakeAvailableKHRShift = 13,
+ SpvMemorySemanticsMakeVisibleShift = 14,
+ SpvMemorySemanticsMakeVisibleKHRShift = 14,
+ SpvMemorySemanticsVolatileShift = 15,
+ 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,
+ SpvMemorySemanticsOutputMemoryMask = 0x00001000,
+ SpvMemorySemanticsOutputMemoryKHRMask = 0x00001000,
+ SpvMemorySemanticsMakeAvailableMask = 0x00002000,
+ SpvMemorySemanticsMakeAvailableKHRMask = 0x00002000,
+ SpvMemorySemanticsMakeVisibleMask = 0x00004000,
+ SpvMemorySemanticsMakeVisibleKHRMask = 0x00004000,
+ SpvMemorySemanticsVolatileMask = 0x00008000,
+} SpvMemorySemanticsMask;
+
+typedef enum SpvMemoryAccessShift_ {
+ SpvMemoryAccessVolatileShift = 0,
+ SpvMemoryAccessAlignedShift = 1,
+ SpvMemoryAccessNontemporalShift = 2,
+ SpvMemoryAccessMakePointerAvailableShift = 3,
+ SpvMemoryAccessMakePointerAvailableKHRShift = 3,
+ SpvMemoryAccessMakePointerVisibleShift = 4,
+ SpvMemoryAccessMakePointerVisibleKHRShift = 4,
+ SpvMemoryAccessNonPrivatePointerShift = 5,
+ SpvMemoryAccessNonPrivatePointerKHRShift = 5,
+ SpvMemoryAccessAliasScopeINTELMaskShift = 16,
+ SpvMemoryAccessNoAliasINTELMaskShift = 17,
+ SpvMemoryAccessMax = 0x7fffffff,
+} SpvMemoryAccessShift;
+
+typedef enum SpvMemoryAccessMask_ {
+ SpvMemoryAccessMaskNone = 0,
+ SpvMemoryAccessVolatileMask = 0x00000001,
+ SpvMemoryAccessAlignedMask = 0x00000002,
+ SpvMemoryAccessNontemporalMask = 0x00000004,
+ SpvMemoryAccessMakePointerAvailableMask = 0x00000008,
+ SpvMemoryAccessMakePointerAvailableKHRMask = 0x00000008,
+ SpvMemoryAccessMakePointerVisibleMask = 0x00000010,
+ SpvMemoryAccessMakePointerVisibleKHRMask = 0x00000010,
+ SpvMemoryAccessNonPrivatePointerMask = 0x00000020,
+ SpvMemoryAccessNonPrivatePointerKHRMask = 0x00000020,
+ SpvMemoryAccessAliasScopeINTELMaskMask = 0x00010000,
+ SpvMemoryAccessNoAliasINTELMaskMask = 0x00020000,
+} SpvMemoryAccessMask;
+
+typedef enum SpvScope_ {
+ SpvScopeCrossDevice = 0,
+ SpvScopeDevice = 1,
+ SpvScopeWorkgroup = 2,
+ SpvScopeSubgroup = 3,
+ SpvScopeInvocation = 4,
+ SpvScopeQueueFamily = 5,
+ SpvScopeQueueFamilyKHR = 5,
+ SpvScopeShaderCallKHR = 6,
+ 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,
+ SpvCapabilityShaderLayer = 69,
+ SpvCapabilityShaderViewportIndex = 70,
+ SpvCapabilityUniformDecoration = 71,
+ SpvCapabilityCoreBuiltinsARM = 4165,
+ SpvCapabilityTileImageColorReadAccessEXT = 4166,
+ SpvCapabilityTileImageDepthReadAccessEXT = 4167,
+ SpvCapabilityTileImageStencilReadAccessEXT = 4168,
+ SpvCapabilityFragmentShadingRateKHR = 4422,
+ SpvCapabilitySubgroupBallotKHR = 4423,
+ SpvCapabilityDrawParameters = 4427,
+ SpvCapabilityWorkgroupMemoryExplicitLayoutKHR = 4428,
+ SpvCapabilityWorkgroupMemoryExplicitLayout8BitAccessKHR = 4429,
+ SpvCapabilityWorkgroupMemoryExplicitLayout16BitAccessKHR = 4430,
+ 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,
+ SpvCapabilityStorageBuffer8BitAccess = 4448,
+ SpvCapabilityUniformAndStorageBuffer8BitAccess = 4449,
+ SpvCapabilityStoragePushConstant8 = 4450,
+ SpvCapabilityDenormPreserve = 4464,
+ SpvCapabilityDenormFlushToZero = 4465,
+ SpvCapabilitySignedZeroInfNanPreserve = 4466,
+ SpvCapabilityRoundingModeRTE = 4467,
+ SpvCapabilityRoundingModeRTZ = 4468,
+ SpvCapabilityRayQueryProvisionalKHR = 4471,
+ SpvCapabilityRayQueryKHR = 4472,
+ SpvCapabilityRayTraversalPrimitiveCullingKHR = 4478,
+ SpvCapabilityRayTracingKHR = 4479,
+ SpvCapabilityTextureSampleWeightedQCOM = 4484,
+ SpvCapabilityTextureBoxFilterQCOM = 4485,
+ SpvCapabilityTextureBlockMatchQCOM = 4486,
+ SpvCapabilityFloat16ImageAMD = 5008,
+ SpvCapabilityImageGatherBiasLodAMD = 5009,
+ SpvCapabilityFragmentMaskAMD = 5010,
+ SpvCapabilityStencilExportEXT = 5013,
+ SpvCapabilityImageReadWriteLodAMD = 5015,
+ SpvCapabilityInt64ImageEXT = 5016,
+ SpvCapabilityShaderClockKHR = 5055,
+ SpvCapabilitySampleMaskOverrideCoverageNV = 5249,
+ SpvCapabilityGeometryShaderPassthroughNV = 5251,
+ SpvCapabilityShaderViewportIndexLayerEXT = 5254,
+ SpvCapabilityShaderViewportIndexLayerNV = 5254,
+ SpvCapabilityShaderViewportMaskNV = 5255,
+ SpvCapabilityShaderStereoViewNV = 5259,
+ SpvCapabilityPerViewAttributesNV = 5260,
+ SpvCapabilityFragmentFullyCoveredEXT = 5265,
+ SpvCapabilityMeshShadingNV = 5266,
+ SpvCapabilityImageFootprintNV = 5282,
+ SpvCapabilityMeshShadingEXT = 5283,
+ SpvCapabilityFragmentBarycentricKHR = 5284,
+ SpvCapabilityFragmentBarycentricNV = 5284,
+ SpvCapabilityComputeDerivativeGroupQuadsNV = 5288,
+ SpvCapabilityFragmentDensityEXT = 5291,
+ SpvCapabilityShadingRateNV = 5291,
+ SpvCapabilityGroupNonUniformPartitionedNV = 5297,
+ SpvCapabilityShaderNonUniform = 5301,
+ SpvCapabilityShaderNonUniformEXT = 5301,
+ SpvCapabilityRuntimeDescriptorArray = 5302,
+ SpvCapabilityRuntimeDescriptorArrayEXT = 5302,
+ SpvCapabilityInputAttachmentArrayDynamicIndexing = 5303,
+ SpvCapabilityInputAttachmentArrayDynamicIndexingEXT = 5303,
+ SpvCapabilityUniformTexelBufferArrayDynamicIndexing = 5304,
+ SpvCapabilityUniformTexelBufferArrayDynamicIndexingEXT = 5304,
+ SpvCapabilityStorageTexelBufferArrayDynamicIndexing = 5305,
+ SpvCapabilityStorageTexelBufferArrayDynamicIndexingEXT = 5305,
+ SpvCapabilityUniformBufferArrayNonUniformIndexing = 5306,
+ SpvCapabilityUniformBufferArrayNonUniformIndexingEXT = 5306,
+ SpvCapabilitySampledImageArrayNonUniformIndexing = 5307,
+ SpvCapabilitySampledImageArrayNonUniformIndexingEXT = 5307,
+ SpvCapabilityStorageBufferArrayNonUniformIndexing = 5308,
+ SpvCapabilityStorageBufferArrayNonUniformIndexingEXT = 5308,
+ SpvCapabilityStorageImageArrayNonUniformIndexing = 5309,
+ SpvCapabilityStorageImageArrayNonUniformIndexingEXT = 5309,
+ SpvCapabilityInputAttachmentArrayNonUniformIndexing = 5310,
+ SpvCapabilityInputAttachmentArrayNonUniformIndexingEXT = 5310,
+ SpvCapabilityUniformTexelBufferArrayNonUniformIndexing = 5311,
+ SpvCapabilityUniformTexelBufferArrayNonUniformIndexingEXT = 5311,
+ SpvCapabilityStorageTexelBufferArrayNonUniformIndexing = 5312,
+ SpvCapabilityStorageTexelBufferArrayNonUniformIndexingEXT = 5312,
+ SpvCapabilityRayTracingPositionFetchKHR = 5336,
+ SpvCapabilityRayTracingNV = 5340,
+ SpvCapabilityRayTracingMotionBlurNV = 5341,
+ SpvCapabilityVulkanMemoryModel = 5345,
+ SpvCapabilityVulkanMemoryModelKHR = 5345,
+ SpvCapabilityVulkanMemoryModelDeviceScope = 5346,
+ SpvCapabilityVulkanMemoryModelDeviceScopeKHR = 5346,
+ SpvCapabilityPhysicalStorageBufferAddresses = 5347,
+ SpvCapabilityPhysicalStorageBufferAddressesEXT = 5347,
+ SpvCapabilityComputeDerivativeGroupLinearNV = 5350,
+ SpvCapabilityRayTracingProvisionalKHR = 5353,
+ SpvCapabilityCooperativeMatrixNV = 5357,
+ SpvCapabilityFragmentShaderSampleInterlockEXT = 5363,
+ SpvCapabilityFragmentShaderShadingRateInterlockEXT = 5372,
+ SpvCapabilityShaderSMBuiltinsNV = 5373,
+ SpvCapabilityFragmentShaderPixelInterlockEXT = 5378,
+ SpvCapabilityDemoteToHelperInvocation = 5379,
+ SpvCapabilityDemoteToHelperInvocationEXT = 5379,
+ SpvCapabilityRayTracingOpacityMicromapEXT = 5381,
+ SpvCapabilityShaderInvocationReorderNV = 5383,
+ SpvCapabilityBindlessTextureNV = 5390,
+ SpvCapabilityRayQueryPositionFetchKHR = 5391,
+ SpvCapabilitySubgroupShuffleINTEL = 5568,
+ SpvCapabilitySubgroupBufferBlockIOINTEL = 5569,
+ SpvCapabilitySubgroupImageBlockIOINTEL = 5570,
+ SpvCapabilitySubgroupImageMediaBlockIOINTEL = 5579,
+ SpvCapabilityRoundToInfinityINTEL = 5582,
+ SpvCapabilityFloatingPointModeINTEL = 5583,
+ SpvCapabilityIntegerFunctions2INTEL = 5584,
+ SpvCapabilityFunctionPointersINTEL = 5603,
+ SpvCapabilityIndirectReferencesINTEL = 5604,
+ SpvCapabilityAsmINTEL = 5606,
+ SpvCapabilityAtomicFloat32MinMaxEXT = 5612,
+ SpvCapabilityAtomicFloat64MinMaxEXT = 5613,
+ SpvCapabilityAtomicFloat16MinMaxEXT = 5616,
+ SpvCapabilityVectorComputeINTEL = 5617,
+ SpvCapabilityVectorAnyINTEL = 5619,
+ SpvCapabilityExpectAssumeKHR = 5629,
+ SpvCapabilitySubgroupAvcMotionEstimationINTEL = 5696,
+ SpvCapabilitySubgroupAvcMotionEstimationIntraINTEL = 5697,
+ SpvCapabilitySubgroupAvcMotionEstimationChromaINTEL = 5698,
+ SpvCapabilityVariableLengthArrayINTEL = 5817,
+ SpvCapabilityFunctionFloatControlINTEL = 5821,
+ SpvCapabilityFPGAMemoryAttributesINTEL = 5824,
+ SpvCapabilityFPFastMathModeINTEL = 5837,
+ SpvCapabilityArbitraryPrecisionIntegersINTEL = 5844,
+ SpvCapabilityArbitraryPrecisionFloatingPointINTEL = 5845,
+ SpvCapabilityUnstructuredLoopControlsINTEL = 5886,
+ SpvCapabilityFPGALoopControlsINTEL = 5888,
+ SpvCapabilityKernelAttributesINTEL = 5892,
+ SpvCapabilityFPGAKernelAttributesINTEL = 5897,
+ SpvCapabilityFPGAMemoryAccessesINTEL = 5898,
+ SpvCapabilityFPGAClusterAttributesINTEL = 5904,
+ SpvCapabilityLoopFuseINTEL = 5906,
+ SpvCapabilityFPGADSPControlINTEL = 5908,
+ SpvCapabilityMemoryAccessAliasingINTEL = 5910,
+ SpvCapabilityFPGAInvocationPipeliningAttributesINTEL = 5916,
+ SpvCapabilityFPGABufferLocationINTEL = 5920,
+ SpvCapabilityArbitraryPrecisionFixedPointINTEL = 5922,
+ SpvCapabilityUSMStorageClassesINTEL = 5935,
+ SpvCapabilityRuntimeAlignedAttributeINTEL = 5939,
+ SpvCapabilityIOPipesINTEL = 5943,
+ SpvCapabilityBlockingPipesINTEL = 5945,
+ SpvCapabilityFPGARegINTEL = 5948,
+ SpvCapabilityDotProductInputAll = 6016,
+ SpvCapabilityDotProductInputAllKHR = 6016,
+ SpvCapabilityDotProductInput4x8Bit = 6017,
+ SpvCapabilityDotProductInput4x8BitKHR = 6017,
+ SpvCapabilityDotProductInput4x8BitPacked = 6018,
+ SpvCapabilityDotProductInput4x8BitPackedKHR = 6018,
+ SpvCapabilityDotProduct = 6019,
+ SpvCapabilityDotProductKHR = 6019,
+ SpvCapabilityRayCullMaskKHR = 6020,
+ SpvCapabilityCooperativeMatrixKHR = 6022,
+ SpvCapabilityBitInstructions = 6025,
+ SpvCapabilityGroupNonUniformRotateKHR = 6026,
+ SpvCapabilityAtomicFloat32AddEXT = 6033,
+ SpvCapabilityAtomicFloat64AddEXT = 6034,
+ SpvCapabilityLongConstantCompositeINTEL = 6089,
+ SpvCapabilityOptNoneINTEL = 6094,
+ SpvCapabilityAtomicFloat16AddEXT = 6095,
+ SpvCapabilityDebugInfoModuleINTEL = 6114,
+ SpvCapabilityBFloat16ConversionINTEL = 6115,
+ SpvCapabilitySplitBarrierINTEL = 6141,
+ SpvCapabilityFPGAKernelAttributesv2INTEL = 6161,
+ SpvCapabilityFPGALatencyControlINTEL = 6171,
+ SpvCapabilityFPGAArgumentInterfacesINTEL = 6174,
+ SpvCapabilityGroupUniformArithmeticKHR = 6400,
+ SpvCapabilityMax = 0x7fffffff,
+} SpvCapability;
+
+typedef enum SpvRayFlagsShift_ {
+ SpvRayFlagsOpaqueKHRShift = 0,
+ SpvRayFlagsNoOpaqueKHRShift = 1,
+ SpvRayFlagsTerminateOnFirstHitKHRShift = 2,
+ SpvRayFlagsSkipClosestHitShaderKHRShift = 3,
+ SpvRayFlagsCullBackFacingTrianglesKHRShift = 4,
+ SpvRayFlagsCullFrontFacingTrianglesKHRShift = 5,
+ SpvRayFlagsCullOpaqueKHRShift = 6,
+ SpvRayFlagsCullNoOpaqueKHRShift = 7,
+ SpvRayFlagsSkipTrianglesKHRShift = 8,
+ SpvRayFlagsSkipAABBsKHRShift = 9,
+ SpvRayFlagsForceOpacityMicromap2StateEXTShift = 10,
+ SpvRayFlagsMax = 0x7fffffff,
+} SpvRayFlagsShift;
+
+typedef enum SpvRayFlagsMask_ {
+ SpvRayFlagsMaskNone = 0,
+ SpvRayFlagsOpaqueKHRMask = 0x00000001,
+ SpvRayFlagsNoOpaqueKHRMask = 0x00000002,
+ SpvRayFlagsTerminateOnFirstHitKHRMask = 0x00000004,
+ SpvRayFlagsSkipClosestHitShaderKHRMask = 0x00000008,
+ SpvRayFlagsCullBackFacingTrianglesKHRMask = 0x00000010,
+ SpvRayFlagsCullFrontFacingTrianglesKHRMask = 0x00000020,
+ SpvRayFlagsCullOpaqueKHRMask = 0x00000040,
+ SpvRayFlagsCullNoOpaqueKHRMask = 0x00000080,
+ SpvRayFlagsSkipTrianglesKHRMask = 0x00000100,
+ SpvRayFlagsSkipAABBsKHRMask = 0x00000200,
+ SpvRayFlagsForceOpacityMicromap2StateEXTMask = 0x00000400,
+} SpvRayFlagsMask;
+
+typedef enum SpvRayQueryIntersection_ {
+ SpvRayQueryIntersectionRayQueryCandidateIntersectionKHR = 0,
+ SpvRayQueryIntersectionRayQueryCommittedIntersectionKHR = 1,
+ SpvRayQueryIntersectionMax = 0x7fffffff,
+} SpvRayQueryIntersection;
+
+typedef enum SpvRayQueryCommittedIntersectionType_ {
+ SpvRayQueryCommittedIntersectionTypeRayQueryCommittedIntersectionNoneKHR = 0,
+ SpvRayQueryCommittedIntersectionTypeRayQueryCommittedIntersectionTriangleKHR =
+ 1,
+ SpvRayQueryCommittedIntersectionTypeRayQueryCommittedIntersectionGeneratedKHR =
+ 2,
+ SpvRayQueryCommittedIntersectionTypeMax = 0x7fffffff,
+} SpvRayQueryCommittedIntersectionType;
+
+typedef enum SpvRayQueryCandidateIntersectionType_ {
+ SpvRayQueryCandidateIntersectionTypeRayQueryCandidateIntersectionTriangleKHR =
+ 0,
+ SpvRayQueryCandidateIntersectionTypeRayQueryCandidateIntersectionAABBKHR = 1,
+ SpvRayQueryCandidateIntersectionTypeMax = 0x7fffffff,
+} SpvRayQueryCandidateIntersectionType;
+
+typedef enum SpvFragmentShadingRateShift_ {
+ SpvFragmentShadingRateVertical2PixelsShift = 0,
+ SpvFragmentShadingRateVertical4PixelsShift = 1,
+ SpvFragmentShadingRateHorizontal2PixelsShift = 2,
+ SpvFragmentShadingRateHorizontal4PixelsShift = 3,
+ SpvFragmentShadingRateMax = 0x7fffffff,
+} SpvFragmentShadingRateShift;
+
+typedef enum SpvFragmentShadingRateMask_ {
+ SpvFragmentShadingRateMaskNone = 0,
+ SpvFragmentShadingRateVertical2PixelsMask = 0x00000001,
+ SpvFragmentShadingRateVertical4PixelsMask = 0x00000002,
+ SpvFragmentShadingRateHorizontal2PixelsMask = 0x00000004,
+ SpvFragmentShadingRateHorizontal4PixelsMask = 0x00000008,
+} SpvFragmentShadingRateMask;
+
+typedef enum SpvFPDenormMode_ {
+ SpvFPDenormModePreserve = 0,
+ SpvFPDenormModeFlushToZero = 1,
+ SpvFPDenormModeMax = 0x7fffffff,
+} SpvFPDenormMode;
+
+typedef enum SpvFPOperationMode_ {
+ SpvFPOperationModeIEEE = 0,
+ SpvFPOperationModeALT = 1,
+ SpvFPOperationModeMax = 0x7fffffff,
+} SpvFPOperationMode;
+
+typedef enum SpvQuantizationModes_ {
+ SpvQuantizationModesTRN = 0,
+ SpvQuantizationModesTRN_ZERO = 1,
+ SpvQuantizationModesRND = 2,
+ SpvQuantizationModesRND_ZERO = 3,
+ SpvQuantizationModesRND_INF = 4,
+ SpvQuantizationModesRND_MIN_INF = 5,
+ SpvQuantizationModesRND_CONV = 6,
+ SpvQuantizationModesRND_CONV_ODD = 7,
+ SpvQuantizationModesMax = 0x7fffffff,
+} SpvQuantizationModes;
+
+typedef enum SpvOverflowModes_ {
+ SpvOverflowModesWRAP = 0,
+ SpvOverflowModesSAT = 1,
+ SpvOverflowModesSAT_ZERO = 2,
+ SpvOverflowModesSAT_SYM = 3,
+ SpvOverflowModesMax = 0x7fffffff,
+} SpvOverflowModes;
+
+typedef enum SpvPackedVectorFormat_ {
+ SpvPackedVectorFormatPackedVectorFormat4x8Bit = 0,
+ SpvPackedVectorFormatPackedVectorFormat4x8BitKHR = 0,
+ SpvPackedVectorFormatMax = 0x7fffffff,
+} SpvPackedVectorFormat;
+
+typedef enum SpvCooperativeMatrixOperandsShift_ {
+ SpvCooperativeMatrixOperandsMatrixASignedComponentsShift = 0,
+ SpvCooperativeMatrixOperandsMatrixBSignedComponentsShift = 1,
+ SpvCooperativeMatrixOperandsMatrixCSignedComponentsShift = 2,
+ SpvCooperativeMatrixOperandsMatrixResultSignedComponentsShift = 3,
+ SpvCooperativeMatrixOperandsSaturatingAccumulationShift = 4,
+ SpvCooperativeMatrixOperandsMax = 0x7fffffff,
+} SpvCooperativeMatrixOperandsShift;
+
+typedef enum SpvCooperativeMatrixOperandsMask_ {
+ SpvCooperativeMatrixOperandsMaskNone = 0,
+ SpvCooperativeMatrixOperandsMatrixASignedComponentsMask = 0x00000001,
+ SpvCooperativeMatrixOperandsMatrixBSignedComponentsMask = 0x00000002,
+ SpvCooperativeMatrixOperandsMatrixCSignedComponentsMask = 0x00000004,
+ SpvCooperativeMatrixOperandsMatrixResultSignedComponentsMask = 0x00000008,
+ SpvCooperativeMatrixOperandsSaturatingAccumulationMask = 0x00000010,
+} SpvCooperativeMatrixOperandsMask;
+
+typedef enum SpvCooperativeMatrixLayout_ {
+ SpvCooperativeMatrixLayoutRowMajorKHR = 0,
+ SpvCooperativeMatrixLayoutColumnMajorKHR = 1,
+ SpvCooperativeMatrixLayoutMax = 0x7fffffff,
+} SpvCooperativeMatrixLayout;
+
+typedef enum SpvCooperativeMatrixUse_ {
+ SpvCooperativeMatrixUseMatrixAKHR = 0,
+ SpvCooperativeMatrixUseMatrixBKHR = 1,
+ SpvCooperativeMatrixUseMatrixAccumulatorKHR = 2,
+ SpvCooperativeMatrixUseMax = 0x7fffffff,
+} SpvCooperativeMatrixUse;
+
+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,
+ SpvOpCopyLogical = 400,
+ SpvOpPtrEqual = 401,
+ SpvOpPtrNotEqual = 402,
+ SpvOpPtrDiff = 403,
+ SpvOpColorAttachmentReadEXT = 4160,
+ SpvOpDepthAttachmentReadEXT = 4161,
+ SpvOpStencilAttachmentReadEXT = 4162,
+ SpvOpTerminateInvocation = 4416,
+ SpvOpSubgroupBallotKHR = 4421,
+ SpvOpSubgroupFirstInvocationKHR = 4422,
+ SpvOpSubgroupAllKHR = 4428,
+ SpvOpSubgroupAnyKHR = 4429,
+ SpvOpSubgroupAllEqualKHR = 4430,
+ SpvOpGroupNonUniformRotateKHR = 4431,
+ SpvOpSubgroupReadInvocationKHR = 4432,
+ SpvOpTraceRayKHR = 4445,
+ SpvOpExecuteCallableKHR = 4446,
+ SpvOpConvertUToAccelerationStructureKHR = 4447,
+ SpvOpIgnoreIntersectionKHR = 4448,
+ SpvOpTerminateRayKHR = 4449,
+ SpvOpSDot = 4450,
+ SpvOpSDotKHR = 4450,
+ SpvOpUDot = 4451,
+ SpvOpUDotKHR = 4451,
+ SpvOpSUDot = 4452,
+ SpvOpSUDotKHR = 4452,
+ SpvOpSDotAccSat = 4453,
+ SpvOpSDotAccSatKHR = 4453,
+ SpvOpUDotAccSat = 4454,
+ SpvOpUDotAccSatKHR = 4454,
+ SpvOpSUDotAccSat = 4455,
+ SpvOpSUDotAccSatKHR = 4455,
+ SpvOpTypeCooperativeMatrixKHR = 4456,
+ SpvOpCooperativeMatrixLoadKHR = 4457,
+ SpvOpCooperativeMatrixStoreKHR = 4458,
+ SpvOpCooperativeMatrixMulAddKHR = 4459,
+ SpvOpCooperativeMatrixLengthKHR = 4460,
+ SpvOpTypeRayQueryKHR = 4472,
+ SpvOpRayQueryInitializeKHR = 4473,
+ SpvOpRayQueryTerminateKHR = 4474,
+ SpvOpRayQueryGenerateIntersectionKHR = 4475,
+ SpvOpRayQueryConfirmIntersectionKHR = 4476,
+ SpvOpRayQueryProceedKHR = 4477,
+ SpvOpRayQueryGetIntersectionTypeKHR = 4479,
+ SpvOpImageSampleWeightedQCOM = 4480,
+ SpvOpImageBoxFilterQCOM = 4481,
+ SpvOpImageBlockMatchSSDQCOM = 4482,
+ SpvOpImageBlockMatchSADQCOM = 4483,
+ SpvOpGroupIAddNonUniformAMD = 5000,
+ SpvOpGroupFAddNonUniformAMD = 5001,
+ SpvOpGroupFMinNonUniformAMD = 5002,
+ SpvOpGroupUMinNonUniformAMD = 5003,
+ SpvOpGroupSMinNonUniformAMD = 5004,
+ SpvOpGroupFMaxNonUniformAMD = 5005,
+ SpvOpGroupUMaxNonUniformAMD = 5006,
+ SpvOpGroupSMaxNonUniformAMD = 5007,
+ SpvOpFragmentMaskFetchAMD = 5011,
+ SpvOpFragmentFetchAMD = 5012,
+ SpvOpReadClockKHR = 5056,
+ SpvOpHitObjectRecordHitMotionNV = 5249,
+ SpvOpHitObjectRecordHitWithIndexMotionNV = 5250,
+ SpvOpHitObjectRecordMissMotionNV = 5251,
+ SpvOpHitObjectGetWorldToObjectNV = 5252,
+ SpvOpHitObjectGetObjectToWorldNV = 5253,
+ SpvOpHitObjectGetObjectRayDirectionNV = 5254,
+ SpvOpHitObjectGetObjectRayOriginNV = 5255,
+ SpvOpHitObjectTraceRayMotionNV = 5256,
+ SpvOpHitObjectGetShaderRecordBufferHandleNV = 5257,
+ SpvOpHitObjectGetShaderBindingTableRecordIndexNV = 5258,
+ SpvOpHitObjectRecordEmptyNV = 5259,
+ SpvOpHitObjectTraceRayNV = 5260,
+ SpvOpHitObjectRecordHitNV = 5261,
+ SpvOpHitObjectRecordHitWithIndexNV = 5262,
+ SpvOpHitObjectRecordMissNV = 5263,
+ SpvOpHitObjectExecuteShaderNV = 5264,
+ SpvOpHitObjectGetCurrentTimeNV = 5265,
+ SpvOpHitObjectGetAttributesNV = 5266,
+ SpvOpHitObjectGetHitKindNV = 5267,
+ SpvOpHitObjectGetPrimitiveIndexNV = 5268,
+ SpvOpHitObjectGetGeometryIndexNV = 5269,
+ SpvOpHitObjectGetInstanceIdNV = 5270,
+ SpvOpHitObjectGetInstanceCustomIndexNV = 5271,
+ SpvOpHitObjectGetWorldRayDirectionNV = 5272,
+ SpvOpHitObjectGetWorldRayOriginNV = 5273,
+ SpvOpHitObjectGetRayTMaxNV = 5274,
+ SpvOpHitObjectGetRayTMinNV = 5275,
+ SpvOpHitObjectIsEmptyNV = 5276,
+ SpvOpHitObjectIsHitNV = 5277,
+ SpvOpHitObjectIsMissNV = 5278,
+ SpvOpReorderThreadWithHitObjectNV = 5279,
+ SpvOpReorderThreadWithHintNV = 5280,
+ SpvOpTypeHitObjectNV = 5281,
+ SpvOpImageSampleFootprintNV = 5283,
+ SpvOpEmitMeshTasksEXT = 5294,
+ SpvOpSetMeshOutputsEXT = 5295,
+ SpvOpGroupNonUniformPartitionNV = 5296,
+ SpvOpWritePackedPrimitiveIndices4x8NV = 5299,
+ SpvOpReportIntersectionKHR = 5334,
+ SpvOpReportIntersectionNV = 5334,
+ SpvOpIgnoreIntersectionNV = 5335,
+ SpvOpTerminateRayNV = 5336,
+ SpvOpTraceNV = 5337,
+ SpvOpTraceMotionNV = 5338,
+ SpvOpTraceRayMotionNV = 5339,
+ SpvOpRayQueryGetIntersectionTriangleVertexPositionsKHR = 5340,
+ SpvOpTypeAccelerationStructureKHR = 5341,
+ SpvOpTypeAccelerationStructureNV = 5341,
+ SpvOpExecuteCallableNV = 5344,
+ SpvOpTypeCooperativeMatrixNV = 5358,
+ SpvOpCooperativeMatrixLoadNV = 5359,
+ SpvOpCooperativeMatrixStoreNV = 5360,
+ SpvOpCooperativeMatrixMulAddNV = 5361,
+ SpvOpCooperativeMatrixLengthNV = 5362,
+ SpvOpBeginInvocationInterlockEXT = 5364,
+ SpvOpEndInvocationInterlockEXT = 5365,
+ SpvOpDemoteToHelperInvocation = 5380,
+ SpvOpDemoteToHelperInvocationEXT = 5380,
+ SpvOpIsHelperInvocationEXT = 5381,
+ SpvOpConvertUToImageNV = 5391,
+ SpvOpConvertUToSamplerNV = 5392,
+ SpvOpConvertImageToUNV = 5393,
+ SpvOpConvertSamplerToUNV = 5394,
+ SpvOpConvertUToSampledImageNV = 5395,
+ SpvOpConvertSampledImageToUNV = 5396,
+ SpvOpSamplerImageAddressingModeNV = 5397,
+ SpvOpSubgroupShuffleINTEL = 5571,
+ SpvOpSubgroupShuffleDownINTEL = 5572,
+ SpvOpSubgroupShuffleUpINTEL = 5573,
+ SpvOpSubgroupShuffleXorINTEL = 5574,
+ SpvOpSubgroupBlockReadINTEL = 5575,
+ SpvOpSubgroupBlockWriteINTEL = 5576,
+ SpvOpSubgroupImageBlockReadINTEL = 5577,
+ SpvOpSubgroupImageBlockWriteINTEL = 5578,
+ SpvOpSubgroupImageMediaBlockReadINTEL = 5580,
+ SpvOpSubgroupImageMediaBlockWriteINTEL = 5581,
+ SpvOpUCountLeadingZerosINTEL = 5585,
+ SpvOpUCountTrailingZerosINTEL = 5586,
+ SpvOpAbsISubINTEL = 5587,
+ SpvOpAbsUSubINTEL = 5588,
+ SpvOpIAddSatINTEL = 5589,
+ SpvOpUAddSatINTEL = 5590,
+ SpvOpIAverageINTEL = 5591,
+ SpvOpUAverageINTEL = 5592,
+ SpvOpIAverageRoundedINTEL = 5593,
+ SpvOpUAverageRoundedINTEL = 5594,
+ SpvOpISubSatINTEL = 5595,
+ SpvOpUSubSatINTEL = 5596,
+ SpvOpIMul32x16INTEL = 5597,
+ SpvOpUMul32x16INTEL = 5598,
+ SpvOpConstantFunctionPointerINTEL = 5600,
+ SpvOpFunctionPointerCallINTEL = 5601,
+ SpvOpAsmTargetINTEL = 5609,
+ SpvOpAsmINTEL = 5610,
+ SpvOpAsmCallINTEL = 5611,
+ SpvOpAtomicFMinEXT = 5614,
+ SpvOpAtomicFMaxEXT = 5615,
+ SpvOpAssumeTrueKHR = 5630,
+ SpvOpExpectKHR = 5631,
+ SpvOpDecorateString = 5632,
+ SpvOpDecorateStringGOOGLE = 5632,
+ SpvOpMemberDecorateString = 5633,
+ SpvOpMemberDecorateStringGOOGLE = 5633,
+ SpvOpVmeImageINTEL = 5699,
+ SpvOpTypeVmeImageINTEL = 5700,
+ SpvOpTypeAvcImePayloadINTEL = 5701,
+ SpvOpTypeAvcRefPayloadINTEL = 5702,
+ SpvOpTypeAvcSicPayloadINTEL = 5703,
+ SpvOpTypeAvcMcePayloadINTEL = 5704,
+ SpvOpTypeAvcMceResultINTEL = 5705,
+ SpvOpTypeAvcImeResultINTEL = 5706,
+ SpvOpTypeAvcImeResultSingleReferenceStreamoutINTEL = 5707,
+ SpvOpTypeAvcImeResultDualReferenceStreamoutINTEL = 5708,
+ SpvOpTypeAvcImeSingleReferenceStreaminINTEL = 5709,
+ SpvOpTypeAvcImeDualReferenceStreaminINTEL = 5710,
+ SpvOpTypeAvcRefResultINTEL = 5711,
+ SpvOpTypeAvcSicResultINTEL = 5712,
+ SpvOpSubgroupAvcMceGetDefaultInterBaseMultiReferencePenaltyINTEL = 5713,
+ SpvOpSubgroupAvcMceSetInterBaseMultiReferencePenaltyINTEL = 5714,
+ SpvOpSubgroupAvcMceGetDefaultInterShapePenaltyINTEL = 5715,
+ SpvOpSubgroupAvcMceSetInterShapePenaltyINTEL = 5716,
+ SpvOpSubgroupAvcMceGetDefaultInterDirectionPenaltyINTEL = 5717,
+ SpvOpSubgroupAvcMceSetInterDirectionPenaltyINTEL = 5718,
+ SpvOpSubgroupAvcMceGetDefaultIntraLumaShapePenaltyINTEL = 5719,
+ SpvOpSubgroupAvcMceGetDefaultInterMotionVectorCostTableINTEL = 5720,
+ SpvOpSubgroupAvcMceGetDefaultHighPenaltyCostTableINTEL = 5721,
+ SpvOpSubgroupAvcMceGetDefaultMediumPenaltyCostTableINTEL = 5722,
+ SpvOpSubgroupAvcMceGetDefaultLowPenaltyCostTableINTEL = 5723,
+ SpvOpSubgroupAvcMceSetMotionVectorCostFunctionINTEL = 5724,
+ SpvOpSubgroupAvcMceGetDefaultIntraLumaModePenaltyINTEL = 5725,
+ SpvOpSubgroupAvcMceGetDefaultNonDcLumaIntraPenaltyINTEL = 5726,
+ SpvOpSubgroupAvcMceGetDefaultIntraChromaModeBasePenaltyINTEL = 5727,
+ SpvOpSubgroupAvcMceSetAcOnlyHaarINTEL = 5728,
+ SpvOpSubgroupAvcMceSetSourceInterlacedFieldPolarityINTEL = 5729,
+ SpvOpSubgroupAvcMceSetSingleReferenceInterlacedFieldPolarityINTEL = 5730,
+ SpvOpSubgroupAvcMceSetDualReferenceInterlacedFieldPolaritiesINTEL = 5731,
+ SpvOpSubgroupAvcMceConvertToImePayloadINTEL = 5732,
+ SpvOpSubgroupAvcMceConvertToImeResultINTEL = 5733,
+ SpvOpSubgroupAvcMceConvertToRefPayloadINTEL = 5734,
+ SpvOpSubgroupAvcMceConvertToRefResultINTEL = 5735,
+ SpvOpSubgroupAvcMceConvertToSicPayloadINTEL = 5736,
+ SpvOpSubgroupAvcMceConvertToSicResultINTEL = 5737,
+ SpvOpSubgroupAvcMceGetMotionVectorsINTEL = 5738,
+ SpvOpSubgroupAvcMceGetInterDistortionsINTEL = 5739,
+ SpvOpSubgroupAvcMceGetBestInterDistortionsINTEL = 5740,
+ SpvOpSubgroupAvcMceGetInterMajorShapeINTEL = 5741,
+ SpvOpSubgroupAvcMceGetInterMinorShapeINTEL = 5742,
+ SpvOpSubgroupAvcMceGetInterDirectionsINTEL = 5743,
+ SpvOpSubgroupAvcMceGetInterMotionVectorCountINTEL = 5744,
+ SpvOpSubgroupAvcMceGetInterReferenceIdsINTEL = 5745,
+ SpvOpSubgroupAvcMceGetInterReferenceInterlacedFieldPolaritiesINTEL = 5746,
+ SpvOpSubgroupAvcImeInitializeINTEL = 5747,
+ SpvOpSubgroupAvcImeSetSingleReferenceINTEL = 5748,
+ SpvOpSubgroupAvcImeSetDualReferenceINTEL = 5749,
+ SpvOpSubgroupAvcImeRefWindowSizeINTEL = 5750,
+ SpvOpSubgroupAvcImeAdjustRefOffsetINTEL = 5751,
+ SpvOpSubgroupAvcImeConvertToMcePayloadINTEL = 5752,
+ SpvOpSubgroupAvcImeSetMaxMotionVectorCountINTEL = 5753,
+ SpvOpSubgroupAvcImeSetUnidirectionalMixDisableINTEL = 5754,
+ SpvOpSubgroupAvcImeSetEarlySearchTerminationThresholdINTEL = 5755,
+ SpvOpSubgroupAvcImeSetWeightedSadINTEL = 5756,
+ SpvOpSubgroupAvcImeEvaluateWithSingleReferenceINTEL = 5757,
+ SpvOpSubgroupAvcImeEvaluateWithDualReferenceINTEL = 5758,
+ SpvOpSubgroupAvcImeEvaluateWithSingleReferenceStreaminINTEL = 5759,
+ SpvOpSubgroupAvcImeEvaluateWithDualReferenceStreaminINTEL = 5760,
+ SpvOpSubgroupAvcImeEvaluateWithSingleReferenceStreamoutINTEL = 5761,
+ SpvOpSubgroupAvcImeEvaluateWithDualReferenceStreamoutINTEL = 5762,
+ SpvOpSubgroupAvcImeEvaluateWithSingleReferenceStreaminoutINTEL = 5763,
+ SpvOpSubgroupAvcImeEvaluateWithDualReferenceStreaminoutINTEL = 5764,
+ SpvOpSubgroupAvcImeConvertToMceResultINTEL = 5765,
+ SpvOpSubgroupAvcImeGetSingleReferenceStreaminINTEL = 5766,
+ SpvOpSubgroupAvcImeGetDualReferenceStreaminINTEL = 5767,
+ SpvOpSubgroupAvcImeStripSingleReferenceStreamoutINTEL = 5768,
+ SpvOpSubgroupAvcImeStripDualReferenceStreamoutINTEL = 5769,
+ SpvOpSubgroupAvcImeGetStreamoutSingleReferenceMajorShapeMotionVectorsINTEL =
+ 5770,
+ SpvOpSubgroupAvcImeGetStreamoutSingleReferenceMajorShapeDistortionsINTEL =
+ 5771,
+ SpvOpSubgroupAvcImeGetStreamoutSingleReferenceMajorShapeReferenceIdsINTEL =
+ 5772,
+ SpvOpSubgroupAvcImeGetStreamoutDualReferenceMajorShapeMotionVectorsINTEL =
+ 5773,
+ SpvOpSubgroupAvcImeGetStreamoutDualReferenceMajorShapeDistortionsINTEL = 5774,
+ SpvOpSubgroupAvcImeGetStreamoutDualReferenceMajorShapeReferenceIdsINTEL =
+ 5775,
+ SpvOpSubgroupAvcImeGetBorderReachedINTEL = 5776,
+ SpvOpSubgroupAvcImeGetTruncatedSearchIndicationINTEL = 5777,
+ SpvOpSubgroupAvcImeGetUnidirectionalEarlySearchTerminationINTEL = 5778,
+ SpvOpSubgroupAvcImeGetWeightingPatternMinimumMotionVectorINTEL = 5779,
+ SpvOpSubgroupAvcImeGetWeightingPatternMinimumDistortionINTEL = 5780,
+ SpvOpSubgroupAvcFmeInitializeINTEL = 5781,
+ SpvOpSubgroupAvcBmeInitializeINTEL = 5782,
+ SpvOpSubgroupAvcRefConvertToMcePayloadINTEL = 5783,
+ SpvOpSubgroupAvcRefSetBidirectionalMixDisableINTEL = 5784,
+ SpvOpSubgroupAvcRefSetBilinearFilterEnableINTEL = 5785,
+ SpvOpSubgroupAvcRefEvaluateWithSingleReferenceINTEL = 5786,
+ SpvOpSubgroupAvcRefEvaluateWithDualReferenceINTEL = 5787,
+ SpvOpSubgroupAvcRefEvaluateWithMultiReferenceINTEL = 5788,
+ SpvOpSubgroupAvcRefEvaluateWithMultiReferenceInterlacedINTEL = 5789,
+ SpvOpSubgroupAvcRefConvertToMceResultINTEL = 5790,
+ SpvOpSubgroupAvcSicInitializeINTEL = 5791,
+ SpvOpSubgroupAvcSicConfigureSkcINTEL = 5792,
+ SpvOpSubgroupAvcSicConfigureIpeLumaINTEL = 5793,
+ SpvOpSubgroupAvcSicConfigureIpeLumaChromaINTEL = 5794,
+ SpvOpSubgroupAvcSicGetMotionVectorMaskINTEL = 5795,
+ SpvOpSubgroupAvcSicConvertToMcePayloadINTEL = 5796,
+ SpvOpSubgroupAvcSicSetIntraLumaShapePenaltyINTEL = 5797,
+ SpvOpSubgroupAvcSicSetIntraLumaModeCostFunctionINTEL = 5798,
+ SpvOpSubgroupAvcSicSetIntraChromaModeCostFunctionINTEL = 5799,
+ SpvOpSubgroupAvcSicSetBilinearFilterEnableINTEL = 5800,
+ SpvOpSubgroupAvcSicSetSkcForwardTransformEnableINTEL = 5801,
+ SpvOpSubgroupAvcSicSetBlockBasedRawSkipSadINTEL = 5802,
+ SpvOpSubgroupAvcSicEvaluateIpeINTEL = 5803,
+ SpvOpSubgroupAvcSicEvaluateWithSingleReferenceINTEL = 5804,
+ SpvOpSubgroupAvcSicEvaluateWithDualReferenceINTEL = 5805,
+ SpvOpSubgroupAvcSicEvaluateWithMultiReferenceINTEL = 5806,
+ SpvOpSubgroupAvcSicEvaluateWithMultiReferenceInterlacedINTEL = 5807,
+ SpvOpSubgroupAvcSicConvertToMceResultINTEL = 5808,
+ SpvOpSubgroupAvcSicGetIpeLumaShapeINTEL = 5809,
+ SpvOpSubgroupAvcSicGetBestIpeLumaDistortionINTEL = 5810,
+ SpvOpSubgroupAvcSicGetBestIpeChromaDistortionINTEL = 5811,
+ SpvOpSubgroupAvcSicGetPackedIpeLumaModesINTEL = 5812,
+ SpvOpSubgroupAvcSicGetIpeChromaModeINTEL = 5813,
+ SpvOpSubgroupAvcSicGetPackedSkcLumaCountThresholdINTEL = 5814,
+ SpvOpSubgroupAvcSicGetPackedSkcLumaSumThresholdINTEL = 5815,
+ SpvOpSubgroupAvcSicGetInterRawSadsINTEL = 5816,
+ SpvOpVariableLengthArrayINTEL = 5818,
+ SpvOpSaveMemoryINTEL = 5819,
+ SpvOpRestoreMemoryINTEL = 5820,
+ SpvOpArbitraryFloatSinCosPiINTEL = 5840,
+ SpvOpArbitraryFloatCastINTEL = 5841,
+ SpvOpArbitraryFloatCastFromIntINTEL = 5842,
+ SpvOpArbitraryFloatCastToIntINTEL = 5843,
+ SpvOpArbitraryFloatAddINTEL = 5846,
+ SpvOpArbitraryFloatSubINTEL = 5847,
+ SpvOpArbitraryFloatMulINTEL = 5848,
+ SpvOpArbitraryFloatDivINTEL = 5849,
+ SpvOpArbitraryFloatGTINTEL = 5850,
+ SpvOpArbitraryFloatGEINTEL = 5851,
+ SpvOpArbitraryFloatLTINTEL = 5852,
+ SpvOpArbitraryFloatLEINTEL = 5853,
+ SpvOpArbitraryFloatEQINTEL = 5854,
+ SpvOpArbitraryFloatRecipINTEL = 5855,
+ SpvOpArbitraryFloatRSqrtINTEL = 5856,
+ SpvOpArbitraryFloatCbrtINTEL = 5857,
+ SpvOpArbitraryFloatHypotINTEL = 5858,
+ SpvOpArbitraryFloatSqrtINTEL = 5859,
+ SpvOpArbitraryFloatLogINTEL = 5860,
+ SpvOpArbitraryFloatLog2INTEL = 5861,
+ SpvOpArbitraryFloatLog10INTEL = 5862,
+ SpvOpArbitraryFloatLog1pINTEL = 5863,
+ SpvOpArbitraryFloatExpINTEL = 5864,
+ SpvOpArbitraryFloatExp2INTEL = 5865,
+ SpvOpArbitraryFloatExp10INTEL = 5866,
+ SpvOpArbitraryFloatExpm1INTEL = 5867,
+ SpvOpArbitraryFloatSinINTEL = 5868,
+ SpvOpArbitraryFloatCosINTEL = 5869,
+ SpvOpArbitraryFloatSinCosINTEL = 5870,
+ SpvOpArbitraryFloatSinPiINTEL = 5871,
+ SpvOpArbitraryFloatCosPiINTEL = 5872,
+ SpvOpArbitraryFloatASinINTEL = 5873,
+ SpvOpArbitraryFloatASinPiINTEL = 5874,
+ SpvOpArbitraryFloatACosINTEL = 5875,
+ SpvOpArbitraryFloatACosPiINTEL = 5876,
+ SpvOpArbitraryFloatATanINTEL = 5877,
+ SpvOpArbitraryFloatATanPiINTEL = 5878,
+ SpvOpArbitraryFloatATan2INTEL = 5879,
+ SpvOpArbitraryFloatPowINTEL = 5880,
+ SpvOpArbitraryFloatPowRINTEL = 5881,
+ SpvOpArbitraryFloatPowNINTEL = 5882,
+ SpvOpLoopControlINTEL = 5887,
+ SpvOpAliasDomainDeclINTEL = 5911,
+ SpvOpAliasScopeDeclINTEL = 5912,
+ SpvOpAliasScopeListDeclINTEL = 5913,
+ SpvOpFixedSqrtINTEL = 5923,
+ SpvOpFixedRecipINTEL = 5924,
+ SpvOpFixedRsqrtINTEL = 5925,
+ SpvOpFixedSinINTEL = 5926,
+ SpvOpFixedCosINTEL = 5927,
+ SpvOpFixedSinCosINTEL = 5928,
+ SpvOpFixedSinPiINTEL = 5929,
+ SpvOpFixedCosPiINTEL = 5930,
+ SpvOpFixedSinCosPiINTEL = 5931,
+ SpvOpFixedLogINTEL = 5932,
+ SpvOpFixedExpINTEL = 5933,
+ SpvOpPtrCastToCrossWorkgroupINTEL = 5934,
+ SpvOpCrossWorkgroupCastToPtrINTEL = 5938,
+ SpvOpReadPipeBlockingINTEL = 5946,
+ SpvOpWritePipeBlockingINTEL = 5947,
+ SpvOpFPGARegINTEL = 5949,
+ SpvOpRayQueryGetRayTMinKHR = 6016,
+ SpvOpRayQueryGetRayFlagsKHR = 6017,
+ SpvOpRayQueryGetIntersectionTKHR = 6018,
+ SpvOpRayQueryGetIntersectionInstanceCustomIndexKHR = 6019,
+ SpvOpRayQueryGetIntersectionInstanceIdKHR = 6020,
+ SpvOpRayQueryGetIntersectionInstanceShaderBindingTableRecordOffsetKHR = 6021,
+ SpvOpRayQueryGetIntersectionGeometryIndexKHR = 6022,
+ SpvOpRayQueryGetIntersectionPrimitiveIndexKHR = 6023,
+ SpvOpRayQueryGetIntersectionBarycentricsKHR = 6024,
+ SpvOpRayQueryGetIntersectionFrontFaceKHR = 6025,
+ SpvOpRayQueryGetIntersectionCandidateAABBOpaqueKHR = 6026,
+ SpvOpRayQueryGetIntersectionObjectRayDirectionKHR = 6027,
+ SpvOpRayQueryGetIntersectionObjectRayOriginKHR = 6028,
+ SpvOpRayQueryGetWorldRayDirectionKHR = 6029,
+ SpvOpRayQueryGetWorldRayOriginKHR = 6030,
+ SpvOpRayQueryGetIntersectionObjectToWorldKHR = 6031,
+ SpvOpRayQueryGetIntersectionWorldToObjectKHR = 6032,
+ SpvOpAtomicFAddEXT = 6035,
+ SpvOpTypeBufferSurfaceINTEL = 6086,
+ SpvOpTypeStructContinuedINTEL = 6090,
+ SpvOpConstantCompositeContinuedINTEL = 6091,
+ SpvOpSpecConstantCompositeContinuedINTEL = 6092,
+ SpvOpConvertFToBF16INTEL = 6116,
+ SpvOpConvertBF16ToFINTEL = 6117,
+ SpvOpControlBarrierArriveINTEL = 6142,
+ SpvOpControlBarrierWaitINTEL = 6143,
+ SpvOpGroupIMulKHR = 6401,
+ SpvOpGroupFMulKHR = 6402,
+ SpvOpGroupBitwiseAndKHR = 6403,
+ SpvOpGroupBitwiseOrKHR = 6404,
+ SpvOpGroupBitwiseXorKHR = 6405,
+ SpvOpGroupLogicalAndKHR = 6406,
+ SpvOpGroupLogicalOrKHR = 6407,
+ SpvOpGroupLogicalXorKHR = 6408,
+ SpvOpMax = 0x7fffffff,
+} SpvOp;
+
+#ifdef SPV_ENABLE_UTILITY_CODE
+#ifndef __cplusplus
+#include <stdbool.h>
+#endif
+inline void SpvHasResultAndType(SpvOp opcode, bool* hasResult,
+ bool* hasResultType) {
+ *hasResult = *hasResultType = false;
+ switch (opcode) {
+ default: /* unknown opcode */
+ break;
+ case SpvOpNop:
+ *hasResult = false;
+ *hasResultType = false;
+ break;
+ case SpvOpUndef:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSourceContinued:
+ *hasResult = false;
+ *hasResultType = false;
+ break;
+ case SpvOpSource:
+ *hasResult = false;
+ *hasResultType = false;
+ break;
+ case SpvOpSourceExtension:
+ *hasResult = false;
+ *hasResultType = false;
+ break;
+ case SpvOpName:
+ *hasResult = false;
+ *hasResultType = false;
+ break;
+ case SpvOpMemberName:
+ *hasResult = false;
+ *hasResultType = false;
+ break;
+ case SpvOpString:
+ *hasResult = true;
+ *hasResultType = false;
+ break;
+ case SpvOpLine:
+ *hasResult = false;
+ *hasResultType = false;
+ break;
+ case SpvOpExtension:
+ *hasResult = false;
+ *hasResultType = false;
+ break;
+ case SpvOpExtInstImport:
+ *hasResult = true;
+ *hasResultType = false;
+ break;
+ case SpvOpExtInst:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpMemoryModel:
+ *hasResult = false;
+ *hasResultType = false;
+ break;
+ case SpvOpEntryPoint:
+ *hasResult = false;
+ *hasResultType = false;
+ break;
+ case SpvOpExecutionMode:
+ *hasResult = false;
+ *hasResultType = false;
+ break;
+ case SpvOpCapability:
+ *hasResult = false;
+ *hasResultType = false;
+ break;
+ case SpvOpTypeVoid:
+ *hasResult = true;
+ *hasResultType = false;
+ break;
+ case SpvOpTypeBool:
+ *hasResult = true;
+ *hasResultType = false;
+ break;
+ case SpvOpTypeInt:
+ *hasResult = true;
+ *hasResultType = false;
+ break;
+ case SpvOpTypeFloat:
+ *hasResult = true;
+ *hasResultType = false;
+ break;
+ case SpvOpTypeVector:
+ *hasResult = true;
+ *hasResultType = false;
+ break;
+ case SpvOpTypeMatrix:
+ *hasResult = true;
+ *hasResultType = false;
+ break;
+ case SpvOpTypeImage:
+ *hasResult = true;
+ *hasResultType = false;
+ break;
+ case SpvOpTypeSampler:
+ *hasResult = true;
+ *hasResultType = false;
+ break;
+ case SpvOpTypeSampledImage:
+ *hasResult = true;
+ *hasResultType = false;
+ break;
+ case SpvOpTypeArray:
+ *hasResult = true;
+ *hasResultType = false;
+ break;
+ case SpvOpTypeRuntimeArray:
+ *hasResult = true;
+ *hasResultType = false;
+ break;
+ case SpvOpTypeStruct:
+ *hasResult = true;
+ *hasResultType = false;
+ break;
+ case SpvOpTypeOpaque:
+ *hasResult = true;
+ *hasResultType = false;
+ break;
+ case SpvOpTypePointer:
+ *hasResult = true;
+ *hasResultType = false;
+ break;
+ case SpvOpTypeFunction:
+ *hasResult = true;
+ *hasResultType = false;
+ break;
+ case SpvOpTypeEvent:
+ *hasResult = true;
+ *hasResultType = false;
+ break;
+ case SpvOpTypeDeviceEvent:
+ *hasResult = true;
+ *hasResultType = false;
+ break;
+ case SpvOpTypeReserveId:
+ *hasResult = true;
+ *hasResultType = false;
+ break;
+ case SpvOpTypeQueue:
+ *hasResult = true;
+ *hasResultType = false;
+ break;
+ case SpvOpTypePipe:
+ *hasResult = true;
+ *hasResultType = false;
+ break;
+ case SpvOpTypeForwardPointer:
+ *hasResult = false;
+ *hasResultType = false;
+ break;
+ case SpvOpConstantTrue:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpConstantFalse:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpConstant:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpConstantComposite:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpConstantSampler:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpConstantNull:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSpecConstantTrue:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSpecConstantFalse:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSpecConstant:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSpecConstantComposite:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSpecConstantOp:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpFunction:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpFunctionParameter:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpFunctionEnd:
+ *hasResult = false;
+ *hasResultType = false;
+ break;
+ case SpvOpFunctionCall:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpVariable:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpImageTexelPointer:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpLoad:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpStore:
+ *hasResult = false;
+ *hasResultType = false;
+ break;
+ case SpvOpCopyMemory:
+ *hasResult = false;
+ *hasResultType = false;
+ break;
+ case SpvOpCopyMemorySized:
+ *hasResult = false;
+ *hasResultType = false;
+ break;
+ case SpvOpAccessChain:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpInBoundsAccessChain:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpPtrAccessChain:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpArrayLength:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpGenericPtrMemSemantics:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpInBoundsPtrAccessChain:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpDecorate:
+ *hasResult = false;
+ *hasResultType = false;
+ break;
+ case SpvOpMemberDecorate:
+ *hasResult = false;
+ *hasResultType = false;
+ break;
+ case SpvOpDecorationGroup:
+ *hasResult = true;
+ *hasResultType = false;
+ break;
+ case SpvOpGroupDecorate:
+ *hasResult = false;
+ *hasResultType = false;
+ break;
+ case SpvOpGroupMemberDecorate:
+ *hasResult = false;
+ *hasResultType = false;
+ break;
+ case SpvOpVectorExtractDynamic:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpVectorInsertDynamic:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpVectorShuffle:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpCompositeConstruct:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpCompositeExtract:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpCompositeInsert:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpCopyObject:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpTranspose:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSampledImage:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpImageSampleImplicitLod:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpImageSampleExplicitLod:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpImageSampleDrefImplicitLod:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpImageSampleDrefExplicitLod:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpImageSampleProjImplicitLod:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpImageSampleProjExplicitLod:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpImageSampleProjDrefImplicitLod:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpImageSampleProjDrefExplicitLod:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpImageFetch:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpImageGather:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpImageDrefGather:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpImageRead:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpImageWrite:
+ *hasResult = false;
+ *hasResultType = false;
+ break;
+ case SpvOpImage:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpImageQueryFormat:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpImageQueryOrder:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpImageQuerySizeLod:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpImageQuerySize:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpImageQueryLod:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpImageQueryLevels:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpImageQuerySamples:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpConvertFToU:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpConvertFToS:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpConvertSToF:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpConvertUToF:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpUConvert:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSConvert:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpFConvert:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpQuantizeToF16:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpConvertPtrToU:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSatConvertSToU:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSatConvertUToS:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpConvertUToPtr:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpPtrCastToGeneric:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpGenericCastToPtr:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpGenericCastToPtrExplicit:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpBitcast:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSNegate:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpFNegate:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpIAdd:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpFAdd:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpISub:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpFSub:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpIMul:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpFMul:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpUDiv:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSDiv:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpFDiv:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpUMod:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSRem:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSMod:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpFRem:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpFMod:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpVectorTimesScalar:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpMatrixTimesScalar:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpVectorTimesMatrix:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpMatrixTimesVector:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpMatrixTimesMatrix:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpOuterProduct:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpDot:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpIAddCarry:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpISubBorrow:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpUMulExtended:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSMulExtended:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpAny:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpAll:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpIsNan:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpIsInf:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpIsFinite:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpIsNormal:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSignBitSet:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpLessOrGreater:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpOrdered:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpUnordered:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpLogicalEqual:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpLogicalNotEqual:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpLogicalOr:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpLogicalAnd:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpLogicalNot:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSelect:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpIEqual:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpINotEqual:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpUGreaterThan:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSGreaterThan:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpUGreaterThanEqual:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSGreaterThanEqual:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpULessThan:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSLessThan:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpULessThanEqual:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSLessThanEqual:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpFOrdEqual:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpFUnordEqual:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpFOrdNotEqual:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpFUnordNotEqual:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpFOrdLessThan:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpFUnordLessThan:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpFOrdGreaterThan:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpFUnordGreaterThan:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpFOrdLessThanEqual:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpFUnordLessThanEqual:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpFOrdGreaterThanEqual:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpFUnordGreaterThanEqual:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpShiftRightLogical:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpShiftRightArithmetic:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpShiftLeftLogical:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpBitwiseOr:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpBitwiseXor:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpBitwiseAnd:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpNot:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpBitFieldInsert:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpBitFieldSExtract:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpBitFieldUExtract:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpBitReverse:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpBitCount:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpDPdx:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpDPdy:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpFwidth:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpDPdxFine:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpDPdyFine:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpFwidthFine:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpDPdxCoarse:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpDPdyCoarse:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpFwidthCoarse:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpEmitVertex:
+ *hasResult = false;
+ *hasResultType = false;
+ break;
+ case SpvOpEndPrimitive:
+ *hasResult = false;
+ *hasResultType = false;
+ break;
+ case SpvOpEmitStreamVertex:
+ *hasResult = false;
+ *hasResultType = false;
+ break;
+ case SpvOpEndStreamPrimitive:
+ *hasResult = false;
+ *hasResultType = false;
+ break;
+ case SpvOpControlBarrier:
+ *hasResult = false;
+ *hasResultType = false;
+ break;
+ case SpvOpMemoryBarrier:
+ *hasResult = false;
+ *hasResultType = false;
+ break;
+ case SpvOpAtomicLoad:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpAtomicStore:
+ *hasResult = false;
+ *hasResultType = false;
+ break;
+ case SpvOpAtomicExchange:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpAtomicCompareExchange:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpAtomicCompareExchangeWeak:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpAtomicIIncrement:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpAtomicIDecrement:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpAtomicIAdd:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpAtomicISub:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpAtomicSMin:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpAtomicUMin:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpAtomicSMax:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpAtomicUMax:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpAtomicAnd:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpAtomicOr:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpAtomicXor:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpPhi:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpLoopMerge:
+ *hasResult = false;
+ *hasResultType = false;
+ break;
+ case SpvOpSelectionMerge:
+ *hasResult = false;
+ *hasResultType = false;
+ break;
+ case SpvOpLabel:
+ *hasResult = true;
+ *hasResultType = false;
+ break;
+ case SpvOpBranch:
+ *hasResult = false;
+ *hasResultType = false;
+ break;
+ case SpvOpBranchConditional:
+ *hasResult = false;
+ *hasResultType = false;
+ break;
+ case SpvOpSwitch:
+ *hasResult = false;
+ *hasResultType = false;
+ break;
+ case SpvOpKill:
+ *hasResult = false;
+ *hasResultType = false;
+ break;
+ case SpvOpReturn:
+ *hasResult = false;
+ *hasResultType = false;
+ break;
+ case SpvOpReturnValue:
+ *hasResult = false;
+ *hasResultType = false;
+ break;
+ case SpvOpUnreachable:
+ *hasResult = false;
+ *hasResultType = false;
+ break;
+ case SpvOpLifetimeStart:
+ *hasResult = false;
+ *hasResultType = false;
+ break;
+ case SpvOpLifetimeStop:
+ *hasResult = false;
+ *hasResultType = false;
+ break;
+ case SpvOpGroupAsyncCopy:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpGroupWaitEvents:
+ *hasResult = false;
+ *hasResultType = false;
+ break;
+ case SpvOpGroupAll:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpGroupAny:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpGroupBroadcast:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpGroupIAdd:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpGroupFAdd:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpGroupFMin:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpGroupUMin:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpGroupSMin:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpGroupFMax:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpGroupUMax:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpGroupSMax:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpReadPipe:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpWritePipe:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpReservedReadPipe:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpReservedWritePipe:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpReserveReadPipePackets:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpReserveWritePipePackets:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpCommitReadPipe:
+ *hasResult = false;
+ *hasResultType = false;
+ break;
+ case SpvOpCommitWritePipe:
+ *hasResult = false;
+ *hasResultType = false;
+ break;
+ case SpvOpIsValidReserveId:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpGetNumPipePackets:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpGetMaxPipePackets:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpGroupReserveReadPipePackets:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpGroupReserveWritePipePackets:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpGroupCommitReadPipe:
+ *hasResult = false;
+ *hasResultType = false;
+ break;
+ case SpvOpGroupCommitWritePipe:
+ *hasResult = false;
+ *hasResultType = false;
+ break;
+ case SpvOpEnqueueMarker:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpEnqueueKernel:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpGetKernelNDrangeSubGroupCount:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpGetKernelNDrangeMaxSubGroupSize:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpGetKernelWorkGroupSize:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpGetKernelPreferredWorkGroupSizeMultiple:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpRetainEvent:
+ *hasResult = false;
+ *hasResultType = false;
+ break;
+ case SpvOpReleaseEvent:
+ *hasResult = false;
+ *hasResultType = false;
+ break;
+ case SpvOpCreateUserEvent:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpIsValidEvent:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSetUserEventStatus:
+ *hasResult = false;
+ *hasResultType = false;
+ break;
+ case SpvOpCaptureEventProfilingInfo:
+ *hasResult = false;
+ *hasResultType = false;
+ break;
+ case SpvOpGetDefaultQueue:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpBuildNDRange:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpImageSparseSampleImplicitLod:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpImageSparseSampleExplicitLod:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpImageSparseSampleDrefImplicitLod:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpImageSparseSampleDrefExplicitLod:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpImageSparseSampleProjImplicitLod:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpImageSparseSampleProjExplicitLod:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpImageSparseSampleProjDrefImplicitLod:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpImageSparseSampleProjDrefExplicitLod:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpImageSparseFetch:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpImageSparseGather:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpImageSparseDrefGather:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpImageSparseTexelsResident:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpNoLine:
+ *hasResult = false;
+ *hasResultType = false;
+ break;
+ case SpvOpAtomicFlagTestAndSet:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpAtomicFlagClear:
+ *hasResult = false;
+ *hasResultType = false;
+ break;
+ case SpvOpImageSparseRead:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSizeOf:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpTypePipeStorage:
+ *hasResult = true;
+ *hasResultType = false;
+ break;
+ case SpvOpConstantPipeStorage:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpCreatePipeFromPipeStorage:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpGetKernelLocalSizeForSubgroupCount:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpGetKernelMaxNumSubgroups:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpTypeNamedBarrier:
+ *hasResult = true;
+ *hasResultType = false;
+ break;
+ case SpvOpNamedBarrierInitialize:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpMemoryNamedBarrier:
+ *hasResult = false;
+ *hasResultType = false;
+ break;
+ case SpvOpModuleProcessed:
+ *hasResult = false;
+ *hasResultType = false;
+ break;
+ case SpvOpExecutionModeId:
+ *hasResult = false;
+ *hasResultType = false;
+ break;
+ case SpvOpDecorateId:
+ *hasResult = false;
+ *hasResultType = false;
+ break;
+ case SpvOpGroupNonUniformElect:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpGroupNonUniformAll:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpGroupNonUniformAny:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpGroupNonUniformAllEqual:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpGroupNonUniformBroadcast:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpGroupNonUniformBroadcastFirst:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpGroupNonUniformBallot:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpGroupNonUniformInverseBallot:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpGroupNonUniformBallotBitExtract:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpGroupNonUniformBallotBitCount:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpGroupNonUniformBallotFindLSB:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpGroupNonUniformBallotFindMSB:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpGroupNonUniformShuffle:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpGroupNonUniformShuffleXor:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpGroupNonUniformShuffleUp:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpGroupNonUniformShuffleDown:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpGroupNonUniformIAdd:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpGroupNonUniformFAdd:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpGroupNonUniformIMul:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpGroupNonUniformFMul:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpGroupNonUniformSMin:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpGroupNonUniformUMin:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpGroupNonUniformFMin:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpGroupNonUniformSMax:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpGroupNonUniformUMax:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpGroupNonUniformFMax:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpGroupNonUniformBitwiseAnd:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpGroupNonUniformBitwiseOr:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpGroupNonUniformBitwiseXor:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpGroupNonUniformLogicalAnd:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpGroupNonUniformLogicalOr:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpGroupNonUniformLogicalXor:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpGroupNonUniformQuadBroadcast:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpGroupNonUniformQuadSwap:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpCopyLogical:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpPtrEqual:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpPtrNotEqual:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpPtrDiff:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpColorAttachmentReadEXT:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpDepthAttachmentReadEXT:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpStencilAttachmentReadEXT:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpTerminateInvocation:
+ *hasResult = false;
+ *hasResultType = false;
+ break;
+ case SpvOpSubgroupBallotKHR:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSubgroupFirstInvocationKHR:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSubgroupAllKHR:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSubgroupAnyKHR:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSubgroupAllEqualKHR:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpGroupNonUniformRotateKHR:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSubgroupReadInvocationKHR:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpTraceRayKHR:
+ *hasResult = false;
+ *hasResultType = false;
+ break;
+ case SpvOpExecuteCallableKHR:
+ *hasResult = false;
+ *hasResultType = false;
+ break;
+ case SpvOpConvertUToAccelerationStructureKHR:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpIgnoreIntersectionKHR:
+ *hasResult = false;
+ *hasResultType = false;
+ break;
+ case SpvOpTerminateRayKHR:
+ *hasResult = false;
+ *hasResultType = false;
+ break;
+ case SpvOpSDot:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpUDot:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSUDot:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSDotAccSat:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpUDotAccSat:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSUDotAccSat:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpTypeCooperativeMatrixKHR:
+ *hasResult = true;
+ *hasResultType = false;
+ break;
+ case SpvOpCooperativeMatrixLoadKHR:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpCooperativeMatrixStoreKHR:
+ *hasResult = false;
+ *hasResultType = false;
+ break;
+ case SpvOpCooperativeMatrixMulAddKHR:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpCooperativeMatrixLengthKHR:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpTypeRayQueryKHR:
+ *hasResult = true;
+ *hasResultType = false;
+ break;
+ case SpvOpRayQueryInitializeKHR:
+ *hasResult = false;
+ *hasResultType = false;
+ break;
+ case SpvOpRayQueryTerminateKHR:
+ *hasResult = false;
+ *hasResultType = false;
+ break;
+ case SpvOpRayQueryGenerateIntersectionKHR:
+ *hasResult = false;
+ *hasResultType = false;
+ break;
+ case SpvOpRayQueryConfirmIntersectionKHR:
+ *hasResult = false;
+ *hasResultType = false;
+ break;
+ case SpvOpRayQueryProceedKHR:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpRayQueryGetIntersectionTypeKHR:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpImageSampleWeightedQCOM:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpImageBoxFilterQCOM:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpImageBlockMatchSSDQCOM:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpImageBlockMatchSADQCOM:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpGroupIAddNonUniformAMD:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpGroupFAddNonUniformAMD:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpGroupFMinNonUniformAMD:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpGroupUMinNonUniformAMD:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpGroupSMinNonUniformAMD:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpGroupFMaxNonUniformAMD:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpGroupUMaxNonUniformAMD:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpGroupSMaxNonUniformAMD:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpFragmentMaskFetchAMD:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpFragmentFetchAMD:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpReadClockKHR:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpHitObjectRecordHitMotionNV:
+ *hasResult = false;
+ *hasResultType = false;
+ break;
+ case SpvOpHitObjectRecordHitWithIndexMotionNV:
+ *hasResult = false;
+ *hasResultType = false;
+ break;
+ case SpvOpHitObjectRecordMissMotionNV:
+ *hasResult = false;
+ *hasResultType = false;
+ break;
+ case SpvOpHitObjectGetWorldToObjectNV:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpHitObjectGetObjectToWorldNV:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpHitObjectGetObjectRayDirectionNV:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpHitObjectGetObjectRayOriginNV:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpHitObjectTraceRayMotionNV:
+ *hasResult = false;
+ *hasResultType = false;
+ break;
+ case SpvOpHitObjectGetShaderRecordBufferHandleNV:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpHitObjectGetShaderBindingTableRecordIndexNV:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpHitObjectRecordEmptyNV:
+ *hasResult = false;
+ *hasResultType = false;
+ break;
+ case SpvOpHitObjectTraceRayNV:
+ *hasResult = false;
+ *hasResultType = false;
+ break;
+ case SpvOpHitObjectRecordHitNV:
+ *hasResult = false;
+ *hasResultType = false;
+ break;
+ case SpvOpHitObjectRecordHitWithIndexNV:
+ *hasResult = false;
+ *hasResultType = false;
+ break;
+ case SpvOpHitObjectRecordMissNV:
+ *hasResult = false;
+ *hasResultType = false;
+ break;
+ case SpvOpHitObjectExecuteShaderNV:
+ *hasResult = false;
+ *hasResultType = false;
+ break;
+ case SpvOpHitObjectGetCurrentTimeNV:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpHitObjectGetAttributesNV:
+ *hasResult = false;
+ *hasResultType = false;
+ break;
+ case SpvOpHitObjectGetHitKindNV:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpHitObjectGetPrimitiveIndexNV:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpHitObjectGetGeometryIndexNV:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpHitObjectGetInstanceIdNV:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpHitObjectGetInstanceCustomIndexNV:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpHitObjectGetWorldRayDirectionNV:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpHitObjectGetWorldRayOriginNV:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpHitObjectGetRayTMaxNV:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpHitObjectGetRayTMinNV:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpHitObjectIsEmptyNV:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpHitObjectIsHitNV:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpHitObjectIsMissNV:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpReorderThreadWithHitObjectNV:
+ *hasResult = false;
+ *hasResultType = false;
+ break;
+ case SpvOpReorderThreadWithHintNV:
+ *hasResult = false;
+ *hasResultType = false;
+ break;
+ case SpvOpTypeHitObjectNV:
+ *hasResult = true;
+ *hasResultType = false;
+ break;
+ case SpvOpImageSampleFootprintNV:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpEmitMeshTasksEXT:
+ *hasResult = false;
+ *hasResultType = false;
+ break;
+ case SpvOpSetMeshOutputsEXT:
+ *hasResult = false;
+ *hasResultType = false;
+ break;
+ case SpvOpGroupNonUniformPartitionNV:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpWritePackedPrimitiveIndices4x8NV:
+ *hasResult = false;
+ *hasResultType = false;
+ break;
+ case SpvOpReportIntersectionNV:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpIgnoreIntersectionNV:
+ *hasResult = false;
+ *hasResultType = false;
+ break;
+ case SpvOpTerminateRayNV:
+ *hasResult = false;
+ *hasResultType = false;
+ break;
+ case SpvOpTraceNV:
+ *hasResult = false;
+ *hasResultType = false;
+ break;
+ case SpvOpTraceMotionNV:
+ *hasResult = false;
+ *hasResultType = false;
+ break;
+ case SpvOpTraceRayMotionNV:
+ *hasResult = false;
+ *hasResultType = false;
+ break;
+ case SpvOpRayQueryGetIntersectionTriangleVertexPositionsKHR:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpTypeAccelerationStructureNV:
+ *hasResult = true;
+ *hasResultType = false;
+ break;
+ case SpvOpExecuteCallableNV:
+ *hasResult = false;
+ *hasResultType = false;
+ break;
+ case SpvOpTypeCooperativeMatrixNV:
+ *hasResult = true;
+ *hasResultType = false;
+ break;
+ case SpvOpCooperativeMatrixLoadNV:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpCooperativeMatrixStoreNV:
+ *hasResult = false;
+ *hasResultType = false;
+ break;
+ case SpvOpCooperativeMatrixMulAddNV:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpCooperativeMatrixLengthNV:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpBeginInvocationInterlockEXT:
+ *hasResult = false;
+ *hasResultType = false;
+ break;
+ case SpvOpEndInvocationInterlockEXT:
+ *hasResult = false;
+ *hasResultType = false;
+ break;
+ case SpvOpDemoteToHelperInvocation:
+ *hasResult = false;
+ *hasResultType = false;
+ break;
+ case SpvOpIsHelperInvocationEXT:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpConvertUToImageNV:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpConvertUToSamplerNV:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpConvertImageToUNV:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpConvertSamplerToUNV:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpConvertUToSampledImageNV:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpConvertSampledImageToUNV:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSamplerImageAddressingModeNV:
+ *hasResult = false;
+ *hasResultType = false;
+ break;
+ case SpvOpSubgroupShuffleINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSubgroupShuffleDownINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSubgroupShuffleUpINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSubgroupShuffleXorINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSubgroupBlockReadINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSubgroupBlockWriteINTEL:
+ *hasResult = false;
+ *hasResultType = false;
+ break;
+ case SpvOpSubgroupImageBlockReadINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSubgroupImageBlockWriteINTEL:
+ *hasResult = false;
+ *hasResultType = false;
+ break;
+ case SpvOpSubgroupImageMediaBlockReadINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSubgroupImageMediaBlockWriteINTEL:
+ *hasResult = false;
+ *hasResultType = false;
+ break;
+ case SpvOpUCountLeadingZerosINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpUCountTrailingZerosINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpAbsISubINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpAbsUSubINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpIAddSatINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpUAddSatINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpIAverageINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpUAverageINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpIAverageRoundedINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpUAverageRoundedINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpISubSatINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpUSubSatINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpIMul32x16INTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpUMul32x16INTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpConstantFunctionPointerINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpFunctionPointerCallINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpAsmTargetINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpAsmINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpAsmCallINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpAtomicFMinEXT:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpAtomicFMaxEXT:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpAssumeTrueKHR:
+ *hasResult = false;
+ *hasResultType = false;
+ break;
+ case SpvOpExpectKHR:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpDecorateString:
+ *hasResult = false;
+ *hasResultType = false;
+ break;
+ case SpvOpMemberDecorateString:
+ *hasResult = false;
+ *hasResultType = false;
+ break;
+ case SpvOpVmeImageINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpTypeVmeImageINTEL:
+ *hasResult = true;
+ *hasResultType = false;
+ break;
+ case SpvOpTypeAvcImePayloadINTEL:
+ *hasResult = true;
+ *hasResultType = false;
+ break;
+ case SpvOpTypeAvcRefPayloadINTEL:
+ *hasResult = true;
+ *hasResultType = false;
+ break;
+ case SpvOpTypeAvcSicPayloadINTEL:
+ *hasResult = true;
+ *hasResultType = false;
+ break;
+ case SpvOpTypeAvcMcePayloadINTEL:
+ *hasResult = true;
+ *hasResultType = false;
+ break;
+ case SpvOpTypeAvcMceResultINTEL:
+ *hasResult = true;
+ *hasResultType = false;
+ break;
+ case SpvOpTypeAvcImeResultINTEL:
+ *hasResult = true;
+ *hasResultType = false;
+ break;
+ case SpvOpTypeAvcImeResultSingleReferenceStreamoutINTEL:
+ *hasResult = true;
+ *hasResultType = false;
+ break;
+ case SpvOpTypeAvcImeResultDualReferenceStreamoutINTEL:
+ *hasResult = true;
+ *hasResultType = false;
+ break;
+ case SpvOpTypeAvcImeSingleReferenceStreaminINTEL:
+ *hasResult = true;
+ *hasResultType = false;
+ break;
+ case SpvOpTypeAvcImeDualReferenceStreaminINTEL:
+ *hasResult = true;
+ *hasResultType = false;
+ break;
+ case SpvOpTypeAvcRefResultINTEL:
+ *hasResult = true;
+ *hasResultType = false;
+ break;
+ case SpvOpTypeAvcSicResultINTEL:
+ *hasResult = true;
+ *hasResultType = false;
+ break;
+ case SpvOpSubgroupAvcMceGetDefaultInterBaseMultiReferencePenaltyINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSubgroupAvcMceSetInterBaseMultiReferencePenaltyINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSubgroupAvcMceGetDefaultInterShapePenaltyINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSubgroupAvcMceSetInterShapePenaltyINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSubgroupAvcMceGetDefaultInterDirectionPenaltyINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSubgroupAvcMceSetInterDirectionPenaltyINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSubgroupAvcMceGetDefaultIntraLumaShapePenaltyINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSubgroupAvcMceGetDefaultInterMotionVectorCostTableINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSubgroupAvcMceGetDefaultHighPenaltyCostTableINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSubgroupAvcMceGetDefaultMediumPenaltyCostTableINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSubgroupAvcMceGetDefaultLowPenaltyCostTableINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSubgroupAvcMceSetMotionVectorCostFunctionINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSubgroupAvcMceGetDefaultIntraLumaModePenaltyINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSubgroupAvcMceGetDefaultNonDcLumaIntraPenaltyINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSubgroupAvcMceGetDefaultIntraChromaModeBasePenaltyINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSubgroupAvcMceSetAcOnlyHaarINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSubgroupAvcMceSetSourceInterlacedFieldPolarityINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSubgroupAvcMceSetSingleReferenceInterlacedFieldPolarityINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSubgroupAvcMceSetDualReferenceInterlacedFieldPolaritiesINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSubgroupAvcMceConvertToImePayloadINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSubgroupAvcMceConvertToImeResultINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSubgroupAvcMceConvertToRefPayloadINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSubgroupAvcMceConvertToRefResultINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSubgroupAvcMceConvertToSicPayloadINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSubgroupAvcMceConvertToSicResultINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSubgroupAvcMceGetMotionVectorsINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSubgroupAvcMceGetInterDistortionsINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSubgroupAvcMceGetBestInterDistortionsINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSubgroupAvcMceGetInterMajorShapeINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSubgroupAvcMceGetInterMinorShapeINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSubgroupAvcMceGetInterDirectionsINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSubgroupAvcMceGetInterMotionVectorCountINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSubgroupAvcMceGetInterReferenceIdsINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSubgroupAvcMceGetInterReferenceInterlacedFieldPolaritiesINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSubgroupAvcImeInitializeINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSubgroupAvcImeSetSingleReferenceINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSubgroupAvcImeSetDualReferenceINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSubgroupAvcImeRefWindowSizeINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSubgroupAvcImeAdjustRefOffsetINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSubgroupAvcImeConvertToMcePayloadINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSubgroupAvcImeSetMaxMotionVectorCountINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSubgroupAvcImeSetUnidirectionalMixDisableINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSubgroupAvcImeSetEarlySearchTerminationThresholdINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSubgroupAvcImeSetWeightedSadINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSubgroupAvcImeEvaluateWithSingleReferenceINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSubgroupAvcImeEvaluateWithDualReferenceINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSubgroupAvcImeEvaluateWithSingleReferenceStreaminINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSubgroupAvcImeEvaluateWithDualReferenceStreaminINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSubgroupAvcImeEvaluateWithSingleReferenceStreamoutINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSubgroupAvcImeEvaluateWithDualReferenceStreamoutINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSubgroupAvcImeEvaluateWithSingleReferenceStreaminoutINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSubgroupAvcImeEvaluateWithDualReferenceStreaminoutINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSubgroupAvcImeConvertToMceResultINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSubgroupAvcImeGetSingleReferenceStreaminINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSubgroupAvcImeGetDualReferenceStreaminINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSubgroupAvcImeStripSingleReferenceStreamoutINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSubgroupAvcImeStripDualReferenceStreamoutINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSubgroupAvcImeGetStreamoutSingleReferenceMajorShapeMotionVectorsINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSubgroupAvcImeGetStreamoutSingleReferenceMajorShapeDistortionsINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSubgroupAvcImeGetStreamoutSingleReferenceMajorShapeReferenceIdsINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSubgroupAvcImeGetStreamoutDualReferenceMajorShapeMotionVectorsINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSubgroupAvcImeGetStreamoutDualReferenceMajorShapeDistortionsINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSubgroupAvcImeGetStreamoutDualReferenceMajorShapeReferenceIdsINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSubgroupAvcImeGetBorderReachedINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSubgroupAvcImeGetTruncatedSearchIndicationINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSubgroupAvcImeGetUnidirectionalEarlySearchTerminationINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSubgroupAvcImeGetWeightingPatternMinimumMotionVectorINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSubgroupAvcImeGetWeightingPatternMinimumDistortionINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSubgroupAvcFmeInitializeINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSubgroupAvcBmeInitializeINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSubgroupAvcRefConvertToMcePayloadINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSubgroupAvcRefSetBidirectionalMixDisableINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSubgroupAvcRefSetBilinearFilterEnableINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSubgroupAvcRefEvaluateWithSingleReferenceINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSubgroupAvcRefEvaluateWithDualReferenceINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSubgroupAvcRefEvaluateWithMultiReferenceINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSubgroupAvcRefEvaluateWithMultiReferenceInterlacedINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSubgroupAvcRefConvertToMceResultINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSubgroupAvcSicInitializeINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSubgroupAvcSicConfigureSkcINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSubgroupAvcSicConfigureIpeLumaINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSubgroupAvcSicConfigureIpeLumaChromaINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSubgroupAvcSicGetMotionVectorMaskINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSubgroupAvcSicConvertToMcePayloadINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSubgroupAvcSicSetIntraLumaShapePenaltyINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSubgroupAvcSicSetIntraLumaModeCostFunctionINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSubgroupAvcSicSetIntraChromaModeCostFunctionINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSubgroupAvcSicSetBilinearFilterEnableINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSubgroupAvcSicSetSkcForwardTransformEnableINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSubgroupAvcSicSetBlockBasedRawSkipSadINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSubgroupAvcSicEvaluateIpeINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSubgroupAvcSicEvaluateWithSingleReferenceINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSubgroupAvcSicEvaluateWithDualReferenceINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSubgroupAvcSicEvaluateWithMultiReferenceINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSubgroupAvcSicEvaluateWithMultiReferenceInterlacedINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSubgroupAvcSicConvertToMceResultINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSubgroupAvcSicGetIpeLumaShapeINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSubgroupAvcSicGetBestIpeLumaDistortionINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSubgroupAvcSicGetBestIpeChromaDistortionINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSubgroupAvcSicGetPackedIpeLumaModesINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSubgroupAvcSicGetIpeChromaModeINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSubgroupAvcSicGetPackedSkcLumaCountThresholdINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSubgroupAvcSicGetPackedSkcLumaSumThresholdINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSubgroupAvcSicGetInterRawSadsINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpVariableLengthArrayINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpSaveMemoryINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpRestoreMemoryINTEL:
+ *hasResult = false;
+ *hasResultType = false;
+ break;
+ case SpvOpArbitraryFloatSinCosPiINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpArbitraryFloatCastINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpArbitraryFloatCastFromIntINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpArbitraryFloatCastToIntINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpArbitraryFloatAddINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpArbitraryFloatSubINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpArbitraryFloatMulINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpArbitraryFloatDivINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpArbitraryFloatGTINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpArbitraryFloatGEINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpArbitraryFloatLTINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpArbitraryFloatLEINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpArbitraryFloatEQINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpArbitraryFloatRecipINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpArbitraryFloatRSqrtINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpArbitraryFloatCbrtINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpArbitraryFloatHypotINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpArbitraryFloatSqrtINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpArbitraryFloatLogINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpArbitraryFloatLog2INTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpArbitraryFloatLog10INTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpArbitraryFloatLog1pINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpArbitraryFloatExpINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpArbitraryFloatExp2INTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpArbitraryFloatExp10INTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpArbitraryFloatExpm1INTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpArbitraryFloatSinINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpArbitraryFloatCosINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpArbitraryFloatSinCosINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpArbitraryFloatSinPiINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpArbitraryFloatCosPiINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpArbitraryFloatASinINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpArbitraryFloatASinPiINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpArbitraryFloatACosINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpArbitraryFloatACosPiINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpArbitraryFloatATanINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpArbitraryFloatATanPiINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpArbitraryFloatATan2INTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpArbitraryFloatPowINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpArbitraryFloatPowRINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpArbitraryFloatPowNINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpLoopControlINTEL:
+ *hasResult = false;
+ *hasResultType = false;
+ break;
+ case SpvOpAliasDomainDeclINTEL:
+ *hasResult = true;
+ *hasResultType = false;
+ break;
+ case SpvOpAliasScopeDeclINTEL:
+ *hasResult = true;
+ *hasResultType = false;
+ break;
+ case SpvOpAliasScopeListDeclINTEL:
+ *hasResult = true;
+ *hasResultType = false;
+ break;
+ case SpvOpFixedSqrtINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpFixedRecipINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpFixedRsqrtINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpFixedSinINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpFixedCosINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpFixedSinCosINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpFixedSinPiINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpFixedCosPiINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpFixedSinCosPiINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpFixedLogINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpFixedExpINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpPtrCastToCrossWorkgroupINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpCrossWorkgroupCastToPtrINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpReadPipeBlockingINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpWritePipeBlockingINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpFPGARegINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpRayQueryGetRayTMinKHR:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpRayQueryGetRayFlagsKHR:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpRayQueryGetIntersectionTKHR:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpRayQueryGetIntersectionInstanceCustomIndexKHR:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpRayQueryGetIntersectionInstanceIdKHR:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpRayQueryGetIntersectionInstanceShaderBindingTableRecordOffsetKHR:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpRayQueryGetIntersectionGeometryIndexKHR:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpRayQueryGetIntersectionPrimitiveIndexKHR:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpRayQueryGetIntersectionBarycentricsKHR:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpRayQueryGetIntersectionFrontFaceKHR:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpRayQueryGetIntersectionCandidateAABBOpaqueKHR:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpRayQueryGetIntersectionObjectRayDirectionKHR:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpRayQueryGetIntersectionObjectRayOriginKHR:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpRayQueryGetWorldRayDirectionKHR:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpRayQueryGetWorldRayOriginKHR:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpRayQueryGetIntersectionObjectToWorldKHR:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpRayQueryGetIntersectionWorldToObjectKHR:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpAtomicFAddEXT:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpTypeBufferSurfaceINTEL:
+ *hasResult = true;
+ *hasResultType = false;
+ break;
+ case SpvOpTypeStructContinuedINTEL:
+ *hasResult = false;
+ *hasResultType = false;
+ break;
+ case SpvOpConstantCompositeContinuedINTEL:
+ *hasResult = false;
+ *hasResultType = false;
+ break;
+ case SpvOpSpecConstantCompositeContinuedINTEL:
+ *hasResult = false;
+ *hasResultType = false;
+ break;
+ case SpvOpConvertFToBF16INTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpConvertBF16ToFINTEL:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpControlBarrierArriveINTEL:
+ *hasResult = false;
+ *hasResultType = false;
+ break;
+ case SpvOpControlBarrierWaitINTEL:
+ *hasResult = false;
+ *hasResultType = false;
+ break;
+ case SpvOpGroupIMulKHR:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpGroupFMulKHR:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpGroupBitwiseAndKHR:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpGroupBitwiseOrKHR:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpGroupBitwiseXorKHR:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpGroupLogicalAndKHR:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpGroupLogicalOrKHR:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ case SpvOpGroupLogicalXorKHR:
+ *hasResult = true;
+ *hasResultType = true;
+ break;
+ }
+}
+#endif /* SPV_ENABLE_UTILITY_CODE */
+
+#endif
--- /dev/null
+/*
+ Copyright 2017-2022 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 <crtdbg.h>
+#include <stdlib.h>
+#else
+#include <stdlib.h>
+#endif
+
+#if defined(__clang__) || (defined(__GNUC__) && __GNUC__ >= 7) || defined(__APPLE_CC__)
+#define FALLTHROUGH __attribute__((fallthrough))
+#else
+#define FALLTHROUGH
+#endif
+
+#if defined(SPIRV_REFLECT_ENABLE_ASSERTS)
+#define SPV_REFLECT_ASSERT(COND) assert(COND);
+#else
+#define SPV_REFLECT_ASSERT(COND)
+#endif
+
+// 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,
+};
+
+enum {
+ INVALID_VALUE = 0xFFFFFFFF,
+};
+
+enum {
+ MAX_NODE_NAME_LENGTH = 1024,
+ // Number of unique PhysicalStorageBuffer structs tracked to detect recursion
+ MAX_RECURSIVE_PHYSICAL_POINTER_CHECK = 128,
+};
+
+enum {
+ IMAGE_SAMPLED = 1,
+ IMAGE_STORAGE = 2,
+};
+
+typedef struct SpvReflectPrvArrayTraits {
+ uint32_t element_type_id;
+ uint32_t length_id;
+} SpvReflectPrvArrayTraits;
+
+typedef struct SpvReflectPrvImageTraits {
+ uint32_t sampled_type_id;
+ SpvDim dim;
+ uint32_t depth;
+ uint32_t arrayed;
+ uint32_t ms;
+ uint32_t sampled;
+ SpvImageFormat image_format;
+} SpvReflectPrvImageTraits;
+
+typedef struct SpvReflectPrvNumberDecoration {
+ uint32_t word_offset;
+ uint32_t value;
+} SpvReflectPrvNumberDecoration;
+
+typedef struct SpvReflectPrvStringDecoration {
+ uint32_t word_offset;
+ const char* value;
+} SpvReflectPrvStringDecoration;
+
+typedef struct SpvReflectPrvDecorations {
+ bool is_relaxed_precision;
+ 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;
+ bool is_non_readable;
+ bool is_patch;
+ bool is_per_vertex;
+ bool is_per_task;
+ bool is_weight_texture;
+ bool is_block_match_texture;
+ SpvReflectUserType user_type;
+ SpvReflectPrvNumberDecoration set;
+ SpvReflectPrvNumberDecoration binding;
+ SpvReflectPrvNumberDecoration input_attachment_index;
+ SpvReflectPrvNumberDecoration location;
+ SpvReflectPrvNumberDecoration component;
+ SpvReflectPrvNumberDecoration offset;
+ SpvReflectPrvNumberDecoration uav_counter_buffer;
+ SpvReflectPrvStringDecoration semantic;
+ uint32_t array_stride;
+ uint32_t matrix_stride;
+ uint32_t spec_id;
+ SpvBuiltIn built_in;
+} SpvReflectPrvDecorations;
+
+typedef struct SpvReflectPrvNode {
+ uint32_t result_id;
+ SpvOp op;
+ uint32_t result_type_id;
+ uint32_t type_id;
+ SpvCapability capability;
+ SpvStorageClass storage_class;
+ uint32_t word_offset;
+ uint32_t word_count;
+ bool is_type;
+
+ SpvReflectPrvArrayTraits array_traits;
+ SpvReflectPrvImageTraits image_traits;
+ uint32_t image_type_id;
+
+ const char* name;
+ SpvReflectPrvDecorations decorations;
+ uint32_t member_count;
+ const char** member_names;
+ SpvReflectPrvDecorations* member_decorations;
+} SpvReflectPrvNode;
+
+typedef struct SpvReflectPrvString {
+ uint32_t result_id;
+ const char* string;
+} SpvReflectPrvString;
+
+// There are a limit set of instructions that can touch an OpVariable,
+// these are represented here with how it was accessed
+// Examples:
+// OpImageRead -> OpLoad -> OpVariable
+// OpImageWrite -> OpLoad -> OpVariable
+// OpStore -> OpAccessChain -> OpAccessChain -> OpVariable
+// OpAtomicIAdd -> OpAccessChain -> OpVariable
+// OpAtomicLoad -> OpImageTexelPointer -> OpVariable
+typedef struct SpvReflectPrvAccessedVariable {
+ SpvReflectPrvNode* p_node;
+ uint32_t result_id;
+ uint32_t variable_ptr;
+ uint32_t function_id;
+ uint32_t function_parameter_index;
+} SpvReflectPrvAccessedVariable;
+
+typedef struct SpvReflectPrvFunction {
+ uint32_t id;
+ uint32_t parameter_count;
+ uint32_t* parameters;
+ uint32_t callee_count;
+ uint32_t* callees;
+ struct SpvReflectPrvFunction** callee_ptrs;
+ uint32_t accessed_variable_count;
+ SpvReflectPrvAccessedVariable* accessed_variables;
+} SpvReflectPrvFunction;
+
+typedef struct SpvReflectPrvAccessChain {
+ 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;
+ //
+ // Block variable ac is pointing to (for block references)
+ SpvReflectBlockVariable* block_var;
+} SpvReflectPrvAccessChain;
+
+// To prevent infinite recursion, we never walk down a
+// PhysicalStorageBuffer struct twice, but incase a 2nd variable
+// needs to use that struct, save a copy
+typedef struct SpvReflectPrvPhysicalPointerStruct {
+ uint32_t struct_id;
+ // first variable to see the PhysicalStorageBuffer struct
+ SpvReflectBlockVariable* p_var;
+} SpvReflectPrvPhysicalPointerStruct;
+
+typedef struct SpvReflectPrvParser {
+ size_t spirv_word_count;
+ uint32_t* spirv_code;
+ uint32_t string_count;
+ SpvReflectPrvString* strings;
+ SpvSourceLanguage source_language;
+ uint32_t source_language_version;
+ uint32_t source_file_id;
+ const char* source_embedded;
+ size_t node_count;
+ SpvReflectPrvNode* nodes;
+ uint32_t entry_point_count;
+ uint32_t capability_count;
+ uint32_t function_count;
+ SpvReflectPrvFunction* functions;
+ uint32_t access_chain_count;
+ SpvReflectPrvAccessChain* access_chains;
+
+ uint32_t type_count;
+ uint32_t descriptor_count;
+ uint32_t push_constant_count;
+
+ SpvReflectTypeDescription* physical_pointer_check[MAX_RECURSIVE_PHYSICAL_POINTER_CHECK];
+ uint32_t physical_pointer_count;
+
+ SpvReflectPrvPhysicalPointerStruct* physical_pointer_structs;
+ uint32_t physical_pointer_struct_count;
+} SpvReflectPrvParser;
+// clang-format on
+
+static uint32_t Max(uint32_t a, uint32_t b) { return a > b ? a : b; }
+static uint32_t Min(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) \
+ { \
+ 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;
+}
+
+static int SortCompareAccessedVariable(const void* a, const void* b) {
+ const SpvReflectPrvAccessedVariable* p_a = (const SpvReflectPrvAccessedVariable*)a;
+ const SpvReflectPrvAccessedVariable* p_b = (const SpvReflectPrvAccessedVariable*)b;
+
+ return (int)p_a->variable_ptr - (int)p_b->variable_ptr;
+}
+
+//
+// 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 IntersectSortedAccessedVariable(const SpvReflectPrvAccessedVariable* p_arr0, size_t arr0_size,
+ const uint32_t* p_arr1, size_t arr1_size, uint32_t** pp_res,
+ size_t* res_size) {
+ *pp_res = NULL;
+ *res_size = 0;
+ if (IsNull(p_arr0) || IsNull(p_arr1)) {
+ return SPV_REFLECT_RESULT_SUCCESS;
+ }
+
+ const SpvReflectPrvAccessedVariable* p_arr0_end = p_arr0 + arr0_size;
+ const uint32_t* p_arr1_end = p_arr1 + arr1_size;
+
+ const SpvReflectPrvAccessedVariable* p_idx0 = p_arr0;
+ const uint32_t* p_idx1 = p_arr1;
+ while (p_idx0 != p_arr0_end && p_idx1 != p_arr1_end) {
+ if (p_idx0->variable_ptr < *p_idx1) {
+ ++p_idx0;
+ } else if (p_idx0->variable_ptr > *p_idx1) {
+ ++p_idx1;
+ } else {
+ ++*res_size;
+ ++p_idx0;
+ ++p_idx1;
+ }
+ }
+
+ 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* p_idxr = *pp_res;
+ p_idx0 = p_arr0;
+ p_idx1 = p_arr1;
+ while (p_idx0 != p_arr0_end && p_idx1 != p_arr1_end) {
+ if (p_idx0->variable_ptr < *p_idx1) {
+ ++p_idx0;
+ } else if (p_idx0->variable_ptr > *p_idx1) {
+ ++p_idx1;
+ } else {
+ *(p_idxr++) = p_idx0->variable_ptr;
+ ++p_idx0;
+ ++p_idx1;
+ }
+ }
+ }
+ return SPV_REFLECT_RESULT_SUCCESS;
+}
+
+static bool InRange(const SpvReflectPrvParser* 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(SpvReflectPrvParser* 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 UNCHECKED_READU32(parser, word_offset, value) \
+ { (void)ReadU32(parser, word_offset, (uint32_t*)&(value)); }
+
+#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(SpvReflectPrvParser* 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 SpvReflectPrvDecorations* p_decoration_fields) {
+ SpvReflectDecorationFlags decorations = SPV_REFLECT_DECORATION_NONE;
+ if (p_decoration_fields->is_relaxed_precision) {
+ decorations |= SPV_REFLECT_DECORATION_RELAXED_PRECISION;
+ }
+ 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;
+ }
+ if (p_decoration_fields->is_non_readable) {
+ decorations |= SPV_REFLECT_DECORATION_NON_READABLE;
+ }
+ if (p_decoration_fields->is_patch) {
+ decorations |= SPV_REFLECT_DECORATION_PATCH;
+ }
+ if (p_decoration_fields->is_per_vertex) {
+ decorations |= SPV_REFLECT_DECORATION_PER_VERTEX;
+ }
+ if (p_decoration_fields->is_per_task) {
+ decorations |= SPV_REFLECT_DECORATION_PER_TASK;
+ }
+ if (p_decoration_fields->is_weight_texture) {
+ decorations |= SPV_REFLECT_DECORATION_WEIGHT_TEXTURE;
+ }
+ if (p_decoration_fields->is_block_match_texture) {
+ decorations |= SPV_REFLECT_DECORATION_BLOCK_MATCH_TEXTURE;
+ }
+ 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 bool IsSpecConstant(const SpvReflectPrvNode* p_node) {
+ return (p_node->op == SpvOpSpecConstant || p_node->op == SpvOpSpecConstantOp || p_node->op == SpvOpSpecConstantTrue ||
+ p_node->op == SpvOpSpecConstantFalse);
+}
+
+static SpvReflectPrvNode* FindNode(SpvReflectPrvParser* p_parser, uint32_t result_id) {
+ SpvReflectPrvNode* p_node = NULL;
+ for (size_t i = 0; i < p_parser->node_count; ++i) {
+ SpvReflectPrvNode* 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 SpvReflectPrvAccessChain* FindAccessChain(SpvReflectPrvParser* p_parser, uint32_t id) {
+ const uint32_t ac_count = p_parser->access_chain_count;
+ for (uint32_t i = 0; i < ac_count; i++) {
+ if (p_parser->access_chains[i].result_id == id) {
+ return &p_parser->access_chains[i];
+ }
+ }
+ return 0;
+}
+
+// Access Chains mostly have their Base ID pointed directly to a OpVariable, but sometimes
+// it will be through a load and this funciton handles the edge cases how to find that
+static uint32_t FindAccessChainBaseVariable(SpvReflectPrvParser* p_parser, SpvReflectPrvAccessChain* p_access_chain) {
+ uint32_t base_id = p_access_chain->base_id;
+ SpvReflectPrvNode* base_node = FindNode(p_parser, base_id);
+ // TODO - This is just a band-aid to fix crashes.
+ // Need to understand why here and hopefully remove
+ // https://github.com/KhronosGroup/SPIRV-Reflect/pull/206
+ if (IsNull(base_node)) {
+ return 0;
+ }
+ while (base_node->op != SpvOpVariable) {
+ switch (base_node->op) {
+ case SpvOpLoad: {
+ UNCHECKED_READU32(p_parser, base_node->word_offset + 3, base_id);
+ } break;
+ case SpvOpFunctionParameter: {
+ UNCHECKED_READU32(p_parser, base_node->word_offset + 2, base_id);
+ } break;
+ case SpvOpBitcast:
+ // This can be caused by something like GL_EXT_buffer_reference_uvec2 trying to load a pointer.
+ // We currently call from a push constant, so no way to have a reference loop back into the PC block
+ return 0;
+ default: {
+ assert(false);
+ } break;
+ }
+
+ SpvReflectPrvAccessChain* base_ac = FindAccessChain(p_parser, base_id);
+ if (base_ac == 0) {
+ return 0;
+ }
+ base_id = base_ac->base_id;
+ base_node = FindNode(p_parser, base_id);
+ if (IsNull(base_node)) {
+ return 0;
+ }
+ }
+ return base_id;
+}
+
+static SpvReflectBlockVariable* GetRefBlkVar(SpvReflectPrvParser* p_parser, SpvReflectPrvAccessChain* p_access_chain) {
+ uint32_t base_id = p_access_chain->base_id;
+ SpvReflectPrvNode* base_node = FindNode(p_parser, base_id);
+ assert(base_node->op == SpvOpLoad);
+ UNCHECKED_READU32(p_parser, base_node->word_offset + 3, base_id);
+ SpvReflectPrvAccessChain* base_ac = FindAccessChain(p_parser, base_id);
+ assert(base_ac != 0);
+ SpvReflectBlockVariable* base_var = base_ac->block_var;
+ assert(base_var != 0);
+ return base_var;
+}
+
+bool IsPointerToPointer(SpvReflectPrvParser* p_parser, uint32_t type_id) {
+ SpvReflectPrvNode* ptr_node = FindNode(p_parser, type_id);
+ if (IsNull(ptr_node) || (ptr_node->op != SpvOpTypePointer)) {
+ return false;
+ }
+ uint32_t pte_id = 0;
+ UNCHECKED_READU32(p_parser, ptr_node->word_offset + 3, pte_id);
+ SpvReflectPrvNode* pte_node = FindNode(p_parser, pte_id);
+ if (IsNull(pte_node)) {
+ return false;
+ }
+ return pte_node->op == SpvOpTypePointer;
+}
+
+static SpvReflectResult CreateParser(size_t size, void* p_code, SpvReflectPrvParser* 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(SpvReflectPrvParser* p_parser) {
+ if (!IsNull(p_parser->nodes)) {
+ // Free nodes
+ for (size_t i = 0; i < p_parser->node_count; ++i) {
+ SpvReflectPrvNode* 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].parameters);
+ SafeFree(p_parser->functions[i].callees);
+ SafeFree(p_parser->functions[i].callee_ptrs);
+ SafeFree(p_parser->functions[i].accessed_variables);
+ }
+
+ // 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->source_embedded);
+ SafeFree(p_parser->functions);
+ SafeFree(p_parser->access_chains);
+
+ if (IsNotNull(p_parser->physical_pointer_structs)) {
+ SafeFree(p_parser->physical_pointer_structs);
+ }
+ p_parser->node_count = 0;
+ }
+}
+
+static SpvReflectResult ParseNodes(SpvReflectPrvParser* 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 = (SpvReflectPrvNode*)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.component.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.spec_id = (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;
+ p_parser->source_embedded = NULL;
+
+ // Function node
+ uint32_t function_node = (uint32_t)INVALID_VALUE;
+
+ // Allocate access chain
+ if (p_parser->access_chain_count > 0) {
+ p_parser->access_chains = (SpvReflectPrvAccessChain*)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;
+
+ SpvReflectPrvNode* 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);
+ }
+ if (p_node->word_count >= 5) {
+ const char* p_source = (const char*)(p_parser->spirv_code + p_node->word_offset + 4);
+
+ const size_t source_len = strlen(p_source);
+ char* p_source_temp = (char*)calloc(source_len + 1, sizeof(char));
+
+ if (IsNull(p_source_temp)) {
+ return SPV_REFLECT_RESULT_ERROR_ALLOC_FAILED;
+ }
+
+#ifdef _WIN32
+ strcpy_s(p_source_temp, source_len + 1, p_source);
+#else
+ strcpy(p_source_temp, p_source);
+#endif
+
+ SafeFree(p_parser->source_embedded);
+ p_parser->source_embedded = p_source_temp;
+ }
+ } break;
+
+ case SpvOpSourceContinued: {
+ const char* p_source = (const char*)(p_parser->spirv_code + p_node->word_offset + 1);
+
+ const size_t source_len = strlen(p_source);
+ const size_t embedded_source_len = strlen(p_parser->source_embedded);
+ char* p_continued_source = (char*)calloc(source_len + embedded_source_len + 1, sizeof(char));
+
+ if (IsNull(p_continued_source)) {
+ return SPV_REFLECT_RESULT_ERROR_ALLOC_FAILED;
+ }
+
+#ifdef _WIN32
+ strcpy_s(p_continued_source, embedded_source_len + 1, p_parser->source_embedded);
+ strcat_s(p_continued_source, embedded_source_len + source_len + 1, p_source);
+#else
+ strcpy(p_continued_source, p_parser->source_embedded);
+ strcat(p_continued_source, p_source);
+#endif
+
+ SafeFree(p_parser->source_embedded);
+ p_parser->source_embedded = p_continued_source;
+ } break;
+
+ case SpvOpEntryPoint: {
+ ++(p_parser->entry_point_count);
+ } break;
+
+ case SpvOpCapability: {
+ CHECKED_READU32(p_parser, p_node->word_offset + 1, p_node->capability);
+ ++(p_parser->capability_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;
+ FALLTHROUGH;
+ } // Fall through
+
+ // This is all the rest of OpType* that need to be tracked
+ // Possible new extensions might expose new type, will need to be added
+ // here
+ 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:
+ case SpvOpTypeAccelerationStructureKHR:
+ case SpvOpTypeRayQueryKHR:
+ case SpvOpTypeHitObjectNV:
+ case SpvOpTypeCooperativeMatrixNV:
+ case SpvOpTypeCooperativeMatrixKHR: {
+ 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: {
+ uint32_t result_id;
+ CHECKED_READU32(p_parser, p_node->word_offset + 1, result_id);
+ // Look for forward pointer. Clear result id if found
+ SpvReflectPrvNode* p_fwd_node = FindNode(p_parser, result_id);
+ if (p_fwd_node) {
+ p_fwd_node->result_id = 0;
+ }
+ // Register pointer type
+ p_node->result_id = 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: {
+ SpvReflectPrvAccessChain* 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
+ SpvReflectPrvNode* p_index_value_node = FindNode(p_parser, index_id);
+ if ((p_index_value_node != NULL) &&
+ (p_index_value_node->op == SpvOpConstant || p_index_value_node->op == SpvOpSpecConstant)) {
+ // 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) {
+ SpvReflectPrvNode* 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);
+ }
+ FALLTHROUGH;
+ } // Fall through
+
+ case SpvOpFunctionEnd: {
+ function_node = (uint32_t)INVALID_VALUE;
+ } break;
+ case SpvOpFunctionParameter: {
+ CHECKED_READU32(p_parser, p_node->word_offset + 2, p_node->result_id);
+ } break;
+ case SpvOpBitcast:
+ case SpvOpShiftRightLogical:
+ case SpvOpIAdd:
+ case SpvOpISub:
+ case SpvOpIMul:
+ case SpvOpUDiv:
+ case SpvOpSDiv: {
+ CHECKED_READU32(p_parser, p_node->word_offset + 2, p_node->result_id);
+ } 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(SpvReflectPrvParser* 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 = (SpvReflectPrvString*)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) {
+ SpvReflectPrvNode* 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
+ SpvReflectPrvString* 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(SpvReflectPrvParser* 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) {
+ SpvReflectPrvString* p_string = &(p_parser->strings[i]);
+ if (p_string->result_id == p_parser->source_file_id) {
+ p_module->source_file = p_string->string;
+ break;
+ }
+ }
+ }
+
+ // Source code
+ if (IsNotNull(p_parser->source_embedded)) {
+ const size_t source_len = strlen(p_parser->source_embedded);
+ char* p_source = (char*)calloc(source_len + 1, sizeof(char));
+
+ if (IsNull(p_source)) {
+ return SPV_REFLECT_RESULT_ERROR_ALLOC_FAILED;
+ }
+
+#ifdef _WIN32
+ strcpy_s(p_source, source_len + 1, p_parser->source_embedded);
+#else
+ strcpy(p_source, p_parser->source_embedded);
+#endif
+
+ p_module->source_source = p_source;
+ }
+ }
+
+ return SPV_REFLECT_RESULT_SUCCESS;
+}
+
+static SpvReflectResult ParseFunction(SpvReflectPrvParser* p_parser, SpvReflectPrvNode* p_func_node, SpvReflectPrvFunction* p_func,
+ size_t first_label_index) {
+ p_func->id = p_func_node->result_id;
+
+ p_func->parameter_count = 0;
+ p_func->callee_count = 0;
+ p_func->accessed_variable_count = 0;
+
+ // First get count to know how much to allocate
+ for (size_t i = first_label_index; i < p_parser->node_count; ++i) {
+ SpvReflectPrvNode* p_node = &(p_parser->nodes[i]);
+ if (p_node->op == SpvOpFunctionEnd) {
+ break;
+ }
+ switch (p_node->op) {
+ case SpvOpFunctionParameter: {
+ ++(p_func->parameter_count);
+ } break;
+ case SpvOpFunctionCall: {
+ p_func->accessed_variable_count += p_node->word_count - 4;
+ ++(p_func->callee_count);
+ } break;
+ case SpvOpLoad:
+ case SpvOpAccessChain:
+ case SpvOpInBoundsAccessChain:
+ case SpvOpPtrAccessChain:
+ case SpvOpArrayLength:
+ case SpvOpGenericPtrMemSemantics:
+ case SpvOpInBoundsPtrAccessChain:
+ case SpvOpStore:
+ case SpvOpImageTexelPointer: {
+ ++(p_func->accessed_variable_count);
+ } break;
+ case SpvOpCopyMemory:
+ case SpvOpCopyMemorySized: {
+ p_func->accessed_variable_count += 2;
+ } break;
+ default:
+ break;
+ }
+ }
+
+ if (p_func->parameter_count > 0) {
+ p_func->parameters = (uint32_t*)calloc(p_func->parameter_count, sizeof(*(p_func->parameters)));
+ if (IsNull(p_func->parameters)) {
+ return SPV_REFLECT_RESULT_ERROR_ALLOC_FAILED;
+ }
+ }
+
+ 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_variable_count > 0) {
+ p_func->accessed_variables =
+ (SpvReflectPrvAccessedVariable*)calloc(p_func->accessed_variable_count, sizeof(*(p_func->accessed_variables)));
+ if (IsNull(p_func->accessed_variables)) {
+ return SPV_REFLECT_RESULT_ERROR_ALLOC_FAILED;
+ }
+ }
+
+ p_func->parameter_count = 0;
+ p_func->callee_count = 0;
+ p_func->accessed_variable_count = 0;
+ // Now have allocation, fill in values
+ for (size_t i = first_label_index; i < p_parser->node_count; ++i) {
+ SpvReflectPrvNode* p_node = &(p_parser->nodes[i]);
+ if (p_node->op == SpvOpFunctionEnd) {
+ break;
+ }
+ switch (p_node->op) {
+ case SpvOpFunctionParameter: {
+ CHECKED_READU32(p_parser, p_node->word_offset + 2, p_func->parameters[p_func->parameter_count]);
+ (++p_func->parameter_count);
+ } break;
+ case SpvOpFunctionCall: {
+ CHECKED_READU32(p_parser, p_node->word_offset + 3, p_func->callees[p_func->callee_count]);
+ const uint32_t result_index = p_node->word_offset + 2;
+ for (uint32_t j = 0, parameter_count = p_node->word_count - 4; j < parameter_count; j++) {
+ const uint32_t ptr_index = p_node->word_offset + 4 + j;
+ SpvReflectPrvAccessedVariable* access_ptr = &p_func->accessed_variables[p_func->accessed_variable_count];
+
+ access_ptr->p_node = p_node;
+ // Need to track Result ID as not sure there has been any memory access through here yet
+ CHECKED_READU32(p_parser, result_index, access_ptr->result_id);
+ CHECKED_READU32(p_parser, ptr_index, access_ptr->variable_ptr);
+ access_ptr->function_id = p_func->callees[p_func->callee_count];
+ access_ptr->function_parameter_index = j;
+ (++p_func->accessed_variable_count);
+ }
+ (++p_func->callee_count);
+ } break;
+ case SpvOpLoad:
+ case SpvOpAccessChain:
+ case SpvOpInBoundsAccessChain:
+ case SpvOpPtrAccessChain:
+ case SpvOpArrayLength:
+ case SpvOpGenericPtrMemSemantics:
+ case SpvOpInBoundsPtrAccessChain:
+ case SpvOpImageTexelPointer: {
+ const uint32_t result_index = p_node->word_offset + 2;
+ const uint32_t ptr_index = p_node->word_offset + 3;
+ SpvReflectPrvAccessedVariable* access_ptr = &p_func->accessed_variables[p_func->accessed_variable_count];
+
+ access_ptr->p_node = p_node;
+ // Need to track Result ID as not sure there has been any memory access through here yet
+ CHECKED_READU32(p_parser, result_index, access_ptr->result_id);
+ CHECKED_READU32(p_parser, ptr_index, access_ptr->variable_ptr);
+ (++p_func->accessed_variable_count);
+ } break;
+ case SpvOpStore: {
+ const uint32_t result_index = p_node->word_offset + 2;
+ CHECKED_READU32(p_parser, result_index, p_func->accessed_variables[p_func->accessed_variable_count].variable_ptr);
+ p_func->accessed_variables[p_func->accessed_variable_count].p_node = p_node;
+ (++p_func->accessed_variable_count);
+ } break;
+ case SpvOpCopyMemory:
+ case SpvOpCopyMemorySized: {
+ // There is no result_id or node, being zero is same as being invalid
+ CHECKED_READU32(p_parser, p_node->word_offset + 1,
+ p_func->accessed_variables[p_func->accessed_variable_count].variable_ptr);
+ (++p_func->accessed_variable_count);
+ CHECKED_READU32(p_parser, p_node->word_offset + 2,
+ p_func->accessed_variables[p_func->accessed_variable_count].variable_ptr);
+ (++p_func->accessed_variable_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_variable_count > 0) {
+ qsort(p_func->accessed_variables, p_func->accessed_variable_count, sizeof(*(p_func->accessed_variables)),
+ SortCompareAccessedVariable);
+ }
+
+ return SPV_REFLECT_RESULT_SUCCESS;
+}
+
+static int SortCompareFunctions(const void* a, const void* b) {
+ const SpvReflectPrvFunction* af = (const SpvReflectPrvFunction*)a;
+ const SpvReflectPrvFunction* bf = (const SpvReflectPrvFunction*)b;
+ return (int)af->id - (int)bf->id;
+}
+
+static SpvReflectResult ParseFunctions(SpvReflectPrvParser* 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 = (SpvReflectPrvFunction*)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) {
+ SpvReflectPrvNode* p_node = &(p_parser->nodes[i]);
+ if (p_node->op != SpvOpFunction) {
+ continue;
+ }
+
+ // Skip over function declarations that aren't definitions
+ bool func_definition = false;
+ for (size_t j = i; j < p_parser->node_count; ++j) {
+ if (p_parser->nodes[j].op == SpvOpLabel) {
+ func_definition = true;
+ break;
+ }
+ if (p_parser->nodes[j].op == SpvOpFunctionEnd) {
+ break;
+ }
+ }
+ if (!func_definition) {
+ continue;
+ }
+
+ SpvReflectPrvFunction* 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) {
+ SpvReflectPrvFunction* p_func = &(p_parser->functions[i]);
+ if (p_func->callee_count == 0) {
+ continue;
+ }
+ p_func->callee_ptrs = (SpvReflectPrvFunction**)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(SpvReflectPrvParser* 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) {
+ SpvReflectPrvNode* 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);
+ SpvReflectPrvNode* 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) {
+ SpvReflectPrvNode* 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 = (SpvReflectPrvDecorations*)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(SpvReflectPrvParser* 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) {
+ SpvReflectPrvNode* 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);
+ SpvReflectPrvNode* 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;
+}
+
+// Returns true if user_type matches pattern or if user_type begins with pattern and the next character is ':'
+// For example, UserTypeMatches("rwbuffer", "rwbuffer") will be true, UserTypeMatches("rwbuffer", "rwbuffer:<S>") will be true, and
+// UserTypeMatches("rwbuffer", "rwbufferfoo") will be false.
+static bool UserTypeMatches(const char* user_type, const char* pattern) {
+ const size_t pattern_length = strlen(pattern);
+ if (strncmp(user_type, pattern, pattern_length) == 0) {
+ if (user_type[pattern_length] == ':' || user_type[pattern_length] == '\0') {
+ return true;
+ }
+ }
+ return false;
+}
+
+static SpvReflectResult ParseDecorations(SpvReflectPrvParser* p_parser, SpvReflectShaderModule* p_module) {
+ uint32_t spec_constant_count = 0;
+ for (uint32_t i = 0; i < p_parser->node_count; ++i) {
+ SpvReflectPrvNode* p_node = &(p_parser->nodes[i]);
+
+ if ((p_node->op != SpvOpDecorate) && (p_node->op != SpvOpMemberDecorate) && (p_node->op != SpvOpDecorateId) &&
+ (p_node->op != SpvOpDecorateString) && (p_node->op != SpvOpMemberDecorateString)) {
+ 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 SpvDecorationRelaxedPrecision:
+ case SpvDecorationBlock:
+ case SpvDecorationBufferBlock:
+ case SpvDecorationColMajor:
+ case SpvDecorationRowMajor:
+ case SpvDecorationArrayStride:
+ case SpvDecorationMatrixStride:
+ case SpvDecorationBuiltIn:
+ case SpvDecorationNoPerspective:
+ case SpvDecorationFlat:
+ case SpvDecorationNonWritable:
+ case SpvDecorationNonReadable:
+ case SpvDecorationPatch:
+ case SpvDecorationPerVertexKHR:
+ case SpvDecorationPerTaskNV:
+ case SpvDecorationLocation:
+ case SpvDecorationComponent:
+ case SpvDecorationBinding:
+ case SpvDecorationDescriptorSet:
+ case SpvDecorationOffset:
+ case SpvDecorationInputAttachmentIndex:
+ case SpvDecorationSpecId:
+ case SpvDecorationWeightTextureQCOM:
+ case SpvDecorationBlockMatchTextureQCOM:
+ case SpvDecorationUserTypeGOOGLE:
+ case SpvDecorationHlslCounterBufferGOOGLE:
+ case SpvDecorationHlslSemanticGOOGLE: {
+ skip = false;
+ } break;
+ }
+ if (skip) {
+ continue;
+ }
+
+ // Find target node
+ uint32_t target_id = 0;
+ CHECKED_READU32(p_parser, p_node->word_offset + 1, target_id);
+ SpvReflectPrvNode* p_target_node = FindNode(p_parser, target_id);
+ if (IsNull(p_target_node)) {
+ if ((p_node->op == (uint32_t)SpvOpDecorate) && (decoration == SpvDecorationRelaxedPrecision)) {
+ // Many OPs can be decorated that we don't care about. Ignore those.
+ // See https://github.com/KhronosGroup/SPIRV-Reflect/issues/134
+ continue;
+ }
+ return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE;
+ }
+ // Get decorations
+ SpvReflectPrvDecorations* p_target_decorations = &(p_target_node->decorations);
+ // Update pointer if this is a 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 SpvDecorationRelaxedPrecision: {
+ p_target_decorations->is_relaxed_precision = true;
+ } 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 SpvDecorationNonReadable: {
+ p_target_decorations->is_non_readable = true;
+ } break;
+
+ case SpvDecorationPatch: {
+ p_target_decorations->is_patch = true;
+ } break;
+
+ case SpvDecorationPerVertexKHR: {
+ p_target_decorations->is_per_vertex = true;
+ } break;
+
+ case SpvDecorationPerTaskNV: {
+ p_target_decorations->is_per_task = 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 SpvDecorationComponent: {
+ uint32_t word_offset = p_node->word_offset + member_offset + 3;
+ CHECKED_READU32(p_parser, word_offset, p_target_decorations->component.value);
+ p_target_decorations->component.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 SpvDecorationSpecId: {
+ spec_constant_count++;
+ } break;
+
+ case SpvDecorationHlslCounterBufferGOOGLE: {
+ 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 SpvDecorationHlslSemanticGOOGLE: {
+ 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;
+
+ case SpvDecorationWeightTextureQCOM: {
+ p_target_decorations->is_weight_texture = true;
+ } break;
+
+ case SpvDecorationBlockMatchTextureQCOM: {
+ p_target_decorations->is_block_match_texture = true;
+ } break;
+ }
+
+ if (p_node->op == SpvOpDecorateString && decoration == SpvDecorationUserTypeGOOGLE) {
+ uint32_t terminator = 0;
+ SpvReflectResult result = ReadStr(p_parser, p_node->word_offset + 3, 0, p_node->word_count, &terminator, NULL);
+ if (result != SPV_REFLECT_RESULT_SUCCESS) {
+ return result;
+ }
+ const char* name = (const char*)(p_parser->spirv_code + p_node->word_offset + 3);
+ if (UserTypeMatches(name, "cbuffer")) {
+ p_target_decorations->user_type = SPV_REFLECT_USER_TYPE_CBUFFER;
+ } else if (UserTypeMatches(name, "tbuffer")) {
+ p_target_decorations->user_type = SPV_REFLECT_USER_TYPE_TBUFFER;
+ } else if (UserTypeMatches(name, "appendstructuredbuffer")) {
+ p_target_decorations->user_type = SPV_REFLECT_USER_TYPE_APPEND_STRUCTURED_BUFFER;
+ } else if (UserTypeMatches(name, "buffer")) {
+ p_target_decorations->user_type = SPV_REFLECT_USER_TYPE_BUFFER;
+ } else if (UserTypeMatches(name, "byteaddressbuffer")) {
+ p_target_decorations->user_type = SPV_REFLECT_USER_TYPE_BYTE_ADDRESS_BUFFER;
+ } else if (UserTypeMatches(name, "constantbuffer")) {
+ p_target_decorations->user_type = SPV_REFLECT_USER_TYPE_CONSTANT_BUFFER;
+ } else if (UserTypeMatches(name, "consumestructuredbuffer")) {
+ p_target_decorations->user_type = SPV_REFLECT_USER_TYPE_CONSUME_STRUCTURED_BUFFER;
+ } else if (UserTypeMatches(name, "inputpatch")) {
+ p_target_decorations->user_type = SPV_REFLECT_USER_TYPE_INPUT_PATCH;
+ } else if (UserTypeMatches(name, "outputpatch")) {
+ p_target_decorations->user_type = SPV_REFLECT_USER_TYPE_OUTPUT_PATCH;
+ } else if (UserTypeMatches(name, "rasterizerorderedbuffer")) {
+ p_target_decorations->user_type = SPV_REFLECT_USER_TYPE_RASTERIZER_ORDERED_BUFFER;
+ } else if (UserTypeMatches(name, "rasterizerorderedbyteaddressbuffer")) {
+ p_target_decorations->user_type = SPV_REFLECT_USER_TYPE_RASTERIZER_ORDERED_BYTE_ADDRESS_BUFFER;
+ } else if (UserTypeMatches(name, "rasterizerorderedstructuredbuffer")) {
+ p_target_decorations->user_type = SPV_REFLECT_USER_TYPE_RASTERIZER_ORDERED_STRUCTURED_BUFFER;
+ } else if (UserTypeMatches(name, "rasterizerorderedtexture1d")) {
+ p_target_decorations->user_type = SPV_REFLECT_USER_TYPE_RASTERIZER_ORDERED_TEXTURE_1D;
+ } else if (UserTypeMatches(name, "rasterizerorderedtexture1darray")) {
+ p_target_decorations->user_type = SPV_REFLECT_USER_TYPE_RASTERIZER_ORDERED_TEXTURE_1D_ARRAY;
+ } else if (UserTypeMatches(name, "rasterizerorderedtexture2d")) {
+ p_target_decorations->user_type = SPV_REFLECT_USER_TYPE_RASTERIZER_ORDERED_TEXTURE_2D;
+ } else if (UserTypeMatches(name, "rasterizerorderedtexture2darray")) {
+ p_target_decorations->user_type = SPV_REFLECT_USER_TYPE_RASTERIZER_ORDERED_TEXTURE_2D_ARRAY;
+ } else if (UserTypeMatches(name, "rasterizerorderedtexture3d")) {
+ p_target_decorations->user_type = SPV_REFLECT_USER_TYPE_RASTERIZER_ORDERED_TEXTURE_3D;
+ } else if (UserTypeMatches(name, "raytracingaccelerationstructure")) {
+ p_target_decorations->user_type = SPV_REFLECT_USER_TYPE_RAYTRACING_ACCELERATION_STRUCTURE;
+ } else if (UserTypeMatches(name, "rwbuffer")) {
+ p_target_decorations->user_type = SPV_REFLECT_USER_TYPE_RW_BUFFER;
+ } else if (UserTypeMatches(name, "rwbyteaddressbuffer")) {
+ p_target_decorations->user_type = SPV_REFLECT_USER_TYPE_RW_BYTE_ADDRESS_BUFFER;
+ } else if (UserTypeMatches(name, "rwstructuredbuffer")) {
+ p_target_decorations->user_type = SPV_REFLECT_USER_TYPE_RW_STRUCTURED_BUFFER;
+ } else if (UserTypeMatches(name, "rwtexture1d")) {
+ p_target_decorations->user_type = SPV_REFLECT_USER_TYPE_RW_TEXTURE_1D;
+ } else if (UserTypeMatches(name, "rwtexture1darray")) {
+ p_target_decorations->user_type = SPV_REFLECT_USER_TYPE_RW_TEXTURE_1D_ARRAY;
+ } else if (UserTypeMatches(name, "rwtexture2d")) {
+ p_target_decorations->user_type = SPV_REFLECT_USER_TYPE_RW_TEXTURE_2D;
+ } else if (UserTypeMatches(name, "rwtexture2darray")) {
+ p_target_decorations->user_type = SPV_REFLECT_USER_TYPE_RW_TEXTURE_2D_ARRAY;
+ } else if (UserTypeMatches(name, "rwtexture3d")) {
+ p_target_decorations->user_type = SPV_REFLECT_USER_TYPE_RW_TEXTURE_3D;
+ } else if (UserTypeMatches(name, "structuredbuffer")) {
+ p_target_decorations->user_type = SPV_REFLECT_USER_TYPE_STRUCTURED_BUFFER;
+ } else if (UserTypeMatches(name, "subpassinput")) {
+ p_target_decorations->user_type = SPV_REFLECT_USER_TYPE_SUBPASS_INPUT;
+ } else if (UserTypeMatches(name, "subpassinputms")) {
+ p_target_decorations->user_type = SPV_REFLECT_USER_TYPE_SUBPASS_INPUT_MS;
+ } else if (UserTypeMatches(name, "texture1d")) {
+ p_target_decorations->user_type = SPV_REFLECT_USER_TYPE_TEXTURE_1D;
+ } else if (UserTypeMatches(name, "texture1darray")) {
+ p_target_decorations->user_type = SPV_REFLECT_USER_TYPE_TEXTURE_1D_ARRAY;
+ } else if (UserTypeMatches(name, "texture2d")) {
+ p_target_decorations->user_type = SPV_REFLECT_USER_TYPE_TEXTURE_2D;
+ } else if (UserTypeMatches(name, "texture2darray")) {
+ p_target_decorations->user_type = SPV_REFLECT_USER_TYPE_TEXTURE_2D_ARRAY;
+ } else if (UserTypeMatches(name, "texture2dms")) {
+ p_target_decorations->user_type = SPV_REFLECT_USER_TYPE_TEXTURE_2DMS;
+ } else if (UserTypeMatches(name, "texture2dmsarray")) {
+ p_target_decorations->user_type = SPV_REFLECT_USER_TYPE_TEXTURE_2DMS_ARRAY;
+ } else if (UserTypeMatches(name, "texture3d")) {
+ p_target_decorations->user_type = SPV_REFLECT_USER_TYPE_TEXTURE_3D;
+ } else if (UserTypeMatches(name, "texturebuffer")) {
+ p_target_decorations->user_type = SPV_REFLECT_USER_TYPE_TEXTURE_BUFFER;
+ } else if (UserTypeMatches(name, "texturecube")) {
+ p_target_decorations->user_type = SPV_REFLECT_USER_TYPE_TEXTURE_CUBE;
+ } else if (UserTypeMatches(name, "texturecubearray")) {
+ p_target_decorations->user_type = SPV_REFLECT_USER_TYPE_TEXTURE_CUBE_ARRAY;
+ }
+ }
+ }
+
+ if (spec_constant_count > 0) {
+ p_module->spec_constants = (SpvReflectSpecializationConstant*)calloc(spec_constant_count, sizeof(*p_module->spec_constants));
+ if (IsNull(p_module->spec_constants)) {
+ return SPV_REFLECT_RESULT_ERROR_ALLOC_FAILED;
+ }
+ }
+ for (uint32_t i = 0; i < p_parser->node_count; ++i) {
+ SpvReflectPrvNode* p_node = &(p_parser->nodes[i]);
+ if (p_node->op == SpvOpDecorate) {
+ uint32_t decoration = (uint32_t)INVALID_VALUE;
+ CHECKED_READU32(p_parser, p_node->word_offset + 2, decoration);
+ if (decoration == SpvDecorationSpecId) {
+ const uint32_t count = p_module->spec_constant_count;
+ CHECKED_READU32(p_parser, p_node->word_offset + 1, p_module->spec_constants[count].spirv_id);
+ CHECKED_READU32(p_parser, p_node->word_offset + 3, p_module->spec_constants[count].constant_id);
+ // If being used for a OpSpecConstantComposite (ex. LocalSizeId), there won't be a name
+ SpvReflectPrvNode* target_node = FindNode(p_parser, p_module->spec_constants[count].spirv_id);
+ if (IsNotNull(target_node)) {
+ p_module->spec_constants[count].name = target_node->name;
+ }
+ p_module->spec_constant_count++;
+ }
+ }
+ }
+
+ 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(SpvReflectPrvParser* p_parser, SpvReflectPrvNode* p_node,
+ SpvReflectPrvDecorations* p_struct_member_decorations, SpvReflectShaderModule* p_module,
+ SpvReflectTypeDescription* p_type) {
+ SpvReflectResult result = SPV_REFLECT_RESULT_SUCCESS;
+
+ if (p_node->member_count > 0) {
+ p_type->struct_type_description = FindType(p_module, p_node->result_id);
+ 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
+ SpvReflectPrvNode* 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;
+ SPV_REFLECT_ASSERT(false);
+ }
+ } 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);
+ SpvReflectPrvNode* 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;
+ SPV_REFLECT_ASSERT(false);
+ }
+ 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;
+ uint32_t sampled_type_id = (uint32_t)INVALID_VALUE;
+ IF_READU32(result, p_parser, p_node->word_offset + 2, sampled_type_id);
+ SpvReflectPrvNode* p_next_node = FindNode(p_parser, sampled_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;
+ }
+ 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);
+ SpvReflectPrvNode* 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;
+ SPV_REFLECT_ASSERT(false);
+ }
+ } 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
+ SpvReflectPrvNode* p_length_node = FindNode(p_parser, length_id);
+ if (IsNotNull(p_length_node)) {
+ uint32_t dim_index = p_type->traits.array.dims_count;
+ uint32_t length = 0;
+ IF_READU32(result, p_parser, p_length_node->word_offset + 3, length);
+ if (result == SPV_REFLECT_RESULT_SUCCESS) {
+ p_type->traits.array.dims[dim_index] = length;
+ p_type->traits.array.dims_count += 1;
+ p_type->traits.array.spec_constant_op_ids[dim_index] =
+ IsSpecConstant(p_length_node) ? p_length_node->decorations.spec_id : (uint32_t)INVALID_VALUE;
+ } else {
+ result = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE;
+ SPV_REFLECT_ASSERT(false);
+ }
+ // Parse next dimension or element type
+ SpvReflectPrvNode* 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;
+ SPV_REFLECT_ASSERT(false);
+ }
+ }
+ } break;
+
+ case SpvOpTypeRuntimeArray: {
+ p_type->type_flags |= SPV_REFLECT_TYPE_FLAG_ARRAY;
+ uint32_t element_type_id = (uint32_t)INVALID_VALUE;
+ IF_READU32(result, p_parser, p_node->word_offset + 2, element_type_id);
+ p_type->traits.array.stride = p_node->decorations.array_stride;
+ uint32_t dim_index = p_type->traits.array.dims_count;
+ p_type->traits.array.dims[dim_index] = (uint32_t)SPV_REFLECT_ARRAY_DIM_RUNTIME;
+ p_type->traits.array.spec_constant_op_ids[dim_index] = (uint32_t)INVALID_VALUE;
+ p_type->traits.array.dims_count += 1;
+ // Parse next dimension or element type
+ SpvReflectPrvNode* 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;
+ SPV_REFLECT_ASSERT(false);
+ }
+ } 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
+ SpvReflectPrvNode* p_member_node = FindNode(p_parser, member_id);
+ if (IsNull(p_member_node)) {
+ result = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE;
+ SPV_REFLECT_ASSERT(false);
+ break;
+ }
+
+ // Member decorations
+ SpvReflectPrvDecorations* 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: {
+ p_type->type_flags |= SPV_REFLECT_TYPE_FLAG_REF;
+ IF_READU32_CAST(result, p_parser, p_node->word_offset + 2, SpvStorageClass, p_type->storage_class);
+
+ bool found_recursion = false;
+ if (p_type->storage_class == SpvStorageClassPhysicalStorageBuffer) {
+ // Need to make sure we haven't started an infinite recursive loop
+ for (uint32_t i = 0; i < p_parser->physical_pointer_count; i++) {
+ if (p_type->id == p_parser->physical_pointer_check[i]->id) {
+ found_recursion = true;
+ memcpy(p_type, p_parser->physical_pointer_check[i], sizeof(SpvReflectTypeDescription));
+ p_type->copied = 1;
+ return SPV_REFLECT_RESULT_SUCCESS;
+ }
+ }
+ if (!found_recursion) {
+ p_parser->physical_pointer_struct_count++;
+ p_parser->physical_pointer_check[p_parser->physical_pointer_count] = p_type;
+ p_parser->physical_pointer_count++;
+ if (p_parser->physical_pointer_count >= MAX_RECURSIVE_PHYSICAL_POINTER_CHECK) {
+ return SPV_REFLECT_RESULT_ERROR_SPIRV_MAX_RECURSIVE_EXCEEDED;
+ }
+ }
+ }
+
+ // Parse type
+ SpvReflectPrvNode* p_next_node = FindNode(p_parser, p_node->type_id);
+ if (IsNull(p_next_node)) {
+ result = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE;
+ SPV_REFLECT_ASSERT(false);
+ } else if (!found_recursion) {
+ if (p_next_node->op == SpvOpTypeStruct) {
+ p_type->struct_type_description = FindType(p_module, p_next_node->result_id);
+ }
+
+ result = ParseType(p_parser, p_next_node, NULL, p_module, p_type);
+ }
+ } break;
+
+ case SpvOpTypeAccelerationStructureKHR: {
+ p_type->type_flags |= SPV_REFLECT_TYPE_FLAG_EXTERNAL_ACCELERATION_STRUCTURE;
+ } 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(SpvReflectPrvParser* 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) {
+ SpvReflectPrvNode* p_node = &(p_parser->nodes[i]);
+ if (!p_node->is_type) {
+ continue;
+ }
+
+ SpvReflectTypeDescription* p_type = &(p_module->_internal->type_descriptions[type_index]);
+ p_parser->physical_pointer_count = 0;
+ SpvReflectResult result = ParseType(p_parser, p_node, NULL, p_module, p_type);
+ if (result != SPV_REFLECT_RESULT_SUCCESS) {
+ return result;
+ }
+ ++type_index;
+ }
+
+ // allocate now and fill in when parsing struct variable later
+ if (p_parser->physical_pointer_struct_count > 0) {
+ p_parser->physical_pointer_structs = (SpvReflectPrvPhysicalPointerStruct*)calloc(p_parser->physical_pointer_struct_count,
+ sizeof(*(p_parser->physical_pointer_structs)));
+ if (IsNull(p_parser->physical_pointer_structs)) {
+ return SPV_REFLECT_RESULT_ERROR_ALLOC_FAILED;
+ }
+ }
+ return SPV_REFLECT_RESULT_SUCCESS;
+}
+
+static SpvReflectResult ParseCapabilities(SpvReflectPrvParser* p_parser, SpvReflectShaderModule* p_module) {
+ if (p_parser->capability_count == 0) {
+ return SPV_REFLECT_RESULT_SUCCESS;
+ }
+
+ p_module->capability_count = p_parser->capability_count;
+ p_module->capabilities = (SpvReflectCapability*)calloc(p_module->capability_count, sizeof(*(p_module->capabilities)));
+ if (IsNull(p_module->capabilities)) {
+ return SPV_REFLECT_RESULT_ERROR_ALLOC_FAILED;
+ }
+
+ // Mark all types with an invalid state
+ for (size_t i = 0; i < p_module->capability_count; ++i) {
+ SpvReflectCapability* p_cap = &(p_module->capabilities[i]);
+ p_cap->value = SpvCapabilityMax;
+ p_cap->word_offset = (uint32_t)INVALID_VALUE;
+ }
+
+ size_t capability_index = 0;
+ for (size_t i = 0; i < p_parser->node_count; ++i) {
+ SpvReflectPrvNode* p_node = &(p_parser->nodes[i]);
+ if (SpvOpCapability != p_node->op) {
+ continue;
+ }
+
+ SpvReflectCapability* p_cap = &(p_module->capabilities[capability_index]);
+ p_cap->value = p_node->capability;
+ p_cap->word_offset = p_node->word_offset + 1;
+ ++capability_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(SpvReflectPrvParser* p_parser, SpvReflectShaderModule* p_module) {
+ p_module->descriptor_binding_count = 0;
+ for (size_t i = 0; i < p_parser->node_count; ++i) {
+ SpvReflectPrvNode* p_node = &(p_parser->nodes[i]);
+ if ((p_node->op != SpvOpVariable) ||
+ ((p_node->storage_class != SpvStorageClassUniform) && (p_node->storage_class != SpvStorageClassStorageBuffer) &&
+ (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) {
+ SpvReflectPrvNode* p_node = &(p_parser->nodes[i]);
+ if ((p_node->op != SpvOpVariable) ||
+ ((p_node->storage_class != SpvStorageClassUniform) && (p_node->storage_class != SpvStorageClassStorageBuffer) &&
+ (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. We need to retain the storage class
+ // from the pointer so that we can use it to deduce deescriptor types.
+ SpvStorageClass pointer_storage_class = SpvStorageClassMax;
+ if (p_type->op == SpvOpTypePointer) {
+ pointer_storage_class = p_type->storage_class;
+ // Find the type's node
+ SpvReflectPrvNode* 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;
+ p_descriptor->decoration_flags = ApplyDecorations(&p_node->decorations);
+ p_descriptor->user_type = p_node->decorations.user_type;
+
+ // Flags like non-writable and non-readable are found as member decorations only.
+ // If all members have one of those decorations set, promote the decoration up
+ // to the whole descriptor.
+ const SpvReflectPrvNode* p_type_node = FindNode(p_parser, p_type->id);
+ if (IsNotNull(p_type_node) && p_type_node->member_count) {
+ SpvReflectPrvDecorations common_flags = p_type_node->member_decorations[0];
+
+ for (uint32_t m = 1; m < p_type_node->member_count; ++m) {
+ common_flags.is_relaxed_precision &= p_type_node->member_decorations[m].is_relaxed_precision;
+ common_flags.is_block &= p_type_node->member_decorations[m].is_block;
+ common_flags.is_buffer_block &= p_type_node->member_decorations[m].is_buffer_block;
+ common_flags.is_row_major &= p_type_node->member_decorations[m].is_row_major;
+ common_flags.is_column_major &= p_type_node->member_decorations[m].is_column_major;
+ common_flags.is_built_in &= p_type_node->member_decorations[m].is_built_in;
+ common_flags.is_noperspective &= p_type_node->member_decorations[m].is_noperspective;
+ common_flags.is_flat &= p_type_node->member_decorations[m].is_flat;
+ common_flags.is_non_writable &= p_type_node->member_decorations[m].is_non_writable;
+ common_flags.is_non_readable &= p_type_node->member_decorations[m].is_non_readable;
+ common_flags.is_patch &= p_type_node->member_decorations[m].is_patch;
+ common_flags.is_per_vertex &= p_type_node->member_decorations[m].is_per_vertex;
+ common_flags.is_per_task &= p_type_node->member_decorations[m].is_per_task;
+ common_flags.is_weight_texture &= p_type_node->member_decorations[m].is_weight_texture;
+ common_flags.is_block_match_texture &= p_type_node->member_decorations[m].is_block_match_texture;
+ }
+
+ p_descriptor->decoration_flags |= ApplyDecorations(&common_flags);
+ }
+
+ // If this is in the StorageBuffer storage class, it's for sure a storage
+ // buffer descriptor. We need to handle this case earlier because in SPIR-V
+ // there are two ways to indicate a storage buffer:
+ // 1) Uniform storage class + BufferBlock decoration, or
+ // 2) StorageBuffer storage class + Buffer decoration.
+ // The 1) way is deprecated since SPIR-V v1.3. But the Buffer decoration is
+ // also used together with Uniform storage class to mean uniform buffer..
+ // We'll handle the pre-v1.3 cases in ParseDescriptorType().
+ if (pointer_storage_class == SpvStorageClassStorageBuffer) {
+ p_descriptor->descriptor_type = SPV_REFLECT_DESCRIPTOR_TYPE_STORAGE_BUFFER;
+ }
+
+ // 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;
+
+ if ((int)p_descriptor->descriptor_type == (int)INVALID_VALUE) {
+ 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;
+
+ case SPV_REFLECT_TYPE_FLAG_EXTERNAL_ACCELERATION_STRUCTURE: {
+ p_descriptor->descriptor_type = SPV_REFLECT_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR;
+ } 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;
+ case SPV_REFLECT_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR:
+ p_descriptor->resource_type = SPV_REFLECT_RESOURCE_FLAG_SRV;
+ 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(SpvReflectPrvParser* 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;
+ }
+
+ SpvReflectPrvNode* 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
+ while (p_type_node->op == SpvOpTypeArray || p_type_node->op == SpvOpTypeRuntimeArray) {
+ if (p_type_node->op == SpvOpTypeArray) {
+ p_type_node = FindNode(p_parser, p_type_node->array_traits.element_type_id);
+ } else {
+ // Element type description
+ SpvReflectTypeDescription* p_type_temp = FindType(p_module, p_type_node->array_traits.element_type_id);
+ if (IsNull(p_type_temp)) {
+ return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE;
+ }
+ // Element type node
+ p_type_node = FindNode(p_parser, p_type_temp->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];
+ // If pointer type, treat like reference and resolve to pointee type
+ SpvReflectTypeDescription* p_member_ptr_type = 0;
+ bool found_recursion = false;
+
+ if ((p_member_type->storage_class == SpvStorageClassPhysicalStorageBuffer) &&
+ (p_member_type->type_flags & SPV_REFLECT_TYPE_FLAG_REF)) {
+ // Remember the original type
+ p_member_ptr_type = p_member_type;
+
+ // strip array
+ if (p_member_type->op == SpvOpTypeArray || p_member_type->op == SpvOpTypeRuntimeArray) {
+ SpvReflectPrvNode* p_node = FindNode(p_parser, p_member_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;
+ p_member_type = FindType(p_module, element_type_id);
+ if (p_member_type == NULL) {
+ return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE;
+ }
+ }
+
+ // Need to make sure we haven't started an infinite recursive loop
+ for (uint32_t i = 0; i < p_parser->physical_pointer_count; i++) {
+ if (p_member_type->id == p_parser->physical_pointer_check[i]->id) {
+ found_recursion = true;
+ break; // still need to fill in p_member_type values
+ }
+ }
+ if (!found_recursion) {
+ uint32_t struct_id = FindType(p_module, p_member_type->id)->struct_type_description->id;
+ p_parser->physical_pointer_structs[p_parser->physical_pointer_struct_count].struct_id = struct_id;
+ p_parser->physical_pointer_structs[p_parser->physical_pointer_struct_count].p_var = p_member_var;
+ p_parser->physical_pointer_struct_count++;
+
+ p_parser->physical_pointer_check[p_parser->physical_pointer_count] = p_member_type;
+ p_parser->physical_pointer_count++;
+ if (p_parser->physical_pointer_count >= MAX_RECURSIVE_PHYSICAL_POINTER_CHECK) {
+ return SPV_REFLECT_RESULT_ERROR_SPIRV_MAX_RECURSIVE_EXCEEDED;
+ }
+ }
+
+ SpvReflectPrvNode* p_member_type_node = FindNode(p_parser, p_member_type->id);
+ if (IsNull(p_member_type_node)) {
+ return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE;
+ }
+ // Should be the pointee type
+ p_member_type = FindType(p_module, p_member_type_node->type_id);
+ if (IsNull(p_member_type)) {
+ return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE;
+ }
+ }
+ bool is_struct = (p_member_type->type_flags & SPV_REFLECT_TYPE_FLAG_STRUCT) == SPV_REFLECT_TYPE_FLAG_STRUCT;
+ if (is_struct) {
+ if (!found_recursion) {
+ SpvReflectResult result = ParseDescriptorBlockVariable(p_parser, p_module, p_member_type, p_member_var);
+ if (result != SPV_REFLECT_RESULT_SUCCESS) {
+ return result;
+ }
+ } else {
+ // if 2 member of structs are same PhysicalPointer type, copy the
+ // members values that aren't found skipping the recursion call
+ for (uint32_t i = 0; i < p_parser->physical_pointer_struct_count; i++) {
+ if (p_parser->physical_pointer_structs[i].struct_id == p_member_type->id) {
+ p_member_var->members = p_parser->physical_pointer_structs[i].p_var->members;
+ p_member_var->member_count = p_parser->physical_pointer_structs[i].p_var->member_count;
+ // Set here as it is the first time we need to walk down structs
+ p_member_var->flags |= SPV_REFLECT_VARIABLE_FLAGS_PHYSICAL_POINTER_COPY;
+ }
+ }
+ }
+ }
+
+ if (p_type_node->storage_class == SpvStorageClassPhysicalStorageBuffer && !p_type_node->member_names) {
+ // TODO 212 - If a buffer ref has an array of itself, all members are null
+ continue;
+ }
+
+ 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->word_offset.offset = p_type_node->member_decorations[member_index].offset.word_offset;
+ p_member_var->type_description = p_member_ptr_type ? p_member_ptr_type : 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 uint32_t GetPhysicalPointerStructSize(SpvReflectPrvParser* p_parser, uint32_t id) {
+ for (uint32_t i = 0; i < p_parser->physical_pointer_struct_count; i++) {
+ if (p_parser->physical_pointer_structs[i].struct_id == id) {
+ return p_parser->physical_pointer_structs[i].p_var->size;
+ }
+ }
+ return 0;
+}
+
+static SpvReflectResult ParseDescriptorBlockVariableSizes(SpvReflectPrvParser* 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;
+ }
+
+ bool is_parent_ref = p_var->type_description->op == SpvOpTypePointer;
+
+ // 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 : (is_parent_ref ? p_member_var->offset : 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;
+
+ if (!p_member_type) {
+ // TODO 212 - If a buffer ref has an array of itself, all members are null
+ continue;
+ }
+ 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) {
+ if (p_member_var->flags & SPV_REFLECT_VARIABLE_FLAGS_PHYSICAL_POINTER_COPY) {
+ p_member_var->size = GetPhysicalPointerStructSize(p_parser, p_member_type->id);
+ } else {
+ 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 SpvOpTypePointer: {
+ // Reference. Get to underlying struct type.
+ SpvReflectPrvNode* p_member_type_node = FindNode(p_parser, p_member_type->id);
+ if (IsNull(p_member_type_node)) {
+ return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE;
+ }
+ // Get the pointee type
+ p_member_type = FindType(p_module, p_member_type_node->type_id);
+ if (IsNull(p_member_type)) {
+ return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE;
+ }
+ assert(p_member_type->op == SpvOpTypeStruct);
+ FALLTHROUGH;
+ }
+
+ case SpvOpTypeStruct: {
+ if (p_member_var->flags & SPV_REFLECT_VARIABLE_FLAGS_PHYSICAL_POINTER_COPY) {
+ p_member_var->size = GetPhysicalPointerStructSize(p_parser, p_member_type->id);
+ } else {
+ 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;
+ }
+ }
+
+ // Structs can offset order don't need to match the index order, so first order by offset
+ // example:
+ // OpMemberDecorate %struct 0 Offset 4
+ // OpMemberDecorate %struct 1 Offset 0
+ SpvReflectBlockVariable** pp_member_offset_order =
+ (SpvReflectBlockVariable**)calloc(p_var->member_count, sizeof(SpvReflectBlockVariable*));
+ if (IsNull(pp_member_offset_order)) {
+ return SPV_REFLECT_RESULT_ERROR_ALLOC_FAILED;
+ }
+
+ uint32_t bottom_bound = 0;
+ for (uint32_t i = 0; i < p_var->member_count; ++i) {
+ uint32_t lowest_offset = UINT32_MAX;
+ uint32_t member_index = 0;
+ for (uint32_t j = 0; j < p_var->member_count; ++j) {
+ const uint32_t offset = p_var->members[j].offset;
+ if (offset < lowest_offset && offset >= bottom_bound) {
+ member_index = j;
+ lowest_offset = offset;
+ }
+ }
+ pp_member_offset_order[i] = &p_var->members[member_index];
+ bottom_bound = lowest_offset + 1; // 2 index can't share the same offset
+ }
+
+ // Parse padded size using offset difference for all member except for the last entry...
+ for (uint32_t i = 0; i < (p_var->member_count - 1); ++i) {
+ SpvReflectBlockVariable* p_member_var = pp_member_offset_order[i];
+ SpvReflectBlockVariable* p_next_member_var = pp_member_offset_order[i + 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.
+ // last entry == entry with largest offset value
+ SpvReflectBlockVariable* p_last_member_var = pp_member_offset_order[p_var->member_count - 1];
+ p_last_member_var->padded_size =
+ RoundUp(p_last_member_var->offset + p_last_member_var->size, SPIRV_DATA_ALIGNMENT) - p_last_member_var->offset;
+ if (p_last_member_var->size > p_last_member_var->padded_size) {
+ p_last_member_var->size = p_last_member_var->padded_size;
+ }
+ if (is_parent_rta) {
+ p_last_member_var->padded_size = p_last_member_var->size;
+ }
+
+ SafeFree(pp_member_offset_order);
+
+ // If buffer ref, sizes are same as uint64_t
+ if (is_parent_ref) {
+ p_var->size = p_var->padded_size = 8;
+ return SPV_REFLECT_RESULT_SUCCESS;
+ }
+
+ // @TODO validate this with assertion
+ p_var->size = p_last_member_var->offset + p_last_member_var->padded_size;
+ p_var->padded_size = p_var->size;
+
+ return SPV_REFLECT_RESULT_SUCCESS;
+}
+
+static void MarkSelfAndAllMemberVarsAsUsed(SpvReflectBlockVariable* p_var) {
+ // Clear the current variable's UNUSED flag
+ p_var->flags &= ~SPV_REFLECT_VARIABLE_FLAGS_UNUSED;
+
+ SpvOp op_type = p_var->type_description->op;
+ switch (op_type) {
+ default:
+ break;
+
+ case SpvOpTypeArray: {
+ } break;
+
+ case SpvOpTypeStruct: {
+ for (uint32_t i = 0; i < p_var->member_count; ++i) {
+ SpvReflectBlockVariable* p_member_var = &p_var->members[i];
+ MarkSelfAndAllMemberVarsAsUsed(p_member_var);
+ }
+ } break;
+ }
+}
+
+static SpvReflectResult ParseDescriptorBlockVariableUsage(SpvReflectPrvParser* p_parser, SpvReflectShaderModule* p_module,
+ SpvReflectPrvAccessChain* p_access_chain, uint32_t index_index,
+ SpvOp override_op_type, SpvReflectBlockVariable* p_var) {
+ // Clear the current variable's UNUSED flag
+ p_var->flags &= ~SPV_REFLECT_VARIABLE_FLAGS_UNUSED;
+
+ // Parsing arrays requires overriding the op type for
+ // for the lowest dim's element type.
+ SpvReflectTypeDescription* p_type = p_var->type_description;
+ SpvOp op_type = p_type->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
+ while ((p_type->op == SpvOpTypeArray) && (index_index < p_access_chain->index_count)) {
+ // Find the array element type id
+ SpvReflectPrvNode* 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 chain index
+ index_index += 1;
+ }
+
+ // Only continue parsing if there's remaining indices in the access
+ // chain. If the end of the access chain has been reached then all
+ // remaining variables (including those in struct hierarchies)
+ // are considered USED.
+ //
+ // See: https://github.com/KhronosGroup/SPIRV-Reflect/issues/78
+ //
+ if (index_index < p_access_chain->index_count) {
+ // 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;
+ }
+ } else {
+ // Clear UNUSED flag for remaining variables
+ MarkSelfAndAllMemberVarsAsUsed(p_var);
+ }
+ } break;
+
+ case SpvOpTypePointer: {
+ // Reference. Get to underlying struct type.
+ SpvReflectPrvNode* p_type_node = FindNode(p_parser, p_type->id);
+ if (IsNull(p_type_node)) {
+ return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE;
+ }
+ // Get the pointee type
+ p_type = FindType(p_module, p_type_node->type_id);
+ if (IsNull(p_type)) {
+ return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE;
+ }
+ if (p_type->op != SpvOpTypeStruct) {
+ break;
+ }
+ FALLTHROUGH;
+ }
+
+ case SpvOpTypeStruct: {
+ assert(p_var->member_count > 0);
+ if (p_var->member_count == 0) {
+ return SPV_REFLECT_RESULT_ERROR_SPIRV_UNEXPECTED_BLOCK_DATA;
+ }
+
+ // The access chain can have zero indexes, if used for a runtime array
+ if (p_access_chain->index_count == 0) {
+ return SPV_REFLECT_RESULT_SUCCESS;
+ }
+
+ // Get member variable at the access's chain current index
+ 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];
+
+ bool is_pointer_to_pointer = IsPointerToPointer(p_parser, p_access_chain->result_type_id);
+ if (is_pointer_to_pointer) {
+ // Remember block var for this access chain for downstream dereference
+ p_access_chain->block_var = p_member_var;
+ }
+
+ // Next access chain index
+ index_index += 1;
+
+ // Only continue parsing if there's remaining indices in the access
+ // chain. If the end of the access chain has been reach then all
+ // remaining variables (including those in struct hierarchies)
+ // are considered USED.
+ //
+ // See: https://github.com/KhronosGroup/SPIRV-Reflect/issues/78
+ //
+ if (index_index < p_access_chain->index_count) {
+ SpvReflectResult result =
+ ParseDescriptorBlockVariableUsage(p_parser, p_module, p_access_chain, index_index, (SpvOp)INVALID_VALUE, p_member_var);
+ if (result != SPV_REFLECT_RESULT_SUCCESS) {
+ return result;
+ }
+ } else if (!is_pointer_to_pointer) {
+ // Clear UNUSED flag for remaining variables
+ MarkSelfAndAllMemberVarsAsUsed(p_member_var);
+ }
+ } break;
+ }
+
+ return SPV_REFLECT_RESULT_SUCCESS;
+}
+
+static SpvReflectResult ParseDescriptorBlocks(SpvReflectPrvParser* p_parser, SpvReflectShaderModule* p_module) {
+ if (p_module->descriptor_binding_count == 0) {
+ return SPV_REFLECT_RESULT_SUCCESS;
+ }
+
+ p_parser->physical_pointer_struct_count = 0;
+
+ 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;
+ p_parser->physical_pointer_count = 0;
+ // 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) {
+ SpvReflectPrvAccessChain* 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 != 0);
+ uint32_t bit_width = p_type->traits.numeric.scalar.width;
+ 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 (bit_width) {
+ case 16: {
+ switch (component_count) {
+ case 2:
+ *p_format = SPV_REFLECT_FORMAT_R16G16_SFLOAT;
+ break;
+ case 3:
+ *p_format = SPV_REFLECT_FORMAT_R16G16B16_SFLOAT;
+ break;
+ case 4:
+ *p_format = SPV_REFLECT_FORMAT_R16G16B16A16_SFLOAT;
+ break;
+ }
+ } break;
+
+ case 32: {
+ 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;
+ }
+ } break;
+
+ case 64: {
+ switch (component_count) {
+ case 2:
+ *p_format = SPV_REFLECT_FORMAT_R64G64_SFLOAT;
+ break;
+ case 3:
+ *p_format = SPV_REFLECT_FORMAT_R64G64B64_SFLOAT;
+ break;
+ case 4:
+ *p_format = SPV_REFLECT_FORMAT_R64G64B64A64_SFLOAT;
+ break;
+ }
+ }
+ }
+ result = SPV_REFLECT_RESULT_SUCCESS;
+ } else if (p_type->type_flags & (SPV_REFLECT_TYPE_FLAG_INT | SPV_REFLECT_TYPE_FLAG_BOOL)) {
+ switch (bit_width) {
+ case 16: {
+ switch (component_count) {
+ case 2:
+ *p_format = signedness ? SPV_REFLECT_FORMAT_R16G16_SINT : SPV_REFLECT_FORMAT_R16G16_UINT;
+ break;
+ case 3:
+ *p_format = signedness ? SPV_REFLECT_FORMAT_R16G16B16_SINT : SPV_REFLECT_FORMAT_R16G16B16_UINT;
+ break;
+ case 4:
+ *p_format = signedness ? SPV_REFLECT_FORMAT_R16G16B16A16_SINT : SPV_REFLECT_FORMAT_R16G16B16A16_UINT;
+ break;
+ }
+ } break;
+
+ case 32: {
+ 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;
+ }
+ } break;
+
+ case 64: {
+ switch (component_count) {
+ case 2:
+ *p_format = signedness ? SPV_REFLECT_FORMAT_R64G64_SINT : SPV_REFLECT_FORMAT_R64G64_UINT;
+ break;
+ case 3:
+ *p_format = signedness ? SPV_REFLECT_FORMAT_R64G64B64_SINT : SPV_REFLECT_FORMAT_R64G64B64_UINT;
+ break;
+ case 4:
+ *p_format = signedness ? SPV_REFLECT_FORMAT_R64G64B64A64_SINT : SPV_REFLECT_FORMAT_R64G64B64A64_UINT;
+ break;
+ }
+ }
+ }
+ result = SPV_REFLECT_RESULT_SUCCESS;
+ }
+ } else if (p_type->type_flags & SPV_REFLECT_TYPE_FLAG_FLOAT) {
+ switch (bit_width) {
+ case 16:
+ *p_format = SPV_REFLECT_FORMAT_R16_SFLOAT;
+ break;
+ case 32:
+ *p_format = SPV_REFLECT_FORMAT_R32_SFLOAT;
+ break;
+ case 64:
+ *p_format = SPV_REFLECT_FORMAT_R64_SFLOAT;
+ break;
+ }
+ result = SPV_REFLECT_RESULT_SUCCESS;
+ } else if (p_type->type_flags & (SPV_REFLECT_TYPE_FLAG_INT | SPV_REFLECT_TYPE_FLAG_BOOL)) {
+ switch (bit_width) {
+ case 16:
+ *p_format = signedness ? SPV_REFLECT_FORMAT_R16_SINT : SPV_REFLECT_FORMAT_R16_UINT;
+ break;
+ break;
+ case 32:
+ *p_format = signedness ? SPV_REFLECT_FORMAT_R32_SINT : SPV_REFLECT_FORMAT_R32_UINT;
+ break;
+ break;
+ case 64:
+ *p_format = signedness ? SPV_REFLECT_FORMAT_R64_SINT : SPV_REFLECT_FORMAT_R64_UINT;
+ break;
+ }
+ 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(SpvReflectPrvParser* p_parser,
+ const SpvReflectPrvDecorations* p_var_node_decorations,
+ const SpvReflectPrvDecorations* p_type_node_decorations,
+ SpvReflectShaderModule* p_module, SpvReflectTypeDescription* p_type,
+ SpvReflectInterfaceVariable* p_var, bool* p_has_built_in) {
+ SpvReflectPrvNode* 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) {
+ SpvReflectPrvDecorations* 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];
+
+ // Storage class is the same throughout the whole struct
+ p_member_var->storage_class = p_var->storage_class;
+
+ SpvReflectResult result =
+ ParseInterfaceVariable(p_parser, NULL, p_member_decorations, p_module, p_member_type, p_member_var, p_has_built_in);
+ if (result != SPV_REFLECT_RESULT_SUCCESS) {
+ SPV_REFLECT_ASSERT(false);
+ return result;
+ }
+ }
+ }
+
+ p_var->name = p_type_node->name;
+ p_var->decoration_flags = ApplyDecorations(p_type_node_decorations);
+ if (p_var_node_decorations != NULL) {
+ p_var->decoration_flags |= ApplyDecorations(p_var_node_decorations);
+ } else {
+ // Apply member decoration values to struct members
+ p_var->location = p_type_node_decorations->location.value;
+ p_var->component = p_type_node_decorations->component.value;
+ }
+
+ 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;
+
+ // Only parse format for interface variables that are input or output
+ if ((p_var->storage_class == SpvStorageClassInput) || (p_var->storage_class == SpvStorageClassOutput)) {
+ SpvReflectResult result = ParseFormat(p_var->type_description, &p_var->format);
+ if (result != SPV_REFLECT_RESULT_SUCCESS) {
+ SPV_REFLECT_ASSERT(false);
+ return result;
+ }
+ }
+
+ return SPV_REFLECT_RESULT_SUCCESS;
+}
+
+static SpvReflectResult ParseInterfaceVariables(SpvReflectPrvParser* p_parser, SpvReflectShaderModule* p_module,
+ SpvReflectEntryPoint* p_entry, uint32_t interface_variable_count,
+ uint32_t* p_interface_variable_ids) {
+ if (interface_variable_count == 0) {
+ return SPV_REFLECT_RESULT_SUCCESS;
+ }
+
+ p_entry->interface_variable_count = interface_variable_count;
+ p_entry->input_variable_count = 0;
+ p_entry->output_variable_count = 0;
+ for (size_t i = 0; i < interface_variable_count; ++i) {
+ uint32_t var_result_id = *(p_interface_variable_ids + i);
+ SpvReflectPrvNode* 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;
+ }
+ }
+
+ if (p_entry->interface_variable_count > 0) {
+ p_entry->interface_variables =
+ (SpvReflectInterfaceVariable*)calloc(p_entry->interface_variable_count, sizeof(*(p_entry->interface_variables)));
+ if (IsNull(p_entry->interface_variables)) {
+ return SPV_REFLECT_RESULT_ERROR_ALLOC_FAILED;
+ }
+ }
+
+ size_t input_index = 0;
+ size_t output_index = 0;
+ for (size_t i = 0; i < interface_variable_count; ++i) {
+ uint32_t var_result_id = *(p_interface_variable_ids + i);
+ SpvReflectPrvNode* 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) || 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
+ SpvReflectPrvNode* 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;
+ }
+ }
+
+ SpvReflectPrvNode* 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 = &(p_entry->interface_variables[i]);
+ p_var->storage_class = p_node->storage_class;
+
+ bool has_built_in = p_node->decorations.is_built_in;
+ SpvReflectResult result =
+ ParseInterfaceVariable(p_parser, &p_node->decorations, &p_type_node->decorations, p_module, p_type, p_var, &has_built_in);
+ if (result != SPV_REFLECT_RESULT_SUCCESS) {
+ SPV_REFLECT_ASSERT(false);
+ return result;
+ }
+
+ // Input and output variables
+ if (p_var->storage_class == SpvStorageClassInput) {
+ p_entry->input_variables[input_index] = p_var;
+ ++input_index;
+ } else if (p_node->storage_class == SpvStorageClassOutput) {
+ p_entry->output_variables[output_index] = p_var;
+ ++output_index;
+ }
+
+ // 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->component = p_node->decorations.component.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(SpvReflectPrvParser* p_parser, SpvReflectPrvFunction* 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 uint32_t GetUint32Constant(SpvReflectPrvParser* p_parser, uint32_t id) {
+ uint32_t result = (uint32_t)INVALID_VALUE;
+ SpvReflectPrvNode* p_node = FindNode(p_parser, id);
+ if (p_node && p_node->op == SpvOpConstant) {
+ UNCHECKED_READU32(p_parser, p_node->word_offset + 3, result);
+ }
+ return result;
+}
+
+static bool HasByteAddressBufferOffset(SpvReflectPrvNode* p_node, SpvReflectDescriptorBinding* p_binding) {
+ return IsNotNull(p_node) && IsNotNull(p_binding) && p_node->op == SpvOpAccessChain && p_node->word_count == 6 &&
+ (p_binding->user_type == SPV_REFLECT_USER_TYPE_BYTE_ADDRESS_BUFFER ||
+ p_binding->user_type == SPV_REFLECT_USER_TYPE_RW_BYTE_ADDRESS_BUFFER);
+}
+
+static SpvReflectResult ParseByteAddressBuffer(SpvReflectPrvParser* p_parser, SpvReflectPrvNode* p_node,
+ SpvReflectDescriptorBinding* p_binding) {
+ const SpvReflectResult not_found = SPV_REFLECT_RESULT_SUCCESS;
+ if (!HasByteAddressBufferOffset(p_node, p_binding)) {
+ return not_found;
+ }
+
+ uint32_t offset = 0; // starting offset
+
+ uint32_t base_id = 0;
+ // expect first index of 2D access is zero
+ UNCHECKED_READU32(p_parser, p_node->word_offset + 4, base_id);
+ if (GetUint32Constant(p_parser, base_id) != 0) {
+ return not_found;
+ }
+ UNCHECKED_READU32(p_parser, p_node->word_offset + 5, base_id);
+ SpvReflectPrvNode* p_next_node = FindNode(p_parser, base_id);
+ if (IsNull(p_next_node)) {
+ return not_found;
+ } else if (p_next_node->op == SpvOpConstant) {
+ // The access chain might just be a constant right to the offset
+ offset = GetUint32Constant(p_parser, base_id);
+ p_binding->byte_address_buffer_offsets[p_binding->byte_address_buffer_offset_count] = offset;
+ p_binding->byte_address_buffer_offset_count++;
+ return SPV_REFLECT_RESULT_SUCCESS;
+ }
+
+ // there is usually 2 (sometimes 3) instrucitons that make up the arithmetic logic to calculate the offset
+ SpvReflectPrvNode* arithmetic_node_stack[8];
+ uint32_t arithmetic_count = 0;
+
+ while (IsNotNull(p_next_node)) {
+ if (p_next_node->op == SpvOpLoad || p_next_node->op == SpvOpBitcast || p_next_node->op == SpvOpConstant) {
+ break; // arithmetic starts here
+ }
+ arithmetic_node_stack[arithmetic_count++] = p_next_node;
+ if (arithmetic_count >= 8) {
+ return not_found;
+ }
+
+ UNCHECKED_READU32(p_parser, p_next_node->word_offset + 3, base_id);
+ p_next_node = FindNode(p_parser, base_id);
+ }
+
+ const uint32_t count = arithmetic_count;
+ for (uint32_t i = 0; i < count; i++) {
+ p_next_node = arithmetic_node_stack[--arithmetic_count];
+ // All arithmetic ops takes 2 operands, assumption is the 2nd operand has the constant
+ UNCHECKED_READU32(p_parser, p_next_node->word_offset + 4, base_id);
+ uint32_t value = GetUint32Constant(p_parser, base_id);
+ if (value == INVALID_VALUE) {
+ return not_found;
+ }
+
+ switch (p_next_node->op) {
+ case SpvOpShiftRightLogical:
+ offset >>= value;
+ break;
+ case SpvOpIAdd:
+ offset += value;
+ break;
+ case SpvOpISub:
+ offset -= value;
+ break;
+ case SpvOpIMul:
+ offset *= value;
+ break;
+ case SpvOpUDiv:
+ offset /= value;
+ break;
+ case SpvOpSDiv:
+ // OpConstant might be signed, but value should never be negative
+ assert((int32_t)value > 0);
+ offset /= value;
+ break;
+ default:
+ return not_found;
+ }
+ }
+
+ p_binding->byte_address_buffer_offsets[p_binding->byte_address_buffer_offset_count] = offset;
+ p_binding->byte_address_buffer_offset_count++;
+ return SPV_REFLECT_RESULT_SUCCESS;
+}
+
+static SpvReflectResult ParseFunctionParameterAccess(SpvReflectPrvParser* p_parser, uint32_t callee_function_id,
+ uint32_t function_parameter_index, uint32_t* p_accessed) {
+ SpvReflectPrvFunction* p_func = NULL;
+ for (size_t i = 0; i < p_parser->function_count; ++i) {
+ if (p_parser->functions[i].id == callee_function_id) {
+ p_func = &(p_parser->functions[i]);
+ break;
+ }
+ }
+ if (p_func == NULL) {
+ return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE;
+ }
+
+ assert(function_parameter_index < p_func->parameter_count);
+
+ for (size_t i = 0; i < p_func->accessed_variable_count; ++i) {
+ if (p_func->parameters[function_parameter_index] == p_func->accessed_variables[i].variable_ptr) {
+ SpvReflectPrvAccessedVariable* p_var = &p_func->accessed_variables[i];
+ if (p_var->function_id > 0) {
+ SpvReflectResult result =
+ ParseFunctionParameterAccess(p_parser, p_var->function_id, p_var->function_parameter_index, p_accessed);
+ if (result != SPV_REFLECT_RESULT_SUCCESS) {
+ return result;
+ }
+ } else {
+ *p_accessed = 1;
+ }
+ // Early out as soon as p_accessed is true
+ if (*p_accessed) {
+ return SPV_REFLECT_RESULT_SUCCESS;
+ }
+ }
+ }
+
+ *p_accessed = 0;
+ return SPV_REFLECT_RESULT_SUCCESS;
+}
+
+static SpvReflectResult ParseStaticallyUsedResources(SpvReflectPrvParser* 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
+ SpvReflectPrvFunction* 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) {
+ SafeFree(p_called_functions);
+ 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_acessed_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_acessed_count += p_parser->functions[j].accessed_variable_count;
+ }
+ SpvReflectPrvAccessedVariable* p_used_accesses = NULL;
+ if (used_acessed_count > 0) {
+ p_used_accesses = (SpvReflectPrvAccessedVariable*)calloc(used_acessed_count, sizeof(SpvReflectPrvAccessedVariable));
+ if (IsNull(p_used_accesses)) {
+ SafeFree(p_called_functions);
+ return SPV_REFLECT_RESULT_ERROR_ALLOC_FAILED;
+ }
+ }
+ used_acessed_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(&p_used_accesses[used_acessed_count], p_parser->functions[j].accessed_variables,
+ p_parser->functions[j].accessed_variable_count * sizeof(SpvReflectPrvAccessedVariable));
+ used_acessed_count += p_parser->functions[j].accessed_variable_count;
+ }
+ SafeFree(p_called_functions);
+
+ if (used_acessed_count > 0) {
+ qsort(p_used_accesses, used_acessed_count, sizeof(*p_used_accesses), SortCompareAccessedVariable);
+ }
+
+ // Do set intersection to find the used uniform and push constants
+ size_t used_uniform_count = 0;
+ result = IntersectSortedAccessedVariable(p_used_accesses, used_acessed_count, uniforms, uniform_count, &p_entry->used_uniforms,
+ &used_uniform_count);
+ if (result != SPV_REFLECT_RESULT_SUCCESS) {
+ SafeFree(p_used_accesses);
+ return result;
+ }
+
+ size_t used_push_constant_count = 0;
+ result = IntersectSortedAccessedVariable(p_used_accesses, used_acessed_count, push_constants, push_constant_count,
+ &p_entry->used_push_constants, &used_push_constant_count);
+ if (result != SPV_REFLECT_RESULT_SUCCESS) {
+ SafeFree(p_used_accesses);
+ return result;
+ }
+
+ for (uint32_t i = 0; i < p_module->descriptor_binding_count; ++i) {
+ SpvReflectDescriptorBinding* p_binding = &p_module->descriptor_bindings[i];
+ uint32_t byte_address_buffer_offset_count = 0;
+
+ for (uint32_t j = 0; j < used_acessed_count; j++) {
+ SpvReflectPrvAccessedVariable* p_var = &p_used_accesses[j];
+ if (p_var->variable_ptr == p_binding->spirv_id) {
+ if (p_var->function_id > 0) {
+ result =
+ ParseFunctionParameterAccess(p_parser, p_var->function_id, p_var->function_parameter_index, &p_binding->accessed);
+ if (result != SPV_REFLECT_RESULT_SUCCESS) {
+ SafeFree(p_used_accesses);
+ return result;
+ }
+ } else {
+ p_binding->accessed = 1;
+ }
+
+ if (HasByteAddressBufferOffset(p_used_accesses[j].p_node, p_binding)) {
+ byte_address_buffer_offset_count++;
+ }
+ }
+ }
+
+ // only if SPIR-V has ByteAddressBuffer user type
+ if (byte_address_buffer_offset_count > 0) {
+ bool multi_entrypoint = p_binding->byte_address_buffer_offset_count > 0;
+ if (multi_entrypoint) {
+ // If there is a 2nd entrypoint, we can have multiple entry points, in this case we want to just combine the accessed
+ // offsets and then de-duplicate it
+ uint32_t* prev_byte_address_buffer_offsets = p_binding->byte_address_buffer_offsets;
+ p_binding->byte_address_buffer_offsets =
+ (uint32_t*)calloc(byte_address_buffer_offset_count + p_binding->byte_address_buffer_offset_count, sizeof(uint32_t));
+ memcpy(p_binding->byte_address_buffer_offsets, prev_byte_address_buffer_offsets,
+ sizeof(uint32_t) * p_binding->byte_address_buffer_offset_count);
+ SafeFree(prev_byte_address_buffer_offsets);
+ } else {
+ // possible not all allocated offset slots are used, but this will be a max per binding
+ p_binding->byte_address_buffer_offsets = (uint32_t*)calloc(byte_address_buffer_offset_count, sizeof(uint32_t));
+ }
+
+ if (IsNull(p_binding->byte_address_buffer_offsets)) {
+ SafeFree(p_used_accesses);
+ return SPV_REFLECT_RESULT_ERROR_ALLOC_FAILED;
+ }
+
+ for (uint32_t j = 0; j < used_acessed_count; j++) {
+ if (p_used_accesses[j].variable_ptr == p_binding->spirv_id) {
+ result = ParseByteAddressBuffer(p_parser, p_used_accesses[j].p_node, p_binding);
+ if (result != SPV_REFLECT_RESULT_SUCCESS) {
+ SafeFree(p_used_accesses);
+ return result;
+ }
+ }
+ }
+
+ if (multi_entrypoint) {
+ qsort(p_binding->byte_address_buffer_offsets, p_binding->byte_address_buffer_offset_count,
+ sizeof(*(p_binding->byte_address_buffer_offsets)), SortCompareUint32);
+ p_binding->byte_address_buffer_offset_count =
+ (uint32_t)DedupSortedUint32(p_binding->byte_address_buffer_offsets, p_binding->byte_address_buffer_offset_count);
+ }
+ }
+ }
+
+ SafeFree(p_used_accesses);
+
+ 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(SpvReflectPrvParser* 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) {
+ SpvReflectPrvNode* 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;
+ case SpvExecutionModelTaskNV:
+ p_entry_point->shader_stage = SPV_REFLECT_SHADER_STAGE_TASK_BIT_NV;
+ break;
+ case SpvExecutionModelTaskEXT:
+ p_entry_point->shader_stage = SPV_REFLECT_SHADER_STAGE_TASK_BIT_EXT;
+ break;
+ case SpvExecutionModelMeshNV:
+ p_entry_point->shader_stage = SPV_REFLECT_SHADER_STAGE_MESH_BIT_NV;
+ break;
+ case SpvExecutionModelMeshEXT:
+ p_entry_point->shader_stage = SPV_REFLECT_SHADER_STAGE_MESH_BIT_EXT;
+ break;
+ case SpvExecutionModelRayGenerationKHR:
+ p_entry_point->shader_stage = SPV_REFLECT_SHADER_STAGE_RAYGEN_BIT_KHR;
+ break;
+ case SpvExecutionModelIntersectionKHR:
+ p_entry_point->shader_stage = SPV_REFLECT_SHADER_STAGE_INTERSECTION_BIT_KHR;
+ break;
+ case SpvExecutionModelAnyHitKHR:
+ p_entry_point->shader_stage = SPV_REFLECT_SHADER_STAGE_ANY_HIT_BIT_KHR;
+ break;
+ case SpvExecutionModelClosestHitKHR:
+ p_entry_point->shader_stage = SPV_REFLECT_SHADER_STAGE_CLOSEST_HIT_BIT_KHR;
+ break;
+ case SpvExecutionModelMissKHR:
+ p_entry_point->shader_stage = SPV_REFLECT_SHADER_STAGE_MISS_BIT_KHR;
+ break;
+ case SpvExecutionModelCallableKHR:
+ p_entry_point->shader_stage = SPV_REFLECT_SHADER_STAGE_CALLABLE_BIT_KHR;
+ 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;
+ uint32_t interface_variable_count = (p_node->word_count - (name_start_word_offset + name_word_count));
+ uint32_t* p_interface_variables = NULL;
+ if (interface_variable_count > 0) {
+ p_interface_variables = (uint32_t*)calloc(interface_variable_count, sizeof(*(p_interface_variables)));
+ if (IsNull(p_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);
+ p_interface_variables[var_index] = var_result_id;
+ }
+
+ result = ParseInterfaceVariables(p_parser, p_module, p_entry_point, interface_variable_count, p_interface_variables);
+ if (result != SPV_REFLECT_RESULT_SUCCESS) {
+ return result;
+ }
+ SafeFree(p_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 ParseExecutionModes(SpvReflectPrvParser* p_parser, SpvReflectShaderModule* p_module) {
+ assert(IsNotNull(p_parser));
+ assert(IsNotNull(p_parser->nodes));
+ assert(IsNotNull(p_module));
+
+ if (IsNotNull(p_parser) && IsNotNull(p_parser->spirv_code) && IsNotNull(p_parser->nodes)) {
+ for (size_t node_idx = 0; node_idx < p_parser->node_count; ++node_idx) {
+ SpvReflectPrvNode* p_node = &(p_parser->nodes[node_idx]);
+ if (p_node->op != SpvOpExecutionMode && p_node->op != SpvOpExecutionModeId) {
+ continue;
+ }
+
+ // Read entry point id
+ uint32_t entry_point_id = 0;
+ CHECKED_READU32(p_parser, p_node->word_offset + 1, entry_point_id);
+
+ // Find entry point
+ SpvReflectEntryPoint* p_entry_point = NULL;
+ for (size_t entry_point_idx = 0; entry_point_idx < p_module->entry_point_count; ++entry_point_idx) {
+ if (p_module->entry_points[entry_point_idx].id == entry_point_id) {
+ p_entry_point = &p_module->entry_points[entry_point_idx];
+ break;
+ }
+ }
+ // Bail if entry point is null
+ if (IsNull(p_entry_point)) {
+ return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ENTRY_POINT;
+ }
+
+ // Read execution mode
+ uint32_t execution_mode = (uint32_t)INVALID_VALUE;
+ CHECKED_READU32(p_parser, p_node->word_offset + 2, execution_mode);
+
+ // Parse execution mode
+ switch (execution_mode) {
+ case SpvExecutionModeInvocations: {
+ CHECKED_READU32(p_parser, p_node->word_offset + 3, p_entry_point->invocations);
+ } break;
+
+ case SpvExecutionModeLocalSize: {
+ CHECKED_READU32(p_parser, p_node->word_offset + 3, p_entry_point->local_size.x);
+ CHECKED_READU32(p_parser, p_node->word_offset + 4, p_entry_point->local_size.y);
+ CHECKED_READU32(p_parser, p_node->word_offset + 5, p_entry_point->local_size.z);
+ } break;
+ case SpvExecutionModeLocalSizeId: {
+ uint32_t local_size_x_id = 0;
+ uint32_t local_size_y_id = 0;
+ uint32_t local_size_z_id = 0;
+ CHECKED_READU32(p_parser, p_node->word_offset + 3, local_size_x_id);
+ CHECKED_READU32(p_parser, p_node->word_offset + 4, local_size_y_id);
+ CHECKED_READU32(p_parser, p_node->word_offset + 5, local_size_z_id);
+
+ SpvReflectPrvNode* x_node = FindNode(p_parser, local_size_x_id);
+ SpvReflectPrvNode* y_node = FindNode(p_parser, local_size_y_id);
+ SpvReflectPrvNode* z_node = FindNode(p_parser, local_size_z_id);
+ if (IsNotNull(x_node) && IsNotNull(y_node) && IsNotNull(z_node)) {
+ if (IsSpecConstant(x_node)) {
+ p_entry_point->local_size.x = (uint32_t)SPV_REFLECT_EXECUTION_MODE_SPEC_CONSTANT;
+ } else {
+ CHECKED_READU32(p_parser, x_node->word_offset + 3, p_entry_point->local_size.x);
+ }
+
+ if (IsSpecConstant(y_node)) {
+ p_entry_point->local_size.y = (uint32_t)SPV_REFLECT_EXECUTION_MODE_SPEC_CONSTANT;
+ } else {
+ CHECKED_READU32(p_parser, y_node->word_offset + 3, p_entry_point->local_size.y);
+ }
+
+ if (IsSpecConstant(z_node)) {
+ p_entry_point->local_size.z = (uint32_t)SPV_REFLECT_EXECUTION_MODE_SPEC_CONSTANT;
+ } else {
+ CHECKED_READU32(p_parser, z_node->word_offset + 3, p_entry_point->local_size.z);
+ }
+ }
+ } break;
+
+ case SpvExecutionModeOutputVertices: {
+ CHECKED_READU32(p_parser, p_node->word_offset + 3, p_entry_point->output_vertices);
+ } break;
+
+ default:
+ break;
+ }
+ p_entry_point->execution_mode_count++;
+ }
+ uint32_t* indices = (uint32_t*)calloc(p_module->entry_point_count, sizeof(indices));
+ if (IsNull(indices)) {
+ return SPV_REFLECT_RESULT_ERROR_ALLOC_FAILED;
+ }
+ for (size_t entry_point_idx = 0; entry_point_idx < p_module->entry_point_count; ++entry_point_idx) {
+ SpvReflectEntryPoint* p_entry_point = &p_module->entry_points[entry_point_idx];
+ if (p_entry_point->execution_mode_count > 0) {
+ p_entry_point->execution_modes =
+ (SpvExecutionMode*)calloc(p_entry_point->execution_mode_count, sizeof(*p_entry_point->execution_modes));
+ if (IsNull(p_entry_point->execution_modes)) {
+ SafeFree(indices);
+ return SPV_REFLECT_RESULT_ERROR_ALLOC_FAILED;
+ }
+ }
+ }
+
+ for (size_t node_idx = 0; node_idx < p_parser->node_count; ++node_idx) {
+ SpvReflectPrvNode* p_node = &(p_parser->nodes[node_idx]);
+ if (p_node->op != SpvOpExecutionMode) {
+ continue;
+ }
+
+ // Read entry point id
+ uint32_t entry_point_id = 0;
+ CHECKED_READU32(p_parser, p_node->word_offset + 1, entry_point_id);
+
+ // Find entry point
+ SpvReflectEntryPoint* p_entry_point = NULL;
+ uint32_t* idx = NULL;
+ for (size_t entry_point_idx = 0; entry_point_idx < p_module->entry_point_count; ++entry_point_idx) {
+ if (p_module->entry_points[entry_point_idx].id == entry_point_id) {
+ p_entry_point = &p_module->entry_points[entry_point_idx];
+ idx = &indices[entry_point_idx];
+ break;
+ }
+ }
+
+ // Read execution mode
+ uint32_t execution_mode = (uint32_t)INVALID_VALUE;
+ CHECKED_READU32(p_parser, p_node->word_offset + 2, execution_mode);
+ p_entry_point->execution_modes[(*idx)++] = (SpvExecutionMode)execution_mode;
+ }
+ SafeFree(indices);
+ }
+ return SPV_REFLECT_RESULT_SUCCESS;
+}
+
+static SpvReflectResult ParsePushConstantBlocks(SpvReflectPrvParser* p_parser, SpvReflectShaderModule* p_module) {
+ for (size_t i = 0; i < p_parser->node_count; ++i) {
+ SpvReflectPrvNode* 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;
+ }
+
+ p_parser->physical_pointer_struct_count = 0;
+ uint32_t push_constant_index = 0;
+ for (size_t i = 0; i < p_parser->node_count; ++i) {
+ SpvReflectPrvNode* 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) || 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
+ SpvReflectPrvNode* 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;
+ }
+ }
+
+ SpvReflectPrvNode* 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;
+ p_parser->physical_pointer_count = 0;
+ SpvReflectResult result = ParseDescriptorBlockVariable(p_parser, p_module, p_type, p_push_constant);
+ 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) {
+ SpvReflectPrvAccessChain* p_access_chain = &(p_parser->access_chains[access_chain_index]);
+ // Skip any access chains that aren't touching this push constant block
+ if (p_push_constant->spirv_id != FindAccessChainBaseVariable(p_parser, p_access_chain)) {
+ continue;
+ }
+ SpvReflectBlockVariable* p_var =
+ (p_access_chain->base_id == p_push_constant->spirv_id) ? p_push_constant : GetRefBlkVar(p_parser, p_access_chain);
+ result = ParseDescriptorBlockVariableUsage(p_parser, p_module, p_access_chain, 0, (SpvOp)INVALID_VALUE, p_var);
+ if (result != SPV_REFLECT_RESULT_SUCCESS) {
+ return result;
+ }
+ }
+
+ p_push_constant->name = p_node->name;
+ result = ParseDescriptorBlockVariableSizes(p_parser, p_module, true, false, false, p_push_constant);
+ if (result != SPV_REFLECT_RESULT_SUCCESS) {
+ return result;
+ }
+
+ // Get minimum offset for whole Push Constant block
+ // It is not valid SPIR-V to have an empty Push Constant Block
+ p_push_constant->offset = UINT32_MAX;
+ for (uint32_t k = 0; k < p_push_constant->member_count; ++k) {
+ const uint32_t member_offset = p_push_constant->members[k].offset;
+ p_push_constant->offset = Min(p_push_constant->offset, member_offset);
+ }
+
+ ++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;
+}
+
+static SpvReflectResult CreateShaderModule(uint32_t flags, 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;
+ }
+ // Copy flags
+ p_module->_internal->module_flags = flags;
+ // Figure out if we need to copy the SPIR-V code or not
+ if (flags & SPV_REFLECT_MODULE_FLAG_NO_COPY) {
+ // Set internal size and pointer to args passed in
+ p_module->_internal->spirv_size = size;
+#if defined(__cplusplus)
+ p_module->_internal->spirv_code = const_cast<uint32_t*>(static_cast<const uint32_t*>(p_code)); // cast that const away
+#else
+ p_module->_internal->spirv_code = (void*)p_code; // cast that const away
+#endif
+ p_module->_internal->spirv_word_count = (uint32_t)(size / SPIRV_WORD_SIZE);
+ } else {
+ // 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;
+ }
+ // Copy SPIR-V to code storage
+ memcpy(p_module->_internal->spirv_code, p_code, size);
+ }
+
+ // Initialize everything to zero
+ SpvReflectPrvParser parser;
+ memset(&parser, 0, sizeof(SpvReflectPrvParser));
+
+ // Create parser
+ 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);
+ SPV_REFLECT_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS);
+ }
+ if (result == SPV_REFLECT_RESULT_SUCCESS) {
+ result = ParseStrings(&parser);
+ SPV_REFLECT_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS);
+ }
+ if (result == SPV_REFLECT_RESULT_SUCCESS) {
+ result = ParseSource(&parser, p_module);
+ SPV_REFLECT_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS);
+ }
+ if (result == SPV_REFLECT_RESULT_SUCCESS) {
+ result = ParseFunctions(&parser);
+ SPV_REFLECT_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS);
+ }
+ if (result == SPV_REFLECT_RESULT_SUCCESS) {
+ result = ParseMemberCounts(&parser);
+ SPV_REFLECT_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS);
+ }
+ if (result == SPV_REFLECT_RESULT_SUCCESS) {
+ result = ParseNames(&parser);
+ SPV_REFLECT_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS);
+ }
+ if (result == SPV_REFLECT_RESULT_SUCCESS) {
+ result = ParseDecorations(&parser, p_module);
+ SPV_REFLECT_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS);
+ }
+
+ // 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);
+ SPV_REFLECT_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS);
+ }
+ if (result == SPV_REFLECT_RESULT_SUCCESS) {
+ result = ParseDescriptorBindings(&parser, p_module);
+ SPV_REFLECT_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS);
+ }
+ if (result == SPV_REFLECT_RESULT_SUCCESS) {
+ result = ParseDescriptorType(p_module);
+ SPV_REFLECT_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS);
+ }
+ if (result == SPV_REFLECT_RESULT_SUCCESS) {
+ result = ParseUAVCounterBindings(p_module);
+ SPV_REFLECT_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS);
+ }
+ if (result == SPV_REFLECT_RESULT_SUCCESS) {
+ result = ParseDescriptorBlocks(&parser, p_module);
+ SPV_REFLECT_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS);
+ }
+ if (result == SPV_REFLECT_RESULT_SUCCESS) {
+ result = ParsePushConstantBlocks(&parser, p_module);
+ SPV_REFLECT_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS);
+ }
+ if (result == SPV_REFLECT_RESULT_SUCCESS) {
+ result = ParseEntryPoints(&parser, p_module);
+ SPV_REFLECT_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS);
+ }
+ if (result == SPV_REFLECT_RESULT_SUCCESS) {
+ result = ParseCapabilities(&parser, p_module);
+ SPV_REFLECT_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS);
+ }
+ 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;
+ p_module->interface_variable_count = p_entry->interface_variable_count;
+ p_module->interface_variables = p_entry->interface_variables;
+ }
+ if (result == SPV_REFLECT_RESULT_SUCCESS) {
+ result = DisambiguateStorageBufferSrvUav(p_module);
+ SPV_REFLECT_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS);
+ }
+ if (result == SPV_REFLECT_RESULT_SUCCESS) {
+ result = SynchronizeDescriptorSets(p_module);
+ SPV_REFLECT_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS);
+ }
+ if (result == SPV_REFLECT_RESULT_SUCCESS) {
+ result = ParseExecutionModes(&parser, p_module);
+ SPV_REFLECT_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS);
+ }
+
+ // Destroy module if parse was not successful
+ if (result != SPV_REFLECT_RESULT_SUCCESS) {
+ spvReflectDestroyShaderModule(p_module);
+ }
+
+ DestroyParser(&parser);
+
+ return result;
+}
+
+SpvReflectResult spvReflectCreateShaderModule(size_t size, const void* p_code, SpvReflectShaderModule* p_module) {
+ return CreateShaderModule(0, size, p_code, p_module);
+}
+
+SpvReflectResult spvReflectCreateShaderModule2(uint32_t flags, size_t size, const void* p_code, SpvReflectShaderModule* p_module) {
+ return CreateShaderModule(flags, size, p_code, p_module);
+}
+
+SpvReflectResult spvReflectGetShaderModule(size_t size, const void* p_code, SpvReflectShaderModule* p_module) {
+ return spvReflectCreateShaderModule(size, p_code, p_module);
+}
+
+static void SafeFreeTypes(SpvReflectTypeDescription* p_type) {
+ if (IsNull(p_type) || p_type->copied) {
+ 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;
+ }
+
+ // We share pointers to Physical Pointer structs and don't want to double free
+ if (p_block->flags & SPV_REFLECT_VARIABLE_FLAGS_PHYSICAL_POINTER_COPY) {
+ 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;
+ }
+
+ SafeFree(p_module->source_source);
+
+ // 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];
+ if (IsNotNull(p_descriptor->byte_address_buffer_offsets)) {
+ SafeFree(p_descriptor->byte_address_buffer_offsets);
+ }
+ 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->interface_variable_count; j++) {
+ SafeFreeInterfaceVariable(&p_entry->interface_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->interface_variables);
+ SafeFree(p_entry->used_uniforms);
+ SafeFree(p_entry->used_push_constants);
+ SafeFree(p_entry->execution_modes);
+ }
+ SafeFree(p_module->capabilities);
+ SafeFree(p_module->entry_points);
+ SafeFree(p_module->spec_constants);
+
+ // 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 if there was a copy
+ if ((p_module->_internal->module_flags & SPV_REFLECT_MODULE_FLAG_NO_COPY) == 0) {
+ 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 spvReflectEnumerateInterfaceVariables(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->interface_variable_count) {
+ return SPV_REFLECT_RESULT_ERROR_COUNT_MISMATCH;
+ }
+
+ for (uint32_t index = 0; index < *p_count; ++index) {
+ SpvReflectInterfaceVariable* p_var = &p_module->interface_variables[index];
+ pp_variables[index] = p_var;
+ }
+ } else {
+ *p_count = p_module->interface_variable_count;
+ }
+
+ return SPV_REFLECT_RESULT_SUCCESS;
+}
+
+SpvReflectResult spvReflectEnumerateEntryPointInterfaceVariables(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->interface_variable_count) {
+ return SPV_REFLECT_RESULT_ERROR_COUNT_MISMATCH;
+ }
+
+ for (uint32_t index = 0; index < *p_count; ++index) {
+ SpvReflectInterfaceVariable* p_var = &p_entry->interface_variables[index];
+ pp_variables[index] = p_var;
+ }
+ } else {
+ *p_count = p_entry->interface_variable_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 = 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 = 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 = 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 = 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;
+}
+
+SpvReflectResult spvReflectEnumerateSpecializationConstants(const SpvReflectShaderModule* p_module, uint32_t* p_count,
+ SpvReflectSpecializationConstant** pp_constants) {
+ 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_constants)) {
+ if (*p_count != p_module->spec_constant_count) {
+ return SPV_REFLECT_RESULT_ERROR_COUNT_MISMATCH;
+ }
+
+ for (uint32_t index = 0; index < *p_count; ++index) {
+ SpvReflectSpecializationConstant* p_constant = (SpvReflectSpecializationConstant*)&p_module->spec_constants[index];
+ pp_constants[index] = p_constant;
+ }
+ } else {
+ *p_count = p_module->spec_constant_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 != (uint32_t)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 != (uint32_t)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 != (uint32_t)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 != (uint32_t)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 SpvSourceLanguageESSL:
+ return "ESSL";
+ case SpvSourceLanguageGLSL:
+ return "GLSL";
+ case SpvSourceLanguageOpenCL_C:
+ return "OpenCL_C";
+ case SpvSourceLanguageOpenCL_CPP:
+ return "OpenCL_CPP";
+ case SpvSourceLanguageHLSL:
+ return "HLSL";
+ case SpvSourceLanguageCPP_for_OpenCL:
+ return "CPP_for_OpenCL";
+ case SpvSourceLanguageSYCL:
+ return "SYCL";
+ case SpvSourceLanguageHERO_C:
+ return "Hero C";
+ case SpvSourceLanguageNZSL:
+ return "NZSL";
+ default:
+ break;
+ }
+ // The source language is SpvSourceLanguageUnknown, SpvSourceLanguageMax, or
+ // some other value that does not correspond to a knonwn language.
+ return "Unknown";
+}
+
+const char* spvReflectBlockVariableTypeName(const SpvReflectBlockVariable* p_var) {
+ if (p_var == NULL) {
+ return NULL;
+ }
+ return p_var->type_description->type_name;
+}
--- /dev/null
+//
+// This file exists to force compiling spirv_reflect.c as C++.
+//
+#include "spirv_reflect.c"
\ No newline at end of file
--- /dev/null
+/*
+ Copyright 2017-2022 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
+
+*/
+
+// clang-format off
+/*!
+
+ @file spirv_reflect.h
+
+*/
+#ifndef SPIRV_REFLECT_H
+#define SPIRV_REFLECT_H
+
+#if defined(SPIRV_REFLECT_USE_SYSTEM_SPIRV_H)
+#include <spirv/unified1/spirv.h>
+#else
+#include "./include/spirv/unified1/spirv.h"
+#endif
+
+
+#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,
+ SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ENTRY_POINT,
+ SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_EXECUTION_MODE,
+ SPV_REFLECT_RESULT_ERROR_SPIRV_MAX_RECURSIVE_EXCEEDED,
+} SpvReflectResult;
+
+/*! @enum SpvReflectModuleFlagBits
+
+SPV_REFLECT_MODULE_FLAG_NO_COPY - Disables copying of SPIR-V code
+ when a SPIRV-Reflect shader module is created. It is the
+ responsibility of the calling program to ensure that the pointer
+ remains valid and the memory it's pointing to is not freed while
+ SPIRV-Reflect operations are taking place. Freeing the backing
+ memory will cause undefined behavior or most likely a crash.
+ This is flag is intended for cases where the memory overhead of
+ storing the copied SPIR-V is undesirable.
+
+*/
+typedef enum SpvReflectModuleFlagBits {
+ SPV_REFLECT_MODULE_FLAG_NONE = 0x00000000,
+ SPV_REFLECT_MODULE_FLAG_NO_COPY = 0x00000001,
+} SpvReflectModuleFlagBits;
+
+typedef uint32_t SpvReflectModuleFlags;
+
+/*! @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_ACCELERATION_STRUCTURE = 0x00100000,
+ SPV_REFLECT_TYPE_FLAG_EXTERNAL_MASK = 0x00FF0000,
+ SPV_REFLECT_TYPE_FLAG_STRUCT = 0x10000000,
+ SPV_REFLECT_TYPE_FLAG_ARRAY = 0x20000000,
+ SPV_REFLECT_TYPE_FLAG_REF = 0x40000000,
+} SpvReflectTypeFlagBits;
+
+typedef uint32_t SpvReflectTypeFlags;
+
+/*! @enum SpvReflectDecorationBits
+
+NOTE: HLSL row_major and column_major decorations are reversed
+ in SPIR-V. Meaning that matrices declrations with row_major
+ will get reflected as column_major and vice versa. The
+ row and column decorations get appied during the compilation.
+ SPIRV-Reflect reads the data as is and does not make any
+ attempt to correct it to match what's in the source.
+
+ The Patch, PerVertex, and PerTask are used for Interface
+ variables that can have array
+
+*/
+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,
+ SPV_REFLECT_DECORATION_RELAXED_PRECISION = 0x00000100,
+ SPV_REFLECT_DECORATION_NON_READABLE = 0x00000200,
+ SPV_REFLECT_DECORATION_PATCH = 0x00000400,
+ SPV_REFLECT_DECORATION_PER_VERTEX = 0x00000800,
+ SPV_REFLECT_DECORATION_PER_TASK = 0x00001000,
+ SPV_REFLECT_DECORATION_WEIGHT_TEXTURE = 0x00002000,
+ SPV_REFLECT_DECORATION_BLOCK_MATCH_TEXTURE = 0x00004000,
+} SpvReflectDecorationFlagBits;
+
+typedef uint32_t SpvReflectDecorationFlags;
+
+// Based of SPV_GOOGLE_user_type
+typedef enum SpvReflectUserType {
+ SPV_REFLECT_USER_TYPE_INVALID = 0,
+ SPV_REFLECT_USER_TYPE_CBUFFER,
+ SPV_REFLECT_USER_TYPE_TBUFFER,
+ SPV_REFLECT_USER_TYPE_APPEND_STRUCTURED_BUFFER,
+ SPV_REFLECT_USER_TYPE_BUFFER,
+ SPV_REFLECT_USER_TYPE_BYTE_ADDRESS_BUFFER,
+ SPV_REFLECT_USER_TYPE_CONSTANT_BUFFER,
+ SPV_REFLECT_USER_TYPE_CONSUME_STRUCTURED_BUFFER,
+ SPV_REFLECT_USER_TYPE_INPUT_PATCH,
+ SPV_REFLECT_USER_TYPE_OUTPUT_PATCH,
+ SPV_REFLECT_USER_TYPE_RASTERIZER_ORDERED_BUFFER,
+ SPV_REFLECT_USER_TYPE_RASTERIZER_ORDERED_BYTE_ADDRESS_BUFFER,
+ SPV_REFLECT_USER_TYPE_RASTERIZER_ORDERED_STRUCTURED_BUFFER,
+ SPV_REFLECT_USER_TYPE_RASTERIZER_ORDERED_TEXTURE_1D,
+ SPV_REFLECT_USER_TYPE_RASTERIZER_ORDERED_TEXTURE_1D_ARRAY,
+ SPV_REFLECT_USER_TYPE_RASTERIZER_ORDERED_TEXTURE_2D,
+ SPV_REFLECT_USER_TYPE_RASTERIZER_ORDERED_TEXTURE_2D_ARRAY,
+ SPV_REFLECT_USER_TYPE_RASTERIZER_ORDERED_TEXTURE_3D,
+ SPV_REFLECT_USER_TYPE_RAYTRACING_ACCELERATION_STRUCTURE,
+ SPV_REFLECT_USER_TYPE_RW_BUFFER,
+ SPV_REFLECT_USER_TYPE_RW_BYTE_ADDRESS_BUFFER,
+ SPV_REFLECT_USER_TYPE_RW_STRUCTURED_BUFFER,
+ SPV_REFLECT_USER_TYPE_RW_TEXTURE_1D,
+ SPV_REFLECT_USER_TYPE_RW_TEXTURE_1D_ARRAY,
+ SPV_REFLECT_USER_TYPE_RW_TEXTURE_2D,
+ SPV_REFLECT_USER_TYPE_RW_TEXTURE_2D_ARRAY,
+ SPV_REFLECT_USER_TYPE_RW_TEXTURE_3D,
+ SPV_REFLECT_USER_TYPE_STRUCTURED_BUFFER,
+ SPV_REFLECT_USER_TYPE_SUBPASS_INPUT,
+ SPV_REFLECT_USER_TYPE_SUBPASS_INPUT_MS,
+ SPV_REFLECT_USER_TYPE_TEXTURE_1D,
+ SPV_REFLECT_USER_TYPE_TEXTURE_1D_ARRAY,
+ SPV_REFLECT_USER_TYPE_TEXTURE_2D,
+ SPV_REFLECT_USER_TYPE_TEXTURE_2D_ARRAY,
+ SPV_REFLECT_USER_TYPE_TEXTURE_2DMS,
+ SPV_REFLECT_USER_TYPE_TEXTURE_2DMS_ARRAY,
+ SPV_REFLECT_USER_TYPE_TEXTURE_3D,
+ SPV_REFLECT_USER_TYPE_TEXTURE_BUFFER,
+ SPV_REFLECT_USER_TYPE_TEXTURE_CUBE,
+ SPV_REFLECT_USER_TYPE_TEXTURE_CUBE_ARRAY,
+} SpvReflectUserType;
+
+/*! @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_R16_UINT = 74, // = VK_FORMAT_R16_UINT
+ SPV_REFLECT_FORMAT_R16_SINT = 75, // = VK_FORMAT_R16_SINT
+ SPV_REFLECT_FORMAT_R16_SFLOAT = 76, // = VK_FORMAT_R16_SFLOAT
+ SPV_REFLECT_FORMAT_R16G16_UINT = 81, // = VK_FORMAT_R16G16_UINT
+ SPV_REFLECT_FORMAT_R16G16_SINT = 82, // = VK_FORMAT_R16G16_SINT
+ SPV_REFLECT_FORMAT_R16G16_SFLOAT = 83, // = VK_FORMAT_R16G16_SFLOAT
+ SPV_REFLECT_FORMAT_R16G16B16_UINT = 88, // = VK_FORMAT_R16G16B16_UINT
+ SPV_REFLECT_FORMAT_R16G16B16_SINT = 89, // = VK_FORMAT_R16G16B16_SINT
+ SPV_REFLECT_FORMAT_R16G16B16_SFLOAT = 90, // = VK_FORMAT_R16G16B16_SFLOAT
+ SPV_REFLECT_FORMAT_R16G16B16A16_UINT = 95, // = VK_FORMAT_R16G16B16A16_UINT
+ SPV_REFLECT_FORMAT_R16G16B16A16_SINT = 96, // = VK_FORMAT_R16G16B16A16_SINT
+ SPV_REFLECT_FORMAT_R16G16B16A16_SFLOAT = 97, // = VK_FORMAT_R16G16B16A16_SFLOAT
+ 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
+ SPV_REFLECT_FORMAT_R64_UINT = 110, // = VK_FORMAT_R64_UINT
+ SPV_REFLECT_FORMAT_R64_SINT = 111, // = VK_FORMAT_R64_SINT
+ SPV_REFLECT_FORMAT_R64_SFLOAT = 112, // = VK_FORMAT_R64_SFLOAT
+ SPV_REFLECT_FORMAT_R64G64_UINT = 113, // = VK_FORMAT_R64G64_UINT
+ SPV_REFLECT_FORMAT_R64G64_SINT = 114, // = VK_FORMAT_R64G64_SINT
+ SPV_REFLECT_FORMAT_R64G64_SFLOAT = 115, // = VK_FORMAT_R64G64_SFLOAT
+ SPV_REFLECT_FORMAT_R64G64B64_UINT = 116, // = VK_FORMAT_R64G64B64_UINT
+ SPV_REFLECT_FORMAT_R64G64B64_SINT = 117, // = VK_FORMAT_R64G64B64_SINT
+ SPV_REFLECT_FORMAT_R64G64B64_SFLOAT = 118, // = VK_FORMAT_R64G64B64_SFLOAT
+ SPV_REFLECT_FORMAT_R64G64B64A64_UINT = 119, // = VK_FORMAT_R64G64B64A64_UINT
+ SPV_REFLECT_FORMAT_R64G64B64A64_SINT = 120, // = VK_FORMAT_R64G64B64A64_SINT
+ SPV_REFLECT_FORMAT_R64G64B64A64_SFLOAT = 121, // = VK_FORMAT_R64G64B64A64_SFLOAT
+} SpvReflectFormat;
+
+/*! @enum SpvReflectVariableFlagBits
+
+*/
+enum SpvReflectVariableFlagBits{
+ SPV_REFLECT_VARIABLE_FLAGS_NONE = 0x00000000,
+ SPV_REFLECT_VARIABLE_FLAGS_UNUSED = 0x00000001,
+ // If variable points to a copy of the PhysicalStorageBuffer struct
+ SPV_REFLECT_VARIABLE_FLAGS_PHYSICAL_POINTER_COPY = 0x00000002,
+};
+
+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
+ SPV_REFLECT_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR = 1000150000 // = VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR
+} 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
+ SPV_REFLECT_SHADER_STAGE_TASK_BIT_NV = 0x00000040, // = VK_SHADER_STAGE_TASK_BIT_NV
+ SPV_REFLECT_SHADER_STAGE_TASK_BIT_EXT = SPV_REFLECT_SHADER_STAGE_TASK_BIT_NV, // = VK_SHADER_STAGE_CALLABLE_BIT_EXT
+ SPV_REFLECT_SHADER_STAGE_MESH_BIT_NV = 0x00000080, // = VK_SHADER_STAGE_MESH_BIT_NV
+ SPV_REFLECT_SHADER_STAGE_MESH_BIT_EXT = SPV_REFLECT_SHADER_STAGE_MESH_BIT_NV, // = VK_SHADER_STAGE_CALLABLE_BIT_EXT
+ SPV_REFLECT_SHADER_STAGE_RAYGEN_BIT_KHR = 0x00000100, // = VK_SHADER_STAGE_RAYGEN_BIT_KHR
+ SPV_REFLECT_SHADER_STAGE_ANY_HIT_BIT_KHR = 0x00000200, // = VK_SHADER_STAGE_ANY_HIT_BIT_KHR
+ SPV_REFLECT_SHADER_STAGE_CLOSEST_HIT_BIT_KHR = 0x00000400, // = VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR
+ SPV_REFLECT_SHADER_STAGE_MISS_BIT_KHR = 0x00000800, // = VK_SHADER_STAGE_MISS_BIT_KHR
+ SPV_REFLECT_SHADER_STAGE_INTERSECTION_BIT_KHR = 0x00001000, // = VK_SHADER_STAGE_INTERSECTION_BIT_KHR
+ SPV_REFLECT_SHADER_STAGE_CALLABLE_BIT_KHR = 0x00002000, // = VK_SHADER_STAGE_CALLABLE_BIT_KHR
+
+} 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 enum SpvReflectArrayDimType {
+ SPV_REFLECT_ARRAY_DIM_RUNTIME = 0, // OpTypeRuntimeArray
+} SpvReflectArrayDimType;
+
+typedef struct SpvReflectArrayTraits {
+ uint32_t dims_count;
+ // Each entry is either:
+ // - specialization constant dimension
+ // - OpTypeRuntimeArray
+ // - the array length otherwise
+ uint32_t dims[SPV_REFLECT_MAX_ARRAY_DIMS];
+ // Stores Ids for dimensions that are specialization constants
+ uint32_t spec_constant_op_ids[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
+ @brief Information about an OpType* instruction
+*/
+typedef struct SpvReflectTypeDescription {
+ uint32_t id;
+ SpvOp op;
+ const char* type_name;
+ // Non-NULL if type is member of a struct
+ const char* struct_member_name;
+ SpvStorageClass storage_class;
+ SpvReflectTypeFlags type_flags;
+ SpvReflectDecorationFlags decoration_flags;
+
+ struct Traits {
+ SpvReflectNumericTraits numeric;
+ SpvReflectImageTraits image;
+ SpvReflectArrayTraits array;
+ } traits;
+
+ // If underlying type is a struct (ex. array of structs)
+ // this gives access to the OpTypeStruct
+ struct SpvReflectTypeDescription* struct_type_description;
+
+ // Some pointers to SpvReflectTypeDescription are really
+ // just copies of another reference to the same OpType
+ uint32_t copied;
+
+ // @deprecated use struct_type_description instead
+ uint32_t member_count;
+ // @deprecated use struct_type_description instead
+ struct SpvReflectTypeDescription* members;
+} SpvReflectTypeDescription;
+
+
+/*! @struct SpvReflectInterfaceVariable
+ @brief The OpVariable that is either an Input or Output to the module
+*/
+typedef struct SpvReflectInterfaceVariable {
+ uint32_t spirv_id;
+ const char* name;
+ uint32_t location;
+ uint32_t component;
+ 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;
+ // For Push Constants, this is the lowest offset of all memebers
+ 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;
+
+ struct {
+ uint32_t offset;
+ } word_offset;
+
+} 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;
+ uint32_t byte_address_buffer_offset_count;
+ uint32_t* byte_address_buffer_offsets;
+
+ SpvReflectTypeDescription* type_description;
+
+ struct {
+ uint32_t binding;
+ uint32_t set;
+ } word_offset;
+
+ SpvReflectDecorationFlags decoration_flags;
+ // Requires SPV_GOOGLE_user_type
+ SpvReflectUserType user_type;
+} SpvReflectDescriptorBinding;
+
+/*! @struct SpvReflectDescriptorSet
+
+*/
+typedef struct SpvReflectDescriptorSet {
+ uint32_t set;
+ uint32_t binding_count;
+ SpvReflectDescriptorBinding** bindings;
+} SpvReflectDescriptorSet;
+
+typedef enum SpvReflectExecutionModeValue {
+ SPV_REFLECT_EXECUTION_MODE_SPEC_CONSTANT = 0xFFFFFFFF // specialization constant
+} SpvReflectExecutionModeValue;
+
+/*! @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 interface_variable_count;
+ SpvReflectInterfaceVariable* interface_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;
+
+ uint32_t execution_mode_count;
+ SpvExecutionMode* execution_modes;
+
+ struct LocalSize {
+ uint32_t x;
+ uint32_t y;
+ uint32_t z;
+ } local_size;
+ uint32_t invocations; // valid for geometry
+ uint32_t output_vertices; // valid for geometry, tesselation
+} SpvReflectEntryPoint;
+
+/*! @struct SpvReflectCapability
+
+*/
+typedef struct SpvReflectCapability {
+ SpvCapability value;
+ uint32_t word_offset;
+} SpvReflectCapability;
+
+
+/*! @struct SpvReflectSpecId
+
+*/
+typedef struct SpvReflectSpecializationConstant {
+ uint32_t spirv_id;
+ uint32_t constant_id;
+ const char* name;
+} SpvReflectSpecializationConstant;
+
+/*! @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;
+ uint32_t capability_count;
+ SpvReflectCapability* capabilities;
+ SpvExecutionModel spirv_execution_model; // Uses value(s) from first entry point
+ SpvReflectShaderStageFlagBits shader_stage; // Uses value(s) from first entry point
+ uint32_t descriptor_binding_count; // Uses value(s) from first entry point
+ SpvReflectDescriptorBinding* descriptor_bindings; // Uses value(s) from first entry point
+ uint32_t descriptor_set_count; // Uses value(s) from first entry point
+ SpvReflectDescriptorSet descriptor_sets[SPV_REFLECT_MAX_DESCRIPTOR_SETS]; // Uses value(s) from first entry point
+ uint32_t input_variable_count; // Uses value(s) from first entry point
+ SpvReflectInterfaceVariable** input_variables; // Uses value(s) from first entry point
+ uint32_t output_variable_count; // Uses value(s) from first entry point
+ SpvReflectInterfaceVariable** output_variables; // Uses value(s) from first entry point
+ uint32_t interface_variable_count; // Uses value(s) from first entry point
+ SpvReflectInterfaceVariable* interface_variables; // Uses value(s) from first entry point
+ uint32_t push_constant_block_count; // Uses value(s) from first entry point
+ SpvReflectBlockVariable* push_constant_blocks; // Uses value(s) from first entry point
+ uint32_t spec_constant_count; // Uses value(s) from first entry point
+ SpvReflectSpecializationConstant* spec_constants; // Uses value(s) from first entry point
+
+ struct Internal {
+ SpvReflectModuleFlags module_flags;
+ 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
+);
+
+/*! @fn spvReflectCreateShaderModule2
+
+ @param flags Flags for module creations.
+ @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 spvReflectCreateShaderModule2(
+ SpvReflectModuleFlags flags,
+ 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 spvReflectEnumerateInterfaceVariables
+ @brief If the module contains multiple entry points, this will only get
+ the interface 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 interface variable
+ count will be stored here.
+ If pp_variables is not NULL, *p_count must contain
+ the module's interface variable count.
+ @param pp_variables If NULL, the module's interface 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
+ interface 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 spvReflectEnumerateInterfaceVariables(
+ const SpvReflectShaderModule* p_module,
+ uint32_t* p_count,
+ SpvReflectInterfaceVariable** pp_variables
+);
+
+/*! @fn spvReflectEnumerateEntryPointInterfaceVariables
+ @brief Enumerate the interface variables for a given entry point.
+ @param entry_point The name of the entry point to get the interface variables for.
+ @param p_module Pointer to an instance of SpvReflectShaderModule.
+ @param p_count If pp_variables is NULL, the entry point's interface variable
+ count will be stored here.
+ If pp_variables is not NULL, *p_count must contain
+ the entry point's interface variable count.
+ @param pp_variables If NULL, the entry point's interface 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
+ interface 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 spvReflectEnumerateEntryPointInterfaceVariables(
+ const SpvReflectShaderModule* p_module,
+ const char* entry_point,
+ uint32_t* p_count,
+ SpvReflectInterfaceVariable** pp_variables
+);
+
+
+/*! @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 spvReflectEnumerateSpecializationConstants
+ @param p_module Pointer to an instance of SpvReflectShaderModule.
+ @param p_count If pp_blocks is NULL, the module's specialization constant
+ count will be stored here. If pp_blocks is not NULL, *p_count
+ must contain the module's specialization constant count.
+ @param pp_constants If NULL, the module's specialization constant 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 specialization constant blocks will be written.
+ The caller must not free the variables written to this array.
+ @return If successful, returns SPV_REFLECT_RESULT_SUCCESS.
+ Otherwise, the error code indicates the cause of the failure.
+*/
+SpvReflectResult spvReflectEnumerateSpecializationConstants(
+ const SpvReflectShaderModule* p_module,
+ uint32_t* p_count,
+ SpvReflectSpecializationConstant** pp_constants
+);
+
+/*! @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);
+
+/*! @fn spvReflectBlockVariableTypeName
+
+ @param p_var Pointer to block variable.
+ @return Returns string of block variable's type description type name
+ or NULL if p_var is NULL.
+*/
+const char* spvReflectBlockVariableTypeName(
+ const SpvReflectBlockVariable* p_var
+);
+
+#if defined(__cplusplus)
+};
+#endif
+
+#if defined(__cplusplus) && !defined(SPIRV_REFLECT_DISABLE_CPP_BINDINGS)
+#include <cstdlib>
+#include <string>
+#include <vector>
+
+namespace spv_reflect {
+
+/*! \class ShaderModule
+
+*/
+class ShaderModule {
+public:
+ ShaderModule();
+ ShaderModule(size_t size, const void* p_code, SpvReflectModuleFlags flags = SPV_REFLECT_MODULE_FLAG_NONE);
+ ShaderModule(const std::vector<uint8_t>& code, SpvReflectModuleFlags flags = SPV_REFLECT_MODULE_FLAG_NONE);
+ ShaderModule(const std::vector<uint32_t>& code, SpvReflectModuleFlags flags = SPV_REFLECT_MODULE_FLAG_NONE);
+ ~ShaderModule();
+
+ ShaderModule(ShaderModule&& other);
+ ShaderModule& operator=(ShaderModule&& other);
+
+ 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 GetEntryPointShaderStage(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 EnumerateInterfaceVariables(uint32_t* p_count, SpvReflectInterfaceVariable** pp_variables) const;
+ SpvReflectResult EnumerateEntryPointInterfaceVariables(const char* entry_point, uint32_t* p_count, SpvReflectInterfaceVariable** pp_variables) 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);
+ }
+ SpvReflectResult EnumerateSpecializationConstants(uint32_t* p_count, SpvReflectSpecializationConstant** pp_constants) const;
+
+ 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:
+ // Make noncopyable
+ ShaderModule(const ShaderModule&);
+ ShaderModule& operator=(const ShaderModule&);
+
+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, SpvReflectModuleFlags flags) {
+ m_result = spvReflectCreateShaderModule2(
+ flags,
+ size,
+ p_code,
+ &m_module);
+}
+
+/*! @fn ShaderModule
+
+ @param code
+
+*/
+inline ShaderModule::ShaderModule(const std::vector<uint8_t>& code, SpvReflectModuleFlags flags) {
+ m_result = spvReflectCreateShaderModule2(
+ flags,
+ code.size(),
+ code.data(),
+ &m_module);
+}
+
+/*! @fn ShaderModule
+
+ @param code
+
+*/
+inline ShaderModule::ShaderModule(const std::vector<uint32_t>& code, SpvReflectModuleFlags flags) {
+ m_result = spvReflectCreateShaderModule2(
+ flags,
+ code.size() * sizeof(uint32_t),
+ code.data(),
+ &m_module);
+}
+
+/*! @fn ~ShaderModule
+
+*/
+inline ShaderModule::~ShaderModule() {
+ spvReflectDestroyShaderModule(&m_module);
+}
+
+
+inline ShaderModule::ShaderModule(ShaderModule&& other)
+{
+ *this = std::move(other);
+}
+
+inline ShaderModule& ShaderModule::operator=(ShaderModule&& other)
+{
+ m_result = std::move(other.m_result);
+ m_module = std::move(other.m_module);
+
+ other.m_module = {};
+ return *this;
+}
+
+/*! @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 GetEntryPointShaderStage
+
+ @param index
+ @return Returns the shader stage for the entry point at \b index
+*/
+inline SpvReflectShaderStageFlagBits ShaderModule::GetEntryPointShaderStage(uint32_t index) const {
+ return m_module.entry_points[index].shader_stage;
+}
+
+/*! @fn GetShaderStage
+
+ @return Returns shader stage for the first entry point
+
+*/
+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 EnumerateInterfaceVariables
+
+ @param count
+ @param pp_variables
+ @return
+
+*/
+inline SpvReflectResult ShaderModule::EnumerateInterfaceVariables(
+ uint32_t* p_count,
+ SpvReflectInterfaceVariable** pp_variables
+) const
+{
+ m_result = spvReflectEnumerateInterfaceVariables(
+ &m_module,
+ p_count,
+ pp_variables);
+ return m_result;
+}
+
+/*! @fn EnumerateEntryPointInterfaceVariables
+
+ @param entry_point
+ @param count
+ @param pp_variables
+ @return
+
+*/
+inline SpvReflectResult ShaderModule::EnumerateEntryPointInterfaceVariables(
+ const char* entry_point,
+ uint32_t* p_count,
+ SpvReflectInterfaceVariable** pp_variables
+) const
+{
+ m_result = spvReflectEnumerateEntryPointInterfaceVariables(
+ &m_module,
+ entry_point,
+ p_count,
+ pp_variables);
+ 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 EnumerateSpecializationConstants
+ @param p_count
+ @param pp_constants
+ @return
+*/
+inline SpvReflectResult ShaderModule::EnumerateSpecializationConstants(
+ uint32_t* p_count,
+ SpvReflectSpecializationConstant** pp_constants
+) const
+{
+ m_result = spvReflectEnumerateSpecializationConstants(
+ &m_module,
+ p_count,
+ pp_constants
+ );
+ 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) && !defined(SPIRV_REFLECT_DISABLE_CPP_WRAPPER)
+#endif // SPIRV_REFLECT_H
+
+// clang-format on
SET( adaptor_macos_platform_src_files
${adaptor_thirdparty_dir}/macos-platform/thread.cpp
)
+
+SET( adaptor_libraries_spirv_reflect_src_files
+ ${adaptor_thirdparty_dir}/SPIRV-Reflect/spirv_reflect.cpp
+)
\ No newline at end of file