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::*;