Jump to content
  • Advertisement
KarimIO

Vulkan Remove secondary buffer Vulkan / other ways to remove objects

This topic is 384 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hey guys. Vulkan newbie from OpenGL here. Is there a way to remove a secondary buffer from a primary buffer in Vulkan? If not, how else can I remove objects? I'm binding my primary buffer to:

Bind RenderPass

Draw Related Secondary Command Buffers

End RenderPass

 

And my secondary buffers to:

Bind Graphics Pipeline

Bind Vertex Buffer

Bind Index Buffer

Bind Descriptors

Draw Indexed

 

The only other way I can guess to have objects be removeable is to have one command buffer per object and add them all to submitInfo.pCommandBuffers, but then I'll be rebinding the renderpass a lot, plus I figure it's more work for the GPU. Also, how would object removal be handled with indirect draws, as I'm planning on looking into that relatively soon?

 

EDIT: One more question, is there a way to bind one descriptor set (for the projection, view, model, and combination matrices) to multiple graphics pipelines? And is there a way to bind graphics pipelines to multiple secondary command buffers?

Edited by KarimIO

Share this post


Link to post
Share on other sites
Advertisement

If the number of draw calls changes, its best just to re-record the command buffer.  Recording command buffers in Vulkan is not an overly expensive operation, you can create dozens per frame.  Creating pipelines, renderpasses, etc... they can be slow, but the command buffers themselves are designed to be recreated each frame.  That's not to say you shouldn't re-use them where it makes sense, but you should not be splitting renderpasses up.

If you really want to do the 'only create command buffers once' approach, then the best option is to record the command buffer using vkCmdDrawIndirect().  Then each frame all you have to do is update the indirect buffer which stores all the actual draw commands.  That way you can change the number of objects without re-recording the command buffer and you also don't need lots of little command buffers, a few large will usually suffice. 

Share this post


Link to post
Share on other sites
11 minutes ago, Ryan_001 said:

If the number of draw calls changes, its best just to re-record the command buffer.  Recording command buffers in Vulkan is not an overly expensive operation, you can create dozens per frame.  Creating pipelines, renderpasses, etc... they can be slow, but the command buffers themselves are designed to be recreated each frame.  That's not to say you shouldn't re-use them where it makes sense, but you should not be splitting renderpasses up.

If you really want to do the 'only create command buffers once' approach, then the best option is to record the command buffer using vkCmdDrawIndirect().  Then each frame all you have to do is update the indirect buffer which stores all the actual draw commands.  That way you can change the number of objects without re-recording the command buffer and you also don't need lots of little command buffers, a few large will usually suffice. 

Thank you very much! That makes a lot of sense.

How, though, would I bind a graphics pipeline and descriptor set for multiple command buffers? 

Share this post


Link to post
Share on other sites
1 hour ago, KarimIO said:

Thank you very much! That makes a lot of sense.

How, though, would I bind a graphics pipeline and descriptor set for multiple command buffers? 

Yes :)

You are supposed to reuse graphics pipelines and descriptor sets in multiple command buffers.  In fact the design of pipelines was that the slow/computationally expensive portion of command buffer creation was moved to pipelines so that they only have to be created once and can be reused.

Share this post


Link to post
Share on other sites
1 minute ago, Ryan_001 said:

Yes :)

You are supposed to reuse graphics pipelines and descriptor sets in multiple command buffers.  In fact the design of pipelines was that the slow/computationally expensive portion of command buffer creation was moved to pipelines so that they only have to be created once and can be reused.

Yes, but what I mean is that, is there a way to bind one graphics pipeline once for some command buffers, and then bind another one once for others. Right now I'm just binding it for every single model (and therefore every single command buffer).

Share this post


Link to post
Share on other sites

 Its hard to say exactly what you 'should' and 'should not' do.  I'm hardly an expert, the spec is still rather new, drivers are still new, and there is quite a diverse amount of hardware out there.  That said I feel you are making the command buffers far too small.  One command buffer per object sounds like a sub-optimal approach.  I would personally attempt to place more objects in a command buffer; but I can't say for certain how/what you should exactly do, given how little I know about what you are attempting.

To answer your question binding a single pipeline to multiple command buffers isn't possible.  The only state that transfers between command buffers is from primary to secondary through VkCommandBufferInheritanceInfo.  So that list only includes (at this time) renderpass/subpass, framebuffer, query/pipeline stuff.

The spec states:

Quote

Each command buffer manages state independently of other command buffers. There is no inheritance of state across primary and secondary command buffers, or between secondary command buffers. When a command buffer begins recording, all state in that command buffer is undefined. When secondary command buffer(s) are recorded to execute on a primary command buffer, the secondary command buffer inherits no state from the primary command buffer, and all state of the primary command buffer is undefined after an execute secondary command buffer command is recorded. There is one exception to this rule - if the primary command buffer is inside a render pass instance, then the render pass and subpass state is not disturbed by executing secondary command buffers. Whenever the state of a command buffer is undefined, the application must set all relevant state on the command buffer before any state dependent commands such as draws and dispatches are recorded, otherwise the behavior of executing that command buffer is undefined.

Pipeline's are part of that state.

Share this post


Link to post
Share on other sites
3 minutes ago, Ryan_001 said:

 Its hard to say exactly what you 'should' and 'should not' do.  I'm hardly an expert, the spec is still rather new, drivers are still new, and there is quite a diverse amount of hardware out there.  That said I feel you are making the command buffers far too small.  One command buffer per object sounds like a sub-optimal approach.  I would personally attempt to place more objects in a command buffer; but I can't say for certain how/what you should exactly do, given how little I know about what you are attempting.

To answer your question binding a single pipeline to multiple command buffers isn't possible.  The only state that transfers between command buffers is from primary to secondary through VkCommandBufferInheritanceInfo.  So that list only includes (at this time) renderpass/subpass, framebuffer, query/pipeline stuff.

The spec states:

Pipeline's are part of that state.

I'm mostly asking about best practices. I know every application is unique but there's still stuff that's a good guideline.

Well in that case would it make sense for one secondary command buffer per graphics pipeline? I'd have to recreate it more often but it would be larger and therefore faster, I suppose. 

Thanks! 

Share this post


Link to post
Share on other sites

I don't know how fast/slow binding pipelines in, compared to drawing.  There's going to be some sweet spot obviously where you want at least X amount of GPU work per pipeline bind command, but I don't know what it would be.  Not only would it change for pretty much every single hardware/driver configuration.  The best bet it to pick something and try it.  Its not what I would want to hear (you don't want to change your rendering architecture 'after the fact'), but understand that any advice I give you at this point is just a guess and nothing more.

If I were making a game, say a 1st/3rd person shooter or MMO, where there were a few dozen characters/enemies on screen at once.  I'd probably put each character in a single secondary command buffer.  Since each character consists not only of the base model but multiple items of gear, weaponry, armor, etc... and would probably have unique textures (ie. their own descriptor set).  So in this scenario where each character is very different (even two of identical base models might have different skins/items) then each would get a secondary command buffer.

If I were making a game like an RTS, simulation game, where you have many objects but each one is near identical (with just minor variations of color/texture).  I'd have a few large command buffers, and focus more on using draw indirect or something similar.

The real problem I find, is how you plan on updating the buffer data.  The two main methods of transferring small amounts of data are push constants and VkCmdUpdateBuffer().  Since these are recorded into the command buffer, it almost necessitates a new command buffer be recorded every frame.  The other option, of course, is to use map/unmap with a staging buffer, but this still requires a command buffer to be created to copy the data from the staging buffer to its final buffer.  So either way you're creating a new command buffer (or 3) every frame.

In the end I don't think it makes much of a difference.  Command buffer creation in Vulkan is much faster than OpenGL (due to pipelines and descriptor sets) and easy to multithread.

Share this post


Link to post
Share on other sites

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!