Is vkCmdPushDescriptorSetKHR efficient?

Started by
2 comments, last by acerskyline 4 years, 10 months ago

I am new to Vulkan. Compared to DX12, the resource binding procedure seems a little bit complicated. In terms of per draw call uniform buffers, I currently have two approaches in mind, and they both seem to work (haven't tested/benchmarked yet). Can someone shine some light on which is the standard way to do this, with pros and cons. You are welcome to provide other ways but I am not considering push constants because I want a universal approach that I can apply to other kinds of uniform buffers as well (i.e. per pass, per frame, per scene and etc.).

 

approach A) One descriptor set and multiple buffers (one buffer for each object). Bind the descriptor set to pipeline only once before rendering. Bind buffers to the only descriptor set between draw calls using vkCmdPushDescriptorSetKHR.

approach B) Multiple descriptor sets (one descriptor set for each object). (Multiple or single buffers, it doesn't really matter. If single buffer is used, I think it's called a dynamic uniform buffer and all that I need to do is to specify the offset when binding the descriptor set.) Bind buffer/buffers to descriptor sets only once before rendering. Bind the matching descriptor set to the pipeline between draw calls using vkCmdBindDescriptorSets.

 

I am used to DX12 so approach A seems more natural because in my understanding vkCmdPushDescriptorSetKHR in Vulkan is just like SetGraphicsRootConstantBufferView in DX12, because they both bind buffer to pipeline and this operation is buffered with other commands. But the Vulkan one do feels a little bit slower mainly because 1) it is not a root descriptor, 2) Vulkan does not use GPU address and also 3) a descriptor set write operation is needed.

Advertisement

Your approach B) has a problem. The problem being that most devices have a limitation of maxBoundDescriptorSets (https://vulkan.gpuinfo.org/listlimits.php) so you might not get away with that approach for more complicated draws.

Approach A) is generally a reasonable solution, provided that you divide your rendering data based on frequency of updates. E.g. PerFrame, PerView, PerMaterial, PerDraw. The per frame descriptor set is created and set 1x per frame, per view has a descriptor per view and bound per view. The per material, well you can build descriptor sets per material and then just set the descriptor set (not update). Per draw, well here performance matters and in my own experiments I have found dynamic constant buffers and push constants to be really helpful for performance. To your point creating descriptor sets for this type of short lived data carries an overhead that's not really acceptable and is usually solved in DX12 by setting the buffer as a root constant.

The DX12 approach you describe is partially true... the root constants are limited in size (similar to the vulkan problem of maxBoundDescriptorSets) and you can't set certain resources (e.g. ShaderResourceViews)

I hope this helps.

Very helpful! Thanks!

This topic is closed to new replies.

Advertisement