Some background information, can be skipped.
I have been trying to dig into Vulkan after working on hobby projects with OpenGL for 2 years. Succesfully following the tutorial from Alexander Overvoorde, I started abstracting certain parts to make it more usable and extendable. This has been a tough learning path, but I managed to abstract all the parts used in the tutorial. I have however been struggling with descriptor sets and layouts, as I am sure many people have. This was a completely new concept to me and was hard to grasp at first. I still don't have a thorough understanding of how exactly it works, but the basics are there. Below may be verbose, but that is done with the sole purpose of trying to give people the best understanding of the situation and to prevent questions that could have been prevented. Most of it can be skimmed through unless you feel you need all the context.
Context & Problem
I have abtracted most of Vulkan's enums/structs into a format I use in my program. For all enum classes, there exists a method to convert from/to Vulkan specific enums.
On to the problem.
I had descriptors working, including rendering an image instead of just a color. This was done using the following fragment shader (vertex shader not relevant in this case)
#version 450
layout(location = 0) in vec4 fColor;
layout(location = 1) in vec2 fTexCoord;
layout(location = 2) in float fTexIndex;
layout(location = 0) out vec4 outColor;
layout(binding = 1) uniform sampler2D texSampler[32];
void main()
{
outColor = fColor;
outColor *= texture(texSampler[int(fTexIndex)], fTexCoord);
if (outColor.a == 0)
discard;
}
All is well, but at the moment I wasn't differentating between sets. As I have seen in some guides, specifically focussing on game engine dev, it could be a good idea to seperate sets per use case. I have followed vkguide.dev's advice on this.
Set 0 = per frame global data --> Bound once per frame
Set 1 = per frame renderpass data --> Bound once per render pass
Set 2 = per frame material data --> Bound once per material
Set 3 = per frame object data --> Bound once per object
So I did a minor change to above shader:
layout(set = 2, binding = 1) uniform sampler2D texSampler[32];
I ofcourse made sure that the correct set is referenced everywhere necessary. Since I first wanted this implemented before I started complicating the shader, this is the one and only uniform there is. As such, I have no bindings for set 0, 1 and 3.
I went on to recompile the shader, run my program and it breaks on creating the graphics pipeline.
Validation Error: [ VUID-VkGraphicsPipelineCreateInfo-layout-00756 ] Object 0: handle = 0x1c580c12c70, type = VK_OBJECT_TYPE_DEVICE; | MessageID = 0x45717876 | Shader uses descriptor slot 2.1 (expected `VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER`) but not declared in pipeline layout
And that is exactly what has been haunting me for a lot of hours now. My descriptor set layouts are created from the reflection data of the shader compiler. I then directly pass them into the pipeline layout creation. The pipeline layout gets created succesfully but then it breaks on the pipeline creation. I cannot understand why changing the layout breaks the pipeline creation. I would have expected it to fail somewhere where I forgot to change the set, but I am completely flabbergasted as to why this is happening.
I think below question might have something to do with it, but I couldn't get through to a solution. Because I do not know which code snippets might be relevant in this question, feel free to ask me for anything you might need to clarify. Vulkan is quite explicit so this question got quite verbose otherwise. (Which it already has because I keep on talking)
Can I bind a descriptor at 2 without binding 0 and 1?