-
-
Notifications
You must be signed in to change notification settings - Fork 4k
Add release notes and a migration guide for RenderStartup
.
#20024
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
Open
andriyDev
wants to merge
1
commit into
bevyengine:main
Choose a base branch
from
andriyDev:render_startup_writing
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+219
−0
Open
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
--- | ||
title: Many render resources now initialized in `RenderStartup` | ||
pull_requests: [19841, 19926, 19885, 19886, 19897, 19898, 19901] | ||
--- | ||
|
||
Many render resources are **no longer present** during `Plugin::finish`. Instead they are | ||
initialized during `RenderStartup` (which occurs once the app starts running). If you only access | ||
the resource during the `Render` schedule, then there should be no change. However, if you need one | ||
of these render resources to initialize your own resource, you will need to convert your resource | ||
initialization into a system. | ||
|
||
The following are the (public) resources that are now initialized in `RenderStartup`. | ||
|
||
- `CasPipeline` | ||
- `FxaaPipeline` | ||
- `SmaaPipelines` | ||
- `TaaPipeline` | ||
- `BoxShadowPipeline` | ||
- `GradientPipeline` | ||
- `UiPipeline` | ||
- `UiMaterialPipeline<M>` | ||
- `UiTextureSlicePipeline` | ||
|
||
The vast majority of cases for initializing render resources look like so: | ||
|
||
```rust | ||
impl Plugin for MyRenderingPlugin { | ||
fn build(&self, app: &mut App) { | ||
// Do nothing?? | ||
} | ||
|
||
fn finish(&self, app: &mut App) { | ||
let Some(render_app) = app.get_sub_app_mut(RenderApp) else { | ||
return; | ||
}; | ||
|
||
render_app.init_resource::<MyRenderResource>(); | ||
render_app.add_systems(Render, my_render_system); | ||
} | ||
} | ||
|
||
pub struct MyRenderResource { | ||
... | ||
} | ||
|
||
impl FromWorld for MyRenderResource { | ||
fn from_world(world: &mut World) -> Self { | ||
let render_device = world.resource::<RenderDevice>(); | ||
let render_adapter = world.resource::<RenderAdapter>(); | ||
let asset_server = world.resource::<AssetServer>(); | ||
|
||
MyRenderResource { | ||
... | ||
} | ||
} | ||
} | ||
``` | ||
|
||
The two main things to focus on are: | ||
|
||
1. The resource implements the `FromWorld` trait which collects all its dependent resources (most | ||
commonly, `RenderDevice`), and then creates an instance of the resource. | ||
2. The plugin adds its systems and resources in `Plugin::finish`. | ||
|
||
First, we need to rewrite our `FromWorld` implementation as a system. This generally means | ||
converting calls to `World::resource` into system params, and then using `Commands` to insert the | ||
resource. In the above case, that would look like: | ||
|
||
```rust | ||
// Just a regular old system!! | ||
fn init_my_resource( | ||
mut commands: Commands, | ||
render_device: Res<RenderDevice>, | ||
render_adapter: Res<RenderAdapter>, | ||
asset_server: Res<AssetServer>, | ||
) { | ||
commands.insert_resource(MyRenderResource { | ||
... | ||
}); | ||
} | ||
``` | ||
|
||
Each case will be a slightly different. Two notes to be wary of: | ||
|
||
1. Functions that accept `&RenderDevice` for example may no longer compile after switching to | ||
`Res<RenderDevice>`. This can be resolved by passing `&render_device` instead of | ||
`render_device`. | ||
2. If you are using `load_embedded_asset(world, "my_asset.png")`, you may need to first add | ||
`asset_server` as a system param, then change this to | ||
`load_embedded_asset(asset_server.as_ref(), "my_asset.png")`. | ||
|
||
Now that we have our initialization system, we just need to add the system to `RenderStartup`: | ||
|
||
```rust | ||
impl Plugin for MyRenderingPlugin { | ||
fn build(&self, app: &mut App) { | ||
let Some(render_app) = app.get_sub_app_mut(RenderApp) else { | ||
return; | ||
}; | ||
|
||
render_app | ||
.add_systems(RenderStartup, init_my_resource) | ||
.add_systems(Render, my_render_system); | ||
} | ||
|
||
// No more finish!! | ||
} | ||
``` | ||
|
||
In addition, if your resource requires one of the affected systems above, you will need to use | ||
system ordering to ensure your resource initializes after the other system. For example, if your | ||
system uses `Res<UiPipeline>`, you will need to add an ordering like: | ||
|
||
```rust | ||
render_app.add_systems(RenderStartup, init_my_resource.after(init_ui_pipeline)); | ||
``` |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
--- | ||
title: `RenderStartup` and making the renderer my ECS-y | ||
authors: ["@IceSentry", "@andriyDev"] | ||
pull_requests: [19841, 19926, 19885, 19886, 19897, 19898, 19901] | ||
--- | ||
|
||
Previous rendering code looked quite different from other Bevy code. In general, resources were | ||
initialized with the `FromWorld` trait (where most Bevy code only uses the `Default` trait for most | ||
resources) and systems/resources were added in `Plugin::finish` (where nearly all Bevy code does not | ||
use `Plugin::finish` at all). This difference with Bevy code can make it harder for new developers | ||
to learn rendering, and can result in "cargo cult" copying of rendering code (e.g., "is it important | ||
to be using `FromWorld` here? Better to be safe and just do what the rendering code is doing!"). | ||
|
||
As a step towards making the renderer more accessible (and maintainable), we have introduced the | ||
`RenderStartup` schedule and ported many rendering resources to be initialized in `RenderStartup` | ||
with systems! This has several benefits: | ||
|
||
1. Creating resources in systems makes it clearer that rendering resources **are just regular | ||
resources**. Hopefully, this better communicates that how you initialize these resources is | ||
totally up to you! | ||
2. We can now use the system ordering API to ensure that resources are initialized in the correct | ||
order. For example, we can do `init_material_pipeline.after(init_mesh_pipeline)` if we need the | ||
mesh pipeline to initialize the material pipeline. | ||
3. These initialization systems clearly describe what resources they require through their argument | ||
list. If a system has an argument of `deferred_lighting_layout: Res<DeferredLightingLayout>`, it | ||
clearly documents that this system needs to be run **after** we initialize the | ||
`DeferredLightingLayout`. | ||
|
||
We want developers to become more familiar and comfortable with Bevy's rendering stack, and hope | ||
that bring the renderer closer to regular ECS code will encourage that. Code that previously looked | ||
like this: | ||
|
||
```rust | ||
impl Plugin for MyRenderingPlugin { | ||
fn build(&self, app: &mut App) { | ||
// Do nothing?? | ||
} | ||
|
||
fn finish(&self, app: &mut App) { | ||
let Some(render_app) = app.get_sub_app_mut(RenderApp) else { | ||
return; | ||
}; | ||
|
||
render_app.init_resource::<MyRenderResource>(); | ||
} | ||
} | ||
|
||
pub struct MyRenderResource { | ||
... | ||
} | ||
|
||
impl FromWorld for MyRenderResource { | ||
fn from_world(world: &mut World) -> Self { | ||
let render_device = world.resource::<RenderDevice>(); | ||
let render_adapter = world.resource::<RenderAdapter>(); | ||
let asset_server = world.resource::<AssetServer>(); | ||
|
||
MyRenderResource { | ||
... | ||
} | ||
} | ||
} | ||
``` | ||
|
||
Can now be written like: | ||
|
||
```rust | ||
impl Plugin for MyRenderingPlugin { | ||
fn build(&self, app: &mut App) { | ||
let Some(render_app) = app.get_sub_app_mut(RenderApp) else { | ||
return; | ||
}; | ||
|
||
render_app.add_systems(RenderStartup, init_my_resource); | ||
} | ||
|
||
// No more finish!! | ||
} | ||
|
||
pub struct MyRenderResource { | ||
... | ||
} | ||
|
||
// Just a regular old system!! | ||
fn init_my_resource( | ||
mut commands: Commands, | ||
render_device: Res<RenderDevice>, | ||
render_adapter: Res<RenderAdapter>, | ||
asset_server: Res<AssetServer>, | ||
) { | ||
commands.insert_resource(MyRenderResource { | ||
... | ||
}); | ||
} | ||
``` | ||
|
||
We highly encourage users to port their own rendering resources to this new system approach (and for | ||
resources whose initialization depends on a Bevy core resource, it may be required). In fact, we | ||
encourage users to abandon `Plugin::finish` entirely and move all their system and resource | ||
initializations for rendering into `Plugin::build` instead. | ||
|
||
As stated before, we've ported many resources to be initialized in `RenderStartup`. See the | ||
migration guide for a full list of affected resources. |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
Looked like this in Bevy 0.16?