Skip to content

Commit 81ac7d7

Browse files
committed
Update docs.
1 parent 436b0bb commit 81ac7d7

8 files changed

+434
-85
lines changed

README.md

+2-3
Original file line numberDiff line numberDiff line change
@@ -188,10 +188,9 @@ This tool currently is only useful for packing assets.
188188
* Nearly all assets are data-driven from serializable and hashable structures rather than hard-coded.
189189
* Buffers and images are asynchronously uploaded on dedicated transfer queue when available
190190
* Multi-pass material abstraction with bindable parameters
191-
* Nodes/Render Jobs system - Inspired by the 2015 GDC talk "Destiny's Multithreaded Rendering Architecture."
191+
* Render Features and Jobs system - Inspired by the 2015 GDC talk "Destiny's Multithreaded Rendering Architecture."
192192
* A job system with extract, prepare, and write phases
193-
* Rendering is pipelined with simulation thread, and the job structure is intended to be highly parallel (not
194-
actually executed parallel yet)
193+
* Rendering is pipelined with simulation thread, and the job structure is parallelizable by the application
195194
* Handles multiple views and phases allowing advanced features like shadow mapping
196195
* Flexible sorting mechanism for interleaving and batching write commands from multiple rendering features
197196
* Visibility Region - Built on top of `rafx-visibility`

docs/framework/adding_features.md

+20-34
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,19 @@
11
# Adding Features
22

3-
Features represent "things" that can be drawn. For example, the could be separate features for meshes, sprites, cloth,
3+
Features represent "things" that can be drawn. For example, the could be separate features for meshes, sprites, cloth,
44
debug draw, imgui, etc.
55

66
## Declare the Feature
77

88
You may either implement `RenderFeature` or use this macro
99

1010
```rust
11+
use rafx::render_feature_mod_prelude::*;
1112
rafx::declare_render_feature!(Debug3DRenderFeature, DEBUG_3D_FEATURE_INDEX);
1213
```
1314

15+
When using `rafx-renderer`, you should implement `RenderFeaturePlugin`.
16+
1417
## Register the Feature
1518

1619
```rust
@@ -20,43 +23,26 @@ let render_registry = rafx::nodes::RenderRegistryBuilder::default()
2023
.register_feature::<MeshRenderFeature>();
2124
```
2225

23-
Features that have been registered are assign a unique index. For example, to get the feature index of
24-
`MeshRenderFeature` call `MeshRenderFeature::feature_index()`.
26+
Features that have been registered are assign a unique index. For example, to get the feature index of `MeshRenderFeature`
27+
call `MeshRenderFeature::feature_index()`.
2528

26-
## Implement `RenderNodeSet` and add it to the frame packet
29+
If using a `RenderFeaturePlugin`, the call to `register_feature` should go into `configure_render_registry`. This will be called
30+
after the `RenderFeaturePlugin` is registered with the `Renderer`. A `RenderFeaturePlugin` can be registered with the `Renderer`
31+
by calling `add_render_feature` on the `RendererBuilder`.
2732

28-
See the demo for examples implementing `RenderNodeSet`. (Maybe there should be a macro to provide a default impl).
33+
## Define the Frame Packet and Submit Packet
2934

30-
Render nodes will be updated during the extract phase and will "belong" to the render thread until the next extract
31-
phase.
35+
Each `RenderFeature` defines two data structures of packed arrays -- the `RenderFeatureFramePacket` and the `RenderFeatureSubmitPacket`.
36+
- `RenderFeatureFramePacket` contains the data extracted from the game world.
37+
- `RenderFeatureSubmitPacket` contains data prepared for the GPU and a list of sortable submit nodes for the `RenderFeatureWriteJob`.
3238

33-
```rust
34-
// Create a frame packet builder. It needs to know about all the render nodes and views.
35-
// (Setting views not shown here)
36-
let frame_packet_builder = {
37-
let mut sprite_render_nodes = resources.get_mut::<SpriteRenderNodeSet>().unwrap();
38-
sprite_render_nodes.update();
39-
let mut mesh_render_nodes = resources.get_mut::<MeshRenderNodeSet>().unwrap();
40-
mesh_render_nodes.update();
41-
let mut all_render_nodes = AllRenderNodes::default();
42-
all_render_nodes.add_render_nodes(&*sprite_render_nodes);
43-
all_render_nodes.add_render_nodes(&*mesh_render_nodes);
44-
45-
FramePacketBuilder::new(&all_render_nodes)
46-
};
47-
```
39+
See the demo for examples of features implementing the `FramePacket` and `SubmitPacket`.
4840

49-
## Implement `ExtractJob` and add it to an extract jobs set
41+
## Implement the `RenderFeatureExtractJob`, `RenderFeaturePrepareJob`, and `RenderFeatureWriteJob`
5042

51-
See the demo for examples implementing `ExtractJob`.
43+
- `RenderFeatureExtractJob` queries data from the game world and copies it into the `RenderFeatureFramePacket`.
44+
- `RenderFeaturePrepareJob` processes extracted data into GPU-friendly data and creates the list of sortable submit nodes in the
45+
`RenderFeatureSubmitPacket`.
46+
- `RenderFeatureWriteJob` defines the GPU commands for rendering each submit node.
5247

53-
```rust
54-
// Create extract jobs for features we will render
55-
let mut extract_job_set = ExtractJobSet::new();
56-
extract_job_set.add_job(create_sprite_extract_job());
57-
extract_job_set.add_job(create_sprite_extract_job());
58-
59-
// Kick off the extract
60-
let frame_packet = frame_packet_builder.build();
61-
extract_job_set.extract(&extract_context, &frame_packet, &extract_views)
62-
```
48+
See the demo for examples of features implementing the `RenderFeature` jobs.

docs/framework/adding_render_phases.md

+3-5
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ could be render phases for shadow maps, standard 3d drawing, or drawing 2d UI on
55

66
Phases combine the draw calls from multiple features into a single pass by sorting them according to a function.
77

8-
## Declare the Feature
8+
## Declare the Render Phase
99

1010
You may either implement `RenderPhase` or use this macro to reduce boilerplate code.
1111

@@ -21,19 +21,17 @@ rafx::declare_render_phase!(
2121
shadow_map_render_phase_sort_submit_nodes
2222
);
2323

24-
fn shadow_map_render_phase_sort_submit_nodes(mut submit_nodes: Vec<SubmitNode>) -> Vec<SubmitNode> {
24+
fn shadow_map_render_phase_sort_submit_nodes(submit_nodes: &mut Vec<SubmitNode>) {
2525
// Sort by feature
2626
log::trace!(
2727
"Sort phase {}",
2828
ShadowMapRenderPhase::render_phase_debug_name()
2929
);
3030
submit_nodes.sort_unstable_by(|a, b| a.feature_index().cmp(&b.feature_index()));
31-
32-
submit_nodes
3331
}
3432
```
3533

36-
## Register the Feature
34+
## Register the Render Phase
3735

3836
```rust
3937
let render_registry = rafx::nodes::RenderRegistryBuilder::default()

docs/framework/framework_architecture.md

+28-29
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Rendering Architecture
1+
# Framework Architecture
22

33
`rafx-framework` provides an architecture similar to what is describe in the 2015 GDC talk
44
"[Destiny's Multithreaded Rendering Architecture](http://advances.realtimerendering.com/destiny/gdc_2015/Tatarchuk_GDC_2015__Destiny_Renderer_web.pdf)".
@@ -28,8 +28,8 @@ Features must be registered.
2828
Features need to submit draw calls at the correct time when rendering a scene. This is usually associated with a
2929
particular render pass.
3030

31-
For example, a mesh may need to be drawn BOTH for creating shadows and for the main view. A feature may emit a "render
32-
node" for a particular mesh in both phases.
31+
For example, a mesh may need to be drawn BOTH for creating shadows and for the main view. A feature may emit a "submit node"
32+
for a particular mesh in both phases.
3333

3434
Phases define a sorting order. This allows front-to-back, back-to-front, or batched-by-feature ordering of draw
3535
calls within the phase.
@@ -43,50 +43,56 @@ When rendering a scene, it's often necessary to draw the scene from different vi
4343
For example, when creating shadow maps, we must render a depth buffer from the viewpoint of all light sources that cast
4444
shadows. In this case, we would create a view for each shadow-casting light that will run just the shadow mapping phase.
4545

46-
## Rendering a Frame
46+
## Render Resources
47+
48+
The framework provides a "resource" table (similar to ECS resources, but simplified) that allows storing shared data
49+
between the draw scheduling logic and extract/prepare jobs. In general, it is better to pass/share data "normally"
50+
with plain rust code. However, there are cases where the flexibility is useful either for code modularity or when rust's
51+
borrow checking cannot verify that your code is safe.
52+
53+
# Rendering a Frame
4754

4855
Each frame will go through these steps:
4956

50-
### Simulation
57+
## Simulation
5158

5259
Process all game logic as normal. Game logic may be stored in whatever way you like. (ECS of your choice, or no ECS at
5360
all).
5461

55-
### Extract Job
62+
## Extract Jobs
5663

57-
Copy all data from game state necessary to render the scene. Extract jobs implement the `ExtractJob` trait.
64+
Copy all data from game state necessary to render the scene. Extract jobs implement the `RenderFeatureExtractJob` trait.
5865

5966
**Game state may not change during this time. This will likely block simulating the next frame until it completes.**
6067
However, extract jobs may run concurrently. (A similar pattern could be followed for other systems like audio.)
6168

6269
Generally only **dynamic** data needs to be copied. Static data is safely shareable between threads
6370
(via `Arc<T>` or other mechanisms).
6471

65-
Extract jobs produce prepare jobs that can run on separate threads from the simulation.
72+
After the data has been extracted, the prepare and write jobs can be run on separate threads from the simulation.
6673

67-
### Prepare Job
74+
## Prepare Jobs
6875

69-
Process all the data collected during the extract job and produce **render nodes**. Prepare jobs implement the
70-
`PrepareJob` trait.
76+
Process all the data collected during the extract job and produce `SubmitNode`s. Prepare jobs implement the
77+
`RenderFeaturePrepareJob` trait.
7178

72-
Render nodes are like a handle for something that can be rendered later. These handles/nodes are added to different
73-
views/phases.
79+
`SubmitNode`s are like a handle for something that can be rendered later. The `SubmitNode`s are associated with a particular
80+
`RenderView` and `RenderPhase`.
7481

7582
This job might make holistic decision for the feature, like choosing the 10 most important pieces of cloth to render at
7683
high LOD. Prepare jobs for different features may run concurrently.
7784

78-
### Sorting
85+
## Submit Node Sorting
7986

80-
The render nodes emitted by all prepare jobs are sorted within their respective phases. When sort order does not matter,
81-
they can be sorted by render feature to reduce pipeline changes. When sort order does matter (like when working with
82-
transparency), features can be sorted as needed, most likely by depth.
87+
The `SubmitNode`s emitted by all prepare jobs are sorted by the `RenderPhase` for each `RenderView`. When sort order does
88+
not matter, they can be sorted by render feature to reduce pipeline changes. When sort order does matter (like when working
89+
with transparency), features can be sorted as needed, most likely by depth.
8390

84-
### Writing to Command Buffers
91+
## Write Jobs
8592

86-
Prepare jobs produce struct that implements `FeatureCommandWriter`. The framework will call functions on the writer
87-
to record draw calls for render nodes that feature emitted.
93+
Record the draw calls needed for each `SubmitNode` into command buffers. Write jobs implement the `RenderFeatureWriteJob` trait.
8894

89-
## Draw Scheduling
95+
# Draw Scheduling
9096

9197
When the frame is renderered, we must set up render passes and run the phases intended for that pass. In the destiny GDC
9298
talk, this was called a "script". It sounds like the manually handled this process. It's certainly not a bad way to go
@@ -104,11 +110,4 @@ graph_callbacks.set_renderpass_callback(node, move |args, user_context| {
104110
.prepared_render_data
105111
.write_view_phase::<OpaqueRenderPhase>(&main_view, &mut write_context)
106112
});
107-
```
108-
109-
## Render Resources
110-
111-
The framework provides a "resource" table (similar to ECS resources, but simplified) that allows storing shared data
112-
between the draw scheduling logic and extract/prepare jobs. In general, it is better to pass/share data "normally"
113-
with plain rust code. However, there are cases where the flexibility is useful either for code modularity or when rust's
114-
borrow checking cannot verify that your code is safe.
113+
```

docs/framework/visibility_region.md

+31-13
Original file line numberDiff line numberDiff line change
@@ -2,34 +2,52 @@
22

33
![Overview](../images/visibility_region.png)
44

5-
A `VisibilityRegion` is a ref-counted wrapper around 2 `Zones`. One of the zones is designated "static" and the other designated "dynamic". When registering objects with the region, the application may pick if it is "static" or "dynamic" -- this will assign it to the corresponding `Zone` and return a `VisibilityObjectArc`. Note that the "static" or "dynamic" assignment is not a meaningful distinction by the underlying `VisibilityWorld` -- it is ok to move an object that was registered as "static". The reason for separating "static" and "dynamic" assignments is to support a future capability for running the "static" visibility calculation earlier in the frame and combining it with the "dynamic" visibility later in the frame. [1] An application view is registered with the `VisibilityRegion` and returned as a `ViewFrustumArc`.
6-
7-
The `VisibilityObjectArc` is a ref-counted wrapper around an `ObjectHandle`. This struct contains functions for setting the position, `id`, and other fields. The set functions are implemented under the hood using async commands over a channel to the `VisibilityWorld`. Each `VisibilityObjectArc` contains a list of features registered with that handle. Particular features may be shown or hidden on an entity in the world by adding or removing the feature from the `VisibilityObjectArc` associated with that entiy.
8-
9-
The `ViewFrustumArc` is a ref-counted wrapper around 1 or 2 `ViewFrustumHandle` representing a view of the "static" `Zone` and a view of the "dynamic" `Zone` in the `VisibilityRegion`. This struct contains functions for setting the location, `id`, projection, and querying for visibility. The set functions are implemented under the hood using async commands over a channel to the `VisibilityWorld`. Each `RenderView` requires a `ViewFrustumArc` so that visibility can be calculated for that view.
10-
11-
`EntityId` is a helper to transmute between a struct `T: Copy` with the same as a `u64` and the `u64` required for the `id` in the `VisibilityWorld`.
5+
A `VisibilityRegion` is a ref-counted wrapper around 2 `Zones`. One of the zones is designated "static" and the other
6+
designated "dynamic". When registering objects with the region, the application may pick if it is "static" or "dynamic"
7+
-- this will assign it to the corresponding `Zone` and return a `VisibilityObjectArc`. Note that the "static" or "dynamic"
8+
assignment is not a meaningful distinction by the underlying `VisibilityWorld` -- it is ok to move an object that was
9+
registered as "static". The reason for separating "static" and "dynamic" assignments is to support a future capability
10+
for running the "static" visibility calculation earlier in the frame and combining it with the "dynamic" visibility later
11+
in the frame. [1] An application view is registered with the `VisibilityRegion` and returned as a `ViewFrustumArc`.
12+
13+
The `VisibilityObjectArc` is a ref-counted wrapper around an `ObjectHandle`. This struct contains functions for setting
14+
the position, `id`, and other fields. The set functions are implemented under the hood using async commands over a channel
15+
to the `VisibilityWorld`. Each `VisibilityObjectArc` contains a list of features registered with that handle. Particular
16+
features may be shown or hidden on an entity in the world by adding or removing the feature from the `VisibilityObjectArc`
17+
associated with that entiy.
18+
19+
The `ViewFrustumArc` is a ref-counted wrapper around 1 or 2 `ViewFrustumHandle` representing a view of the "static" `Zone`
20+
and a view of the "dynamic" `Zone` in the `VisibilityRegion`. This struct contains functions for setting the location,
21+
`id`, projection, and querying for visibility. The set functions are implemented under the hood using async commands over
22+
a channel to the `VisibilityWorld`. Each `RenderView` requires a `ViewFrustumArc` so that visibility can be calculated
23+
for that view.
24+
25+
`ObjectId` is a helper to transmute between a struct `T: 'static + Copy + Hash + Eq + PartialEq` with the same size as a
26+
`u64` and the `u64` required for the `id` in the `VisibilityWorld`.
1227

1328
```rust
14-
let entity = world.push((transform_component, mesh_component));
29+
let entity = world.push((transform_component.clone(), mesh_component));
1530
let mut entry = world.entry(entity).unwrap();
1631
entry.add_component(VisibilityComponent {
17-
handle: {
32+
visibility_object_handle: {
1833
let handle = visibility_region.register_static_object(
19-
EntityId::from(entity),
20-
load_visible_bounds(&floor_mesh_asset),
34+
ObjectId::from(entity),
35+
CullModel::VisibleBounds(load_visible_bounds(&floor_mesh_asset)),
2136
);
2237
handle.set_transform(
2338
transform_component.translation,
2439
transform_component.rotation,
2540
transform_component.scale,
2641
);
27-
handle.add_feature(floor_mesh.as_raw_generic_handle());
42+
handle.add_render_object(&floor_mesh_render_object);
2843
handle
2944
},
3045
});
3146
```
3247

33-
When a `RenderView` is aded to the frame packet using `add_view`, the associated `ViewFrustum` is queried for visibility. Only visible features relevant to the `RenderView` will be added to the frame packet.
48+
When a `RenderView` is needed in the current frame, the associated `ViewFrustum` is queried for visibility. The visible
49+
`ObjectHandle`s are mapped to their `VisibilityObjectArc`s and the associated `RenderObject`s are added to the `FramePacket`
50+
of the relevant `RenderFeature` -- if the `RenderView` is registered for the `RenderFeature` and any `RenderPhase` required
51+
by it.
3452

3553
[1] http://advances.realtimerendering.com/destiny/gdc_2015/Tatarchuk_GDC_2015__Destiny_Renderer_web.pdf

docs/images/extract_prepare_write.png

365 KB
Loading

docs/index.md

+5-1
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@
3131
* rafx-assets
3232
* `distill` Architecture and Features
3333
* [Asset Triangle Example](../rafx/examples/asset_triangle/asset_triangle.rs)
34+
* rafx-renderer
35+
* [Renderer Architecture](renderer/renderer_architecture.md)
36+
* [Renderer Triangle Example](../rafx/examples/renderer_triangle/renderer_triangle.rs)
3437
* Shader Authoring with `rafx-shader-processor`
3538
* [Shader Processor](shaders/shader_processor.md)
3639
* [Custom Shader Markup](shaders/shader_annotation.md)
@@ -60,7 +63,8 @@
6063
* [Key crate dependencies](images/crate_dependencies.png)
6164
* [Pipelining](images/pipelining.png)
6265
* [Shader Processor](images/shader_processor.png)
63-
* [Visibility region](images/visibility_region.jpg)
66+
* [Visibility region](images/visibility_region.png)
67+
* [Extract, prepare, write](images/extract_prepare_write.png)
6468

6569
## Other Resources
6670

0 commit comments

Comments
 (0)