How to pass two uniform bbuffers in shader?

Hello, I am new with vulkan and trying to leasrn it with helping this tutorial vulkan-tutorial com.
Now I am trying to pass two uniform object in vertex shader.

 #version 450
 #extension GL_ARB_separate_shader_objects : enable
 
 layout(binding = 0) uniform UniformBufferObject {
     mat4 model;
     mat4 view;
     mat4 proj;
 } ubo;
 
 layout(binding = 1) uniform OffsetPosition {
   vec2 off;
 } offsetPosition;
 
  
 
 layout(location = 0) in vec2 inPosition;
 layout(location = 1) in vec3 inColor;
 layout(location = 2) in uint vertexPosition;
 layout(location = 0) out vec3 fragColor;
 
 void main() {
     //do something
 }

Uniform buffers is same, except of one of them is struct and second vec2;
To achive that, I create one descriptorPool

 void MainVulkan::createDescriptorPool() {
     VkDescriptorPoolSize poolSize{};
     poolSize.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
     poolSize.descriptorCount = static_cast<uint32_t>(swapChainImages.size()*20);
     VkDescriptorPoolCreateInfo poolInfo{};
     poolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
     poolInfo.poolSizeCount = 1;
     poolInfo.pPoolSizes = &poolSize;
     poolInfo.maxSets = static_cast<uint32_t>(swapChainImages.size()*20);
     if (vkCreateDescriptorPool(device, &poolInfo, nullptr, &descriptorPool) != VK_SUCCESS) {
         throw std::runtime_error("failed to create descriptor pool!");
     }
 }

Then one DescriptorLayer

 void MainVulkan::createDescriptorSetLayout() {
     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; // Optional
     VkDescriptorSetLayoutBinding offsetBinding{};
     offsetBinding.binding = 1;
     offsetBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
     offsetBinding.descriptorCount = 1;
     offsetBinding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
     offsetBinding.pImmutableSamplers = nullptr; // Optional

     VkDescriptorSetLayoutCreateInfo layoutInfo{};
     layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
     layoutInfo.bindingCount = 2;
     VkDescriptorSetLayoutBinding arrb[]= {uboLayoutBinding, offsetBinding};
 
     VkDescriptorSetLayoutBinding* p =arrb; 
     layoutInfo.pBindings =p;
 
 
     if (vkCreateDescriptorSetLayout(device, &layoutInfo, nullptr, &descriptorSetLayout) != VK_SUCCESS) {
         throw std::runtime_error("failed to create descriptor set layout!");
     }
 
 }

Then I allocate descriptors.
I make two call of vkAllocateDescriptorSets func, and then update descriptor set with

 void MainVulkan::createDescriptorSets() {
     std::vector<VkDescriptorSetLayout> layouts(swapChainImages.size(), descriptorSetLayout);
     VkDescriptorSetAllocateInfo allocInfo{};
     allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
     allocInfo.descriptorPool = descriptorPool;
     allocInfo.descriptorSetCount = static_cast<uint32_t>(swapChainImages.size() );
     allocInfo.pSetLayouts = layouts.data();
     descriptorSets.resize(swapChainImages.size() );
     if (vkAllocateDescriptorSets(device, &allocInfo, descriptorSets.data()) != VK_SUCCESS) {
         throw std::runtime_error("failed to allocate descriptor sets!");
     }
     descriptorSetsVec.resize(swapChainImages.size() );
 
 
     if (vkAllocateDescriptorSets(device, &allocInfo,descriptorSetsVec.data()) != VK_SUCCESS) {
         throw std::runtime_error("failed to allocate descriptor sets!");
     }
  
 
     for (size_t i = 0; i < swapChainImages.size(); i++) {
         VkDescriptorBufferInfo bufferInfo{};
         bufferInfo.buffer = uniformBuffers[i];
         bufferInfo.offset = 0;
         bufferInfo.range = sizeof(UniformBufferObject);
 
         VkWriteDescriptorSet descriptorWrite{};
         descriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
         descriptorWrite.dstSet = descriptorSets[i];
         descriptorWrite.dstBinding = 0;
         descriptorWrite.dstArrayElement = 0;
         descriptorWrite.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
         descriptorWrite.descriptorCount = 1;
         descriptorWrite.pBufferInfo = &bufferInfo;
 
         vkUpdateDescriptorSets(device, 1, &descriptorWrite, 0, nullptr);
 
     }
     for (size_t i = 0; i < swapChainImages.size(); i++) {
         VkDescriptorBufferInfo bufferInfo{};
         bufferInfo.buffer = uniformBuffersVec[i];
         bufferInfo.offset = 0;
         bufferInfo.range = sizeof(glm::vec2);
 
         VkWriteDescriptorSet descriptorWrite{};
         descriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
         descriptorWrite.dstSet = descriptorSetsVec[i];
         descriptorWrite.dstBinding = 1;
         descriptorWrite.dstArrayElement = 0;
         descriptorWrite.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
         descriptorWrite.descriptorCount = 1;
         descriptorWrite.pBufferInfo = &bufferInfo;
 
    vkUpdateDescriptorSets(device, 1, &descriptorWrite, 0, nullptr);

     }

 }
nd then I bind data to pipeline.
  vkCmdBindDescriptorSets(commandBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS,
                                  pipelineLayout, 0, 1, &descriptorSetsVec[i], 0, nullptr);
     vkCmdBindDescriptorSets(commandBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS,
                                     pipelineLayout, 0, 1, &descriptorSets[i], 0, nullptr);

But, when I run program I get validation error.

validation layer: Descriptor set 0x2b bound as set #0 encountered the following validation error at vkCmdDrawIndexed() time: Descriptor in binding #1 at global descriptor index 1 is being used in draw but has not been updated.

My program works because second buffer didnt used it shader. If I swap vkCmdBindDescriptorSets calls, I get segfault. So, somehow last call of vkCmdBindDescriptorSets overwrites first.
Where is my mistake?

In your shader both uniform buffers use set 0 (as you didn’t explicitly set this), so you need to provide the descriptors for binding 0 and binding 1 (for set 0) in one consecutive array in one descriptor binding call.

Or if you want so split this up similar to how your application is structured (with descriptors in two different arrays), you need to specify sets in your shader interface like this:

layout(set = 0, binding = 0) uniform UniformBufferObject {
} ubo;

layout(set = 1, binding = 0) uniform OffsetPosition {
} offsetPosition;

And bind like this using an offset:

vkCmdBindDescriptorSets(commandBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS,
pipelineLayout, 0, 1, &descriptorSetsVec[i], 0, nullptr);
vkCmdBindDescriptorSets(commandBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS,
pipelineLayout, 1, 1, &descriptorSets[i], 0, nullptr);

Note the 1 in the second call, which specifies the first set as in your shader interface.

This topic was automatically closed 183 days after the last reply. New replies are no longer allowed.