One Frame, Fully Traced
1. The runner owns the outer loop
App::run transfers the built application into a runner. A windowed build
normally installs the winit runner; a headless schedule runner can call
App::update itself. The runner, not App, defines when another frame begins.
2. Updating advances every sub-application
App::update delegates to SubApps::update. The main world runs first. Each
configured sub-app can extract from the main world and run its own schedule.
3. Main expands into ordered schedules
Main::run_main runs startup schedules once, then First, PreUpdate, the
fixed-step loop, Update, scene spawning, PostUpdate, and Last. These are
coarse semantic barriers; each inner schedule may run many systems in parallel.
4. The schedule prepares an executable graph
Systems have explicit dependency edges and access sets generated from their
parameters. MultiThreadedExecutor::init precomputes conflicting-system
bitsets. A writer conflicts with readers or writers of the same component or
resource; compatible readers do not.
5. Ready compatible systems enter the compute pool
The executor tracks remaining dependencies, ready, running, completed, skipped,
and unapplied systems with bitsets. It scopes tasks on ComputeTaskPool and
starts systems whose dependencies are satisfied and whose access does not
conflict with currently running work. Non-Send and exclusive systems remain
on constrained execution paths.
6. Systems receive checked views
A function system’s SystemParam state constructs values such as Query,
Res, local state, messages, and Commands. The system sees only the access it
declared. Unsafe world access stays inside the scheduler/parameter machinery
whose compatibility checks uphold the public borrowing contract.
7. Deferred buffers become world mutations
Systems can enqueue spawns, despawns, component inserts, and custom commands
without taking exclusive world access immediately. ApplyDeferred or the
schedule’s final apply drains the relevant command queues sequentially into
&mut World.
8. Rendering extracts a snapshot
The render sub-app temporarily exposes the main world during ExtractSchedule.
Extraction systems copy or move render-relevant components and resources into
the render world. Later render schedules prepare assets, queue work, and submit
GPU commands without treating the simulation world as GPU-owned state.
The critical invariant is: parallel systems borrow stable storage; structural mutation happens only after those borrows have ended.