SPIRV-Reflect 深度指南:在 dlssg-to-fsr3 / FidelityFX SDK 工具链中从 SPIR-V 字节码提取着色器反射数据

原创2026-10-03 11:56:13400 阅读
文章标签:图形学游戏开发

SPIRV-Reflect 深度指南:在 dlssg-to-fsr3 / FidelityFX SDK 工具链中从 SPIR-V 字节码提取着色器反射数据

SPIRV-Reflect 是一个轻量级的 C/C++ 反射库,用于从 SPIR-V 着色器字节码中提取描述符绑定、push constant 块、输入输出变量等反射数据,直接服务于 Vulkan 应用的描述符集与管线布局生成。本仓库(dlssg-to-fsr3,通过替换 Nvidia DLSS 帧生成来实现 AMD FSR 3 帧生成的项目)随 FidelityFX SDK 一并携带了该库,并实际将其嵌入 ffx_shader_compiler 工具链,用于从 GLSL 编译产物的 SPIR-V 中自动采集着色器资源布局。读完本文,你将掌握 SPIRV-Reflect 的核心 API、命令行工具用法,以及它在 FidelityFX SDK 着色器编译流水线中的真实集成方式。

SPIRV-Reflect 是什么

SPIRV-Reflect 是一个面向 SPIR-V 着色器字节码的轻量级 C/C++ 反射 API 库,主要服务于 Vulkan 应用,并在 Linux 与 Windows 上完成过测试。它的核心价值在于:着色器经过编译变成二进制 SPIR-V 后,原本 HLSL/GLSL 源码中的资源绑定、布局等结构化信息并不会丢失,而是以 decoration 等指令形式编码在字节码中;SPIRV-Reflect 负责把这些信息解析、整理并暴露给应用层,省去了应用手工维护"着色器资源清单"的巨大成本。

在本仓库中,SPIRV-Reflect 位于 dependencies/FidelityFX-SDK/sdk/tools/ffx_shader_compiler/libs/SPIRV-Reflect 目录,随 FidelityFX SDK 的 ffx_shader_compiler(FidelityFX 着色器编译器,即 ffx-sc 工具)一起分发。同目录下的 CAULDRONREADME.md 记录了其当前随附版本为 sdk-1.3.231.1,并说明了更新流程(从上游下载最新发布版后,将全部 cpp/h 文件、include 目录、readme、license 与 code of conduct 复制到该位置,同时注意清理可能已移除的文件)。

核心特性

根据该库自带的 README.md,SPIRV-Reflect 提供以下能力:

  • 提取描述符绑定(descriptor bindings):从 SPIR-V 字节码中解析描述符绑定信息,用于辅助生成 Vulkan 描述符集(descriptor set)与管线布局(pipeline layout)。
  • 提取 push constant 块大小:从 SPIR-V 字节码中解析 push constant 块尺寸,辅助生成管线布局。
  • 提取 uniform buffer 与 push constant 块的完整布局数据:包括各成员的偏移、大小、对齐等,辅助应用正确更新这些结构。
  • 提取输入/输出变量:从 SPIR-V 字节码中解析输入输出接口变量,并支持 HLSL 着色器的语义(semantic)装饰,辅助校验管线的输入输出设置。
  • 运行时重映射描述符绑定:可在运行时修改描述符的绑定号(binding)与集合号(set),并同步更新底层 SPIR-V 字节码。
  • 将全部反射数据输出为人类可读文本:便于调试与离线检查。

对应到 spirv_reflect.h 中的数据结构,这些特性分别落在 SpvReflectDescriptorBinding/SpvReflectDescriptorSet(描述符绑定)、SpvReflectBlockVariable(块布局)、SpvReflectInterfaceVariable(接口变量)、SpvReflectShaderModule(模块整体信息)等核心结构体上。

关键数据类型与枚举

在深入 API 之前,先了解几个贯穿全文的核心类型(均定义于 spirv_reflect.h):

结果码 SpvReflectResult 是几乎所有 API 的返回值,包含成功与各类失败原因,例如:

枚举值 含义
SPV_REFLECT_RESULT_SUCCESS 操作成功
SPV_REFLECT_RESULT_NOT_READY 模块尚未创建完成
SPV_REFLECT_RESULT_ERROR_PARSE_FAILED SPIR-V 解析失败
SPV_REFLECT_RESULT_ERROR_ALLOC_FAILED 内存分配失败
SPV_REFLECT_RESULT_ERROR_RANGE_EXCEEDED 越界访问
SPV_REFLECT_RESULT_ERROR_NULL_POINTER 空指针参数
SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_CODE_SIZE SPIR-V 代码尺寸非法
SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_MAGIC_NUMBER SPIR-V 魔数非法
SPV_REFLECT_RESULT_ERROR_SPIRV_UNEXPECTED_EOF 意外的文件结束
SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE 无效的 ID 引用
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_ENTRY_POINT 无效入口点
SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_EXECUTION_MODE 无效执行模式
SPV_REFLECT_RESULT_ERROR_ELEMENT_NOT_FOUND 未找到目标元素

描述符类型 SpvReflectDescriptorType 直接映射 Vulkan 描述符类型,枚举数值与 VK_DESCRIPTOR_TYPE_* 一致(如 SAMPLER=0、COMBINED_IMAGE_SAMPLER=1、SAMPLED_IMAGE=2、STORAGE_IMAGE=3、UNIFORM_TEXEL_BUFFER=4、STORAGE_TEXEL_BUFFER=5、UNIFORM_BUFFER=6、STORAGE_BUFFER=7、动态变体为 8/9、INPUT_ATTACHMENT=10、ACCELERATION_STRUCTURE_KHR=1000150000)。

资源类型 SpvReflectResourceType 用于按 DX 习惯区分资源用途:SPV_REFLECT_RESOURCE_FLAG_SAMPLER(采样器)、SPV_REFLECT_RESOURCE_FLAG_CBV(常量缓冲区)、SPV_REFLECT_RESOURCE_FLAG_SRV(着色器资源视图)、SPV_REFLECT_RESOURCE_FLAG_UAV(无序访问视图)。这一区分在 FidelityFX 工具链中被用来决定 STORAGE_BUFFER 归入 SRV 还是 UAV。

着色器阶段 SpvReflectShaderStageFlagBits 覆盖 vertex、tessellation control/evaluation、geometry、fragment、compute、task/mesh(NV)、以及光追各阶段(raygen、any-hit、closest-hit、miss、intersection、callable),与 VK_SHADER_STAGE_* 位掩码对应。

关键结构体包括:

  • SpvReflectShaderModule:模块级容器,承载生成器信息(generator)、入口点(entry_points)、源语言与版本、capabilities、描述符绑定/集合、输入输出变量、push constant 块,以及内部 SPIR-V 代码指针。
  • SpvReflectDescriptorBinding:单个描述符绑定,含 name、binding、set、descriptor_type、resource_type、count(数组元素数)、uav_counter_binding(UAV 计数器绑定)与关联的 SpvReflectBlockVariable block。
  • SpvReflectDescriptorSet:描述符集合,含 set 号与 bindings 数组。
  • SpvReflectInterfaceVariable:接口变量,含 name、location、storage_class、semantic(HLSL 语义)、built_in、format 以及嵌套的 members。
  • SpvReflectBlockVariable:块成员变量,含 offset、absolute_offset、size、padded_size 以及递归的 members。
  • SpvReflectEntryPoint:入口点信息,含入口点名称、shader_stage、输入输出接口变量、所用描述符集、local_size(计算着色器工作组大小)、invocations(几何着色器)与 output_vertices(几何/细分着色器)。

这些结构体之间通过指针互相引用,且 SPIR-V 中同类型变量会共享类型引用,因此多个变量可能对应同一个 SpvReflectTypeDescription(头文件注释中已明确指出这一点)。

将 SPIRV-Reflect 集成进项目

原文档强调 SPIRV-Reflect 以"集成尽可能简单"为设计目标:唯一的外部依赖是 Vulkan SDK。集成方式极简——把 spirv_reflect.h 与 spirv_reflect.c 加入项目构建,并在需要的源文件中 #include "spirv_reflect.h" 即可。

本仓库正是这一方式的实例:在 ffx_shader_compiler/CMakeLists.txt 中,spirv_reflect.h 与 spirv_reflect.c 被直接追加到编译器可执行文件的源列表,同时将 libs/SPIRV-Reflect 目录加入公共包含路径:

list(APPEND sources
	${CMAKE_CURRENT_SOURCE_DIR}/libs/MD5/md5.h
	${CMAKE_CURRENT_SOURCE_DIR}/libs/MD5/md5.cpp
	${CMAKE_CURRENT_SOURCE_DIR}/libs/SPIRV-Reflect/spirv_reflect.h
	${CMAKE_CURRENT_SOURCE_DIR}/libs/SPIRV-Reflect/spirv_reflect.c)

add_executable(${PROJECT_NAME} ${sources})
# ...
target_include_directories (${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/libs/MD5
                                                   ${CMAKE_CURRENT_SOURCE_DIR}/libs/SPIRV-Reflect
                                                   ${CMAKE_CURRENT_SOURCE_DIR}/libs/tiny-process-library)

也就是说,整个 SPIRV-Reflect 库只需两个文件即可落地使用,无任何额外的运行时依赖;头文件内部会根据 SPIRV_REFLECT_USE_SYSTEM_SPIRV_H 宏决定使用系统 <spirv/unified1/spirv.h> 还是仓库内置的 include/spirv/unified1/spirv.h。

核心 API 使用模式

原文档给出了一个完整的 C API 使用骨架:创建模块 → 两段式枚举(先查数量,再取数组)→ 使用完毕后销毁。下面基于 spirv_reflect.h 的实际声明逐层展开。

模块的创建与销毁

#include "spirv_reflect.h"

int SpirvReflectExample(const void* spirv_code, size_t spirv_nbytes)
{
  // 生成着色器的反射数据
  SpvReflectShaderModule module;
  SpvReflectResult result = spvReflectCreateShaderModule(spirv_nbytes, spirv_code, &module);
  assert(result == SPV_REFLECT_RESULT_SUCCESS);

  // ... 使用反射数据 ...

  // 不再需要时销毁反射数据
  spvReflectDestroyShaderModule(&module);
}

两个关键入口:

  • spvReflectCreateShaderModule(size, p_code, p_module):解析 SPIR-V 并填充 SpvReflectShaderModule。
  • spvReflectCreateShaderModule2(flags, size, p_code, p_module):带标志的版本。SPV_REFLECT_MODULE_FLAG_NO_COPY 可禁止库复制 SPIR-V 代码——此时调用方必须保证传入指针在其后整个使用期内持续有效且不被释放,否则会产生未定义行为甚至崩溃;该标志面向对内存开销敏感的场景。

库同时提供 spvReflectGetCodeSize() 与 spvReflectGetCode(),用于取回模块持有的 SPIR-V 字节码(重映射后尤其有用)。

两段式枚举模式

SPIRV-Reflect 的枚举 API 统一采用"先传 NULL 拿数量,再分配数组取数据"的两段式调用,例如提取输入变量:

uint32_t var_count = 0;
result = spvReflectEnumerateInputVariables(&module, &var_count, NULL);
assert(result == SPV_REFLECT_RESULT_SUCCESS);
SpvReflectInterfaceVariable** input_vars =
  (SpvReflectInterfaceVariable**)malloc(var_count * sizeof(SpvReflectInterfaceVariable*));
result = spvReflectEnumerateInputVariables(&module, &var_count, input_vars);
assert(result == SPV_REFLECT_RESULT_SUCCESS);

输出变量、描述符绑定、描述符集与 push constant 块都可以用同样的机制枚举。完整的枚举函数族包括:

函数 说明
spvReflectEnumerateDescriptorBindings 枚举全部描述符绑定
spvReflectEnumerateEntryPointDescriptorBindings 枚举某入口点静态调用树内使用的描述符绑定
spvReflectEnumerateDescriptorSets 枚举描述符集合
spvReflectEnumerateEntryPointDescriptorSets 枚举某入口点使用的描述符集合
spvReflectEnumerateInterfaceVariables 枚举接口变量(多入口点时取第一个)
spvReflectEnumerateEntryPointInterfaceVariables 枚举某入口点的接口变量
spvReflectEnumerateInputVariables / spvReflectEnumerateOutputVariables 枚举输入/输出变量(多入口点时取第一个)
spvReflectEnumerateEntryPointInputVariables / spvReflectEnumerateEntryPointOutputVariables 枚举某入口点的输入/输出变量
spvReflectEnumeratePushConstantBlocks / spvReflectEnumerateEntryPointPushConstantBlocks 枚举 push constant 块

注意:枚举返回的指针数组由库管理,调用方不得释放数组中的元素指针,只需在不再需要时通过 spvReflectDestroyShaderModule 统一销毁模块即可。

定点查询 API

除枚举外,库还提供按 key 直接查询的 API,方便高频路径使用:

  • 描述符:spvReflectGetDescriptorBinding(module, binding_number, set_number, &result) 与 spvReflectGetEntryPointDescriptorBinding(...)。
  • 描述符集:spvReflectGetDescriptorSet(module, set_number, &result) 与入口点版本。
  • 输入/输出变量:按 location 查询(spvReflectGetInputVariableByLocation、spvReflectGetOutputVariableByLocation 及入口点版本)或按语义查询(spvReflectGetInputVariableBySemantic、spvReflectGetOutputVariableBySemantic 及入口点版本)。注意 location 传 0xFFFFFFFF 恒返回 NULL 且结果码为 ELEMENT_NOT_FOUND,空语义字符串同理。
  • push constant:spvReflectGetPushConstantBlock(module, index, &result)(按索引)与 spvReflectGetEntryPointPushConstantBlock(...)(按入口点,Vulkan 规范规定单入口点至多一个 push constant 块)。

运行时重映射

这是 SPIRV-Reflect 的独有亮点,也是其"动态性"所在:

  • spvReflectChangeDescriptorBindingNumbers(module, p_binding, new_binding_number, new_set_number):为单个绑定重设 binding/set 号。传 SPV_REFLECT_BINDING_NUMBER_DONT_CHANGE / SPV_REFLECT_SET_NUMBER_DONT_CHANGE(均为 ~0)可保持对应项不变;成功修改 set 号会使该模块所有既有的 SpvReflectDescriptorBinding 与 SpvReflectDescriptorSet 指针失效,需重新枚举。
  • spvReflectChangeDescriptorSetNumber(module, p_set, new_set_number):为整个描述符集(含其全部绑定)重设 set 号,同样会使既有指针失效。
  • spvReflectChangeInputVariableLocation / spvReflectChangeOutputVariableLocation:为接口变量重设 location,调用方需自行保证不与其它变量冲突。

这些函数在更新反射数据的同时会直接改写底层 SPIR-V 字节码,修改后的代码可通过 spvReflectGetCode() 取回(例如重新序列化后写回磁盘)。若某绑定/变量被多个入口点使用,则所有入口点会一并更新。

C++ 封装

除纯 C API 外,头文件在同名 spv_reflect 命名空间下提供 ShaderModule 类,支持从 (size, p_code)、std::vector<uint8_t> 或 std::vector<uint32_t> 构造(可传模块标志),并将上述枚举与查询全部封装为成员函数,例如 EnumerateDescriptorSets、GetDescriptorBinding、ChangeDescriptorBindingNumbers、GetShaderStage 等。FidelityFX 的 spirv-reflect 命令行工具即基于该封装实现。注意 ShaderModule 被设计为不可拷贝(拷贝构造与拷贝赋值被私有化),仅支持移动语义。

实战:FidelityFX SDK 中的真实集成

原文档是通用库说明,而本仓库提供了它在一线工具链中的真实用法。FidelityFX SDK 的 GLSL 着色器编译器 src/glsl_compiler.cpp 在 ExtractReflectionData(第 318 行起)中完整走了一遍"创建模块 → 枚举描述符集 → 按类型分发 → 销毁"的流程:

SpvReflectShaderModule reflectShaderModule;
SpvReflectResult result = spvReflectCreateShaderModule(glslShaderBinary->BufferSize(), glslShaderBinary->BufferPointer(), &reflectShaderModule);
assert(result == SPV_REFLECT_RESULT_SUCCESS);

uint32_t count = 0;
result = spvReflectEnumerateDescriptorSets(&reflectShaderModule, &count, NULL);
assert(result == SPV_REFLECT_RESULT_SUCCESS);

std::vector<SpvReflectDescriptorSet*> sets(count);
result = spvReflectEnumerateDescriptorSets(&reflectShaderModule, &count, sets.data());
assert(result == SPV_REFLECT_RESULT_SUCCESS);

for (int setIdx = 0; setIdx < sets.size(); setIdx++) {
    SpvReflectDescriptorSet* ds = sets[setIdx];
    for (int bindingIdx = 0; bindingIdx < ds->binding_count; bindingIdx++) {
        SpvReflectDescriptorBinding* binding = ds->bindings[bindingIdx];
        ShaderResourceInfo resourceInfo = {binding->name ? binding->name : "", binding->binding, binding->count, ds->set};
        switch (binding->descriptor_type) {
        case SPV_REFLECT_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
            glslReflectionData->constantBuffers.push_back(resourceInfo);
            break;
        case SPV_REFLECT_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
            glslReflectionData->srvTextures.push_back(resourceInfo);
            break;
        case SPV_REFLECT_DESCRIPTOR_TYPE_SAMPLER:
            glslReflectionData->samplers.push_back(resourceInfo);
            break;
        case SPV_REFLECT_DESCRIPTOR_TYPE_STORAGE_IMAGE:
            glslReflectionData->uavTextures.push_back(resourceInfo);
            break;
        case SPV_REFLECT_DESCRIPTOR_TYPE_STORAGE_BUFFER:
            if (binding->resource_type == SPV_REFLECT_RESOURCE_FLAG_SRV)
                glslReflectionData->srvBuffers.push_back(resourceInfo);
            else
                glslReflectionData->uavBuffers.push_back(resourceInfo);
            break;
        case SPV_REFLECT_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR:
            glslReflectionData->rtAccelerationStructures.push_back(resourceInfo);
            break;
        default:
            throw std::runtime_error("Shader uses an unsupported resource type!");
        }
    }
}
spvReflectDestroyShaderModule(&reflectShaderModule);

这段代码展示了几个重要的工程实践:

  1. 名称空指针防御:binding->name ? binding->name : "",因为并非所有绑定都有名称。
  2. 按 descriptor_type 分发到七类资源清单:constant buffers(CBV)、SRV/UAV 纹理、采样器、SRV/UAV 缓冲区、光追加速结构,恰好对应 DX12 侧的着色器资源视图分类。
  3. STORAGE_BUFFER 的读写判别:同一描述符类型下,借助 resource_type 的 SPV_REFLECT_RESOURCE_FLAG_SRV/SPV_REFLECT_RESOURCE_FLAG_UAV 标志区分只读与读写。
  4. 不支持类型的硬性失败:对 COMBINED_IMAGE_SAMPLER、texel buffer、dynamic buffer、input attachment 等类型直接抛出异常,将不支持的资源类型在编译期就拦截下来。

随后 WriteBinaryHeaderReflectionData(第 389 行起)会把上述资源清单写成 C 头文件中的静态数组(g_{permutation}_{Type}ResourceNames/Bindings/Counts/Sets),供运行时按名称/绑定号查询资源;WritePermutationHeaderReflectionStructMembers 则生成对应的结构体成员声明。这就是"SPIR-V 反射 → 自动生成资源绑定元数据头文件"的完整闭环——也是 FidelityFX SDK 能批量、自动化编译上百个 GLSL 着色器变体并保持绑定一致的底层机制。

命令行工具 spirv-reflect

本仓库随 SPIRV-Reflect 附带了命令行工具 main.cpp,可直接对一个 .spv 文件执行反射并输出人类可读摘要。其用法如下:

spirv-reflect [OPTIONS] path/to/SPIR-V/bytecode.spv
选项 说明
--help 显示帮助信息
-y, --yaml 以 YAML 格式输出(默认关闭)
-v VERBOSITY 仅对 YAML 输出生效:0 输出着色器信息、块变量、接口变量与描述符绑定(默认);1 额外输出类型描述;2 额外输出 SPIR-V 字节码与全部内部类型描述(面向库开发者,一般用户用不到)
-e, --entrypoint 仅打印着色器模块中的入口点名
-s, --stage 仅打印 Vulkan 着色器阶段
-f, --file 仅打印源文件信息
-fcb, --flatten_cbuffers 在非 YAML 输出下展平常量缓冲区

当指定 -e/-s/-f 时,工具按"入口点;阶段;源文件"的分号分隔格式单行输出;否则默认输出完整反射摘要。-e/-s/-f 与 -y/-v/-fcb 互斥(前者优先)。工具内部使用 C++ 封装的 spv_reflect::ShaderModule 完成解析,并在解析失败时报告"不是合法的 SPIR-V 字节码"。

构建示例程序

原文档说明,只有需要构建/运行 SPIRV-Reflect 的示例应用时才需要执行本步骤。SPIRV-Reflect 附带一套示例程序,演示不同使用场景:

  • descriptors:演示描述符绑定的提取,包括从反射数据填充 VkDescriptorSetLayoutCreateInfo 结构。
  • hlsl_resource_types:演示各类 HLSL 资源类型在 SPIR-V 中的表示方式。
  • io_variables:演示输入/输出变量的提取,包括从反射数据填充 VkPipelineVertexInputStateCreateInfo 结构。

构建方式:使用 CMake 生成对应平台的工程文件后按常规方式构建。可通过 VulkanSDK 环境变量指定 Vulkan SDK 位置,例如在 Linux 下:

VULKAN_SDK=$HOME/VulkanSDK/1.1.70.1/x86_64 cmake -G Ninja  ..

需要说明的是,本仓库的打包裁剪掉了 examples/ 目录,仅保留了库本体(spirv_reflect.c/.cpp/.h)、命令行工具与内置的 SPIR-V 头文件;因此当前仓库内可直接验证的是库源码集成与命令行工具,示例程序需参考上游完整源码树。

构建自测套件

SPIRV-Reflect 使用 googletest 进行自测,该组件是可选项,通常只对修改 SPIRV-Reflect 本身的开发者有意义。运行自测的步骤:

  1. git submodule init
  2. git submodule update
  3. 在 CMake 中启用 SPIRV_REFLECT_BUILD_TESTS
  4. 构建并运行 test-spirv-reflect 工程

Bazel 构建

对于使用 Bazel 的工程,原文档给出在 Linux Bazel 1.2.1 下验证过的构建命令:

bazel build :all

使用注意事项

从源码注释与工具链实践可以归纳出以下容易踩坑的点:

  1. 行主序/列主序反转:SpvReflectDecorationFlagBits 注释明确指出,HLSL 的 row_major 与 column_major 装饰在 SPIR-V 中是反过来的——即源码里声明为 row_major 的矩阵,反射出来是 column_major,反之亦然。SPIRV-Reflect 按字节码原样读取,不会修正为与源码一致,需要应用层自行注意。
  2. 模块标志与内存生命周期:使用 SPV_REFLECT_MODULE_FLAG_NO_COPY 时,调用方必须保证 SPIR-V 指针在整个反射生命周期内有效,否则必然崩溃。
  3. 重映射后的指针失效:spvReflectChangeDescriptorBindingNumbers 或 spvReflectChangeDescriptorSetNumber 修改 set 号后,该模块既有的绑定/集合指针全部失效,必须重新枚举。
  4. 枚举指针的归属:枚举 API 返回的指针归模块所有,只能整体通过 spvReflectDestroyShaderModule 释放,不能单独 free。
  5. 共享类型引用:SPIR-V 中相同底层类型的变量共享同一个 SpvReflectTypeDescription,多个变量会看到相同的类型名,分析时需结合变量自身字段。

许可

SPIRV-Reflect 版权归 Google Inc.(2017-2018)所有,基于 Apache License 2.0 发布,仓库内随附 LICENSE 文件;本仓库的 spirv_reflect.c 与 spirv_reflect.cpp 头注释亦标明该许可条款。它作为第三方库以源码形式嵌入 FidelityFX SDK 工具链,随项目整体分发。

小结

SPIRV-Reflect 以极低的集成成本(两个文件、仅依赖 Vulkan SDK)解决了"二进制着色器 ↔ 结构化资源元数据"之间的鸿沟,是 Vulkan 生态中把反射从"手工维护"升级为"编译期自动提取"的关键组件。在本仓库的 FidelityFX SDK 工具链中,它通过与 glslangValidator 产出的 SPIR-V 无缝衔接,支撑起着色器资源清单的自动化生成;对任何需要动态构建管线布局、校验顶点输入或重映射描述符绑定的 Vulkan 工程,这套 API 都值得直接复用。

登录后查看全文
dlssg-to-fsr3