bevyengine / bevy

A refreshingly simple data-driven game engine built in Rust
https://bevyengine.org
Apache License 2.0
35.87k stars 3.54k forks source link

Label the command encoder of the `RenderContext` #16003

Open djeedai opened 4 days ago

djeedai commented 4 days ago

What problem does this solve or what need does it fill?

The command encoder of RenderContext doesn't have any debug label. This makes debugging on Metal quite painful because the top-level items are command encoder in the debug view, and the various other labelled items (e.g. compute or render pass) are collapsed children. At a glance you end up with a list of 10+ unlabelled command encoder, and you have to figure out which are from Bevy, which from wgpu itself, and which others (e.g. from Hanabi).

What solution would you like?

It's slightly annoying because RenderContext::command_encoder() lazily creates the command encoder so it's not clear when exactly it's created and by who (probably by Bevy itself). But at least if it had a standard Bevy-related name, that would help a bit.

What alternative(s) have you considered?

There's no way to label it after creation I believe.

It looks like Bevy is naming its internal encoders, by creating them explicitly from within ViewNode::run() instead of calling RenderContext::command_encoder(), so despite the fact that the RenderContext has already a command encoder which, from the look of the API, feels like it's the one you should be using. It's unclear why Bevy doesn't use the existing command encoder, and I don't think it's documented. If that's the way to go, I can use that in Hanabi too, but it would be nice to explain it somewhere.

Image

djeedai commented 4 days ago

Note that creating your own command encoder appears to be impossible if you use QueryState::iter_manual(), which unlike QueryState::get_manual() (as used in ViewNodeRunner) is bound to the lifetime 'w of the World but also on the self lifetime of the Node, which causes some issue with the callback of RenderContext::add_command_buffer_generation_task(). It seems, probably because it's captured by the closure, that the Rust compiler doesn't understand that after the iteration is done the self lifetime is unused. This makes it impossible to use in a non-view Node that custom encoder pattern found in MainOpaquePass3dNode and similar, which is what Bevy uses to name its encoders.

JMS55 commented 3 days ago

It looks like Bevy is naming its internal encoders, by creating them explicitly from within ViewNode::run() instead of calling RenderContext::command_encoder(), so despite the fact that the RenderContext has already a command encoder which, from the look of the API, feels like it's the one you should be using. It's unclear why Bevy doesn't use the existing command encoder, and I don't think it's documented.

You're talking about how some nodes use RenderContext::add_command_buffer_generation_task() instead of RenderContext::command_encoder(), right?

The reason to use the former method is that it lets you take a couple of different nodes, give them each their own command encoder, and run the command recording in parallel. Command encoding is slow, so this is a large speedup. If every node used the same command encoder (the latter method), then you'd have to record them in serial, which is much slower.

In practice the latter method tends to get used by nodes with only a single command or two to record (cheap), while nodes like the main pass or shadow pass with (potentially) many, many draws, tend to use parallel command encoding.