Some good practices for Vulkan rendering

Hello there.

I am doing some experiments with Vulkan, I love play with this API even if there is some things a bit complicated ^^.

So, I have some questions to have the better performance with rendering :).

Keeping the same pipeline, it is better to reset and do several drawcalls within an unique command buffer (with a bit telling that it will be submit only once)? Or is it better to submits several (for example one for one object) of them to the queue ? According to me, the better way should be the second one because command buffers are already created. But I am not sure, if some of you could guide me :).

About memory management, if I understand well, a good way should to use several big memory pool (maybe 32 or 64 mio) and use one for images, another one for vertex, another one for “buffer like SSBO” etc? Am I right?

Thanks for your advises :).

Reading Direct3D 12 programming guid on the MSDN,they “Command lists are typically executed once.”, so maybe I was wrong and it is better to reset command buffers ^^.

If you manage to reuse command buffers, you will dramatically improve CPU perfomance. In general, however, you want to create and destroy objects, particles and UI elements dynamically, so most of the time you don’t have other choice but to create command buffers from scratch. But, for example, if you have a lot of static geometry, you can record CB during scene loading once use it all the time.

Ultimately, I do not think there are any general answers to these questions as of yet. There are too many ways to structure static vs. dynamic command buffers, and far too little knowledge about how these things get implemented to know for certain.

However, it should be noted that command buffer building is intended to be:

  1. Cheap (relatively speaking, particularly relative to OpenGL)

  2. Threaded. Or at least, separate command buffers can be built simultaneously.

That is, IHVs would not be surprised to see applications that use dynamic command buffers exclusively.

How much effort should you go through to create static command buffers? Could a static primary command buffer with dynamic secondary command buffers be more efficient than submitting that same number of dynamic primary command buffers? What is the cost of submitting a command buffer at all? After all, if you have static command buffers, that generally means having to submit them more than once?

It’s hard to know for sure. But given that each command buffer has its own pipeline state vector, it stands to reason that having a command buffer per-object is probably not a good idea. Such a thing would involve lots of state changes for state that probably isn’t changing, so even doing this for secondary command buffers is probably not going to work well. If you can group lots of objects into a static command buffer, that might help. But then again, it might not.

About memory management, if I understand well, a good way should to use several big memory pool (maybe 32 or 64 mio) and use one for images, another one for vertex, another one for “buffer like SSBO” etc? Am I right?

You should organize your memory allocations based on the organization of your data, not based on some arbitrary division like you suggest here. There is nothing special about buffers or textures; they’re just memory, and you lose nothing by putting them in the same pool of memory (unless you have special needs like mapping and so forth).

If you’re streaming world geometry, then you should have blocks (which could be distinct sections of the same memory allocation) that represent streaming segments. These blocks could contain textures, buffers used for vertex data, buffers for uniforms, etc, all as defined by the needs of that section of world geometry. There’s no reason to try to put such data into different memory allocations just because some of it is intended to be an SSBO and some is intended to be an image.

This has nothing to do with performance per-se; it’s more about reasonable data organization. All your GUI data can go into one allocation, whether that data is a UBO, vertex data, or textures. And so forth.

Remember: the reason Vulkan gives you low-level control is so that you can use that control.

Hello !!
Firstly thanks for your both answers !
I begin to understand the philosophy of Vulkan, so I guess I am going to proceed like follow.

For the Command Buffers, I am going to put ‘static’ geometry into only one command buffer, by static, I mean geometry will not be destroyed, because even if they move, I just have to change data and not the way to render them :). For others geometry, I’ll use dynamic command buffers (particles for examples?).

Talking about particles, is do a lot of vkCmdDraw inside a command buffer result in an overhead? Or it is only recorder like once vkCmdDraw ? I guess it is not a good idea to make a huge number of vkDraw ^^.

About memory management, I am going to be as simple as possible. I don’t want to be bother a lot about it, so I am going to use a memory pool with allocating 64mio / blocks or somethings like that. I am using Vulkan to test, and learn somethings, so if it is not a perfect memory management, it is not important and I guess my idea is not so bad ^^.

Thank you :slight_smile: