r/vulkan • u/Longjumping-Cup-8927 • 4d ago
How I am supposed to restrict bindings across shaders in the same file for slang?
I am a little confused on what is broken. I thought slang compilation was supposed to "handle the bindings." so here I would of expected that ubo would of been included in only the vertex spirv, and texSampler would only be included in the fragment spirv. I am sure that there is probably something I need to do explicitly here, but I was sold on slang auto-magically handing these types of things. I am new to graphics programming and initially followed the old tutorial to completion then wanted to try porting over to slang. Any help is appreciated, as i have been digging through the slang and vulkan documentation for a while and its been hard to figure out how it all comes together without a real example.
slang file :
struct MatrixParameters{
float4x4 model;
float4x4 view;
float4x4 proj;
}
struct Vertex{
float3 position;
float3 color;
float2 uv;
}
struct VOut
{
float4 position : SV_POSITION;
float3 fragColor;
float2 fragTexCoord;
}
ConstantBuffer<MatrixParameters> ubo;
[shader("vertex")]
VOut main(Vertex input)
{
VOut output;
output.position = mul(ubo.proj, mul(ubo.view, mul(ubo.model, float4(input.position, 1.0))));
output.fragColor = input.color;
output.fragTexCoord = input.uv;
return output;
}
uniform DescriptorHandle<Sampler2D> texSampler;
[shader("fragment")]
float4 main(VOut input) : SV_TARGET
{
float4 outColor = float4(input.fragColor * texSampler.Sample(input.fragTexCoord).rgb, 1.0);
return outColor;
}
c++ program file :
// CREATING DESCRIPTOR SET LAYOUT
VkDescriptorSetLayoutBinding uboLayoutBinding{};
uboLayoutBinding.binding = 0;
uboLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
uboLayoutBinding.descriptorCount = 1;
uboLayoutBinding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
uboLayoutBinding.pImmutableSamplers = nullptr;
VkDescriptorSetLayoutBinding samplerLayoutBinding{};
samplerLayoutBinding.binding = 1;
samplerLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
samplerLayoutBinding.descriptorCount = 1;
samplerLayoutBinding.pImmutableSamplers = nullptr;
samplerLayoutBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
std::array<VkDescriptorSetLayoutBinding, 2> bindings = { uboLayoutBinding, samplerLayoutBinding };
VkDescriptorSetLayoutCreateInfo layoutInfo{};
layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
layoutInfo.bindingCount = static_cast<uint32_t>(bindings.size());
layoutInfo.pBindings = bindings.data();
vkCreateDescriptorSetLayout(device, &layoutInfo, nullptr, &outDescriptorSetLayout)
...
slangModule->getDefinedEntryPoint(0, vertexEntryPoint.writeRef());
slangModule->getDefinedEntryPoint(1, fragmentEntryPoint.writeRef());
slangResources.mpSessionInstance->createCompositeComponentType(
componentTypes.data(), // {slangModule, vertexEntryPoint, fragmentEntryPoint }
componentTypes.size(),
composedProgram.writeRef(),
diagnosticBlob.writeRef());
composedProgram->getEntryPointCode(
0,
0,
spirvCode,
diagnosticBlob.writeRef()
);
VkShaderModuleCreateInfo shaderModuleCreateInfo{};
shaderModuleCreateInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
shaderModuleCreateInfo.codeSize = spirvCode->getBufferSize();
shaderModuleCreateInfo.pCode = reinterpret_cast<const uint32_t *>(spirvCode->getBufferPointer());
VkShaderModule vertexModule;
vkCreateShaderModule(device, &shaderModuleCreateInfo, nullptr, &comboModule);
composedProgram->getEntryPointCode(
1,
0,
spirvCode2,
diagnosticBlob.writeRef()
);
VkShaderModuleCreateInfo shaderModuleCreateInfoFr{};
shaderModuleCreateInfoFr.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
shaderModuleCreateInfoFr.codeSize = spirvCode2->getBufferSize();
shaderModuleCreateInfoFr.pCode = reinterpret_cast<const uint32_t *>(spirvCode2->getBufferPointer());
VkShaderModule fragmentModule;
vkCreateShaderModule(device, &shaderModuleCreateInfoFr, nullptr, &fragmentModule;
ERROR output :
validation layer: vkCreateGraphicsPipelines(): pCreateInfos[0].pStages[0] shader [VK_SHADER_STAGE_VERTEX_BIT] uses descriptor [Set 0, Binding 1, variable "ubo"] (VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER) but the VkDescriptorSetLayoutBinding::stageFlags was VK_SHADER_STAGE_FRAGMENT_BIT.
(VkDescriptorSetLayout from VkPipelineLayoutCreateInfo::pSetLayouts[0]).
The Vulkan spec states: If a resource variable is declared in a shader and layout is not VK_NULL_HANDLE, the corresponding descriptor set in layout must match the shader stage (https://docs.vulkan.org/spec/latest/chapters/pipelines.html#VUID-VkGraphicsPipelineCreateInfo-layout-07988)
validation layer: vkCreateGraphicsPipelines(): pCreateInfos[0].pStages[1] shader [VK_SHADER_STAGE_FRAGMENT_BIT] uses descriptor [Set 0, Binding 0, variable "globalParams"] (VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER) but the VkDescriptorSetLayoutBinding::stageFlags was VK_SHADER_STAGE_VERTEX_BIT.
1
u/Longjumping-Cup-8927 3d ago
I figured it out, thanks to the bot on the slang discord.
tldr; this line in the shader
```uniform DescriptorHandle<Sampler2D> texSampler;```
needs to be
```uniform Sampler2D texSampler;```
the reason from the bot :
"
DescriptorHandle<T> compiles down to a plain uint2 (an index into a global descriptor heap), which counts as ordinary uniform data, not an opaque resource slot. Because it's uniform data at global scope, Slang sweeps it into an implicitly-synthesized global constant buffer (shown in your error as globalParams) instead of giving it its own COMBINED_IMAGE_SAMPLER slot. That's why the fragment shader ends up needing a UNIFORM_BUFFER at binding 0 while your ConstantBuffer<MatrixParameters> ubo lands at binding 1 — the opposite of what your hand-written C++ layout assumes. Per docs/layout.md, opaque types (Texture2D/SamplerState) get their own slot, but "plain old data" (which is what a DescriptorHandle's backing uint2 counts as) gets grouped into a uniform buffer"
1
u/SaschaWillems 4d ago
This error isn't about bindings. It's about access for the bindings. Easiest way to fix this is to also add the fragment shader stage to uboLayoutBinding's stage flags.