VulkanでHLSL
わりと久々にブログ更新。
最近、昔にほんのちょろっと触ったVulkanを再入門してみています。
Vulkanは、C APIだと少しツライところがあるので、C++ APIを使います。 (GitHub - KhronosGroup/Vulkan-Hpp: Open-Source Vulkan C++ API)
シェーダ言語どうするか
はじめはなんとなくGLSLでシェーダを記述していたのですが、やっぱりHLSLで書きたいよね!ということで。
VulkanSDK付属の glslangValidator でも変換できるようですが、今回 DirectX Shader Compiler (DXC) を使ってみることにします。 ( DirectXShaderCompiler/SPIR-V.rst at master · microsoft/DirectXShaderCompiler · GitHub)
まずはHLSLを用意する
例として、テクスチャと頂点カラーを乗算して出力するなんの変哲もないピクセルシェーダを用意します。
Texture2D tex : register(t0); SamplerState samp : register(s0); struct PSInput { float4 color : TEXCOORD0; float2 uv : TEXCOORD1; float4 position : SV_POSITION; }; float4 main(PSInput input) : SV_TARGET { float4 output;; output = tex.Sample(samp, input.uv) * input.color; return output; }
HLSL→SPIR-V
dxc に SPIR-V のオプションを渡しつつ、プロファイルやエントリポイントなどを指定します。
dxc -spirv -T ps_6_0 -E main "shader.hlsl" -Fo "shader.spv" -fvk-s-shift 10 0
少し気を付けないといけないのが、-fvk-s-shift の指定。
HLSLだとTextureやSampler,Bufferなど、タイプ別にregister指定が独立していますが、GLSL/Vulkanで同じような役割を担うbindingは各タイプで共通になります。
dxcではコンバート時にregister指定の数値をシフトしてbindingに割り当てることができるようです。
今回は s0 を binding = 10 にシフトさせています。
Descriptor
GLSLで実装している際は特に気にせず sampler2D を使用していました。
HLSLで Texture2D, SamplerState を使用しているので、C++側も変更します。
DescriptorType::eCombinedImageSampler が eSampledImage + eSampler になります。
std::array<vk::WriteDescriptorSet, 2> writeSets; auto& tex = writeSets[0]; vk::DescriptorImageInfo imageInfo; imageInfo.setImageView(m_textureView) .setImageLayout(vk::ImageLayout::eShaderReadOnlyOptimal); tex.setDstSet(m_descriptorSet[0]) .setDstBinding(0) .setDescriptorCount(1) .setDescriptorType(vk::DescriptorType::eSampledImage) .setImageInfo(imageInfo); auto& smp = writeSets[1]; vk::DescriptorImageInfo samplerInfo; samplerInfo.setSampler(m_sampler); smp.setDstSet(m_descriptorSet[0]) .setDstBinding(10) .setDescriptorCount(1) .setDescriptorType(vk::DescriptorType::eSampler) .setImageInfo(samplerInfo); m_device.updateDescriptorSets(writeSets, nullptr);
NsightGraphicsでの見え方
Nsight Graphics でシェーダを確認すると、以下のようにGLSLに変換された状態で確認ができました。 (SPIRV-Cross によって生成されていそうなコメントがついていました)
// GLSL generated using SPIRV-Cross and might not be representative // of original shader source #version 450 layout(set = 0, binding = 0) uniform texture2D tex; layout(set = 0, binding = 10) uniform sampler samp; layout(location = 0) out vec4 out_var_SV_TARGET; layout(location = 1) in vec2 in_var_TEXCOORD1; layout(location = 0) in vec4 in_var_TEXCOORD0; void main() { out_var_SV_TARGET = texture(sampler2D(tex, samp), in_var_TEXCOORD1) * in_var_TEXCOORD0; }
GLSLにはなってしまいますが、Nsight上でのコードの確認や編集がひとまずできました。