Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Changing the access descriptor for a Unifrom multiple times within the same pass. #71

Open
DGriffin91 opened this issue Apr 10, 2024 · 2 comments

Comments

@DGriffin91
Copy link
Contributor

DGriffin91 commented Apr 10, 2024

I'm trying to figure out the best way to bind a different uniform buffer for each draw where each uniform has the same layout, and the rest of the pass/pipeline remains consistent.

Another example would be changing texture bindings for each draw within the same pass.

This is what I've tried, but it's very slow as it results in a new subpass for every draw. It's my understanding that in vulkan, pipelines and bindings can change within a subpass (but not attachments).

let mut pass = frame
    .render_graph
    .begin_pass("Triangle Example")
    .bind_pipeline(&triangle_pipeline)
    .access_node(index_node, AccessType::IndexBuffer)
    .access_node(vertex_node, AccessType::VertexBuffer)
    .clear_color(0, frame.swapchain_image)
    .store_color(0, frame.swapchain_image);

for (i, uniform_node) in uniform_nodes.iter().enumerate() {
    pass = pass
        .access_descriptor(
            5,
            uniform_node.clone(),
            AccessType::VertexShaderReadUniformBuffer,
        )
        .record_subpass(move |subpass, _| {
            subpass.bind_index_buffer(index_node, vk::IndexType::UINT16);
            subpass.bind_vertex_buffer(vertex_node);
            subpass.draw_indexed(3, 1, 0, 0, i as u32);
        });
}
@attackgoat
Copy link
Owner

You might be able to improve the performance by using a bindless approach where you record one subpass and use push constants or gl_InstanceIndex to change what index the next draw references out of that bindless array. Example.

If you are changing other bindings or pipelines this won't help because the code at graph/resolver.rs:1108 ultimately creates one subpass for each "exec" (each call to record_subpass).

This could be done in a smarter way to avoid creating new subpasses when the rules allow. There is also some performance left on the table because fresh descriptor sets are written and bound for each subpass. I can't say how soon I can fix these items they should not change any public API.

... it's very slow ...

There is a performance tax of the runtime approach compared to pre-baked command buffers and descriptor sets. I do think there should be a compatible solution for times when a section of the render graph is known to stay the same or just need descriptor writes. Right now it's possible to use record_cmd_buf and do raw Vulkan inside of a larger graph but I would like to provide a better solution.

Aside from finding solutions that might work for you in the meantime, I see three issues to correct here:

  • Create subpasses only if required
  • Re-use existing descriptor sets when possible
  • Provide a way to "bake" render graphs and replay them over many frames

@DGriffin91
Copy link
Contributor Author

Thanks for your reply. And thanks for your work on this project, it's really awesome!

I am planning on using bindless where possible. But there's some cases where rebinding within a pass is somewhat inevitable.

It would be great to be able to cache/record pipelines, descriptor sets, etc... In my case, the majority of these don't change from frame to frame.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants