-
-
Notifications
You must be signed in to change notification settings - Fork 3.5k
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
Add bevy_shader_hot_reloading feature for easier renderer development #3673
Conversation
bevy_core_shader_hot_reloading.mp4 |
3927e7d
to
9879258
Compare
b089cd2
to
9c73bcc
Compare
I only get a gray window with when running the I also checked on #3643 and there sprite shows up as it should. |
The goal of this change is to add a non-default feature that allows bevy renderer feature developers to edit core bevy renderer shaders and have them hot reload. This will _enormously_ speed up development due to reducing iteration time. More changes may be needed to not replace shader assets if they are invalid, but this should be a good start.
9c73bcc
to
e6959af
Compare
Fixed. |
@@ -53,7 +53,7 @@ impl Default for AssetServerSettings { | |||
fn default() -> Self { | |||
Self { | |||
asset_folder: "assets".to_string(), | |||
watch_for_changes: false, | |||
watch_for_changes: cfg!(feature = "bevy_shader_hot_reloading"), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just noting that I did this for convenience. It saves adding this as a resource in example just to set it to true when hacking/testing stuff.
I also updated the usage example in the PR description for shaders with entrypoints and for imports. |
the new feature should be mentioned in https://github.com/bevyengine/bevy/blob/main/docs/cargo_features.md |
Adds "hot reloading" of internal assets, which is normally not possible because they are loaded using `include_str` / direct Asset collection access. This is accomplished via the following: * Add a new `debug_asset_server` feature flag * When that feature flag is enabled, create a second App with a second AssetServer that points to a configured location (by default the `crates` folder). Plugins that want to add hot reloading support for their assets can call the new `app.add_debug_asset::<T>()` and `app.init_debug_asset_loader::<T>()` functions. * Load "internal" assets using the new `load_internal_asset` macro. By default this is identical to the current "include_str + register in asset collection" approach. But if the `debug_asset_server` feature flag is enabled, it will also load the asset dynamically in the debug asset server using the file path. It will then set up a correlation between the "debug asset" and the "actual asset" by listening for asset change events. This is an alternative to #3673. The goal was to keep the boilerplate and features flags to a minimum for bevy plugin authors, and allow them to home their shaders near relevant code. This is a draft because I haven't done _any_ quality control on this yet. I'll probably rename things and remove a bunch of unwraps. I just got it working and wanted to use it to start a conversation. Fixes #3660
Should this PR be closed now that #3966 has been merged? |
Implemented differently by #3966 |
Adds "hot reloading" of internal assets, which is normally not possible because they are loaded using `include_str` / direct Asset collection access. This is accomplished via the following: * Add a new `debug_asset_server` feature flag * When that feature flag is enabled, create a second App with a second AssetServer that points to a configured location (by default the `crates` folder). Plugins that want to add hot reloading support for their assets can call the new `app.add_debug_asset::<T>()` and `app.init_debug_asset_loader::<T>()` functions. * Load "internal" assets using the new `load_internal_asset` macro. By default this is identical to the current "include_str + register in asset collection" approach. But if the `debug_asset_server` feature flag is enabled, it will also load the asset dynamically in the debug asset server using the file path. It will then set up a correlation between the "debug asset" and the "actual asset" by listening for asset change events. This is an alternative to bevyengine#3673. The goal was to keep the boilerplate and features flags to a minimum for bevy plugin authors, and allow them to home their shaders near relevant code. This is a draft because I haven't done _any_ quality control on this yet. I'll probably rename things and remove a bunch of unwraps. I just got it working and wanted to use it to start a conversation. Fixes bevyengine#3660
Adds "hot reloading" of internal assets, which is normally not possible because they are loaded using `include_str` / direct Asset collection access. This is accomplished via the following: * Add a new `debug_asset_server` feature flag * When that feature flag is enabled, create a second App with a second AssetServer that points to a configured location (by default the `crates` folder). Plugins that want to add hot reloading support for their assets can call the new `app.add_debug_asset::<T>()` and `app.init_debug_asset_loader::<T>()` functions. * Load "internal" assets using the new `load_internal_asset` macro. By default this is identical to the current "include_str + register in asset collection" approach. But if the `debug_asset_server` feature flag is enabled, it will also load the asset dynamically in the debug asset server using the file path. It will then set up a correlation between the "debug asset" and the "actual asset" by listening for asset change events. This is an alternative to bevyengine#3673. The goal was to keep the boilerplate and features flags to a minimum for bevy plugin authors, and allow them to home their shaders near relevant code. This is a draft because I haven't done _any_ quality control on this yet. I'll probably rename things and remove a bunch of unwraps. I just got it working and wanted to use it to start a conversation. Fixes bevyengine#3660
Description
Having to recompile bevy and re-run test apps in order to iterate on shaders for bevy renderer features is slower than necessary. The goal of this change is to add a non-default feature that allows bevy renderer feature developers to edit core bevy renderer shaders and have them hot reload. This will enormously speed up development due to reducing iteration time. More changes may be needed to not replace shader assets if they in any way invalid, but this should be a good start.
Solution
NOTE: Builds on top of #3643 and watch for changes needs to be enabled using the resource as in that PR for this PR to work.
This was way more complicated than I expected:
AssetServer::load
which is constructed from theAssetPath
. This is convenient as the filesystem watcher for hot-reloading naturally and unsurprisingly produces events based on paths to files that changed.aliases: HashMap<HandleId, HashSet<HandleId>>
toAssets<T>
to hold all handles that are aliases for the strong handle for an asset as obtained fromAssetServer::load()
. An alias handle is a handle made via other means, such aspub const PBR_SHADER_HANDLE: HandleUntyped = HandleUntyped::weak_from_u64(Shader::TYPE_UUID, 4805239651767701046);
.alias_to_handle: HashMap<HandleId, HandleId>
toAssets<T>
add_alias<H: Into<HandleId>, A: Into<HandleId>>(&mut self, handle: H, alias: A)
,remove_alias<H: Into<HandleId>, A: Into<HandleId>>(&mut self, handle: H, alias: A)
,get_handle_from_alias<A: Into<HandleId>>(&self, alias: A) -> Option<&HandleId>
Assets<T>
to be able to add/remove aliases, and for a given alias handle, get the strong handle.Assets<T>::get()
uses the latter to attempt to get the asset using an alias handle if it exists. This allows materials to usePBR_SHADER_HANDLE
and due to setting that as an alias handle for the strong handle,Assets<Shader>::get()
'just works'.Assets<Shader>::set_untracked()
with theconst
HandleUntyped
(e.g.PBR_SHADER_HANDLE
), theShader
is constructed and immediately chained withShader::with_import_path()
to define the shader import. When usingAssetServer::load()
, theShader
does not exist until loaded.assets/shaders/
directory in subdirectories named after their respective crates, e.g.assets/shaders/bevy_pbr/pbr.wgsl
.bevy_shader_hot_reloading
featureAssets<Shader>::set_untracked()
code into a block for when the feature is not set.