Skip to content

Commit 1cc8764

Browse files
committed
improved documentation
1 parent 2d727af commit 1cc8764

File tree

6 files changed

+307
-187
lines changed

6 files changed

+307
-187
lines changed

crates/bevy_render/src/lib.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ pub mod extract_resource;
1111
pub mod globals;
1212
pub mod mesh;
1313
pub mod primitives;
14-
pub mod rangefinder;
1514
pub mod render_asset;
1615
pub mod render_graph;
1716
pub mod render_phase;

crates/bevy_render/src/render_phase/draw.rs

Lines changed: 55 additions & 135 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,30 @@
1-
use crate::{
2-
render_phase::TrackedRenderPass,
3-
render_resource::{CachedRenderPipelineId, PipelineCache},
4-
};
1+
use crate::render_phase::{PhaseItem, TrackedRenderPass};
52
use bevy_app::App;
63
use bevy_ecs::{
74
all_tuples,
85
entity::Entity,
96
query::{QueryState, ROQueryItem, ReadOnlyWorldQuery},
10-
system::{
11-
lifetimeless::SRes, ReadOnlySystemParam, Resource, SystemParam, SystemParamItem,
12-
SystemState,
13-
},
7+
system::{ReadOnlySystemParam, Resource, SystemParam, SystemParamItem, SystemState},
148
world::World,
159
};
1610
use bevy_utils::HashMap;
1711
use parking_lot::{RwLock, RwLockReadGuard, RwLockWriteGuard};
18-
use std::{any::TypeId, fmt::Debug, hash::Hash, ops::Range};
12+
use std::{any::TypeId, fmt::Debug, hash::Hash};
1913

20-
/// A draw function which is used to draw a specific [`PhaseItem`].
14+
/// A draw function used to draw [`PhaseItem`]s.
15+
///
16+
/// The draw function can retrieve and query the required ECS data from the render world.
2117
///
22-
/// They are the general form of drawing items, whereas [`RenderCommands`](RenderCommand)
23-
/// are more modular.
18+
/// This trait can either be implemented directly or implicitly composed out of multiple modular
19+
/// [`RenderCommand`]s. For more details and an example see the [`RenderCommand`] documentation.
2420
pub trait Draw<P: PhaseItem>: Send + Sync + 'static {
2521
/// Prepares the draw function to be used. This is called once and only once before the phase
26-
/// begins. There may be zero or more `draw` calls following a call to this function..
22+
/// begins. There may be zero or more `draw` calls following a call to this function.
2723
/// Implementing this is optional.
2824
#[allow(unused_variables)]
2925
fn prepare(&mut self, world: &'_ World) {}
3026

31-
/// Draws the [`PhaseItem`] by issuing draw calls via the [`TrackedRenderPass`].
27+
/// Draws a [`PhaseItem`] by issuing zero or more `draw` calls via the [`TrackedRenderPass`].
3228
fn draw<'w>(
3329
&mut self,
3430
world: &'w World,
@@ -38,64 +34,33 @@ pub trait Draw<P: PhaseItem>: Send + Sync + 'static {
3834
);
3935
}
4036

41-
/// An item which will be drawn to the screen. A phase item should be queued up for rendering
42-
/// during the [`RenderStage::Queue`](crate::RenderStage::Queue) stage.
43-
/// Afterwards it will be sorted and rendered automatically in the
44-
/// [`RenderStage::PhaseSort`](crate::RenderStage::PhaseSort) stage and
45-
/// [`RenderStage::Render`](crate::RenderStage::Render) stage, respectively.
46-
pub trait PhaseItem: Sized + Send + Sync + 'static {
47-
/// The type used for ordering the items. The smallest values are drawn first.
48-
type SortKey: Ord;
49-
fn entity(&self) -> Entity;
50-
51-
/// Determines the order in which the items are drawn during the corresponding [`RenderPhase`](super::RenderPhase).
52-
fn sort_key(&self) -> Self::SortKey;
53-
/// Specifies the [`Draw`] function used to render the item.
54-
fn draw_function(&self) -> DrawFunctionId;
55-
56-
/// Sorts a slice of phase items into render order. Generally if the same type
57-
/// implements [`BatchedPhaseItem`], this should use a stable sort like [`slice::sort_by_key`].
58-
/// In almost all other cases, this should not be altered from the default,
59-
/// which uses a unstable sort, as this provides the best balance of CPU and GPU
60-
/// performance.
61-
///
62-
/// Implementers can optionally not sort the list at all. This is generally advisable if and
63-
/// only if the renderer supports a depth prepass, which is by default not supported by
64-
/// the rest of Bevy's first party rendering crates. Even then, this may have a negative
65-
/// impact on GPU-side performance due to overdraw.
66-
///
67-
/// It's advised to always profile for performance changes when changing this implementation.
68-
#[inline]
69-
fn sort(items: &mut [Self]) {
70-
items.sort_unstable_by_key(|item| item.sort_key());
71-
}
72-
}
73-
7437
// TODO: make this generic?
7538
/// An identifier for a [`Draw`] function stored in [`DrawFunctions`].
7639
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
7740
pub struct DrawFunctionId(u32);
7841

79-
/// Stores all draw functions for the [`PhaseItem`] type.
80-
/// For retrieval they are associated with their [`TypeId`].
42+
/// Stores all [`Draw`] functions for the [`PhaseItem`] type.
43+
///
44+
/// For retrieval, the [`Draw`] functions are mapped to their respective [`TypeId`]s.
8145
pub struct DrawFunctionsInternal<P: PhaseItem> {
8246
pub draw_functions: Vec<Box<dyn Draw<P>>>,
8347
pub indices: HashMap<TypeId, DrawFunctionId>,
8448
}
8549

8650
impl<P: PhaseItem> DrawFunctionsInternal<P> {
51+
/// Prepares all draw function. This is called once and only once before the phase begins.
8752
pub fn prepare(&mut self, world: &World) {
8853
for function in &mut self.draw_functions {
8954
function.prepare(world);
9055
}
9156
}
9257

93-
/// Adds the [`Draw`] function and associates it to its own type.
58+
/// Adds the [`Draw`] function and maps it to its own type.
9459
pub fn add<T: Draw<P>>(&mut self, draw_function: T) -> DrawFunctionId {
9560
self.add_with::<T, T>(draw_function)
9661
}
9762

98-
/// Adds the [`Draw`] function and associates it to the type `T`
63+
/// Adds the [`Draw`] function and maps it to the type `T`
9964
pub fn add_with<T: 'static, D: Draw<P>>(&mut self, draw_function: D) -> DrawFunctionId {
10065
let id = DrawFunctionId(self.draw_functions.len().try_into().unwrap());
10166
self.draw_functions.push(Box::new(draw_function));
@@ -118,7 +83,7 @@ impl<P: PhaseItem> DrawFunctionsInternal<P> {
11883
/// Fallible wrapper for [`Self::get_id()`]
11984
///
12085
/// ## Panics
121-
/// If the id doesn't exist it will panic
86+
/// If the id doesn't exist, this function will panic.
12287
pub fn id<T: 'static>(&self) -> DrawFunctionId {
12388
self.get_id::<T>().unwrap_or_else(|| {
12489
panic!(
@@ -131,6 +96,7 @@ impl<P: PhaseItem> DrawFunctionsInternal<P> {
13196
}
13297

13398
/// Stores all draw functions for the [`PhaseItem`] type hidden behind a reader-writer lock.
99+
///
134100
/// To access them the [`DrawFunctions::read`] and [`DrawFunctions::write`] methods are used.
135101
#[derive(Resource)]
136102
pub struct DrawFunctions<P: PhaseItem> {
@@ -160,15 +126,26 @@ impl<P: PhaseItem> DrawFunctions<P> {
160126
}
161127
}
162128

163-
/// [`RenderCommand`] is a trait that runs an ECS query and produces one or more
164-
/// [`TrackedRenderPass`] calls. Types implementing this trait can be composed (as tuples).
129+
/// [`RenderCommand`]s are modular standardized pieces of render logic that can be composed into
130+
/// [`Draw`] functions.
165131
///
166-
/// They can be registered as a [`Draw`] function via the
132+
/// To turn a stateless render command into a usable draw function it has to be wrapped by a
133+
/// [`RenderCommandState`].
134+
/// This is done automatically when registering a render command as a [`Draw`] function via the
167135
/// [`AddRenderCommand::add_render_command`] method.
168136
///
137+
/// Compared to the draw function the required ECS data is fetched automatically
138+
/// (by the [`RenderCommandState`]) from the render world.
139+
/// Therefore the three types [`Param`](RenderCommand::Param),
140+
/// [`ViewWorldQuery`](RenderCommand::ViewWorldQuery) and
141+
/// [`ItemWorldQuery`](RenderCommand::ItemWorldQuery) are used.
142+
/// They specify which information is required to execute the render command.
143+
///
144+
/// Multiple render commands can be combined together by wrapping them in a tuple.
145+
///
169146
/// # Example
170147
/// The `DrawPbr` draw function is created from the following render command
171-
/// tuple. Const generics are used to set specific bind group locations:
148+
/// tuple. Const generics are used to set specific bind group locations:
172149
///
173150
/// ```ignore
174151
/// pub type DrawPbr = (
@@ -180,13 +157,24 @@ impl<P: PhaseItem> DrawFunctions<P> {
180157
/// );
181158
/// ```
182159
pub trait RenderCommand<P: PhaseItem> {
183-
/// Specifies all ECS data required by [`RenderCommand::render`].
160+
/// Specifies the general ECS data (e.g. resources) required by [`RenderCommand::render`].
161+
///
184162
/// All parameters have to be read only.
185163
type Param: SystemParam + 'static;
164+
/// Specifies the ECS data of the view entity required by [`RenderCommand::render`].
165+
///
166+
/// The view entity refers to the camera, or shadow-casting light, etc. from which the phase
167+
/// item will be rendered from.
168+
/// All components have to be accessed read only.
186169
type ViewWorldQuery: ReadOnlyWorldQuery;
170+
/// Specifies the ECS data of the item entity required by [`RenderCommand::render`].
171+
///
172+
/// The item is the entity that will be rendered for the corresponding view.
173+
/// All components have to be accessed read only.
187174
type ItemWorldQuery: ReadOnlyWorldQuery;
188175

189-
/// Renders the [`PhaseItem`] by issuing draw calls via the [`TrackedRenderPass`].
176+
/// Renders a [`PhaseItem`] by recording commands (e.g. setting pipelines, binding bind groups,
177+
/// issuing draw calls, etc.) via the [`TrackedRenderPass`].
190178
fn render<'w>(
191179
item: &P,
192180
view: ROQueryItem<'w, Self::ViewWorldQuery>,
@@ -196,86 +184,12 @@ pub trait RenderCommand<P: PhaseItem> {
196184
) -> RenderCommandResult;
197185
}
198186

187+
/// The result of a [`RenderCommand`].
199188
pub enum RenderCommandResult {
200189
Success,
201190
Failure,
202191
}
203192

204-
pub trait CachedRenderPipelinePhaseItem: PhaseItem {
205-
fn cached_pipeline(&self) -> CachedRenderPipelineId;
206-
}
207-
208-
/// A [`PhaseItem`] that can be batched dynamically.
209-
///
210-
/// Batching is an optimization that regroups multiple items in the same vertex buffer
211-
/// to render them in a single draw call.
212-
///
213-
/// If this is implemented on a type, the implementation of [`PhaseItem::sort`] should
214-
/// be changed to implement a stable sort, or incorrect/suboptimal batching may result.
215-
pub trait BatchedPhaseItem: PhaseItem {
216-
/// Range in the vertex buffer of this item
217-
fn batch_range(&self) -> &Option<Range<u32>>;
218-
219-
/// Range in the vertex buffer of this item
220-
fn batch_range_mut(&mut self) -> &mut Option<Range<u32>>;
221-
222-
/// Batches another item within this item if they are compatible.
223-
/// Items can be batched together if they have the same entity, and consecutive ranges.
224-
/// If batching is successful, the `other` item should be discarded from the render pass.
225-
#[inline]
226-
fn add_to_batch(&mut self, other: &Self) -> BatchResult {
227-
let self_entity = self.entity();
228-
if let (Some(self_batch_range), Some(other_batch_range)) = (
229-
self.batch_range_mut().as_mut(),
230-
other.batch_range().as_ref(),
231-
) {
232-
// If the items are compatible, join their range into `self`
233-
if self_entity == other.entity() {
234-
if self_batch_range.end == other_batch_range.start {
235-
self_batch_range.end = other_batch_range.end;
236-
return BatchResult::Success;
237-
} else if self_batch_range.start == other_batch_range.end {
238-
self_batch_range.start = other_batch_range.start;
239-
return BatchResult::Success;
240-
}
241-
}
242-
}
243-
BatchResult::IncompatibleItems
244-
}
245-
}
246-
247-
pub enum BatchResult {
248-
/// The `other` item was batched into `self`
249-
Success,
250-
/// `self` and `other` cannot be batched together
251-
IncompatibleItems,
252-
}
253-
254-
pub struct SetItemPipeline;
255-
impl<P: CachedRenderPipelinePhaseItem> RenderCommand<P> for SetItemPipeline {
256-
type Param = SRes<PipelineCache>;
257-
type ViewWorldQuery = ();
258-
type ItemWorldQuery = ();
259-
#[inline]
260-
fn render<'w>(
261-
item: &P,
262-
_view: (),
263-
_entity: (),
264-
pipeline_cache: SystemParamItem<'w, '_, Self::Param>,
265-
pass: &mut TrackedRenderPass<'w>,
266-
) -> RenderCommandResult {
267-
if let Some(pipeline) = pipeline_cache
268-
.into_inner()
269-
.get_render_pipeline(item.cached_pipeline())
270-
{
271-
pass.set_render_pipeline(pipeline);
272-
RenderCommandResult::Success
273-
} else {
274-
RenderCommandResult::Failure
275-
}
276-
}
277-
}
278-
279193
macro_rules! render_command_tuple_impl {
280194
($(($name: ident, $view: ident, $entity: ident)),*) => {
281195
impl<P: PhaseItem, $($name: RenderCommand<P>),*> RenderCommand<P> for ($($name,)*) {
@@ -303,14 +217,17 @@ macro_rules! render_command_tuple_impl {
303217
all_tuples!(render_command_tuple_impl, 0, 15, C, V, E);
304218

305219
/// Wraps a [`RenderCommand`] into a state so that it can be used as a [`Draw`] function.
306-
/// Therefore the [`RenderCommand::Param`] is queried from the ECS and passed to the command.
220+
///
221+
/// The [`RenderCommand::Param`], [`RenderCommand::ViewWorldQuery`] and
222+
/// [`RenderCommand::ItemWorldQuery`] are fetched from the ECS and passed to the command.
307223
pub struct RenderCommandState<P: PhaseItem + 'static, C: RenderCommand<P>> {
308224
state: SystemState<C::Param>,
309225
view: QueryState<C::ViewWorldQuery>,
310226
entity: QueryState<C::ItemWorldQuery>,
311227
}
312228

313229
impl<P: PhaseItem, C: RenderCommand<P>> RenderCommandState<P, C> {
230+
/// Creates a new [`RenderCommandState`] for the [`RenderCommand`].
314231
pub fn new(world: &mut World) -> Self {
315232
Self {
316233
state: SystemState::new(world),
@@ -324,12 +241,14 @@ impl<P: PhaseItem, C: RenderCommand<P> + Send + Sync + 'static> Draw<P> for Rend
324241
where
325242
C::Param: ReadOnlySystemParam,
326243
{
244+
/// Prepares the render command to be used. This is called once and only once before the phase
245+
/// begins. There may be zero or more `draw` calls following a call to this function.
327246
fn prepare(&mut self, world: &'_ World) {
328247
self.view.update_archetypes(world);
329248
self.entity.update_archetypes(world);
330249
}
331250

332-
/// Prepares the ECS parameters for the wrapped [`RenderCommand`] and then renders it.
251+
/// Fetches the ECS parameters for the wrapped [`RenderCommand`] and then renders it.
333252
fn draw<'w>(
334253
&mut self,
335254
world: &'w World,
@@ -340,6 +259,7 @@ where
340259
let param = self.state.get(world);
341260
let view = self.view.get_manual(world, view).unwrap();
342261
let entity = self.entity.get_manual(world, item.entity()).unwrap();
262+
// TODO: handle/log `RenderCommand` failure
343263
C::render(item, view, entity, param, pass);
344264
}
345265
}

0 commit comments

Comments
 (0)