-
Notifications
You must be signed in to change notification settings - Fork 31
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Replace nodes
with render_features
and new jobs framework.
#135
Conversation
Great work! I think we should pick just a few of the "most important suggestions" now (like the addition of the rusts-hash crate as a dependency) and follow up on most of the feedback after merging. Almost all of it is very minor/optional suggestion or questions, and I want to make sure we merge this before any other changes so that we avoid merge conflicts on such a huge change. |
c204536
to
50429bf
Compare
Went through anything that was changed, I trust your judgement on what should be addressed now, and what can be done later. If there's anything you think we should do later but you don't want to do right away (or don't want to do yourself), we can just add an issue for it. It's not a bad thing to have a few issues that are first-contributor-friendly, and some of the minor suggestions (like changing the hashing algorithm) would be good candidates for that. |
e61ed8c
to
81ac7d7
Compare
nodes
with render_features
and new jobs framework.nodes
with render_features
and new jobs framework.
- An `OwnedPool<T>` is a lightweight pool that moves a `Pooled<T>` to the user. `Pooled<T>` implements `Deref` and `DerefMut` for `T`. When the `Pooled<T>` is dropped, the `T` is moved back to the `OwnedPool<T>` via a channel. - Added a new key called `RawDropSlabKey` for the drop slab. The `RawDropSlabKey` is a type-erased variant of `DropSlabKey` so that it can be stored as a handle in a type or collection without requiring a generic `T`. There are 3 variants of a generic thread-safe storage that don't require default initialization. - `AtomicOnceCell` is a thread-safe variant of `OnceCell`. - `AtomicOnceCellArray` is an indexed variant representing a contiguous fixed-size array of the cells using an atomic bitvector to track accesses. - `AtomicOnceCellStack` is built on top of `AtomicOnceCellArray` and provides `push` / `reserve` / `set` semantics using an atomic to track the top of the stack. All of the `Atomic` storages will `panic` if used incorrectly, e.g. by trying to set the same cell simultaneously from multiple threads, or by attempting to read a cell that has not yet been initialized via a call to `set` or `push`. `AtomicOnceCell` and `AtomicOnceCellArray` contain tests but `AtomicOnceCellStack` does not because the safety invariants of the `AtomicOnceCellStack` rely on the underlying `AtomicOnceCellArray`.
This is an alternative approach to handling the `FramePacket`, `ViewPacket`, and `SubmitNode` construction. I have tried to closely match the design of the Destiny slides[1]. Each feature now defines custom data for allocation in the frame packet, view packet, and submit packets explicitly. In order to avoid a proliferation of generics, there are type-erased traits (indicated by a `RenderFeature` prefix) that hide the use of the generic types behind a `dyn` trait. This work had two primary goals: 1. Features should not need to know about threads or tasks in order to be parallelized. 2. Writing a new feature should be as ergonomic as possible while maintaining the 1st requirement. `Extract`, `Prepare`, and `Write` jobs now support the same entry points as those defined by Destiny, with the exception of the `per game object` entry points mentioned as perf & memory optimization. Each feature defines their data format in a `FramePacket` and `SubmitPacket`. The `FramePacket` is the data extracted from the world. The `SubmitPacket` is the data prepared for the `Write` job. Both the `FramePacket` and `SubmitPacket` are allocated up-front to minimize allocations and both are accessible to the `Write` job. Each `FramePacket` contains a `ViewPacket` for each `RenderView` and each `SubmitPacket` contains a `ViewSubmitPacket` for each `RenderView`. The `FramePacket` has a `RenderObjectInstance` for each entity and `RenderObject` in the current frame and the `ViewPacket` has a `RenderObjectInstancePerView` for each `RenderObjectInstance` in that particular `RenderView`'s visibility. The same layout follow the `SubmitPacket` and `ViewSubmitPacket`, but the `ViewSubmitPacket` also a pre-allocated list of `SubmitNodeBlock`s for each `RenderPhase` supported by that `RenderFeature`. All of the submit nodes from all features are unioned into `ViewPhaseSubmitNodeBlock`s according to a shared `RenderView` and `RenderPhase` and then sorted by the `RenderPhase`'s defined `SubmitNodeSortFunction`. A feature's `RenderObject`s may be stored in a `RenderObjectRegistry` -- this replaces the `NodeSet` previously used by the demo's `TileLayer`, `Sprite`, and `Mesh` render features. The `Extract` entry points are defined by `ExtractJobEntryPoints` and the `Prepare` entry points are defined by `PrepareJobEntryPoints`. Each entry point receives a `Context` argument (e.g. `ExtractPerFrameContext`) to minimize the loss of performance for unneeded data by that render feature. References to the `World` or other game resources can be cached while creating the `Extract`, `Prepare`, or `Write` jobs. Each job type is tied to an explicit lifetime (e.g. `'extract`) representing that stage of the renderer pipeline. [1] https://advances.realtimerendering.com/destiny/gdc_2015/Tatarchuk_GDC_2015__Destiny_Renderer_web.pdf
- The `RenderFeaturePlugin` has been expanded with additional functions for calculating and allocating frame or submit packets, creating each job type, and determining if a given `RenderView` and `RenderViewVisibilityQuery` is relevant to that feature. - Added `RendererThreadPool` to allow the application to control the parallelization of different stages of the renderer pipeline. `RendererThreadPoolNone` is provided as a single-threaded default if the application does not provide their own implementation. - Seperated `RendererAssetPlugin` from what was previously just a `RendererPlugin` containing both feature code (now moved to `RenderFeaturePlugin`) and asset code. - Added many helper functions to `Renderer` and `RenderFrameJob` to make the implementation of the `RendererThreadPool` easier. The `extract` stage can be seen in `Renderer::try_create_render_job` and the `prepare` or `write` stages are in `RenderFrameJob::do_render_async`.
This example builds on the `asset_triangle` example to show how to use `rafx-renderer` and a `RenderFeaturePlugin` to drive rendering.
- Every feature has been rewritten to use the new `extract` and `prepare` entry points and to define their custom `FramePacket` or `SubmitPacket` data. - The demo includes an example implementation of `RendererThreadPool` using `bevy-tasks`.
@@ -30,7 +29,26 @@ impl ImGuiRendererPlugin { | |||
} | |||
} | |||
|
|||
impl RendererPlugin for ImGuiRendererPlugin { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this be ImGuiRenderFeaturePlugin now?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(lets do any renames after we merge this)
/// 2. back-to-front | ||
/// 3. by feature index | ||
/// 4. unsorted | ||
pub type SubmitNodeSortFunction = fn(&mut Vec<RenderFeatureSubmitNode>); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe one day this would be an enum with a few pre-implemented options + a callback for doing something custom
@@ -0,0 +1,345 @@ | |||
# Renderer Architecture | |||
|
|||
`rafx-renderer` and the `rafx-framework` `render_features` were inspired by the 2015 GDC talk "[Destiny's Multithreaded Rendering Architecture](http://advances.realtimerendering.com/destiny/gdc_2015/Tatarchuk_GDC_2015__Destiny_Renderer_web.pdf)". |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll probably read through this in more detail later
If you are looking for an example of the new entry points, look at the
Mesh
feature in the demo.RenderFeaturePlugin
: https://github.com/DavidVonDerau/rafx/blob/dvd/jobs/demo/src/features/mesh/plugin.rsRenderFeatureExtractJob
: https://github.com/DavidVonDerau/rafx/blob/dvd/jobs/demo/src/features/mesh/jobs/extract.rsRenderFeaturePrepareJob
: https://github.com/DavidVonDerau/rafx/blob/dvd/jobs/demo/src/features/mesh/jobs/prepare.rsRenderFeatureWriteJob
: https://github.com/DavidVonDerau/rafx/blob/dvd/jobs/demo/src/features/mesh/jobs/write.rsFramePacket
,SubmitPacket
: https://github.com/DavidVonDerau/rafx/blob/dvd/jobs/demo/src/features/mesh/internal/frame_packet.rsReplace nodes with render_features and new jobs framework.
401a3e5
This is an alternative approach to handling the
FramePacket
,ViewPacket
, andSubmitNode
construction. I have tried to closely match the design of the Destiny slides[1]. Each feature now defines custom data for allocation in the frame packet, view packet, and submit packets explicitly. In order to avoid a proliferation of generics, there are type-erased traits (indicated by aRenderFeature
prefix) that hide the use of the generic types behind adyn
trait.This work had two primary goals:
Extract
,Prepare
, andWrite
jobs now support the same entry points as those defined by Destiny, with the exception of theper game object
entry points mentioned as perf & memory optimization. Each feature defines their data format in aFramePacket
andSubmitPacket
.The
FramePacket
is the data extracted from the world. TheSubmitPacket
is the data prepared for theWrite
job. Both theFramePacket
andSubmitPacket
are allocated up-front to minimize allocations and both are accessible to theWrite
job.Each
FramePacket
contains aViewPacket
for eachRenderView
and eachSubmitPacket
contains aViewSubmitPacket
for eachRenderView
. TheFramePacket
has aRenderObjectInstance
for each entity andRenderObject
in the current frame and theViewPacket
has aRenderObjectInstancePerView
for eachRenderObjectInstance
in that particularRenderView
's visibility. The same layout follow theSubmitPacket
andViewSubmitPacket
, but theViewSubmitPacket
also a pre-allocated list ofSubmitNodeBlock
s for eachRenderPhase
supported by thatRenderFeature
.All of the submit nodes from all features are unioned into
ViewPhaseSubmitNodeBlock
s according to a sharedRenderView
andRenderPhase
and then sorted by theRenderPhase
's definedSubmitNodeSortFunction
.A feature's
RenderObject
s may be stored in aRenderObjectRegistry
-- this replaces theNodeSet
previously used by the demo'sTileLayer
,Sprite
, andMesh
render features.The
Extract
entry points are defined byExtractJobEntryPoints
and thePrepare
entry points are defined byPrepareJobEntryPoints
. Each entry point receives aContext
argument (e.g.ExtractPerFrameContext
) to minimize the loss of performance for unneeded data by that render feature. References to theWorld
or other game resources can be cached while creating theExtract
,Prepare
, orWrite
jobs. Each job type is tied to an explicit lifetime (e.g.'extract
) representing that stage of the renderer pipeline.[1] https://advances.realtimerendering.com/destiny/gdc_2015/Tatarchuk_GDC_2015__Destiny_Renderer_web.pdf
Add new collections to rafx-base.
ca335df
OwnedPool<T>
is a lightweight pool that moves aPooled<T>
to the user.Pooled<T>
implementsDeref
andDerefMut
forT
. When thePooled<T>
is dropped, theT
is moved back to theOwnedPool<T>
via a channel.RawDropSlabKey
for the drop slab. TheRawDropSlabKey
is a type-erased variant ofDropSlabKey
so that it can be stored as a handle in a type or collection without requiring a genericT
.There are 3 variants of a generic thread-safe storage that don't require default initialization.
AtomicOnceCell
is a thread-safe variant ofOnceCell
.AtomicOnceCellArray
is an indexed variant representing a contiguous fixed-size array of the cells using an atomic bitvector to track accesses.AtomicOnceCellStack
is built on top ofAtomicOnceCellArray
and providespush
/reserve
/set
semantics using an atomic to track the top of the stack.All of the
Atomic
storages willpanic
if used incorrectly, e.g. by trying to set the same cell simultaneously from multiple threads, or by attempting to read a cell that has not yet been initialized via a call toset
orpush
.AtomicOnceCell
andAtomicOnceCellArray
contain tests butAtomicOnceCellStack
does not because the safety invariants of theAtomicOnceCellStack
rely on the underlyingAtomicOnceCellArray
.Update Renderer to use new render_features code.
cfeae1a
RenderFeaturePlugin
has been expanded with additional functions for calculating and allocating frame or submit packets, creating each job type, and determining if a givenRenderView
andRenderViewVisibilityQuery
is relevant to that feature.RendererThreadPool
to allow the application to control the parallelization of different stages of the renderer pipeline.RendererThreadPoolNone
is provided as a single-threaded default if the application does not provide their own implementation.RendererAssetPlugin
from what was previously just aRendererPlugin
containing both feature code (now moved toRenderFeaturePlugin
) and asset code.Renderer
andRenderFrameJob
to make the implementation of theRendererThreadPool
easier.Replace nodes_api_design with renderer_triangle example.
9d11f1f
This example builds on the
asset_triangle
example to show how to userafx-renderer
and aRenderFeaturePlugin
to drive rendering.Update the demo to use the new render_features code.
320909a
extract
andprepare
entry points and to define their customFramePacket
orSubmitPacket
data.RendererThreadPool
usingbevy-tasks
.