bevy/examples/shader/compute_shader_game_of_life.rs

242 lines
7.8 KiB
Rust
Raw Normal View History

//! A compute shader that simulates Conway's Game of Life.
//!
//! Compute shaders use the GPU for computing arbitrary information, that may be independent of what
//! is rendered to the screen.
use bevy::{
prelude::*,
render::{
extract_resource::{ExtractResource, ExtractResourcePlugin},
RenderAssetPersistencePolicy → RenderAssetUsages (#11399) # Objective Right now, all assets in the main world get extracted and prepared in the render world (if the asset's using the RenderAssetPlugin). This is unfortunate for two cases: 1. **TextureAtlas** / **FontAtlas**: This one's huge. The individual `Image` assets that make up the atlas are cloned and prepared individually when there's no reason for them to be. The atlas textures are built on the CPU in the main world. *There can be hundreds of images that get prepared for rendering only not to be used.* 2. If one loads an Image and needs to transform it in a system before rendering it, kind of like the [decompression example](https://github.com/bevyengine/bevy/blob/main/examples/asset/asset_decompression.rs#L120), there's a price paid for extracting & preparing the asset that's not intended to be rendered yet. ------ * References #10520 * References #1782 ## Solution This changes the `RenderAssetPersistencePolicy` enum to bitflags. I felt that the objective with the parameter is so similar in nature to wgpu's [`TextureUsages`](https://docs.rs/wgpu/latest/wgpu/struct.TextureUsages.html) and [`BufferUsages`](https://docs.rs/wgpu/latest/wgpu/struct.BufferUsages.html), that it may as well be just like that. ```rust // This asset only needs to be in the main world. Don't extract and prepare it. RenderAssetUsages::MAIN_WORLD // Keep this asset in the main world and RenderAssetUsages::MAIN_WORLD | RenderAssetUsages::RENDER_WORLD // This asset is only needed in the render world. Remove it from the asset server once extracted. RenderAssetUsages::RENDER_WORLD ``` ### Alternate Solution I considered introducing a third field to `RenderAssetPersistencePolicy` enum: ```rust enum RenderAssetPersistencePolicy { /// Keep the asset in the main world after extracting to the render world. Keep, /// Remove the asset from the main world after extracting to the render world. Unload, /// This doesn't need to be in the render world at all. NoExtract, // <----- } ``` Functional, but this seemed like shoehorning. Another option is renaming the enum to something like: ```rust enum RenderAssetExtractionPolicy { /// Extract the asset and keep it in the main world. Extract, /// Remove the asset from the main world after extracting to the render world. ExtractAndUnload, /// This doesn't need to be in the render world at all. NoExtract, } ``` I think this last one could be a good option if the bitflags are too clunky. ## Migration Guide * `RenderAssetPersistencePolicy::Keep` → `RenderAssetUsage::MAIN_WORLD | RenderAssetUsage::RENDER_WORLD` (or `RenderAssetUsage::default()`) * `RenderAssetPersistencePolicy::Unload` → `RenderAssetUsage::RENDER_WORLD` * For types implementing the `RenderAsset` trait, change `fn persistence_policy(&self) -> RenderAssetPersistencePolicy` to `fn asset_usage(&self) -> RenderAssetUsages`. * Change any references to `cpu_persistent_access` (`RenderAssetPersistencePolicy`) to `asset_usage` (`RenderAssetUsage`). This applies to `Image`, `Mesh`, and a few other types.
2024-01-30 13:22:10 +00:00
render_asset::RenderAssetUsages,
render_asset::RenderAssets,
RenderGraph Labelization (#10644) # Objective The whole `Cow<'static, str>` naming for nodes and subgraphs in `RenderGraph` is a mess. ## Solution Replaces hardcoded and potentially overlapping strings for nodes and subgraphs inside `RenderGraph` with bevy's labelsystem. --- ## Changelog * Two new labels: `RenderLabel` and `RenderSubGraph`. * Replaced all uses for hardcoded strings with those labels * Moved `Taa` label from its own mod to all the other `Labels3d` * `add_render_graph_edges` now needs a tuple of labels * Moved `ScreenSpaceAmbientOcclusion` label from its own mod with the `ShadowPass` label to `LabelsPbr` * Removed `NodeId` * Renamed `Edges.id()` to `Edges.label()` * Removed `NodeLabel` * Changed examples according to the new label system * Introduced new `RenderLabel`s: `Labels2d`, `Labels3d`, `LabelsPbr`, `LabelsUi` * Introduced new `RenderSubGraph`s: `SubGraph2d`, `SubGraph3d`, `SubGraphUi` * Removed `Reflect` and `Default` derive from `CameraRenderGraph` component struct * Improved some error messages ## Migration Guide For Nodes and SubGraphs, instead of using hardcoded strings, you now pass labels, which can be derived with structs and enums. ```rs // old #[derive(Default)] struct MyRenderNode; impl MyRenderNode { pub const NAME: &'static str = "my_render_node" } render_app .add_render_graph_node::<ViewNodeRunner<MyRenderNode>>( core_3d::graph::NAME, MyRenderNode::NAME, ) .add_render_graph_edges( core_3d::graph::NAME, &[ core_3d::graph::node::TONEMAPPING, MyRenderNode::NAME, core_3d::graph::node::END_MAIN_PASS_POST_PROCESSING, ], ); // new use bevy::core_pipeline::core_3d::graph::{Labels3d, SubGraph3d}; #[derive(Debug, Hash, PartialEq, Eq, Clone, RenderLabel)] pub struct MyRenderLabel; #[derive(Default)] struct MyRenderNode; render_app .add_render_graph_node::<ViewNodeRunner<MyRenderNode>>( SubGraph3d, MyRenderLabel, ) .add_render_graph_edges( SubGraph3d, ( Labels3d::Tonemapping, MyRenderLabel, Labels3d::EndMainPassPostProcessing, ), ); ``` ### SubGraphs #### in `bevy_core_pipeline::core_2d::graph` | old string-based path | new label | |-----------------------|-----------| | `NAME` | `SubGraph2d` | #### in `bevy_core_pipeline::core_3d::graph` | old string-based path | new label | |-----------------------|-----------| | `NAME` | `SubGraph3d` | #### in `bevy_ui::render` | old string-based path | new label | |-----------------------|-----------| | `draw_ui_graph::NAME` | `graph::SubGraphUi` | ### Nodes #### in `bevy_core_pipeline::core_2d::graph` | old string-based path | new label | |-----------------------|-----------| | `node::MSAA_WRITEBACK` | `Labels2d::MsaaWriteback` | | `node::MAIN_PASS` | `Labels2d::MainPass` | | `node::BLOOM` | `Labels2d::Bloom` | | `node::TONEMAPPING` | `Labels2d::Tonemapping` | | `node::FXAA` | `Labels2d::Fxaa` | | `node::UPSCALING` | `Labels2d::Upscaling` | | `node::CONTRAST_ADAPTIVE_SHARPENING` | `Labels2d::ConstrastAdaptiveSharpening` | | `node::END_MAIN_PASS_POST_PROCESSING` | `Labels2d::EndMainPassPostProcessing` | #### in `bevy_core_pipeline::core_3d::graph` | old string-based path | new label | |-----------------------|-----------| | `node::MSAA_WRITEBACK` | `Labels3d::MsaaWriteback` | | `node::PREPASS` | `Labels3d::Prepass` | | `node::DEFERRED_PREPASS` | `Labels3d::DeferredPrepass` | | `node::COPY_DEFERRED_LIGHTING_ID` | `Labels3d::CopyDeferredLightingId` | | `node::END_PREPASSES` | `Labels3d::EndPrepasses` | | `node::START_MAIN_PASS` | `Labels3d::StartMainPass` | | `node::MAIN_OPAQUE_PASS` | `Labels3d::MainOpaquePass` | | `node::MAIN_TRANSMISSIVE_PASS` | `Labels3d::MainTransmissivePass` | | `node::MAIN_TRANSPARENT_PASS` | `Labels3d::MainTransparentPass` | | `node::END_MAIN_PASS` | `Labels3d::EndMainPass` | | `node::BLOOM` | `Labels3d::Bloom` | | `node::TONEMAPPING` | `Labels3d::Tonemapping` | | `node::FXAA` | `Labels3d::Fxaa` | | `node::UPSCALING` | `Labels3d::Upscaling` | | `node::CONTRAST_ADAPTIVE_SHARPENING` | `Labels3d::ContrastAdaptiveSharpening` | | `node::END_MAIN_PASS_POST_PROCESSING` | `Labels3d::EndMainPassPostProcessing` | #### in `bevy_core_pipeline` | old string-based path | new label | |-----------------------|-----------| | `taa::draw_3d_graph::node::TAA` | `Labels3d::Taa` | #### in `bevy_pbr` | old string-based path | new label | |-----------------------|-----------| | `draw_3d_graph::node::SHADOW_PASS` | `LabelsPbr::ShadowPass` | | `ssao::draw_3d_graph::node::SCREEN_SPACE_AMBIENT_OCCLUSION` | `LabelsPbr::ScreenSpaceAmbientOcclusion` | | `deferred::DEFFERED_LIGHTING_PASS` | `LabelsPbr::DeferredLightingPass` | #### in `bevy_render` | old string-based path | new label | |-----------------------|-----------| | `main_graph::node::CAMERA_DRIVER` | `graph::CameraDriverLabel` | #### in `bevy_ui::render` | old string-based path | new label | |-----------------------|-----------| | `draw_ui_graph::node::UI_PASS` | `graph::LabelsUi::UiPass` | --- ## Future work * Make `NodeSlot`s also use types. Ideally, we have an enum with unit variants where every variant resembles one slot. Then to make sure you are using the right slot enum and make rust-analyzer play nicely with it, we should make an associated type in the `Node` trait. With today's system, we can introduce 3rd party slots to a node, and i wasnt sure if this was used, so I didn't do this in this PR. ## Unresolved Questions When looking at the `post_processing` example, we have a struct for the label and a struct for the node, this seems like boilerplate and on discord, @IceSentry (sowy for the ping) [asked](https://discord.com/channels/691052431525675048/743663924229963868/1175197016947699742) if a node could automatically introduce a label (or i completely misunderstood that). The problem with that is, that nodes like `EmptyNode` exist multiple times *inside the same* (sub)graph, so there we need extern labels to distinguish between those. Hopefully we can find a way to reduce boilerplate and still have everything unique. For EmptyNode, we could maybe make a macro which implements an "empty node" for a type, but for nodes which contain code and need to be present multiple times, this could get nasty...
2024-01-31 14:51:19 +00:00
render_graph::{self, RenderGraph, RenderLabel},
render_resource::*,
renderer::{RenderContext, RenderDevice},
Render, RenderApp, RenderSet,
},
Windows as Entities (#5589) # Objective Fix https://github.com/bevyengine/bevy/issues/4530 - Make it easier to open/close/modify windows by setting them up as `Entity`s with a `Window` component. - Make multiple windows very simple to set up. (just add a `Window` component to an entity and it should open) ## Solution - Move all properties of window descriptor to ~components~ a component. - Replace `WindowId` with `Entity`. - ~Use change detection for components to update backend rather than events/commands. (The `CursorMoved`/`WindowResized`/... events are kept for user convenience.~ Check each field individually to see what we need to update, events are still kept for user convenience. --- ## Changelog - `WindowDescriptor` renamed to `Window`. - Width/height consolidated into a `WindowResolution` component. - Requesting maximization/minimization is done on the [`Window::state`] field. - `WindowId` is now `Entity`. ## Migration Guide - Replace `WindowDescriptor` with `Window`. - Change `width` and `height` fields in a `WindowResolution`, either by doing ```rust WindowResolution::new(width, height) // Explicitly // or using From<_> for tuples for convenience (1920., 1080.).into() ``` - Replace any `WindowCommand` code to just modify the `Window`'s fields directly and creating/closing windows is now by spawning/despawning an entity with a `Window` component like so: ```rust let window = commands.spawn(Window { ... }).id(); // open window commands.entity(window).despawn(); // close window ``` ## Unresolved - ~How do we tell when a window is minimized by a user?~ ~Currently using the `Resize(0, 0)` as an indicator of minimization.~ No longer attempting to tell given how finnicky this was across platforms, now the user can only request that a window be maximized/minimized. ## Future work - Move `exit_on_close` functionality out from windowing and into app(?) - https://github.com/bevyengine/bevy/issues/5621 - https://github.com/bevyengine/bevy/issues/7099 - https://github.com/bevyengine/bevy/issues/7098 Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2023-01-19 00:38:28 +00:00
window::WindowPlugin,
};
use std::borrow::Cow;
const SIZE: (u32, u32) = (1280, 720);
const WORKGROUP_SIZE: u32 = 8;
fn main() {
App::new()
Migrate from `LegacyColor` to `bevy_color::Color` (#12163) # Objective - As part of the migration process we need to a) see the end effect of the migration on user ergonomics b) check for serious perf regressions c) actually migrate the code - To accomplish this, I'm going to attempt to migrate all of the remaining user-facing usages of `LegacyColor` in one PR, being careful to keep a clean commit history. - Fixes #12056. ## Solution I've chosen to use the polymorphic `Color` type as our standard user-facing API. - [x] Migrate `bevy_gizmos`. - [x] Take `impl Into<Color>` in all `bevy_gizmos` APIs - [x] Migrate sprites - [x] Migrate UI - [x] Migrate `ColorMaterial` - [x] Migrate `MaterialMesh2D` - [x] Migrate fog - [x] Migrate lights - [x] Migrate StandardMaterial - [x] Migrate wireframes - [x] Migrate clear color - [x] Migrate text - [x] Migrate gltf loader - [x] Register color types for reflection - [x] Remove `LegacyColor` - [x] Make sure CI passes Incidental improvements to ease migration: - added `Color::srgba_u8`, `Color::srgba_from_array` and friends - added `set_alpha`, `is_fully_transparent` and `is_fully_opaque` to the `Alpha` trait - add and immediately deprecate (lol) `Color::rgb` and friends in favor of more explicit and consistent `Color::srgb` - standardized on white and black for most example text colors - added vector field traits to `LinearRgba`: ~~`Add`, `Sub`, `AddAssign`, `SubAssign`,~~ `Mul<f32>` and `Div<f32>`. Multiplications and divisions do not scale alpha. `Add` and `Sub` have been cut from this PR. - added `LinearRgba` and `Srgba` `RED/GREEN/BLUE` - added `LinearRgba_to_f32_array` and `LinearRgba::to_u32` ## Migration Guide Bevy's color types have changed! Wherever you used a `bevy::render::Color`, a `bevy::color::Color` is used instead. These are quite similar! Both are enums storing a color in a specific color space (or to be more precise, using a specific color model). However, each of the different color models now has its own type. TODO... - `Color::rgba`, `Color::rgb`, `Color::rbga_u8`, `Color::rgb_u8`, `Color::rgb_from_array` are now `Color::srgba`, `Color::srgb`, `Color::srgba_u8`, `Color::srgb_u8` and `Color::srgb_from_array`. - `Color::set_a` and `Color::a` is now `Color::set_alpha` and `Color::alpha`. These are part of the `Alpha` trait in `bevy_color`. - `Color::is_fully_transparent` is now part of the `Alpha` trait in `bevy_color` - `Color::r`, `Color::set_r`, `Color::with_r` and the equivalents for `g`, `b` `h`, `s` and `l` have been removed due to causing silent relatively expensive conversions. Convert your `Color` into the desired color space, perform your operations there, and then convert it back into a polymorphic `Color` enum. - `Color::hex` is now `Srgba::hex`. Call `.into` or construct a `Color::Srgba` variant manually to convert it. - `WireframeMaterial`, `ExtractedUiNode`, `ExtractedDirectionalLight`, `ExtractedPointLight`, `ExtractedSpotLight` and `ExtractedSprite` now store a `LinearRgba`, rather than a polymorphic `Color` - `Color::rgb_linear` and `Color::rgba_linear` are now `Color::linear_rgb` and `Color::linear_rgba` - The various CSS color constants are no longer stored directly on `Color`. Instead, they're defined in the `Srgba` color space, and accessed via `bevy::color::palettes::css`. Call `.into()` on them to convert them into a `Color` for quick debugging use, and consider using the much prettier `tailwind` palette for prototyping. - The `LIME_GREEN` color has been renamed to `LIMEGREEN` to comply with the standard naming. - Vector field arithmetic operations on `Color` (add, subtract, multiply and divide by a f32) have been removed. Instead, convert your colors into `LinearRgba` space, and perform your operations explicitly there. This is particularly relevant when working with emissive or HDR colors, whose color channel values are routinely outside of the ordinary 0 to 1 range. - `Color::as_linear_rgba_f32` has been removed. Call `LinearRgba::to_f32_array` instead, converting if needed. - `Color::as_linear_rgba_u32` has been removed. Call `LinearRgba::to_u32` instead, converting if needed. - Several other color conversion methods to transform LCH or HSL colors into float arrays or `Vec` types have been removed. Please reimplement these externally or open a PR to re-add them if you found them particularly useful. - Various methods on `Color` such as `rgb` or `hsl` to convert the color into a specific color space have been removed. Convert into `LinearRgba`, then to the color space of your choice. - Various implicitly-converting color value methods on `Color` such as `r`, `g`, `b` or `h` have been removed. Please convert it into the color space of your choice, then check these properties. - `Color` no longer implements `AsBindGroup`. Store a `LinearRgba` internally instead to avoid conversion costs. --------- Co-authored-by: Alice Cecile <alice.i.cecil@gmail.com> Co-authored-by: Afonso Lage <lage.afonso@gmail.com> Co-authored-by: Rob Parrett <robparrett@gmail.com> Co-authored-by: Zachary Harrold <zac@harrold.com.au>
2024-02-29 19:35:12 +00:00
.insert_resource(ClearColor(Color::BLACK))
.add_plugins((
DefaultPlugins.set(WindowPlugin {
primary_window: Some(Window {
// uncomment for unthrottled FPS
// present_mode: bevy::window::PresentMode::AutoNoVsync,
..default()
}),
Plugins own their settings. Rework PluginGroup trait. (#6336) # Objective Fixes #5884 #2879 Alternative to #2988 #5885 #2886 "Immutable" Plugin settings are currently represented as normal ECS resources, which are read as part of plugin init. This presents a number of problems: 1. If a user inserts the plugin settings resource after the plugin is initialized, it will be silently ignored (and use the defaults instead) 2. Users can modify the plugin settings resource after the plugin has been initialized. This creates a false sense of control over settings that can no longer be changed. (1) and (2) are especially problematic and confusing for the `WindowDescriptor` resource, but this is a general problem. ## Solution Immutable Plugin settings now live on each Plugin struct (ex: `WindowPlugin`). PluginGroups have been reworked to support overriding plugin values. This also removes the need for the `add_plugins_with` api, as the `add_plugins` api can use the builder pattern directly. Settings that can be used at runtime continue to be represented as ECS resources. Plugins are now configured like this: ```rust app.add_plugin(AssetPlugin { watch_for_changes: true, ..default() }) ``` PluginGroups are now configured like this: ```rust app.add_plugins(DefaultPlugins .set(AssetPlugin { watch_for_changes: true, ..default() }) ) ``` This is an alternative to #2988, which is similar. But I personally prefer this solution for a couple of reasons: * ~~#2988 doesn't solve (1)~~ #2988 does solve (1) and will panic in that case. I was wrong! * This PR directly ties plugin settings to Plugin types in a 1:1 relationship, rather than a loose "setup resource" <-> plugin coupling (where the setup resource is consumed by the first plugin that uses it). * I'm not a huge fan of overloading the ECS resource concept and implementation for something that has very different use cases and constraints. ## Changelog - PluginGroups can now be configured directly using the builder pattern. Individual plugin values can be overridden by using `plugin_group.set(SomePlugin {})`, which enables overriding default plugin values. - `WindowDescriptor` plugin settings have been moved to `WindowPlugin` and `AssetServerSettings` have been moved to `AssetPlugin` - `app.add_plugins_with` has been replaced by using `add_plugins` with the builder pattern. ## Migration Guide The `WindowDescriptor` settings have been moved from a resource to `WindowPlugin::window`: ```rust // Old (Bevy 0.8) app .insert_resource(WindowDescriptor { width: 400.0, ..default() }) .add_plugins(DefaultPlugins) // New (Bevy 0.9) app.add_plugins(DefaultPlugins.set(WindowPlugin { window: WindowDescriptor { width: 400.0, ..default() }, ..default() })) ``` The `AssetServerSettings` resource has been removed in favor of direct `AssetPlugin` configuration: ```rust // Old (Bevy 0.8) app .insert_resource(AssetServerSettings { watch_for_changes: true, ..default() }) .add_plugins(DefaultPlugins) // New (Bevy 0.9) app.add_plugins(DefaultPlugins.set(AssetPlugin { watch_for_changes: true, ..default() })) ``` `add_plugins_with` has been replaced by `add_plugins` in combination with the builder pattern: ```rust // Old (Bevy 0.8) app.add_plugins_with(DefaultPlugins, |group| group.disable::<AssetPlugin>()); // New (Bevy 0.9) app.add_plugins(DefaultPlugins.build().disable::<AssetPlugin>()); ```
2022-10-24 21:20:33 +00:00
..default()
Windows as Entities (#5589) # Objective Fix https://github.com/bevyengine/bevy/issues/4530 - Make it easier to open/close/modify windows by setting them up as `Entity`s with a `Window` component. - Make multiple windows very simple to set up. (just add a `Window` component to an entity and it should open) ## Solution - Move all properties of window descriptor to ~components~ a component. - Replace `WindowId` with `Entity`. - ~Use change detection for components to update backend rather than events/commands. (The `CursorMoved`/`WindowResized`/... events are kept for user convenience.~ Check each field individually to see what we need to update, events are still kept for user convenience. --- ## Changelog - `WindowDescriptor` renamed to `Window`. - Width/height consolidated into a `WindowResolution` component. - Requesting maximization/minimization is done on the [`Window::state`] field. - `WindowId` is now `Entity`. ## Migration Guide - Replace `WindowDescriptor` with `Window`. - Change `width` and `height` fields in a `WindowResolution`, either by doing ```rust WindowResolution::new(width, height) // Explicitly // or using From<_> for tuples for convenience (1920., 1080.).into() ``` - Replace any `WindowCommand` code to just modify the `Window`'s fields directly and creating/closing windows is now by spawning/despawning an entity with a `Window` component like so: ```rust let window = commands.spawn(Window { ... }).id(); // open window commands.entity(window).despawn(); // close window ``` ## Unresolved - ~How do we tell when a window is minimized by a user?~ ~Currently using the `Resize(0, 0)` as an indicator of minimization.~ No longer attempting to tell given how finnicky this was across platforms, now the user can only request that a window be maximized/minimized. ## Future work - Move `exit_on_close` functionality out from windowing and into app(?) - https://github.com/bevyengine/bevy/issues/5621 - https://github.com/bevyengine/bevy/issues/7099 - https://github.com/bevyengine/bevy/issues/7098 Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2023-01-19 00:38:28 +00:00
}),
GameOfLifeComputePlugin,
))
.add_systems(Startup, setup)
.run();
}
fn setup(mut commands: Commands, mut images: ResMut<Assets<Image>>) {
let mut image = Image::new_fill(
Extent3d {
width: SIZE.0,
height: SIZE.1,
depth_or_array_layers: 1,
},
TextureDimension::D2,
&[0, 0, 0, 255],
TextureFormat::R32Float,
RenderAssetPersistencePolicy → RenderAssetUsages (#11399) # Objective Right now, all assets in the main world get extracted and prepared in the render world (if the asset's using the RenderAssetPlugin). This is unfortunate for two cases: 1. **TextureAtlas** / **FontAtlas**: This one's huge. The individual `Image` assets that make up the atlas are cloned and prepared individually when there's no reason for them to be. The atlas textures are built on the CPU in the main world. *There can be hundreds of images that get prepared for rendering only not to be used.* 2. If one loads an Image and needs to transform it in a system before rendering it, kind of like the [decompression example](https://github.com/bevyengine/bevy/blob/main/examples/asset/asset_decompression.rs#L120), there's a price paid for extracting & preparing the asset that's not intended to be rendered yet. ------ * References #10520 * References #1782 ## Solution This changes the `RenderAssetPersistencePolicy` enum to bitflags. I felt that the objective with the parameter is so similar in nature to wgpu's [`TextureUsages`](https://docs.rs/wgpu/latest/wgpu/struct.TextureUsages.html) and [`BufferUsages`](https://docs.rs/wgpu/latest/wgpu/struct.BufferUsages.html), that it may as well be just like that. ```rust // This asset only needs to be in the main world. Don't extract and prepare it. RenderAssetUsages::MAIN_WORLD // Keep this asset in the main world and RenderAssetUsages::MAIN_WORLD | RenderAssetUsages::RENDER_WORLD // This asset is only needed in the render world. Remove it from the asset server once extracted. RenderAssetUsages::RENDER_WORLD ``` ### Alternate Solution I considered introducing a third field to `RenderAssetPersistencePolicy` enum: ```rust enum RenderAssetPersistencePolicy { /// Keep the asset in the main world after extracting to the render world. Keep, /// Remove the asset from the main world after extracting to the render world. Unload, /// This doesn't need to be in the render world at all. NoExtract, // <----- } ``` Functional, but this seemed like shoehorning. Another option is renaming the enum to something like: ```rust enum RenderAssetExtractionPolicy { /// Extract the asset and keep it in the main world. Extract, /// Remove the asset from the main world after extracting to the render world. ExtractAndUnload, /// This doesn't need to be in the render world at all. NoExtract, } ``` I think this last one could be a good option if the bitflags are too clunky. ## Migration Guide * `RenderAssetPersistencePolicy::Keep` → `RenderAssetUsage::MAIN_WORLD | RenderAssetUsage::RENDER_WORLD` (or `RenderAssetUsage::default()`) * `RenderAssetPersistencePolicy::Unload` → `RenderAssetUsage::RENDER_WORLD` * For types implementing the `RenderAsset` trait, change `fn persistence_policy(&self) -> RenderAssetPersistencePolicy` to `fn asset_usage(&self) -> RenderAssetUsages`. * Change any references to `cpu_persistent_access` (`RenderAssetPersistencePolicy`) to `asset_usage` (`RenderAssetUsage`). This applies to `Image`, `Mesh`, and a few other types.
2024-01-30 13:22:10 +00:00
RenderAssetUsages::RENDER_WORLD,
);
image.texture_descriptor.usage =
TextureUsages::COPY_DST | TextureUsages::STORAGE_BINDING | TextureUsages::TEXTURE_BINDING;
let image = images.add(image);
Spawn now takes a Bundle (#6054) # Objective Now that we can consolidate Bundles and Components under a single insert (thanks to #2975 and #6039), almost 100% of world spawns now look like `world.spawn().insert((Some, Tuple, Here))`. Spawning an entity without any components is an extremely uncommon pattern, so it makes sense to give spawn the "first class" ergonomic api. This consolidated api should be made consistent across all spawn apis (such as World and Commands). ## Solution All `spawn` apis (`World::spawn`, `Commands:;spawn`, `ChildBuilder::spawn`, and `WorldChildBuilder::spawn`) now accept a bundle as input: ```rust // before: commands .spawn() .insert((A, B, C)); world .spawn() .insert((A, B, C); // after commands.spawn((A, B, C)); world.spawn((A, B, C)); ``` All existing instances of `spawn_bundle` have been deprecated in favor of the new `spawn` api. A new `spawn_empty` has been added, replacing the old `spawn` api. By allowing `world.spawn(some_bundle)` to replace `world.spawn().insert(some_bundle)`, this opened the door to removing the initial entity allocation in the "empty" archetype / table done in `spawn()` (and subsequent move to the actual archetype in `.insert(some_bundle)`). This improves spawn performance by over 10%: ![image](https://user-images.githubusercontent.com/2694663/191627587-4ab2f949-4ccd-4231-80eb-80dd4d9ad6b9.png) To take this measurement, I added a new `world_spawn` benchmark. Unfortunately, optimizing `Commands::spawn` is slightly less trivial, as Commands expose the Entity id of spawned entities prior to actually spawning. Doing the optimization would (naively) require assurances that the `spawn(some_bundle)` command is applied before all other commands involving the entity (which would not necessarily be true, if memory serves). Optimizing `Commands::spawn` this way does feel possible, but it will require careful thought (and maybe some additional checks), which deserves its own PR. For now, it has the same performance characteristics of the current `Commands::spawn_bundle` on main. **Note that 99% of this PR is simple renames and refactors. The only code that needs careful scrutiny is the new `World::spawn()` impl, which is relatively straightforward, but it has some new unsafe code (which re-uses battle tested BundlerSpawner code path).** --- ## Changelog - All `spawn` apis (`World::spawn`, `Commands:;spawn`, `ChildBuilder::spawn`, and `WorldChildBuilder::spawn`) now accept a bundle as input - All instances of `spawn_bundle` have been deprecated in favor of the new `spawn` api - World and Commands now have `spawn_empty()`, which is equivalent to the old `spawn()` behavior. ## Migration Guide ```rust // Old (0.8): commands .spawn() .insert_bundle((A, B, C)); // New (0.9) commands.spawn((A, B, C)); // Old (0.8): commands.spawn_bundle((A, B, C)); // New (0.9) commands.spawn((A, B, C)); // Old (0.8): let entity = commands.spawn().id(); // New (0.9) let entity = commands.spawn_empty().id(); // Old (0.8) let entity = world.spawn().id(); // New (0.9) let entity = world.spawn_empty(); ```
2022-09-23 19:55:54 +00:00
commands.spawn(SpriteBundle {
sprite: Sprite {
custom_size: Some(Vec2::new(SIZE.0 as f32, SIZE.1 as f32)),
..default()
},
texture: image.clone(),
..default()
});
Spawn now takes a Bundle (#6054) # Objective Now that we can consolidate Bundles and Components under a single insert (thanks to #2975 and #6039), almost 100% of world spawns now look like `world.spawn().insert((Some, Tuple, Here))`. Spawning an entity without any components is an extremely uncommon pattern, so it makes sense to give spawn the "first class" ergonomic api. This consolidated api should be made consistent across all spawn apis (such as World and Commands). ## Solution All `spawn` apis (`World::spawn`, `Commands:;spawn`, `ChildBuilder::spawn`, and `WorldChildBuilder::spawn`) now accept a bundle as input: ```rust // before: commands .spawn() .insert((A, B, C)); world .spawn() .insert((A, B, C); // after commands.spawn((A, B, C)); world.spawn((A, B, C)); ``` All existing instances of `spawn_bundle` have been deprecated in favor of the new `spawn` api. A new `spawn_empty` has been added, replacing the old `spawn` api. By allowing `world.spawn(some_bundle)` to replace `world.spawn().insert(some_bundle)`, this opened the door to removing the initial entity allocation in the "empty" archetype / table done in `spawn()` (and subsequent move to the actual archetype in `.insert(some_bundle)`). This improves spawn performance by over 10%: ![image](https://user-images.githubusercontent.com/2694663/191627587-4ab2f949-4ccd-4231-80eb-80dd4d9ad6b9.png) To take this measurement, I added a new `world_spawn` benchmark. Unfortunately, optimizing `Commands::spawn` is slightly less trivial, as Commands expose the Entity id of spawned entities prior to actually spawning. Doing the optimization would (naively) require assurances that the `spawn(some_bundle)` command is applied before all other commands involving the entity (which would not necessarily be true, if memory serves). Optimizing `Commands::spawn` this way does feel possible, but it will require careful thought (and maybe some additional checks), which deserves its own PR. For now, it has the same performance characteristics of the current `Commands::spawn_bundle` on main. **Note that 99% of this PR is simple renames and refactors. The only code that needs careful scrutiny is the new `World::spawn()` impl, which is relatively straightforward, but it has some new unsafe code (which re-uses battle tested BundlerSpawner code path).** --- ## Changelog - All `spawn` apis (`World::spawn`, `Commands:;spawn`, `ChildBuilder::spawn`, and `WorldChildBuilder::spawn`) now accept a bundle as input - All instances of `spawn_bundle` have been deprecated in favor of the new `spawn` api - World and Commands now have `spawn_empty()`, which is equivalent to the old `spawn()` behavior. ## Migration Guide ```rust // Old (0.8): commands .spawn() .insert_bundle((A, B, C)); // New (0.9) commands.spawn((A, B, C)); // Old (0.8): commands.spawn_bundle((A, B, C)); // New (0.9) commands.spawn((A, B, C)); // Old (0.8): let entity = commands.spawn().id(); // New (0.9) let entity = commands.spawn_empty().id(); // Old (0.8) let entity = world.spawn().id(); // New (0.9) let entity = world.spawn_empty(); ```
2022-09-23 19:55:54 +00:00
commands.spawn(Camera2dBundle::default());
commands.insert_resource(GameOfLifeImage { texture: image });
}
struct GameOfLifeComputePlugin;
RenderGraph Labelization (#10644) # Objective The whole `Cow<'static, str>` naming for nodes and subgraphs in `RenderGraph` is a mess. ## Solution Replaces hardcoded and potentially overlapping strings for nodes and subgraphs inside `RenderGraph` with bevy's labelsystem. --- ## Changelog * Two new labels: `RenderLabel` and `RenderSubGraph`. * Replaced all uses for hardcoded strings with those labels * Moved `Taa` label from its own mod to all the other `Labels3d` * `add_render_graph_edges` now needs a tuple of labels * Moved `ScreenSpaceAmbientOcclusion` label from its own mod with the `ShadowPass` label to `LabelsPbr` * Removed `NodeId` * Renamed `Edges.id()` to `Edges.label()` * Removed `NodeLabel` * Changed examples according to the new label system * Introduced new `RenderLabel`s: `Labels2d`, `Labels3d`, `LabelsPbr`, `LabelsUi` * Introduced new `RenderSubGraph`s: `SubGraph2d`, `SubGraph3d`, `SubGraphUi` * Removed `Reflect` and `Default` derive from `CameraRenderGraph` component struct * Improved some error messages ## Migration Guide For Nodes and SubGraphs, instead of using hardcoded strings, you now pass labels, which can be derived with structs and enums. ```rs // old #[derive(Default)] struct MyRenderNode; impl MyRenderNode { pub const NAME: &'static str = "my_render_node" } render_app .add_render_graph_node::<ViewNodeRunner<MyRenderNode>>( core_3d::graph::NAME, MyRenderNode::NAME, ) .add_render_graph_edges( core_3d::graph::NAME, &[ core_3d::graph::node::TONEMAPPING, MyRenderNode::NAME, core_3d::graph::node::END_MAIN_PASS_POST_PROCESSING, ], ); // new use bevy::core_pipeline::core_3d::graph::{Labels3d, SubGraph3d}; #[derive(Debug, Hash, PartialEq, Eq, Clone, RenderLabel)] pub struct MyRenderLabel; #[derive(Default)] struct MyRenderNode; render_app .add_render_graph_node::<ViewNodeRunner<MyRenderNode>>( SubGraph3d, MyRenderLabel, ) .add_render_graph_edges( SubGraph3d, ( Labels3d::Tonemapping, MyRenderLabel, Labels3d::EndMainPassPostProcessing, ), ); ``` ### SubGraphs #### in `bevy_core_pipeline::core_2d::graph` | old string-based path | new label | |-----------------------|-----------| | `NAME` | `SubGraph2d` | #### in `bevy_core_pipeline::core_3d::graph` | old string-based path | new label | |-----------------------|-----------| | `NAME` | `SubGraph3d` | #### in `bevy_ui::render` | old string-based path | new label | |-----------------------|-----------| | `draw_ui_graph::NAME` | `graph::SubGraphUi` | ### Nodes #### in `bevy_core_pipeline::core_2d::graph` | old string-based path | new label | |-----------------------|-----------| | `node::MSAA_WRITEBACK` | `Labels2d::MsaaWriteback` | | `node::MAIN_PASS` | `Labels2d::MainPass` | | `node::BLOOM` | `Labels2d::Bloom` | | `node::TONEMAPPING` | `Labels2d::Tonemapping` | | `node::FXAA` | `Labels2d::Fxaa` | | `node::UPSCALING` | `Labels2d::Upscaling` | | `node::CONTRAST_ADAPTIVE_SHARPENING` | `Labels2d::ConstrastAdaptiveSharpening` | | `node::END_MAIN_PASS_POST_PROCESSING` | `Labels2d::EndMainPassPostProcessing` | #### in `bevy_core_pipeline::core_3d::graph` | old string-based path | new label | |-----------------------|-----------| | `node::MSAA_WRITEBACK` | `Labels3d::MsaaWriteback` | | `node::PREPASS` | `Labels3d::Prepass` | | `node::DEFERRED_PREPASS` | `Labels3d::DeferredPrepass` | | `node::COPY_DEFERRED_LIGHTING_ID` | `Labels3d::CopyDeferredLightingId` | | `node::END_PREPASSES` | `Labels3d::EndPrepasses` | | `node::START_MAIN_PASS` | `Labels3d::StartMainPass` | | `node::MAIN_OPAQUE_PASS` | `Labels3d::MainOpaquePass` | | `node::MAIN_TRANSMISSIVE_PASS` | `Labels3d::MainTransmissivePass` | | `node::MAIN_TRANSPARENT_PASS` | `Labels3d::MainTransparentPass` | | `node::END_MAIN_PASS` | `Labels3d::EndMainPass` | | `node::BLOOM` | `Labels3d::Bloom` | | `node::TONEMAPPING` | `Labels3d::Tonemapping` | | `node::FXAA` | `Labels3d::Fxaa` | | `node::UPSCALING` | `Labels3d::Upscaling` | | `node::CONTRAST_ADAPTIVE_SHARPENING` | `Labels3d::ContrastAdaptiveSharpening` | | `node::END_MAIN_PASS_POST_PROCESSING` | `Labels3d::EndMainPassPostProcessing` | #### in `bevy_core_pipeline` | old string-based path | new label | |-----------------------|-----------| | `taa::draw_3d_graph::node::TAA` | `Labels3d::Taa` | #### in `bevy_pbr` | old string-based path | new label | |-----------------------|-----------| | `draw_3d_graph::node::SHADOW_PASS` | `LabelsPbr::ShadowPass` | | `ssao::draw_3d_graph::node::SCREEN_SPACE_AMBIENT_OCCLUSION` | `LabelsPbr::ScreenSpaceAmbientOcclusion` | | `deferred::DEFFERED_LIGHTING_PASS` | `LabelsPbr::DeferredLightingPass` | #### in `bevy_render` | old string-based path | new label | |-----------------------|-----------| | `main_graph::node::CAMERA_DRIVER` | `graph::CameraDriverLabel` | #### in `bevy_ui::render` | old string-based path | new label | |-----------------------|-----------| | `draw_ui_graph::node::UI_PASS` | `graph::LabelsUi::UiPass` | --- ## Future work * Make `NodeSlot`s also use types. Ideally, we have an enum with unit variants where every variant resembles one slot. Then to make sure you are using the right slot enum and make rust-analyzer play nicely with it, we should make an associated type in the `Node` trait. With today's system, we can introduce 3rd party slots to a node, and i wasnt sure if this was used, so I didn't do this in this PR. ## Unresolved Questions When looking at the `post_processing` example, we have a struct for the label and a struct for the node, this seems like boilerplate and on discord, @IceSentry (sowy for the ping) [asked](https://discord.com/channels/691052431525675048/743663924229963868/1175197016947699742) if a node could automatically introduce a label (or i completely misunderstood that). The problem with that is, that nodes like `EmptyNode` exist multiple times *inside the same* (sub)graph, so there we need extern labels to distinguish between those. Hopefully we can find a way to reduce boilerplate and still have everything unique. For EmptyNode, we could maybe make a macro which implements an "empty node" for a type, but for nodes which contain code and need to be present multiple times, this could get nasty...
2024-01-31 14:51:19 +00:00
#[derive(Debug, Hash, PartialEq, Eq, Clone, RenderLabel)]
struct GameOfLifeLabel;
RenderGraph Labelization (#10644) # Objective The whole `Cow<'static, str>` naming for nodes and subgraphs in `RenderGraph` is a mess. ## Solution Replaces hardcoded and potentially overlapping strings for nodes and subgraphs inside `RenderGraph` with bevy's labelsystem. --- ## Changelog * Two new labels: `RenderLabel` and `RenderSubGraph`. * Replaced all uses for hardcoded strings with those labels * Moved `Taa` label from its own mod to all the other `Labels3d` * `add_render_graph_edges` now needs a tuple of labels * Moved `ScreenSpaceAmbientOcclusion` label from its own mod with the `ShadowPass` label to `LabelsPbr` * Removed `NodeId` * Renamed `Edges.id()` to `Edges.label()` * Removed `NodeLabel` * Changed examples according to the new label system * Introduced new `RenderLabel`s: `Labels2d`, `Labels3d`, `LabelsPbr`, `LabelsUi` * Introduced new `RenderSubGraph`s: `SubGraph2d`, `SubGraph3d`, `SubGraphUi` * Removed `Reflect` and `Default` derive from `CameraRenderGraph` component struct * Improved some error messages ## Migration Guide For Nodes and SubGraphs, instead of using hardcoded strings, you now pass labels, which can be derived with structs and enums. ```rs // old #[derive(Default)] struct MyRenderNode; impl MyRenderNode { pub const NAME: &'static str = "my_render_node" } render_app .add_render_graph_node::<ViewNodeRunner<MyRenderNode>>( core_3d::graph::NAME, MyRenderNode::NAME, ) .add_render_graph_edges( core_3d::graph::NAME, &[ core_3d::graph::node::TONEMAPPING, MyRenderNode::NAME, core_3d::graph::node::END_MAIN_PASS_POST_PROCESSING, ], ); // new use bevy::core_pipeline::core_3d::graph::{Labels3d, SubGraph3d}; #[derive(Debug, Hash, PartialEq, Eq, Clone, RenderLabel)] pub struct MyRenderLabel; #[derive(Default)] struct MyRenderNode; render_app .add_render_graph_node::<ViewNodeRunner<MyRenderNode>>( SubGraph3d, MyRenderLabel, ) .add_render_graph_edges( SubGraph3d, ( Labels3d::Tonemapping, MyRenderLabel, Labels3d::EndMainPassPostProcessing, ), ); ``` ### SubGraphs #### in `bevy_core_pipeline::core_2d::graph` | old string-based path | new label | |-----------------------|-----------| | `NAME` | `SubGraph2d` | #### in `bevy_core_pipeline::core_3d::graph` | old string-based path | new label | |-----------------------|-----------| | `NAME` | `SubGraph3d` | #### in `bevy_ui::render` | old string-based path | new label | |-----------------------|-----------| | `draw_ui_graph::NAME` | `graph::SubGraphUi` | ### Nodes #### in `bevy_core_pipeline::core_2d::graph` | old string-based path | new label | |-----------------------|-----------| | `node::MSAA_WRITEBACK` | `Labels2d::MsaaWriteback` | | `node::MAIN_PASS` | `Labels2d::MainPass` | | `node::BLOOM` | `Labels2d::Bloom` | | `node::TONEMAPPING` | `Labels2d::Tonemapping` | | `node::FXAA` | `Labels2d::Fxaa` | | `node::UPSCALING` | `Labels2d::Upscaling` | | `node::CONTRAST_ADAPTIVE_SHARPENING` | `Labels2d::ConstrastAdaptiveSharpening` | | `node::END_MAIN_PASS_POST_PROCESSING` | `Labels2d::EndMainPassPostProcessing` | #### in `bevy_core_pipeline::core_3d::graph` | old string-based path | new label | |-----------------------|-----------| | `node::MSAA_WRITEBACK` | `Labels3d::MsaaWriteback` | | `node::PREPASS` | `Labels3d::Prepass` | | `node::DEFERRED_PREPASS` | `Labels3d::DeferredPrepass` | | `node::COPY_DEFERRED_LIGHTING_ID` | `Labels3d::CopyDeferredLightingId` | | `node::END_PREPASSES` | `Labels3d::EndPrepasses` | | `node::START_MAIN_PASS` | `Labels3d::StartMainPass` | | `node::MAIN_OPAQUE_PASS` | `Labels3d::MainOpaquePass` | | `node::MAIN_TRANSMISSIVE_PASS` | `Labels3d::MainTransmissivePass` | | `node::MAIN_TRANSPARENT_PASS` | `Labels3d::MainTransparentPass` | | `node::END_MAIN_PASS` | `Labels3d::EndMainPass` | | `node::BLOOM` | `Labels3d::Bloom` | | `node::TONEMAPPING` | `Labels3d::Tonemapping` | | `node::FXAA` | `Labels3d::Fxaa` | | `node::UPSCALING` | `Labels3d::Upscaling` | | `node::CONTRAST_ADAPTIVE_SHARPENING` | `Labels3d::ContrastAdaptiveSharpening` | | `node::END_MAIN_PASS_POST_PROCESSING` | `Labels3d::EndMainPassPostProcessing` | #### in `bevy_core_pipeline` | old string-based path | new label | |-----------------------|-----------| | `taa::draw_3d_graph::node::TAA` | `Labels3d::Taa` | #### in `bevy_pbr` | old string-based path | new label | |-----------------------|-----------| | `draw_3d_graph::node::SHADOW_PASS` | `LabelsPbr::ShadowPass` | | `ssao::draw_3d_graph::node::SCREEN_SPACE_AMBIENT_OCCLUSION` | `LabelsPbr::ScreenSpaceAmbientOcclusion` | | `deferred::DEFFERED_LIGHTING_PASS` | `LabelsPbr::DeferredLightingPass` | #### in `bevy_render` | old string-based path | new label | |-----------------------|-----------| | `main_graph::node::CAMERA_DRIVER` | `graph::CameraDriverLabel` | #### in `bevy_ui::render` | old string-based path | new label | |-----------------------|-----------| | `draw_ui_graph::node::UI_PASS` | `graph::LabelsUi::UiPass` | --- ## Future work * Make `NodeSlot`s also use types. Ideally, we have an enum with unit variants where every variant resembles one slot. Then to make sure you are using the right slot enum and make rust-analyzer play nicely with it, we should make an associated type in the `Node` trait. With today's system, we can introduce 3rd party slots to a node, and i wasnt sure if this was used, so I didn't do this in this PR. ## Unresolved Questions When looking at the `post_processing` example, we have a struct for the label and a struct for the node, this seems like boilerplate and on discord, @IceSentry (sowy for the ping) [asked](https://discord.com/channels/691052431525675048/743663924229963868/1175197016947699742) if a node could automatically introduce a label (or i completely misunderstood that). The problem with that is, that nodes like `EmptyNode` exist multiple times *inside the same* (sub)graph, so there we need extern labels to distinguish between those. Hopefully we can find a way to reduce boilerplate and still have everything unique. For EmptyNode, we could maybe make a macro which implements an "empty node" for a type, but for nodes which contain code and need to be present multiple times, this could get nasty...
2024-01-31 14:51:19 +00:00
impl Plugin for GameOfLifeComputePlugin {
fn build(&self, app: &mut App) {
// Extract the game of life image resource from the main world into the render world
// for operation on by the compute shader and display on the sprite.
app.add_plugins(ExtractResourcePlugin::<GameOfLifeImage>::default());
let render_app = app.sub_app_mut(RenderApp);
Reorder render sets, refactor bevy_sprite to take advantage (#9236) This is a continuation of this PR: #8062 # Objective - Reorder render schedule sets to allow data preparation when phase item order is known to support improved batching - Part of the batching/instancing etc plan from here: https://github.com/bevyengine/bevy/issues/89#issuecomment-1379249074 - The original idea came from @inodentry and proved to be a good one. Thanks! - Refactor `bevy_sprite` and `bevy_ui` to take advantage of the new ordering ## Solution - Move `Prepare` and `PrepareFlush` after `PhaseSortFlush` - Add a `PrepareAssets` set that runs in parallel with other systems and sets in the render schedule. - Put prepare_assets systems in the `PrepareAssets` set - If explicit dependencies are needed on Mesh or Material RenderAssets then depend on the appropriate system. - Add `ManageViews` and `ManageViewsFlush` sets between `ExtractCommands` and Queue - Move `queue_mesh*_bind_group` to the Prepare stage - Rename them to `prepare_` - Put systems that prepare resources (buffers, textures, etc.) into a `PrepareResources` set inside `Prepare` - Put the `prepare_..._bind_group` systems into a `PrepareBindGroup` set after `PrepareResources` - Move `prepare_lights` to the `ManageViews` set - `prepare_lights` creates views and this must happen before `Queue` - This system needs refactoring to stop handling all responsibilities - Gather lights, sort, and create shadow map views. Store sorted light entities in a resource - Remove `BatchedPhaseItem` - Replace `batch_range` with `batch_size` representing how many items to skip after rendering the item or to skip the item entirely if `batch_size` is 0. - `queue_sprites` has been split into `queue_sprites` for queueing phase items and `prepare_sprites` for batching after the `PhaseSort` - `PhaseItem`s are still inserted in `queue_sprites` - After sorting adjacent compatible sprite phase items are accumulated into `SpriteBatch` components on the first entity of each batch, containing a range of vertex indices. The associated `PhaseItem`'s `batch_size` is updated appropriately. - `SpriteBatch` items are then drawn skipping over the other items in the batch based on the value in `batch_size` - A very similar refactor was performed on `bevy_ui` --- ## Changelog Changed: - Reordered and reworked render app schedule sets. The main change is that data is extracted, queued, sorted, and then prepared when the order of data is known. - Refactor `bevy_sprite` and `bevy_ui` to take advantage of the reordering. ## Migration Guide - Assets such as materials and meshes should now be created in `PrepareAssets` e.g. `prepare_assets<Mesh>` - Queueing entities to `RenderPhase`s continues to be done in `Queue` e.g. `queue_sprites` - Preparing resources (textures, buffers, etc.) should now be done in `PrepareResources`, e.g. `prepare_prepass_textures`, `prepare_mesh_uniforms` - Prepare bind groups should now be done in `PrepareBindGroups` e.g. `prepare_mesh_bind_group` - Any batching or instancing can now be done in `Prepare` where the order of the phase items is known e.g. `prepare_sprites` ## Next Steps - Introduce some generic mechanism to ensure items that can be batched are grouped in the phase item order, currently you could easily have `[sprite at z 0, mesh at z 0, sprite at z 0]` preventing batching. - Investigate improved orderings for building the MeshUniform buffer - Implementing batching across the rest of bevy --------- Co-authored-by: Robert Swain <robert.swain@gmail.com> Co-authored-by: robtfm <50659922+robtfm@users.noreply.github.com>
2023-08-27 14:33:49 +00:00
render_app.add_systems(
Render,
prepare_bind_group.in_set(RenderSet::PrepareBindGroups),
);
let mut render_graph = render_app.world.resource_mut::<RenderGraph>();
RenderGraph Labelization (#10644) # Objective The whole `Cow<'static, str>` naming for nodes and subgraphs in `RenderGraph` is a mess. ## Solution Replaces hardcoded and potentially overlapping strings for nodes and subgraphs inside `RenderGraph` with bevy's labelsystem. --- ## Changelog * Two new labels: `RenderLabel` and `RenderSubGraph`. * Replaced all uses for hardcoded strings with those labels * Moved `Taa` label from its own mod to all the other `Labels3d` * `add_render_graph_edges` now needs a tuple of labels * Moved `ScreenSpaceAmbientOcclusion` label from its own mod with the `ShadowPass` label to `LabelsPbr` * Removed `NodeId` * Renamed `Edges.id()` to `Edges.label()` * Removed `NodeLabel` * Changed examples according to the new label system * Introduced new `RenderLabel`s: `Labels2d`, `Labels3d`, `LabelsPbr`, `LabelsUi` * Introduced new `RenderSubGraph`s: `SubGraph2d`, `SubGraph3d`, `SubGraphUi` * Removed `Reflect` and `Default` derive from `CameraRenderGraph` component struct * Improved some error messages ## Migration Guide For Nodes and SubGraphs, instead of using hardcoded strings, you now pass labels, which can be derived with structs and enums. ```rs // old #[derive(Default)] struct MyRenderNode; impl MyRenderNode { pub const NAME: &'static str = "my_render_node" } render_app .add_render_graph_node::<ViewNodeRunner<MyRenderNode>>( core_3d::graph::NAME, MyRenderNode::NAME, ) .add_render_graph_edges( core_3d::graph::NAME, &[ core_3d::graph::node::TONEMAPPING, MyRenderNode::NAME, core_3d::graph::node::END_MAIN_PASS_POST_PROCESSING, ], ); // new use bevy::core_pipeline::core_3d::graph::{Labels3d, SubGraph3d}; #[derive(Debug, Hash, PartialEq, Eq, Clone, RenderLabel)] pub struct MyRenderLabel; #[derive(Default)] struct MyRenderNode; render_app .add_render_graph_node::<ViewNodeRunner<MyRenderNode>>( SubGraph3d, MyRenderLabel, ) .add_render_graph_edges( SubGraph3d, ( Labels3d::Tonemapping, MyRenderLabel, Labels3d::EndMainPassPostProcessing, ), ); ``` ### SubGraphs #### in `bevy_core_pipeline::core_2d::graph` | old string-based path | new label | |-----------------------|-----------| | `NAME` | `SubGraph2d` | #### in `bevy_core_pipeline::core_3d::graph` | old string-based path | new label | |-----------------------|-----------| | `NAME` | `SubGraph3d` | #### in `bevy_ui::render` | old string-based path | new label | |-----------------------|-----------| | `draw_ui_graph::NAME` | `graph::SubGraphUi` | ### Nodes #### in `bevy_core_pipeline::core_2d::graph` | old string-based path | new label | |-----------------------|-----------| | `node::MSAA_WRITEBACK` | `Labels2d::MsaaWriteback` | | `node::MAIN_PASS` | `Labels2d::MainPass` | | `node::BLOOM` | `Labels2d::Bloom` | | `node::TONEMAPPING` | `Labels2d::Tonemapping` | | `node::FXAA` | `Labels2d::Fxaa` | | `node::UPSCALING` | `Labels2d::Upscaling` | | `node::CONTRAST_ADAPTIVE_SHARPENING` | `Labels2d::ConstrastAdaptiveSharpening` | | `node::END_MAIN_PASS_POST_PROCESSING` | `Labels2d::EndMainPassPostProcessing` | #### in `bevy_core_pipeline::core_3d::graph` | old string-based path | new label | |-----------------------|-----------| | `node::MSAA_WRITEBACK` | `Labels3d::MsaaWriteback` | | `node::PREPASS` | `Labels3d::Prepass` | | `node::DEFERRED_PREPASS` | `Labels3d::DeferredPrepass` | | `node::COPY_DEFERRED_LIGHTING_ID` | `Labels3d::CopyDeferredLightingId` | | `node::END_PREPASSES` | `Labels3d::EndPrepasses` | | `node::START_MAIN_PASS` | `Labels3d::StartMainPass` | | `node::MAIN_OPAQUE_PASS` | `Labels3d::MainOpaquePass` | | `node::MAIN_TRANSMISSIVE_PASS` | `Labels3d::MainTransmissivePass` | | `node::MAIN_TRANSPARENT_PASS` | `Labels3d::MainTransparentPass` | | `node::END_MAIN_PASS` | `Labels3d::EndMainPass` | | `node::BLOOM` | `Labels3d::Bloom` | | `node::TONEMAPPING` | `Labels3d::Tonemapping` | | `node::FXAA` | `Labels3d::Fxaa` | | `node::UPSCALING` | `Labels3d::Upscaling` | | `node::CONTRAST_ADAPTIVE_SHARPENING` | `Labels3d::ContrastAdaptiveSharpening` | | `node::END_MAIN_PASS_POST_PROCESSING` | `Labels3d::EndMainPassPostProcessing` | #### in `bevy_core_pipeline` | old string-based path | new label | |-----------------------|-----------| | `taa::draw_3d_graph::node::TAA` | `Labels3d::Taa` | #### in `bevy_pbr` | old string-based path | new label | |-----------------------|-----------| | `draw_3d_graph::node::SHADOW_PASS` | `LabelsPbr::ShadowPass` | | `ssao::draw_3d_graph::node::SCREEN_SPACE_AMBIENT_OCCLUSION` | `LabelsPbr::ScreenSpaceAmbientOcclusion` | | `deferred::DEFFERED_LIGHTING_PASS` | `LabelsPbr::DeferredLightingPass` | #### in `bevy_render` | old string-based path | new label | |-----------------------|-----------| | `main_graph::node::CAMERA_DRIVER` | `graph::CameraDriverLabel` | #### in `bevy_ui::render` | old string-based path | new label | |-----------------------|-----------| | `draw_ui_graph::node::UI_PASS` | `graph::LabelsUi::UiPass` | --- ## Future work * Make `NodeSlot`s also use types. Ideally, we have an enum with unit variants where every variant resembles one slot. Then to make sure you are using the right slot enum and make rust-analyzer play nicely with it, we should make an associated type in the `Node` trait. With today's system, we can introduce 3rd party slots to a node, and i wasnt sure if this was used, so I didn't do this in this PR. ## Unresolved Questions When looking at the `post_processing` example, we have a struct for the label and a struct for the node, this seems like boilerplate and on discord, @IceSentry (sowy for the ping) [asked](https://discord.com/channels/691052431525675048/743663924229963868/1175197016947699742) if a node could automatically introduce a label (or i completely misunderstood that). The problem with that is, that nodes like `EmptyNode` exist multiple times *inside the same* (sub)graph, so there we need extern labels to distinguish between those. Hopefully we can find a way to reduce boilerplate and still have everything unique. For EmptyNode, we could maybe make a macro which implements an "empty node" for a type, but for nodes which contain code and need to be present multiple times, this could get nasty...
2024-01-31 14:51:19 +00:00
render_graph.add_node(GameOfLifeLabel, GameOfLifeNode::default());
render_graph.add_node_edge(GameOfLifeLabel, bevy::render::graph::CameraDriverLabel);
}
Webgpu support (#8336) # Objective - Support WebGPU - alternative to #5027 that doesn't need any async / await - fixes #8315 - Surprise fix #7318 ## Solution ### For async renderer initialisation - Update the plugin lifecycle: - app builds the plugin - calls `plugin.build` - registers the plugin - app starts the event loop - event loop waits for `ready` of all registered plugins in the same order - returns `true` by default - then call all `finish` then all `cleanup` in the same order as registered - then execute the schedule In the case of the renderer, to avoid anything async: - building the renderer plugin creates a detached task that will send back the initialised renderer through a mutex in a resource - `ready` will wait for the renderer to be present in the resource - `finish` will take that renderer and place it in the expected resources by other plugins - other plugins (that expect the renderer to be available) `finish` are called and they are able to set up their pipelines - `cleanup` is called, only custom one is still for pipeline rendering ### For WebGPU support - update the `build-wasm-example` script to support passing `--api webgpu` that will build the example with WebGPU support - feature for webgl2 was always enabled when building for wasm. it's now in the default feature list and enabled on all platforms, so check for this feature must also check that the target_arch is `wasm32` --- ## Migration Guide - `Plugin::setup` has been renamed `Plugin::cleanup` - `Plugin::finish` has been added, and plugins adding pipelines should do it in this function instead of `Plugin::build` ```rust // Before impl Plugin for MyPlugin { fn build(&self, app: &mut App) { app.insert_resource::<MyResource> .add_systems(Update, my_system); let render_app = match app.get_sub_app_mut(RenderApp) { Ok(render_app) => render_app, Err(_) => return, }; render_app .init_resource::<RenderResourceNeedingDevice>() .init_resource::<OtherRenderResource>(); } } // After impl Plugin for MyPlugin { fn build(&self, app: &mut App) { app.insert_resource::<MyResource> .add_systems(Update, my_system); let render_app = match app.get_sub_app_mut(RenderApp) { Ok(render_app) => render_app, Err(_) => return, }; render_app .init_resource::<OtherRenderResource>(); } fn finish(&self, app: &mut App) { let render_app = match app.get_sub_app_mut(RenderApp) { Ok(render_app) => render_app, Err(_) => return, }; render_app .init_resource::<RenderResourceNeedingDevice>(); } } ```
2023-05-04 22:07:57 +00:00
fn finish(&self, app: &mut App) {
let render_app = app.sub_app_mut(RenderApp);
render_app.init_resource::<GameOfLifePipeline>();
}
}
#[derive(Resource, Clone, Deref, ExtractResource, AsBindGroup)]
struct GameOfLifeImage {
#[storage_texture(0, image_format = R32Float, access = ReadWrite)]
texture: Handle<Image>,
}
Make `Resource` trait opt-in, requiring `#[derive(Resource)]` V2 (#5577) *This PR description is an edited copy of #5007, written by @alice-i-cecile.* # Objective Follow-up to https://github.com/bevyengine/bevy/pull/2254. The `Resource` trait currently has a blanket implementation for all types that meet its bounds. While ergonomic, this results in several drawbacks: * it is possible to make confusing, silent mistakes such as inserting a function pointer (Foo) rather than a value (Foo::Bar) as a resource * it is challenging to discover if a type is intended to be used as a resource * we cannot later add customization options (see the [RFC](https://github.com/bevyengine/rfcs/blob/main/rfcs/27-derive-component.md) for the equivalent choice for Component). * dependencies can use the same Rust type as a resource in invisibly conflicting ways * raw Rust types used as resources cannot preserve privacy appropriately, as anyone able to access that type can read and write to internal values * we cannot capture a definitive list of possible resources to display to users in an editor ## Notes to reviewers * Review this commit-by-commit; there's effectively no back-tracking and there's a lot of churn in some of these commits. *ira: My commits are not as well organized :')* * I've relaxed the bound on Local to Send + Sync + 'static: I don't think these concerns apply there, so this can keep things simple. Storing e.g. a u32 in a Local is fine, because there's a variable name attached explaining what it does. * I think this is a bad place for the Resource trait to live, but I've left it in place to make reviewing easier. IMO that's best tackled with https://github.com/bevyengine/bevy/issues/4981. ## Changelog `Resource` is no longer automatically implemented for all matching types. Instead, use the new `#[derive(Resource)]` macro. ## Migration Guide Add `#[derive(Resource)]` to all types you are using as a resource. If you are using a third party type as a resource, wrap it in a tuple struct to bypass orphan rules. Consider deriving `Deref` and `DerefMut` to improve ergonomics. `ClearColor` no longer implements `Component`. Using `ClearColor` as a component in 0.8 did nothing. Use the `ClearColorConfig` in the `Camera3d` and `Camera2d` components instead. Co-authored-by: Alice <alice.i.cecile@gmail.com> Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com> Co-authored-by: devil-ira <justthecooldude@gmail.com> Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2022-08-08 21:36:35 +00:00
#[derive(Resource)]
struct GameOfLifeImageBindGroup(BindGroup);
Reorder render sets, refactor bevy_sprite to take advantage (#9236) This is a continuation of this PR: #8062 # Objective - Reorder render schedule sets to allow data preparation when phase item order is known to support improved batching - Part of the batching/instancing etc plan from here: https://github.com/bevyengine/bevy/issues/89#issuecomment-1379249074 - The original idea came from @inodentry and proved to be a good one. Thanks! - Refactor `bevy_sprite` and `bevy_ui` to take advantage of the new ordering ## Solution - Move `Prepare` and `PrepareFlush` after `PhaseSortFlush` - Add a `PrepareAssets` set that runs in parallel with other systems and sets in the render schedule. - Put prepare_assets systems in the `PrepareAssets` set - If explicit dependencies are needed on Mesh or Material RenderAssets then depend on the appropriate system. - Add `ManageViews` and `ManageViewsFlush` sets between `ExtractCommands` and Queue - Move `queue_mesh*_bind_group` to the Prepare stage - Rename them to `prepare_` - Put systems that prepare resources (buffers, textures, etc.) into a `PrepareResources` set inside `Prepare` - Put the `prepare_..._bind_group` systems into a `PrepareBindGroup` set after `PrepareResources` - Move `prepare_lights` to the `ManageViews` set - `prepare_lights` creates views and this must happen before `Queue` - This system needs refactoring to stop handling all responsibilities - Gather lights, sort, and create shadow map views. Store sorted light entities in a resource - Remove `BatchedPhaseItem` - Replace `batch_range` with `batch_size` representing how many items to skip after rendering the item or to skip the item entirely if `batch_size` is 0. - `queue_sprites` has been split into `queue_sprites` for queueing phase items and `prepare_sprites` for batching after the `PhaseSort` - `PhaseItem`s are still inserted in `queue_sprites` - After sorting adjacent compatible sprite phase items are accumulated into `SpriteBatch` components on the first entity of each batch, containing a range of vertex indices. The associated `PhaseItem`'s `batch_size` is updated appropriately. - `SpriteBatch` items are then drawn skipping over the other items in the batch based on the value in `batch_size` - A very similar refactor was performed on `bevy_ui` --- ## Changelog Changed: - Reordered and reworked render app schedule sets. The main change is that data is extracted, queued, sorted, and then prepared when the order of data is known. - Refactor `bevy_sprite` and `bevy_ui` to take advantage of the reordering. ## Migration Guide - Assets such as materials and meshes should now be created in `PrepareAssets` e.g. `prepare_assets<Mesh>` - Queueing entities to `RenderPhase`s continues to be done in `Queue` e.g. `queue_sprites` - Preparing resources (textures, buffers, etc.) should now be done in `PrepareResources`, e.g. `prepare_prepass_textures`, `prepare_mesh_uniforms` - Prepare bind groups should now be done in `PrepareBindGroups` e.g. `prepare_mesh_bind_group` - Any batching or instancing can now be done in `Prepare` where the order of the phase items is known e.g. `prepare_sprites` ## Next Steps - Introduce some generic mechanism to ensure items that can be batched are grouped in the phase item order, currently you could easily have `[sprite at z 0, mesh at z 0, sprite at z 0]` preventing batching. - Investigate improved orderings for building the MeshUniform buffer - Implementing batching across the rest of bevy --------- Co-authored-by: Robert Swain <robert.swain@gmail.com> Co-authored-by: robtfm <50659922+robtfm@users.noreply.github.com>
2023-08-27 14:33:49 +00:00
fn prepare_bind_group(
mut commands: Commands,
pipeline: Res<GameOfLifePipeline>,
gpu_images: Res<RenderAssets<Image>>,
game_of_life_image: Res<GameOfLifeImage>,
render_device: Res<RenderDevice>,
) {
let view = gpu_images.get(&game_of_life_image.texture).unwrap();
Bind group entries (#9694) # Objective Simplify bind group creation code. alternative to (and based on) #9476 ## Solution - Add a `BindGroupEntries` struct that can transparently be used where `&[BindGroupEntry<'b>]` is required in BindGroupDescriptors. Allows constructing the descriptor's entries as: ```rust render_device.create_bind_group( "my_bind_group", &my_layout, &BindGroupEntries::with_indexes(( (2, &my_sampler), (3, my_uniform), )), ); ``` instead of ```rust render_device.create_bind_group( "my_bind_group", &my_layout, &[ BindGroupEntry { binding: 2, resource: BindingResource::Sampler(&my_sampler), }, BindGroupEntry { binding: 3, resource: my_uniform, }, ], ); ``` or ```rust render_device.create_bind_group( "my_bind_group", &my_layout, &BindGroupEntries::sequential((&my_sampler, my_uniform)), ); ``` instead of ```rust render_device.create_bind_group( "my_bind_group", &my_layout, &[ BindGroupEntry { binding: 0, resource: BindingResource::Sampler(&my_sampler), }, BindGroupEntry { binding: 1, resource: my_uniform, }, ], ); ``` the structs has no user facing macros, is tuple-type-based so stack allocated, and has no noticeable impact on compile time. - Also adds a `DynamicBindGroupEntries` struct with a similar api that uses a `Vec` under the hood and allows extending the entries. - Modifies `RenderDevice::create_bind_group` to take separate arguments `label`, `layout` and `entries` instead of a `BindGroupDescriptor` struct. The struct can't be stored due to the internal references, and with only 3 members arguably does not add enough context to justify itself. - Modify the codebase to use the new api and the `BindGroupEntries` / `DynamicBindGroupEntries` structs where appropriate (whenever the entries slice contains more than 1 member). ## Migration Guide - Calls to `RenderDevice::create_bind_group({BindGroupDescriptor { label, layout, entries })` must be amended to `RenderDevice::create_bind_group(label, layout, entries)`. - If `label`s have been specified as `"bind_group_name".into()`, they need to change to just `"bind_group_name"`. `Some("bind_group_name")` and `None` will still work, but `Some("bind_group_name")` can optionally be simplified to just `"bind_group_name"`. --------- Co-authored-by: IceSentry <IceSentry@users.noreply.github.com>
2023-10-21 15:39:22 +00:00
let bind_group = render_device.create_bind_group(
None,
&pipeline.texture_bind_group_layout,
&BindGroupEntries::single(&view.texture_view),
);
commands.insert_resource(GameOfLifeImageBindGroup(bind_group));
}
Make `Resource` trait opt-in, requiring `#[derive(Resource)]` V2 (#5577) *This PR description is an edited copy of #5007, written by @alice-i-cecile.* # Objective Follow-up to https://github.com/bevyengine/bevy/pull/2254. The `Resource` trait currently has a blanket implementation for all types that meet its bounds. While ergonomic, this results in several drawbacks: * it is possible to make confusing, silent mistakes such as inserting a function pointer (Foo) rather than a value (Foo::Bar) as a resource * it is challenging to discover if a type is intended to be used as a resource * we cannot later add customization options (see the [RFC](https://github.com/bevyengine/rfcs/blob/main/rfcs/27-derive-component.md) for the equivalent choice for Component). * dependencies can use the same Rust type as a resource in invisibly conflicting ways * raw Rust types used as resources cannot preserve privacy appropriately, as anyone able to access that type can read and write to internal values * we cannot capture a definitive list of possible resources to display to users in an editor ## Notes to reviewers * Review this commit-by-commit; there's effectively no back-tracking and there's a lot of churn in some of these commits. *ira: My commits are not as well organized :')* * I've relaxed the bound on Local to Send + Sync + 'static: I don't think these concerns apply there, so this can keep things simple. Storing e.g. a u32 in a Local is fine, because there's a variable name attached explaining what it does. * I think this is a bad place for the Resource trait to live, but I've left it in place to make reviewing easier. IMO that's best tackled with https://github.com/bevyengine/bevy/issues/4981. ## Changelog `Resource` is no longer automatically implemented for all matching types. Instead, use the new `#[derive(Resource)]` macro. ## Migration Guide Add `#[derive(Resource)]` to all types you are using as a resource. If you are using a third party type as a resource, wrap it in a tuple struct to bypass orphan rules. Consider deriving `Deref` and `DerefMut` to improve ergonomics. `ClearColor` no longer implements `Component`. Using `ClearColor` as a component in 0.8 did nothing. Use the `ClearColorConfig` in the `Camera3d` and `Camera2d` components instead. Co-authored-by: Alice <alice.i.cecile@gmail.com> Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com> Co-authored-by: devil-ira <justthecooldude@gmail.com> Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2022-08-08 21:36:35 +00:00
#[derive(Resource)]
struct GameOfLifePipeline {
texture_bind_group_layout: BindGroupLayout,
init_pipeline: CachedComputePipelineId,
update_pipeline: CachedComputePipelineId,
}
impl FromWorld for GameOfLifePipeline {
fn from_world(world: &mut World) -> Self {
let render_device = world.resource::<RenderDevice>();
let texture_bind_group_layout = GameOfLifeImage::bind_group_layout(render_device);
let shader = world.load_asset("shaders/game_of_life.wgsl");
let pipeline_cache = world.resource::<PipelineCache>();
let init_pipeline = pipeline_cache.queue_compute_pipeline(ComputePipelineDescriptor {
label: None,
Add push contant config to layout (#7681) # Objective Allow for creating pipelines that use push constants. To be able to use push constants. Fixes #4825 As of right now, trying to call `RenderPass::set_push_constants` will trigger the following error: ``` thread 'main' panicked at 'wgpu error: Validation Error Caused by: In a RenderPass note: encoder = `<CommandBuffer-(0, 59, Vulkan)>` In a set_push_constant command provided push constant is for stage(s) VERTEX | FRAGMENT | VERTEX_FRAGMENT, however the pipeline layout has no push constant range for the stage(s) VERTEX | FRAGMENT | VERTEX_FRAGMENT ``` ## Solution Add a field push_constant_ranges to` RenderPipelineDescriptor` and `ComputePipelineDescriptor`. This PR supersedes #4908 which now contains merge conflicts due to significant changes to `bevy_render`. Meanwhile, this PR also made the `layout` field of `RenderPipelineDescriptor` and `ComputePipelineDescriptor` non-optional. If the user do not need to specify the bind group layouts, they can simply supply an empty vector here. No need for it to be optional. --- ## Changelog - Add a field push_constant_ranges to RenderPipelineDescriptor and ComputePipelineDescriptor - Made the `layout` field of RenderPipelineDescriptor and ComputePipelineDescriptor non-optional. ## Migration Guide - Add push_constant_ranges: Vec::new() to every `RenderPipelineDescriptor` and `ComputePipelineDescriptor` - Unwrap the optional values on the `layout` field of `RenderPipelineDescriptor` and `ComputePipelineDescriptor`. If the descriptor has no layout, supply an empty vector. Co-authored-by: Zhixing Zhang <me@neoto.xin>
2023-02-17 06:20:16 +00:00
layout: vec![texture_bind_group_layout.clone()],
push_constant_ranges: Vec::new(),
shader: shader.clone(),
shader_defs: vec![],
entry_point: Cow::from("init"),
});
let update_pipeline = pipeline_cache.queue_compute_pipeline(ComputePipelineDescriptor {
label: None,
Add push contant config to layout (#7681) # Objective Allow for creating pipelines that use push constants. To be able to use push constants. Fixes #4825 As of right now, trying to call `RenderPass::set_push_constants` will trigger the following error: ``` thread 'main' panicked at 'wgpu error: Validation Error Caused by: In a RenderPass note: encoder = `<CommandBuffer-(0, 59, Vulkan)>` In a set_push_constant command provided push constant is for stage(s) VERTEX | FRAGMENT | VERTEX_FRAGMENT, however the pipeline layout has no push constant range for the stage(s) VERTEX | FRAGMENT | VERTEX_FRAGMENT ``` ## Solution Add a field push_constant_ranges to` RenderPipelineDescriptor` and `ComputePipelineDescriptor`. This PR supersedes #4908 which now contains merge conflicts due to significant changes to `bevy_render`. Meanwhile, this PR also made the `layout` field of `RenderPipelineDescriptor` and `ComputePipelineDescriptor` non-optional. If the user do not need to specify the bind group layouts, they can simply supply an empty vector here. No need for it to be optional. --- ## Changelog - Add a field push_constant_ranges to RenderPipelineDescriptor and ComputePipelineDescriptor - Made the `layout` field of RenderPipelineDescriptor and ComputePipelineDescriptor non-optional. ## Migration Guide - Add push_constant_ranges: Vec::new() to every `RenderPipelineDescriptor` and `ComputePipelineDescriptor` - Unwrap the optional values on the `layout` field of `RenderPipelineDescriptor` and `ComputePipelineDescriptor`. If the descriptor has no layout, supply an empty vector. Co-authored-by: Zhixing Zhang <me@neoto.xin>
2023-02-17 06:20:16 +00:00
layout: vec![texture_bind_group_layout.clone()],
push_constant_ranges: Vec::new(),
shader,
shader_defs: vec![],
entry_point: Cow::from("update"),
});
GameOfLifePipeline {
texture_bind_group_layout,
init_pipeline,
update_pipeline,
}
}
}
enum GameOfLifeState {
Loading,
Init,
Update,
}
struct GameOfLifeNode {
state: GameOfLifeState,
}
impl Default for GameOfLifeNode {
fn default() -> Self {
Self {
state: GameOfLifeState::Loading,
}
}
}
impl render_graph::Node for GameOfLifeNode {
fn update(&mut self, world: &mut World) {
let pipeline = world.resource::<GameOfLifePipeline>();
let pipeline_cache = world.resource::<PipelineCache>();
// if the corresponding pipeline has loaded, transition to the next stage
match self.state {
GameOfLifeState::Loading => {
if let CachedPipelineState::Ok(_) =
pipeline_cache.get_compute_pipeline_state(pipeline.init_pipeline)
{
self.state = GameOfLifeState::Init;
}
}
GameOfLifeState::Init => {
if let CachedPipelineState::Ok(_) =
pipeline_cache.get_compute_pipeline_state(pipeline.update_pipeline)
{
self.state = GameOfLifeState::Update;
}
}
GameOfLifeState::Update => {}
}
}
fn run(
&self,
_graph: &mut render_graph::RenderGraphContext,
render_context: &mut RenderContext,
world: &World,
) -> Result<(), render_graph::NodeRunError> {
let texture_bind_group = &world.resource::<GameOfLifeImageBindGroup>().0;
let pipeline_cache = world.resource::<PipelineCache>();
let pipeline = world.resource::<GameOfLifePipeline>();
let mut pass = render_context
Support recording multiple CommandBuffers in RenderContext (#7248) # Objective `RenderContext`, the core abstraction for running the render graph, currently only supports recording one `CommandBuffer` across the entire render graph. This means the entire buffer must be recorded sequentially, usually via the render graph itself. This prevents parallelization and forces users to only encode their commands in the render graph. ## Solution Allow `RenderContext` to store a `Vec<CommandBuffer>` that it progressively appends to. By default, the context will not have a command encoder, but will create one as soon as either `begin_tracked_render_pass` or the `command_encoder` accesor is first called. `RenderContext::add_command_buffer` allows users to interrupt the current command encoder, flush it to the vec, append a user-provided `CommandBuffer` and reset the command encoder to start a new buffer. Users or the render graph will call `RenderContext::finish` to retrieve the series of buffers for submitting to the queue. This allows users to encode their own `CommandBuffer`s outside of the render graph, potentially in different threads, and store them in components or resources. Ideally, in the future, the core pipeline passes can run in `RenderStage::Render` systems and end up saving the completed command buffers to either `Commands` or a field in `RenderPhase`. ## Alternatives The alternative is to use to use wgpu's `RenderBundle`s, which can achieve similar results; however it's not universally available (no OpenGL, WebGL, and DX11). --- ## Changelog Added: `RenderContext::new` Added: `RenderContext::add_command_buffer` Added: `RenderContext::finish` Changed: `RenderContext::render_device` is now private. Use the accessor `RenderContext::render_device()` instead. Changed: `RenderContext::command_encoder` is now private. Use the accessor `RenderContext::command_encoder()` instead. Changed: `RenderContext` now supports adding external `CommandBuffer`s for inclusion into the render graphs. These buffers can be encoded outside of the render graph (i.e. in a system). ## Migration Guide `RenderContext`'s fields are now private. Use the accessors on `RenderContext` instead, and construct it with `RenderContext::new`.
2023-01-22 00:21:55 +00:00
.command_encoder()
.begin_compute_pass(&ComputePassDescriptor::default());
pass.set_bind_group(0, texture_bind_group, &[]);
// select the pipeline based on the current state
match self.state {
GameOfLifeState::Loading => {}
GameOfLifeState::Init => {
let init_pipeline = pipeline_cache
.get_compute_pipeline(pipeline.init_pipeline)
.unwrap();
pass.set_pipeline(init_pipeline);
pass.dispatch_workgroups(SIZE.0 / WORKGROUP_SIZE, SIZE.1 / WORKGROUP_SIZE, 1);
}
GameOfLifeState::Update => {
let update_pipeline = pipeline_cache
.get_compute_pipeline(pipeline.update_pipeline)
.unwrap();
pass.set_pipeline(update_pipeline);
pass.dispatch_workgroups(SIZE.0 / WORKGROUP_SIZE, SIZE.1 / WORKGROUP_SIZE, 1);
}
}
Ok(())
}
}