Replace nodes with render_features and new jobs framework.#135
Replace nodes with render_features and new jobs framework.#135aclysma merged 6 commits intoaclysma:masterfrom
nodes with render_features and new jobs framework.#135Conversation
|
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`.
| } | ||
| } | ||
|
|
||
| impl RendererPlugin for ImGuiRendererPlugin { |
There was a problem hiding this comment.
Should this be ImGuiRenderFeaturePlugin now?
There was a problem hiding this comment.
(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.
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.
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
Meshfeature 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, andSubmitNodeconstruction. 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 aRenderFeatureprefix) that hide the use of the generic types behind adyntrait.This work had two primary goals:
Extract,Prepare, andWritejobs now support the same entry points as those defined by Destiny, with the exception of theper game objectentry points mentioned as perf & memory optimization. Each feature defines their data format in aFramePacketandSubmitPacket.The
FramePacketis the data extracted from the world. TheSubmitPacketis the data prepared for theWritejob. Both theFramePacketandSubmitPacketare allocated up-front to minimize allocations and both are accessible to theWritejob.Each
FramePacketcontains aViewPacketfor eachRenderViewand eachSubmitPacketcontains aViewSubmitPacketfor eachRenderView. TheFramePackethas aRenderObjectInstancefor each entity andRenderObjectin the current frame and theViewPackethas aRenderObjectInstancePerViewfor eachRenderObjectInstancein that particularRenderView's visibility. The same layout follow theSubmitPacketandViewSubmitPacket, but theViewSubmitPacketalso a pre-allocated list ofSubmitNodeBlocks for eachRenderPhasesupported by thatRenderFeature.All of the submit nodes from all features are unioned into
ViewPhaseSubmitNodeBlocks according to a sharedRenderViewandRenderPhaseand then sorted by theRenderPhase's definedSubmitNodeSortFunction.A feature's
RenderObjects may be stored in aRenderObjectRegistry-- this replaces theNodeSetpreviously used by the demo'sTileLayer,Sprite, andMeshrender features.The
Extractentry points are defined byExtractJobEntryPointsand thePrepareentry points are defined byPrepareJobEntryPoints. Each entry point receives aContextargument (e.g.ExtractPerFrameContext) to minimize the loss of performance for unneeded data by that render feature. References to theWorldor other game resources can be cached while creating theExtract,Prepare, orWritejobs. 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>implementsDerefandDerefMutforT. When thePooled<T>is dropped, theTis moved back to theOwnedPool<T>via a channel.RawDropSlabKeyfor the drop slab. TheRawDropSlabKeyis a type-erased variant ofDropSlabKeyso 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.
AtomicOnceCellis a thread-safe variant ofOnceCell.AtomicOnceCellArrayis an indexed variant representing a contiguous fixed-size array of the cells using an atomic bitvector to track accesses.AtomicOnceCellStackis built on top ofAtomicOnceCellArrayand providespush/reserve/setsemantics using an atomic to track the top of the stack.All of the
Atomicstorages willpanicif 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 tosetorpush.AtomicOnceCellandAtomicOnceCellArraycontain tests butAtomicOnceCellStackdoes not because the safety invariants of theAtomicOnceCellStackrely on the underlyingAtomicOnceCellArray.Update Renderer to use new render_features code.
cfeae1a
RenderFeaturePluginhas been expanded with additional functions for calculating and allocating frame or submit packets, creating each job type, and determining if a givenRenderViewandRenderViewVisibilityQueryis relevant to that feature.RendererThreadPoolto allow the application to control the parallelization of different stages of the renderer pipeline.RendererThreadPoolNoneis provided as a single-threaded default if the application does not provide their own implementation.RendererAssetPluginfrom what was previously just aRendererPlugincontaining both feature code (now moved toRenderFeaturePlugin) and asset code.RendererandRenderFrameJobto make the implementation of theRendererThreadPooleasier.Replace nodes_api_design with renderer_triangle example.
9d11f1f
This example builds on the
asset_triangleexample to show how to userafx-rendererand aRenderFeaturePluginto drive rendering.Update the demo to use the new render_features code.
320909a
extractandprepareentry points and to define their customFramePacketorSubmitPacketdata.RendererThreadPoolusingbevy-tasks.