Using Vulkan -- HLSL in Vulkan

张开发
2026/4/5 10:41:19 15 分钟阅读

分享文章

Using Vulkan -- HLSL in Vulkan
Vulkan 不直接使用人类可读的文本格式着色器而是采用SPIR‑V作为中间表示。这使得只要能生成 Vulkan 环境下的 SPIR‑V就可以使用 GLSL 之外的着色器语言。其中一种语言就是微软用于 DirectX 的高级着色器语言HLSL。借助 Vulkan 1.2 的新增支持HLSL 现已成为 Vulkan 的一等着色器语言使用便捷度与 GLSL 相当。除少数例外情况GLSL 能使用的所有 Vulkan 特性与着色器阶段HLSL 同样支持包括硬件加速光线追踪等新特性。同时HLSL 转 SPIR‑V 还支持部分 DirectX 暂不支持的 Vulkan 专属特性。学习资源若你是 HLSL 新手建议从Microsoft Learn 的 HLSL 资源开始学习。另一个优质参考是DirectX‑Specs文档其中包含最新着色器特性与 HLSL 着色器模型的详细说明。从应用程序视角看从应用程序角度使用 HLSL 与使用 GLSL完全相同。应用程序始终消费 SPIR‑V 格式着色器唯一区别在于将着色器语言编译为 SPIR‑V 的工具链。HLSL 到 SPIR‑V 特性映射手册通过 SPIR‑V 在 Vulkan 中使用 HLSL首选参考HLSL to SPIR‑V feature mapping manual。该手册详细说明语义、语法、支持的特性与扩展等内容必读。Vulkan 与 DirectX 概念与术语的对照表可参考decoder ring。Vulkan HLSL 命名空间为使 HLSL 兼容 Vulkan引入了一个隐式命名空间用于提供 Vulkan 专属特性的接口。语法对比与常规编程语言类似HLSL 与 GLSL 语法存在差异GLSL 更偏向过程式类似 CHLSL 更偏向面向对象类似 C。以下是同一段着色器的两种语言实现可直观对比基础差异其中包含用于显式指定位置的上述命名空间GLSL#version 450 layout (location 0) in vec3 inPosition; layout (location 1) in vec3 inColor; layout (binding 0) uniform UBO { mat4 projectionMatrix; mat4 modelMatrix; mat4 viewMatrix; } ubo; layout (location 0) out vec3 outColor; void main() { outColor inColor * float(gl_VertexIndex); gl_Position ubo.projectionMatrix * ubo.viewMatrix * ubo.modelMatrix * vec4(inPosition.xyz, 1.0); }HLSLstruct VSInput { [[vk::location(0)]] float3 Position : POSITION0; [[vk::location(1)]] float3 Color : COLOR0; }; struct UBO { float4x4 projectionMatrix; float4x4 modelMatrix; float4x4 viewMatrix; }; cbuffer ubo : register(b0, space0) { UBO ubo; } struct VSOutput { float4 Pos : SV_POSITION; [[vk::location(0)]] float3 Color : COLOR0; }; VSOutput main(VSInput input, uint VertexIndex : SV_VertexID) { VSOutput output (VSOutput)0; output.Color input.Color * float(VertexIndex); output.Pos mul(ubo.projectionMatrix, mul(ubo.viewMatrix, mul(ubo.modelMatrix, float4(input.Position.xyz, 1.0)))); return output; }除语法差异外内置变量使用 HLSL 名称。例如gl_VertexIndex在 HLSL 中为VertexIndex。GLSL 与 HLSL 内置变量映射列表可参考对应文档。DirectXShaderCompilerDXC与 GLSL 转 SPIR‑V 同理在 Vulkan 中使用 HLSL 需要着色器编译器。glslang是 GLSL 转 SPIR‑V 的标准编译器而DirectXShaderCompilerDXC是 HLSL 转 SPIR‑V 的标准编译器。得益于开源贡献DXC 的 SPIR‑V 后端已在官方发布版本中支持并启用可直接使用。尽管 glslang 等工具也提供 HLSL 支持但 DXC 支持最完整、最新是从 HLSL 生成 SPIR‑V 的推荐方案。获取途径LunarG Vulkan SDK已包含预编译的 DXC 二进制、库与头文件。如需最新版本可查看DXC 官方仓库。使用独立编译器离线编译使用预编译 dxc 二进制离线编译着色器与 glslang 用法类似dxc.exe -spirv -T vs_6_0 -E main .\triangle.vert -Fo .\triangle.vert.spv-T选择编译目标配置文件vs_6_0 顶点着色器模型 6ps_6_0 像素 / 片元着色器模型 6 等-E指定着色器入口函数扩展会根据特性使用自动启用也可显式指定dxc.exe -spirv -T vs_6_1 -E main .\input.vert -Fo .\output.vert.spv -fspv-extensionSPV_EXT_descriptor_indexing生成的 SPIR‑V 与 GLSL 生成的 SPIR‑V 一样可直接加载使用。使用库运行时编译DXC 可通过 DirectX Compiler API 集成到 Vulkan 应用实现着色器运行时编译。需要包含dxcapi.h并链接dxcompiler库最简单方式是使用动态库并随应用分发Windows 下为dxcompiler.dll。运行时将 HLSL 编译为 SPIR‑V 的简化流程#include include/dxc/dxcapi.h ... HRESULT hres; // 初始化 DXC 库 CComPtrIDxcLibrary library; hres DxcCreateInstance(CLSID_DxcLibrary, IID_PPV_ARGS(library)); if (FAILED(hres)) { throw std::runtime_error(Could not init DXC Library); } // 初始化 DXC 编译器 CComPtrIDxcCompiler3 compiler; hres DxcCreateInstance(CLSID_DxcCompiler, IID_PPV_ARGS(compiler)); if (FAILED(hres)) { throw std::runtime_error(Could not init DXC Compiler); } // 初始化 DXC 工具 CComPtrIDxcUtils utils; hres DxcCreateInstance(CLSID_DxcUtils, IID_PPV_ARGS(utils)); if (FAILED(hres)) { throw std::runtime_error(Could not init DXC Utiliy); } // 从磁盘加载 HLSL 文本着色器 uint32_t codePage DXC_CP_ACP; CComPtrIDxcBlobEncoding sourceBlob; hres utils-LoadFile(filename.c_str(), codePage, sourceBlob); if (FAILED(hres)) { throw std::runtime_error(Could not load shader file); } // 根据着色器文件后缀选择目标配置文件 LPCWSTR targetProfile{}; size_t idx filename.rfind(.); if (idx ! std::string::npos) { std::wstring extension filename.substr(idx 1); if (extension Lvert) { targetProfile Lvs_6_1; } if (extension Lfrag) { targetProfile Lps_6_1; } // 其他文件类型映射cs_x_y、lib_x_y 等 } // 配置编译参数HLSL 转 SPIR‑V std::vectorLPCWSTR arguments { filename.c_str(), L-E, Lmain, L-T, targetProfile, L-spirv }; // 编译着色器 DxcBuffer buffer{}; buffer.Encoding DXC_CP_ACP; buffer.Ptr sourceBlob-GetBufferPointer(); buffer.Size sourceBlob-GetBufferSize(); CComPtrIDxcResult result{ nullptr }; hres compiler-Compile( buffer, arguments.data(), (uint32_t)arguments.size(), nullptr, IID_PPV_ARGS(result)); if (SUCCEEDED(hres)) { result-GetStatus(hres); } // 编译失败输出错误信息 if (FAILED(hres) (result)) { CComPtrIDxcBlobEncoding errorBlob; hres result-GetErrorBuffer(errorBlob); if (SUCCEEDED(hres) errorBlob) { std::cerr Shader compilation failed :\n\n (const char*)errorBlob-GetBufferPointer(); throw std::runtime_error(Compilation failed); } } // 获取编译结果 CComPtrIDxcBlob code; result-GetResult(code); // 由编译结果创建 Vulkan 着色器模块 VkShaderModuleCreateInfo shaderModuleCI{}; shaderModuleCI.sType VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; shaderModuleCI.codeSize code-GetBufferSize(); shaderModuleCI.pCode (uint32_t*)code-GetBufferPointer(); VkShaderModule shaderModule; vkCreateShaderModule(device, shaderModuleCI, nullptr, shaderModule);Vulkan 着色器阶段到 HLSL 目标着色器配置文件映射使用 DXC 编译 HLSL 时需要选择目标着色器配置文件。配置文件名称由着色器类型与目标着色器模型组成。Vulkan 着色器阶段HLSL 目标着色器配置文件备注VK_SHADER_STAGE_VERTEX_BITvsVK_SHADER_STAGE_TESSELLATION_CONTROL_BIThsHLSL 中称为外壳着色器VK_SHADER_STAGE_TESSELLATION_EVALUATION_BITdsHLSL 中称为域着色器VK_SHADER_STAGE_GEOMETRY_BITgsVK_SHADER_STAGE_FRAGMENT_BITpsHLSL 中称为像素着色器VK_SHADER_STAGE_COMPUTE_BITcsVK_SHADER_STAGE_RAYGEN_BIT_KHR、VK_SHADER_STAGE_ANY_HIT_BIT_KHR、VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR、VK_SHADER_STAGE_MISS_BIT_KHR、VK_SHADER_STAGE_INTERSECTION_BIT_KHR、VK_SHADER_STAGE_CALLABLE_BIT_KHRlib所有光线追踪相关着色器使用lib目标配置文件且至少使用着色器模型 6.3如lib_6_3VK_SHADER_STAGE_TASK_BITasHLSL 中称为放大着色器至少使用着色器模型 6.5如as_6_5VK_SHADER_STAGE_MESH_BITms至少使用着色器模型 6.5如ms_6_5示例编译使用着色器模型 6.6 特性的计算着色器目标配置文件为cs_6_6编译光线追踪任意击中着色器目标配置文件为lib_6_3着色器模型支持范围DirectX 与 HLSL 使用固定的着色器模型标识描述支持的特性集这与 Vulkan 和 SPIR‑V 基于扩展灵活添加特性的方式不同。下表尽可能列出 Vulkan 对 HLSL 着色器模型的支持情况不保证完全完整着色器模型支持状态备注Shader Model 5.1 及更低✔不含无 Vulkan 等价物的特性Shader Model 6.0✔Wave 内置函数、64‑bit 整数Shader Model 6.1✔SV_ViewID、SV_BarycentricsShader Model 6.2✔16‑bit 类型、非规格数模式Shader Model 6.3✔硬件加速光线追踪Shader Model 6.4✔着色器整数点积、SV_ShadingRateShader Model 6.5⚠️部分DXR1.1、网格与放大着色器、额外 Wave 内置函数Shader Model 6.6⚠️部分VK_NV_compute_shader_derivatives、VK_KHR_shader_atomic_int64、VK_EXT_descriptor_buffer、VK_EXT_mutable_descriptor_typeShader Model 6.7⚠️部分VK_KHR_shader_quad_control、VkPhysicalDeviceFeatures::shaderStorageImageMultisample

更多文章