Best practice for vk rendering

Hi,

I have to render a scene graph where models share the same shader but with different materials data.
The uniforms are stored in uniform buffer so when I render a model, I need to update this uniform buffer.

For this purpose, my model class contain one descriptorSet and a list of commandBuffer with submitInfo.
Init model :


create vertex/index buffer
send texture data to GPU
create or get instance of shader
create descriptor set
create command buffer
create submitInfo

The render loop :


submit command to clear

foreach shaders :
    foreach models :
        update uniform data buffer
        submit submitInfo of this model

submit command for sync
presentKHR

I’m not sure it’s the best way to render complex scene, I’m beginner in vulkan.
So what do you think about it ?

Thank’s,
Stevens

append the new data to the uniform buffer and use a dynamic offset to point to the correct one.


vkBeginBuffer
vkCmdStartRenderpass
foreach shaders :
    vkCmdBindPipeline
    foreach models :
        append uniform data to buffer
        vkCmdBindDescriptorSets
        vkCmdDraw
vkcmdEndRenderpass

Thank’s Ratchet Freak,

I found that for dynamic offset : https://github.com/SaschaWillems/Vulkan/tree/master/examples/dynamicuniformbuffer
And for material texture per model, I use a second descriptor set :


// Alloc
foreach shaders
    size = 0
    foreach models
        dynamicOffset = size
        size += sizeof(uniform)
       
    alloc ubo with size
    create descriptor set

// Create command
vkBeginBuffer
vkCmdStartRenderpass
foreach shaders :
    vkCmdBindPipeline
    foreach models :
        list<descriptorsSet> descriptors;
        descriptors.add(descriptorSetUBO)

        if(model.hasTexture)
              descriptors.add(descriptorSetTexture)

        vkCmdBindDescriptorSets ( ...., descriptors.size(), descriptors.data(), 1, dynamicOffset )
        vkCmdDraw
vkcmdEndRenderpass

It look better than one descriptor set per model but that require more memory. Maybe push constant or cmdUpdateBuffers are better for large scene.

The render code in your first post is very slow, you are ping ponging the execution so only one of the cpu and gpu is active at a time and most of the time they are waiting on the communication latency and cache flushing. You should instead try to give the gpu a lot of data to crunch through at a time. That way the communication latency is amortized between the render commands in the command buffer.

You cannot cmdUpdateBuffers in the middle of a renderpass, so you need to put all the data in a buffer before you start the renderpass. Updating the pointer with vkCmdBindDescriptorSets is cheap, stopping and starting a renderpass is very expensive.

pushconstants are tiny (128-256 bytes depending on the gpu) so there isn’t a lot of data you can put in them. 2 mat4s already fills the 128 sized one up.

don’t be afraid to use multiple descriptor sets or bigger buffers when you need to, the memory used for the uniform data per mesh is tiny compared to the size of the mesh itself. A mat4 transform for 30 objects is just under 2 kilobytes.

Your gpu will have GigaBytes worth of storage. So that uniform buffer is literally less than 0.0001% of all the memory you have in you GPU.