I'm trying to create a single pipeline with a layout where it requires two bindings, a dynamic UBO and a image/sampler binding. I want each binding to come from a separate descriptor set, so I'd bind two descriptor sets per draw call. One descriptor set is for texture per object, the other is for the dynamic UBO(shared between objects). I want to be able to do something like this in the rendering portion:
commandBuffer.bindPipeline(vk::PipelineBindPoint::eGraphics, pipeline);
for (int ii = 0; ii < mActiveQuads; ii++)
{
uint32_t dynamicOffset = ii * static_cast<uint32_t>(dynamicAlignment);
// bind texture for this quad
commandBuffer.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, sharedPipelineLayout, 0, 1,
&swapResources[current_buffer].textureDescriptors[ii], 1, &dynamicOffset);
// draw the dynamic UBO with offset for this quad
commandBuffer.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, sharedPipelineLayout, 0, 1,
&swapResources[current_buffer].quadDescriptor, 1, &dynamicOffset);
commandBuffer.draw(2 * 3, 1, 0, 0);
}
But this doesn't seem to work. First of all I'm not sure I have understood everything about descriptor sets and pipeline layouts to know if what I'm doing is allowed. Does this even make sense? That I can create a pipeline with a 2 binding layout, but create each descriptor to fill just one of those bindings each, then bind two descriptors per draw call for that pipeline?
If it is allowed. This is how I'm creating the pipeline and descriptors:
vk::DescriptorSetLayoutBinding const layout_bindings[2] = { vk::DescriptorSetLayoutBinding()
.setBinding(0)
.setDescriptorType(vk::DescriptorType::eUniformBufferDynamic)
.setDescriptorCount(1)
.setStageFlags(vk::ShaderStageFlagBits::eVertex)
.setPImmutableSamplers(nullptr),
vk::DescriptorSetLayoutBinding()
.setBinding(1)
.setDescriptorType(vk::DescriptorType::eCombinedImageSampler)
.setDescriptorCount(1)//texture_count)
.setStageFlags(vk::ShaderStageFlagBits::eFragment)
.setPImmutableSamplers(nullptr) };
// note binding count is 1 here
auto const descriptor_layout = vk::DescriptorSetLayoutCreateInfo().setBindingCount(1).setPBindings(&layout_bindings[0]); // using the first part of the above layout
device.createDescriptorSetLayout(&descriptor_layout, nullptr, &quadDescriptorLayout);
// note binding count is 1 here
auto const descriptor_layout2 = vk::DescriptorSetLayoutCreateInfo().setBindingCount(1).setPBindings(&layout_bindings[1]); // using the second part of the above layout
device.createDescriptorSetLayout(&descriptor_layout2, nullptr, &textureDescriptorLayout);
// Now create the pipeline, note we use both the bindings above with
// layout count = 2
auto const pPipelineLayoutCreateInfo = vk::PipelineLayoutCreateInfo().setSetLayoutCount(2).setPSetLayouts(desc_layout);
device.createPipelineLayout(&pPipelineLayoutCreateInfo, nullptr, &sharedPipelineLayout);
and the descriptors themselves:
// alloc quad descriptor
alloc_info =
vk::DescriptorSetAllocateInfo()
.setDescriptorPool(desc_pool)
.setDescriptorSetCount(1)
.setPSetLayouts(&quadDescriptorLayout);
// texture descriptors(multiple descriptors, one per quad object)
alloc_info =
vk::DescriptorSetAllocateInfo()
.setDescriptorPool(desc_pool)
.setDescriptorSetCount(1)
.setPSetLayouts(&textureDescriptorLayout);
Previously, with the texture and UBO in a single descriptor set it worked fine, I could see multiple quads but all sharing a single texture. When I split off the textures into a different descriptor set, that's when I get a hanging app. I get a 'device lost' error on trying to submit the graphics queue.
Any insight as to if this is possible to do or if I'm doing something wrong in my setup would be very appreciated. Thank you very much!
Below adding Shader code:
#version 450
#extension GL_ARB_separate_shader_objects : enable
layout(binding = 0) uniform UniformBufferObject {
mat4 mvp;
vec4 position[6];
vec4 attr[6];
} ubo;
layout(location = 0) out vec2 fragTexCoord;
void main() {
gl_Position = ubo.mvp *ubo.position[gl_VertexIndex];
fragTexCoord = vec2(ubo.attr[gl_VertexIndex].x, ubo.attr[gl_VertexIndex].y);
}
Pixel shader:
#version 450
#extension GL_ARB_separate_shader_objects : enable
layout(set=0, binding = 1) uniform sampler2D texSampler;
layout(location = 0) in vec2 fragTexCoord;
layout(location = 0) out vec4 outColor;
void main() {
outColor = texture(texSampler, fragTexCoord);
}