Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to correctly use decriptor sets for multiple interleaving buffers?

Tags:

vulkan

I have a uniform buffer which should be updated every frame. In order to avoid big stalls I want to create 3 buffers (by the number of my frame buffers) which should be interleaved every frame (0-1-2-0-1-2-...). But I can't understand how to create descriptors and bind them. This is how I'm doing it now:

  1. I created a VkDescriptorSetLayout where I specified that I want to use a uniform buffer at binding position 0 in some shader stage.
  2. I created a VkDescriptorPool with a size for 3 descriptors for uniform buffers.
  3. Next I need to allocate descriptor sets but how many descriptor sets do I need here? I have only one VkDescriptorSetLayout and I'm expecting to get one VkDescriptorSet.
  4. Next I need to update created descriptor sets. Since I have only one binding (0) in my shader I can use only one one buffer in VkDescriptorBufferInfo which will be passed to VkWriteDescriptorSet which will be passed to vkUpdateDescriptorSets. But what about other two buffers? Where to specify them?
  5. When I need to record a command I need to bind my descriptor set. But till now I have a descriptor set which is updated only for one buffer. What about the others?

Do I need to create 3 VkDescriptorSetLayout - one for every frame? Next do I need to allocate and update corresponding descriptor set with a corresponding buffer? And after this do I need to create 3 different command buffers where I should specify corresponding descriptor set.

It seems it's a lot of work - the data is almost the same - all bindings, states stays the same, only the buffer changes.

All it sounds very confusing so please don't hesitate to clarify.

like image 268
nikitablack Avatar asked Feb 19 '18 14:02

nikitablack


1 Answers

Descriptor Set Layouts defines the contents of a descriptor set - what types of resources (descriptors) given set contains. When You need several descriptor sets with a single uniform buffer, You can create all of these descriptor sets using the same layout (layout is only a description, a specification). This way You just tell the driver: "Hey, driver! Give me 3 descriptor sets. But all of them should be exactly the same".

But because they are created from the same layout it doesn't mean they must contain the same resource handles. All them (in Your case) must contain a uniform buffer. But what resource will be used for this uniform buffer depends on You. So each descriptor set can be updated with separate buffer.

Now when You want to use 3 buffers one after another in three consecutive frames, You can do it in several different ways:

  1. You can have a single descriptor set. Then in every frame, before You start preparing command buffers, You update the descriptor set with the next buffer. But when You update a descriptor set, it cannot be used by any submitted (and not yet finished) command buffers. So this would require additional synchronization and wouldn't be that much different than using a single buffer. This way You also cannot "pre-record" command buffers.
  2. You can have a single descriptor set. To change its contents (use a different buffer in it) You can update it through functions added in the VK_KHR_descriptor_update_template extension. It allows descriptor updates to be recorded in command buffers so synchronization should be a bit easier. It should allow You to pre-record command buffers. But it needs an extension to be supported so it's not an option on platforms that do not support it.
  3. Method You probably thought of - You can have 3 separate descriptor sets. All of them allocated using the same layout with a uniform buffer. Then You update each descriptor set with a different buffer (You can use 1st buffer with 1st descriptor set, 2nd buffer with 2nd descriptor set and 3rd buffer with 3rd descriptor set). Now during recording a command buffer, when You want to use a first buffer then You just bind the first descriptor set. In the next frame, You just bind a second descriptor set and so on.

The method 3 is probably the easiest to implement as it requires no synchronization for descriptors (only per frame-level synchronization is required if You have such). It also allows You to pre-record command buffers and it doesn't require any additional extensions to be enabled. But as You noted, it requires more resources to be created and managed.

Don't forget that You need to create a descriptor pool that is big enough to contain 3 uniform buffers but at the same You must also specify that You want to allocate 3 descriptor sets from it (one uniform buffer per descriptor set).

You can read more about descriptor sets in Intel's API without Secrets: Introduction to Vulkan - Part 6 tutorial.

As for Your questions:

Do I need to create 3 VkDescriptorSetLayout - one for every frame?

No - a single layout is enough (as soon as all descriptor sets contain the same types of resources in the same bindings.

Next do I need to allocate and update corresponding descriptor set with a corresponding buffer?

As per option 3 - yes.

And after this do I need to create 3 different command buffers where I should specify corresponding descriptor set.

It depends whether You re-record command buffers every frame or if You pre-record them up front. Usually command buffers are re-recorded each frame. But as having a single command buffer requires waiting until its submission is finished, You probably may need a set(s) of command buffers for each frame, that correspond to Your framebuffer images (and descriptor sets). So in frame 0 You use command buffer #0 (or multiple command buffers reserved for frame 0). In frame 1 You use command buffer #1 etc.

Now You can record a command buffer for a given frame and during recording You provide a descriptor set that is associated with a given frame.

like image 164
Ekzuzy Avatar answered Jan 03 '23 11:01

Ekzuzy