I want to use multiple immutable samplers within one render command in vulkan, but I don't know how to select them within the fragment shader. To understand what I want and what I mean I start first with explaining the working version.
I wrote a render pipeline for multiple textures using vulkan. The first version, which only supported ARGB (VK_FORMAT_R8G8B8A8_UNORM) textures, works fine.
To record the command buffer I did the following:
- vkBeginCommandBuffer
- vkCmdBeginRenderPass
- vkCmdBindPipeline
- for each texture
- vkCmdBindVertexBuffers
- vkCmdBindIndexBuffer
- vkCmdBindDescriptorSets (sets two ubos and the image view)
- vkCmdDrawIndexed
- vkCmdEndRenderPass
- vkEndCommandBuffer
Each texture was drawn correctly, because in 4.3. I bound it's image view to the fragment shader which included the texture sampler.
So now to the part I am struggling with:
The usage of ARGB textures is very ineffizient, if they are updated frequently. So I tried to use YCbCr textures like I420 directly within the shader. After figuring out, how to set them up, I noticed, that they have to be used as immutable samplers (VkDescriptorSetLayoutBinding pImmutableSamplers) which could only be bound statically when the descriptor set layout is defined (vkCreateDescriptorSetLayout). That means using one descriptor set layout over and over again, does not work anymore. Correct?
To fix that, I provided multiple descriptor set layouts (vkCreatePipelineLayout) to the graphics pipeline (vkCreateGraphicsPipelines). Now I am able, to have one binding per texture to the pipeline, which means, I can have multiple immutable samplers statically bound, never exchanged. So far so good, but my fragment shader uses only the first sampler (to be exact, the first descriptor set) to render the output. I thought at first, the descriptor set would be taken from the vkCmdBindDescriptorSets, but I was wrong.
Here is my fragment shader:
#extension GL_ARB_separate_shader_objects : enable
layout(binding = 1) uniform sampler2DArray texSampler;
layout(binding = 2) uniform UniformBufferObject {
float alpha;
uint layer;
} ubo;
layout(location = 0) in vec2 fragTexCoord;
layout(location = 0) out vec4 outColor;
void main() {
vec4 color = texture(texSampler, vec3(fragTexCoord, ubo.layer));
outColor = vec4(color.rgb, color[3] * ubo.alpha);
}
I already figured out, that it is possible to provide a set for the layout of the shader (eg. layout(set=1, binding=1)), but I need to update this set within the rendering task (per texture), like I did with all the other bindings before drawing.
Any suggestions? What is the recommended solution here?