wde_renderer/passes/
mod.rs

1//! This module contains the render graph that describes the render logic of the engine.
2//!
3//! A frame is rendered by executing a render graph, which is made of a set of [`RenderPass`] that execute in a specific order. Each render pass describes a unique render stage (that is, the list of the attachments, load ops, etc.).
4//! Each render pass is composed of muliple [`RenderSubPass`] that execute sequentially and describe the actual rendering logic (setting render or compute pipelines, bind groups, vertex buffers, draw calls, etc.).
5//!
6//! # Examples
7//! ## Render pass
8//! To define a render pass, you need to implement the [`RenderPass`] trait and its `describe` method, which returns a [`RenderPassDesc`] describing the pass attachments, load ops, etc. For example:
9//! ```rust
10//! pub struct DemoRenderPass;
11//! impl RenderPass for DemoRenderPass {
12//!     type Params = SBinding<DepthTexture>;
13//!
14//!     fn describe(depth_texture: &SystemParamItem<Self::Params>) -> RenderPassDesc {
15//!         RenderPassDesc {
16//!            attachments_depth: Some(RenderPassDescDepthAttachment {
17//!                 texture: depth_texture.iter().next().and_then(|(_, t)| t.get_texture(0)),,
18//!                 load: LoadOp::Clear(1.0),
19//!                 ..default()
20//!             }),
21//!             ..default()
22//!         }
23//!     }
24//!     fn id() -> RenderPassId { 100 }
25//!     fn label() -> &'static str { "demo" }
26//! }
27//! ```
28//! Here, we used the [`crate::prelude::SBinding`] system parameter to access the depth texture of a [crate::prelude::RenderBinding] resource. The `id` method returns a unique binding ID used to determine the execution order of the render passes (lower IDs execute first).
29//! To register this render pass in the render graph , you can use the `add_pass` method of the [`RenderGraph`] resource in a plugin:
30//! ```rust
31//! app.get_sub_app_mut(RenderApp).unwrap().world_mut()
32//!    .get_resource_mut::<RenderGraph>().unwrap()
33//!    .add_pass::<DemoRenderPass>();
34//! ```
35//!
36//! ## Render pipeline
37//! Then, as each sub-pass requires a render pipeline, you need to define a render pipeline asset that implements the [`crate::prelude::RenderAsset`] trait, which describes how to prepare the pipeline from a source asset. For example:
38//! ```rust
39//! #[derive(TypePath, Default, Clone, Debug)]
40//! pub struct DemoRenderPipeline(pub CachedPipelineIndex);
41//! impl RenderAsset for DemoRenderPipeline {
42//!     type SourceAsset = RenderPipelineAsset<DemoRenderPipeline>;
43//!     type Params = (SRes<AssetServer>, SResMut<PipelineManager>);
44//!
45//!     fn prepare(
46//!         _asset: Self::SourceAsset,
47//!         (assets_server, pipeline_manager): &mut bevy::ecs::system::SystemParamItem<Self::Params>,
48//!     ) -> Result<Self, PrepareAssetError<Self::SourceAsset>> {
49//!         Ok(DemoRenderPipeline(pipeline_manager.create_render_pipeline(RenderPipelineDescriptor {
50//!             label: "demo-pipeline",
51//!             vert: Some(assets_server.load(".../vert.wgsl")),
52//!             frag: Some(assets_server.load(".../frag.wgsl")),
53//!             bind_group_layouts: vec![DemoBindGroup::layout()],
54//!             ..Default::default()
55//!         })?))
56//!     }
57//! }
58//! ```
59//!
60//! To register this render pipeline asset, you can use the `RenderPipelinePluginRegister` in a plugin
61//! ```rust
62//! app.add_plugins(RenderPipelinePluginRegister::<DemoRenderPipeline>::default());
63//! ```
64//! which will prepare the pipeline and make it available in the render world.
65//!
66//! ## Render sub-pass
67//! Finally, you can define a render sub-pass that uses this pipeline and executes some draw calls. To do this, you need to implement the [`RenderSubPass`] trait and its `describe` method, which returns a [`RenderSubPassDesc`] describing the commands to execute in this sub-pass (see [`SubPassCommand`] for the list of available commands). For example:
68//! ```rust
69//! pub struct DemoSubRenderPass;
70//! impl RenderSubPass for DemoSubRenderPass {
71//!     type Params = (SRes<RenderAssets<DemoRenderPipeline>>, SRes<PostProcessingMesh>);
72//!
73//!     fn describe((pipeline, mesh): &SystemParamItem<Self::Params>) -> RenderSubPassDesc {
74//!         RenderSubPassDesc(vec![
75//!             SubPassCommand::Pipeline(Some(pipeline.iter().next().map(|(_, p)| p.0)).flatten()),
76//!             SubPassCommand::Mesh(mesh.0.as_ref().map(|h| h.id())),
77//!             SubPassCommand::DrawBatches(vec![DrawCommandsBatch {
78//!                 index_range: 0..6,
79//!                 ..Default::default()
80//!             }])
81//!         ])
82//!     }
83//!     fn label() -> &'static str { "demo" }
84//! }
85//! ```
86//! Finally, you can register this sub-pass to the render pass using the `add_sub_pass` method of the [`RenderGraph`] resource:
87//! ```rust
88//! app.get_sub_app_mut(RenderApp).unwrap().world_mut()
89//!   .get_resource_mut::<RenderGraph>().unwrap()
90//!   .add_sub_pass::<DemoSubRenderPass, DemoRenderPass>();
91//! ```
92//!
93//! # Custom rendering
94//! ## Custom render commands
95//! If the available commands in the `SubPassCommand` enum are not sufficient to describe your rendering logic, you can also use the `Custom` command, which takes a closure with access to the render world and the render pass encoder, allowing you to execute any custom rendering logic you want. For example:
96//! ```rust
97//! SubPassCommand::Custom(draw_custom)
98//!```
99//! where `draw_custom` is defined as:
100//! ```rust
101//! fn draw_custom<'pass>(world: &'pass World, render_pass: &mut RenderPassInstance<'pass>) {
102//!    // Custom rendering logic here, with access to the render world and the render pass encoder
103//! }
104//! ```
105//!
106//! ## Custom render passes
107//! If you want to execute a completely custom render pass, you can implement the [`RenderPass::custom_render`] method, which gives you access to the render world and a command buffer to execute commands directly without the restrictions of a render pass encoder. For example:
108//! ```rust
109//! pub struct CustomRenderPass;
110//! impl RenderPass for CustomRenderPass {
111//!    type Params = ();
112//!
113//!    fn describe(_params: &SystemParamItem<Self::Params>) -> RenderPassDesc { RenderPassDesc::default() }
114//!
115//!    fn custom_render(world: &mut World, command_buffer: &mut CommandBuffer) {
116//!       // Custom render pass logic here, with access to the render world and a command buffer to execute commands directly without the restrictions of a render pass encoder
117//!    }
118//! }
119//! ```
120
121mod pipeline_manager;
122mod pipeline_register_plugin;
123mod pipeline_types;
124mod render_graph;
125
126// Reexport wgpu types
127pub use wde_wgpu::pipelines::{
128    BlendComponent, BlendFactor, BlendOperation, BlendState, CompareFunction, DepthDescriptor,
129    Face, RenderTopology, ShaderStages
130};
131pub use wde_wgpu::vertex::Vertex;
132
133pub use pipeline_manager::*;
134pub use pipeline_register_plugin::*;
135pub use pipeline_types::*;
136pub use render_graph::*;