在 Vulkan 中使用 HLSL 着色器与 Vulkan-Hpp
此示例的源代码可以在 Khronos Vulkan 示例 github 存储库 中找到。 |
这是 API 示例的转码版本,说明了 vulkan.hpp 提供的 vulkan C++ 绑定的用法。 |
本教程以及随附的示例代码演示了如何在运行时使用 Vulkan-Hpp 在 Vulkan 中使用用高级着色语言 (HLSL) 编写的着色器。
Vulkan 不直接使用人类可读的文本格式的着色器,而是使用 SPIR-V 作为中间表示。这为使用除 GLSL 以外的其他着色器语言提供了选择,只要它们可以针对 Vulkan SPIR-V 环境。其中一种语言是 Microsoft 的 HLSL,它是 DirectX 的着色语言。
有关 HLSL 如何适应 Vulkan 生态系统的详细信息,请参见此Vulkan 指南章节。
HLSL 语法
HLSL 比 GLSL 更面向对象,但着色器的总体结构类似。Vulkan 特定的函数使用隐式 vk
命名空间标记
struct VSInput
{
[[vk::location(0)]] float3 Pos : POSITION0;
[[vk::location(1)]] float2 UV : TEXCOORD0;
[[vk::location(2)]] float3 Normal : NORMAL0;
};
struct UBO
{
float4x4 projection;
float4x4 model;
float4 viewPos;
};
cbuffer ubo : register(b0, space0) { UBO ubo; }
struct VSOutput
{
float4 Pos : SV_POSITION;
[[vk::location(0)]] float2 UV : TEXCOORD0;
};
VSOutput main(VSInput input)
{
VSOutput output = (VSOutput)0;
output.UV = input.UV;
output.Pos = mul(ubo.projection, mul(ubo.model, float4(input.Pos.xyz, 1.0)));
return output;
}
Glslang
Vulkan 示例使用 Glslang 在运行时将着色器转换为 SPIR-V。Glslang 是参考 GLSL 验证器和转换器,但也支持 HLSL 作为输入语言。
不过,Glslang 中的 HLSL 支持有限,为了获得功能更完整的 HLSL 到 SPIR-V 编译器,您还可以使用 DirectX 着色器编译器。
对于本教程中的基本着色器,我们可以使用 Glslang,因为它支持我们需要的所有功能。
将 HLSL 转换为 SPIR-V
使用 Glslang 加载 HLSL 类似于加载 GLSL,但需要不同的参数。以下是与从示例的 HlslShaders::load_hlsl_shader
函数加载 HLSL 不同的相关部分
std::vector<uint32_t> spirvCode;
// Use HLSL parsing rules and semantics (EShMsgReadHlsl)
EShMessages messages = static_cast<EShMessages>(EShMsgReadHlsl | ...);
...
// Language needs to be selected based on the shader stage
EShLanguage language = EShLangVertex;
glslang::TShader shader(language);
...
// Set the source language to HLSL
shader.setEnvInput(glslang::EShSourceHlsl, language, glslang::EShClientVulkan, 1);
...
// Parse the HLSL input
if (!shader.parse(&glslang::DefaultTBuiltInResource, 100, false, messages))
{
...
}
// Add shader to new program object.
glslang::TProgram program;
program.addShader(&shader);
// Link program.
if (!program.link(messages))
{
...
}
...
// Translate to SPIRV
glslang::TIntermediate *intermediate = program.getIntermediate(language);
...
glslang::GlslangToSpv(*intermediate, spirvCode, &logger);
...