class
RendererObjectStorage
Provides common functionality for types that exist on the main thread, but also need a representation on the render thread.
In particular, it is responsible for:
- Maintaining data arrays that store the render thread data. Arrays are kept packed for fast iteration on the render thread.
- Maintaining persistent ID -> packed ID mapping so objects know at which array index to find their data.
- Synchronizing changes between main and render thread. Once some main thread object property changes the packed array data for that object needs to be updated. Synchronization is done is batches for all objects needing update within a single frame, for best performance.
General concepts
-
On the main thread renderer objects allocate and store a persistent renderer ID during their lifetime.
-
On the render thread the objects are stored in one or multiple packed arrays referenced by PackedRendererIds.
-
Exact data stored in packed array(s) is defined by implementations of this class.
-
Persistent renderer IDs are resolved on the render thread to packed PackedRendererId, which can be used for packed array access.
Allocating renderer object IDs
Renderer object IDs are allocated / deallocated from the main thread using AllocateRendererId() / DeallocateRendererId().
Since RendererId values are allocated/deallocated from the main thread, the render thread needs to be informed about which IDs were allocated/deallocated
every frame so it can update its packed arrays to match. This is done via FlushCommands()/ApplyCommands().
- FlushCommands() must be called on the main thread during SyncRead. It returns a list of all IDs that were allocated or deallocated this frame.
- ApplyCommands() must be called on the render thread during SyncWrite. It updates the mapping of persistent -> packed object IDs, based on the IDs that were allocated/deallocated. It also adds/removes/swaps entries in the associated packed arrays.
Syncing data
Data should be synced from the main thread to the render thread using SyncRead() / SyncWrite().
- SyncRead() is called on the main thread, and should gather dirty data from dirty main thread objects into a buffer allocated by the provided allocator, and return a pointer to that buffer. It must call FlushCommands() to ensure SyncWrite() can replay the commands.
- SyncWrite() is called on the render thread with the buffer generated by SyncRead(). It must call ApplyCommands() first to ensure packed arrays are up to date, then resolve RendererId values to PackedRendererId via GetPackedRendererId() for array access, and copy the data from the buffer into relevant entries in the packed arrays.
This versus CoreObject/RenderProxy system
Note this system serves a similar purpose as the CoreObject/RenderProxy system. The main improvements compared to that system are:
- Updates are done in batches, improving performance (i.e. all objects of the same type at once, each frame).
- Main thread objects can be ECS fragments or regular structs, they don't need to implement CoreObject interface (they just need a persistent renderer ID).
- Management of packed arrays on the render thread is abstracted and generalized, reducing boilerplate.
Public
Methods
~RendererObjectStorage
AllocateRendererId
Allocates a persistent renderer object ID.
DeallocateRendererId
Deallocates a persistent renderer object ID.
GetPackedRendererId
Resolves a RendererId to the current packed PackedRendererId on the render thread.
Returns kInvalidPackedRendererId if the ID is stale or out of range.
Internal
Methods
ApplyCommands
Applies flushed renderer object commands on the render thread, updating packed arrays and freeing command buffers.
Subclasses must call the protected ApplyCommands template with their specific packed arrays.
FlushCommands
Returns all renderer IDs that were allocated and deallocated since the last call to FlushCommands().
Returned command batch is only valid until and during the next ApplyCommands() call.
SyncRead
Scans the provided registry for dirty objects, generates the update packets and stores them into a batch buffer allocated by .
Returns pointer to the batch buffer memory.
SyncWrite
Applies data from a batch buffer generated by SyncRead to objects on the render thread, and frees the frame-allocated batch data via .
Protected
Fields
mObjectIdAllocator
mPendingAllocations
Allocations this frame, not yet flushed.
mPersistentToPackedId
RendererId -> PackedRendererId.
mPackedToPersistentId
PackedRendererId -> RendererId.