当前位置: 首页 > news >正文

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 更偏向过程式(类似 C),HLSL 更偏向面向对象(类似 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); }

HLSL

struct 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 内置变量映射列表可参考对应文档。


DirectXShaderCompiler(DXC)

与 GLSL 转 SPIR‑V 同理,在 Vulkan 中使用 HLSL 需要着色器编译器。glslang是 GLSL 转 SPIR‑V 的标准编译器,而DirectXShaderCompiler(DXC)是 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= 顶点着色器模型 6,ps_6_0= 像素 / 片元着色器模型 6 等)
  • -E:指定着色器入口函数

扩展会根据特性使用自动启用,也可显式指定:

dxc.exe -spirv -T vs_6_1 -E main .\input.vert -Fo .\output.vert.spv -fspv-extension=SPV_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 库 CComPtr<IDxcLibrary> library; hres = DxcCreateInstance(CLSID_DxcLibrary, IID_PPV_ARGS(&library)); if (FAILED(hres)) { throw std::runtime_error("Could not init DXC Library"); } // 初始化 DXC 编译器 CComPtr<IDxcCompiler3> compiler; hres = DxcCreateInstance(CLSID_DxcCompiler, IID_PPV_ARGS(&compiler)); if (FAILED(hres)) { throw std::runtime_error("Could not init DXC Compiler"); } // 初始化 DXC 工具 CComPtr<IDxcUtils> 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; CComPtr<IDxcBlobEncoding> 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 == L"vert") { targetProfile = L"vs_6_1"; } if (extension == L"frag") { targetProfile = L"ps_6_1"; } // 其他文件类型映射(cs_x_y、lib_x_y 等) } // 配置编译参数:HLSL 转 SPIR‑V std::vector<LPCWSTR> arguments = { filename.c_str(), L"-E", L"main", L"-T", targetProfile, L"-spirv" }; // 编译着色器 DxcBuffer buffer{}; buffer.Encoding = DXC_CP_ACP; buffer.Ptr = sourceBlob->GetBufferPointer(); buffer.Size = sourceBlob->GetBufferSize(); CComPtr<IDxcResult> 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)) { CComPtr<IDxcBlobEncoding> 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"); } } // 获取编译结果 CComPtr<IDxcBlob> 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_BITvs
VK_SHADER_STAGE_TESSELLATION_CONTROL_BIThsHLSL 中称为外壳着色器
VK_SHADER_STAGE_TESSELLATION_EVALUATION_BITdsHLSL 中称为域着色器
VK_SHADER_STAGE_GEOMETRY_BITgs
VK_SHADER_STAGE_FRAGMENT_BITpsHLSL 中称为像素着色器
VK_SHADER_STAGE_COMPUTE_BITcs
VK_SHADER_STAGE_RAYGEN_BIT_KHRVK_SHADER_STAGE_ANY_HIT_BIT_KHRVK_SHADER_STAGE_CLOSEST_HIT_BIT_KHRVK_SHADER_STAGE_MISS_BIT_KHRVK_SHADER_STAGE_INTERSECTION_BIT_KHRVK_SHADER_STAGE_CALLABLE_BIT_KHRlib所有光线追踪相关着色器使用lib目标配置文件,且至少使用着色器模型 6.3(如lib_6_3
VK_SHADER_STAGE_TASK_BITasHLSL 中称为放大着色器,至少使用着色器模型 6.5(如as_6_5
VK_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.0Wave 内置函数、64‑bit 整数
Shader Model 6.1SV_ViewIDSV_Barycentrics
Shader Model 6.216‑bit 类型、非规格数模式
Shader Model 6.3硬件加速光线追踪
Shader Model 6.4着色器整数点积、SV_ShadingRate
Shader Model 6.5⚠️(部分)DXR1.1、网格与放大着色器、额外 Wave 内置函数
Shader Model 6.6⚠️(部分)VK_NV_compute_shader_derivativesVK_KHR_shader_atomic_int64VK_EXT_descriptor_bufferVK_EXT_mutable_descriptor_type
Shader Model 6.7⚠️(部分)VK_KHR_shader_quad_controlVkPhysicalDeviceFeatures::shaderStorageImageMultisample
http://www.jsqmd.com/news/591270/

相关文章:

  • B站缓存视频转换与媒体处理全攻略:从本地存储到高效管理
  • Web字体优化与前端性能提升:Fontmin工具全解析
  • 3分钟掌握:让PPT公式排版效率提升10倍的LaTeX插件使用指南
  • 分析1688代运营性价比,能提升自然流量且效果稳定的公司排名 - 工业推荐榜
  • KDD-99数据集实战:基于机器学习的网络入侵检测系统优化
  • ms-swift微调框架实战:10分钟在单卡3090上微调Qwen2.5-7B,新手也能快速上手
  • MATLAB高斯过程回归工具箱:支持多因素单/多输出拟合预测,比神经网络和支持向量机学习速度更...
  • 2种高效方案:Wand-Enhancer工具全功能解锁实战
  • 7个实用技巧:如何在项目中高效应用Plus Jakarta Sans开源字体
  • App-Installer:重新定义你的iOS应用安装体验
  • 微信单向好友困扰?WechatRealFriends一键检测工具助你优化社交关系
  • 诚信通代运营靠谱吗,全国范围内值得推荐的公司有哪些 - myqiye
  • 解决Chrome浏览器中Video标签进度条无法拖动的服务器端配置指南
  • 百考通:AI精准赋能开题报告,让学术研究更高效、更专业
  • ncmdump:让NCM音乐文件重获自由的格式转换工具
  • 突破加密壁垒:ArchivePasswordTestTool让压缩包密码恢复效率提升10倍的秘诀
  • 音频解密工具:打破加密壁垒的本地音乐格式转换解决方案
  • 终极窗口调整指南:如何用WindowResizer突破Windows尺寸限制
  • Altium Designer 20元件库设计新规范:为什么我彻底放弃了Value字段?
  • 零基础也能用AI建站工具:10分钟上手生成你的第一个网站
  • 当Charles抓包失灵时:雷电模拟器上的Postern代理配置备选方案详解
  • B站资源管理终极解决方案:BiliTools跨平台工具箱完整指南
  • 独立站域名选择对SEO的影响有哪些_独立站的技术优化措施有哪些
  • 如何构建全网最全音源系统:LXMusic音源架构深度解析与实战指南
  • 新手友好:在快马平台上手把手搭建你的第一本期刊查询工具
  • 攻克组件库升级难题:vant-weapp从0.x到最新版的平滑迁移方案
  • 分析2026年上海精品搬家公司,居民与公司搬家收费怎么算 - 工业品牌热点
  • 如何用Alternative Mod Launcher轻松管理XCOM 2模组
  • HCL模拟器与CRT高效连接及个性化界面设置指南
  • Pixel Aurora Engine 效果对比:不同算法策略下的图像生成质量评估