Skip to main content

dynamis_world/backend/
registry.rs

1use crate::World;
2use dynamis_abi::{Counters, FrameCounts, RowStreams, StepParamsRecord};
3use dynamis_broadphase::BroadphaseDomain;
4use dynamis_domain::StepFacts;
5use dynamis_gpu::{ComputeRecorder, GpuContext};
6use dynamis_pass::{Pass, PipelineBuilder, Schedule};
7use dynamis_rigid::RigidDomain;
8use dynamis_soft::SoftDomain;
9use dynamis_state::StateDomain;
10use wgpu::CommandEncoder;
11
12dynamis_domain::domains! {
13    state: StateDomain,
14    broadphase: BroadphaseDomain,
15    rigid: RigidDomain,
16    soft: SoftDomain,
17    [rigid <-> soft]
18}
19
20pub(crate) const ACTIVITY_LAG: u32 = dynamis_gpu::Readback::DEPTH as u32 + 2;
21
22#[derive(Clone, Copy)]
23pub(crate) struct Rest {
24    quiet: u32,
25}
26
27impl Rest {
28    pub(crate) const IDLE: Self = Self { quiet: 0 };
29
30    pub(crate) fn gate(&mut self, simulating: bool) -> bool {
31        if simulating {
32            self.quiet = 0;
33            return true;
34        }
35        self.quiet = self.quiet.saturating_add(1);
36        self.quiet < ACTIVITY_LAG
37    }
38}
39
40impl Planning {
41    pub(crate) fn plan(&mut self, measured: &Counters, live: &Live, streams: &Streams) -> Plan {
42        let (broadphase, idle) =
43            self.broadphase
44                .plan(measured, &live.broadphase, &streams.broadphase);
45        let rigid = self.rigid.plan(
46            measured,
47            &live.rigid,
48            idle,
49            broadphase.pairs,
50            &streams.rigid,
51        );
52        let state = dynamis_state::plan(&live.state, idle, &streams.state);
53        let soft = dynamis_soft::plan(&live.soft, idle, state.bodies, &streams.soft);
54        Plan {
55            state,
56            broadphase,
57            rigid,
58            soft,
59        }
60    }
61}
62
63pub(crate) struct StepPasses {
64    schedule: Schedule,
65    runtimes: PassRuntimes,
66}
67
68impl StepPasses {
69    pub(crate) fn new(context: &GpuContext, streams: &Streams) -> Self {
70        let mut builder = PipelineBuilder::new();
71        PassIds::declare(&mut builder);
72        let pipeline = builder.resolve();
73        let ids = PassIds::resolve(&pipeline);
74        Self {
75            schedule: Schedule::new(
76                context,
77                pipeline,
78                #[cfg(feature = "profile")]
79                "dynamis step",
80            ),
81            runtimes: PassRuntimes::build(context, streams, ids),
82        }
83    }
84
85    pub(crate) fn record(
86        &mut self,
87        encoder: &mut CommandEncoder,
88        streams: &Streams,
89        frames: &StepFrames,
90    ) {
91        self.schedule.begin_step();
92        let Self { schedule, runtimes } = self;
93        for index in 0..schedule.pipeline().len() as u32 {
94            let pass = schedule.pass(index);
95            runtimes.record(pass, index, schedule, encoder, streams, frames);
96        }
97    }
98
99    pub(crate) fn encode_queries(
100        &self,
101        encoder: &mut CommandEncoder,
102        streams: &Streams,
103        frames: &StepFrames,
104    ) {
105        let mut commands =
106            ComputeRecorder::begin(encoder, "query commands", self.schedule.per_row());
107        self.runtimes
108            .rigid
109            .simulation
110            .record_query_commands(&mut commands, streams, &frames.rigid);
111        drop(commands);
112
113        let mut sort = ComputeRecorder::begin(encoder, "query sort", self.schedule.per_row());
114        self.runtimes.broadphase.sort_entries(&mut sort, streams);
115        drop(sort);
116
117        let mut flush = ComputeRecorder::begin(encoder, "query flush", self.schedule.per_row());
118        self.runtimes
119            .rigid
120            .simulation
121            .record_query_flush(&mut flush, streams, &frames.rigid);
122        drop(flush);
123    }
124
125    pub(crate) fn declared(&self) -> &[Pass] {
126        self.schedule.pipeline().passes()
127    }
128
129    #[cfg(feature = "profile")]
130    pub(crate) fn capture_timings(
131        &mut self,
132        encoder: &mut dynamis_gpu::SubmissionEncoder,
133    ) -> Option<Vec<dynamis_gpu::GpuPassTiming>> {
134        self.schedule.capture_timings(encoder)
135    }
136
137    #[cfg(feature = "profile")]
138    pub(crate) fn collect_timings(&mut self) -> Vec<Vec<dynamis_gpu::GpuPassTiming>> {
139        self.schedule.collect_timings()
140    }
141}
142
143impl World {
144    pub(crate) fn live(&self) -> Live {
145        let (particles, elements, attachments, adjacency) = self.soft.used();
146        let bodies = self.bodies.alive.len() as u32;
147        let colliders = self.colliders.live();
148        let collider_pool = self.colliders.used();
149        let constraints = self.constraints.alive.len() as u32;
150        let body_commands = self.bodies.commands.len() as u32;
151        let constraint_commands = self.constraints.commands.len() as u32;
152        let queries = self.queries.pending.len() as u32;
153        Live {
154            state: dynamis_state::StateInputs {
155                bodies,
156                body_ids: self.bodies.ids.len() as u32,
157                collider_pool,
158                constraints,
159                body_commands,
160                constraint_commands,
161                queries,
162                shapes: self.shapes.pool.used(),
163                observed: self.view.len(),
164            },
165            broadphase: dynamis_broadphase::BroadphaseInputs {
166                colliders,
167                particles,
168                pending_commands: body_commands > 0 || constraint_commands > 0,
169            },
170            rigid: dynamis_rigid::RigidInputs {
171                bodies,
172                colliders,
173                collider_pool,
174                constraints,
175                queries,
176                observed: self.view.len(),
177                ccd: self.ccd_active(),
178            },
179            soft: dynamis_soft::SoftInputs {
180                particles,
181                elements,
182                attachments,
183                adjacency,
184                bodies: self.soft.ids_len() as u32,
185                material: self.soft.carries_strength(),
186            },
187        }
188    }
189
190    pub(crate) fn host_work(&self) -> HostWork {
191        HostWork {
192            state: dynamis_state::StateWork {
193                queries: self.queries.pending.len() as u32,
194                shape_uploads: self.shapes.uploaded,
195            },
196            broadphase: (),
197            rigid: dynamis_rigid::RigidWork {
198                body_commands: self.bodies.last_edits + self.bodies.last_moves,
199                constraint_commands: self.constraints.last_commands + self.constraints.last_moves,
200            },
201            soft: dynamis_soft::SoftWork {
202                uploads: self.soft.uploaded,
203            },
204        }
205    }
206
207    pub(crate) fn frame_counts(&self) -> FrameCounts {
208        FrameCounts {
209            dynamic_bodies: self.bodies.dynamic_count as u32,
210            bodies: self.bodies.alive.len() as u32,
211            body_ids: self.bodies.ids.len() as u32,
212            colliders: self.colliders.used(),
213            constraints: self.constraints.alive.len() as u32,
214            particles: self.soft.used().0,
215            elements: self.soft.used().1,
216            attachments: self.soft.used().2,
217            soft_bodies: self.soft.ids_len() as u32,
218        }
219    }
220
221    pub(crate) fn step_params(&self, dt: f32) -> StepParamsRecord {
222        StepParamsRecord::new(
223            &self.config,
224            dt,
225            self.frame_counts(),
226            RowStreams {
227                edit_runs: self.bodies.last_edits,
228                body_moves: self.bodies.last_moves,
229                constraint_moves: self.constraints.last_moves,
230                observed: self.view.len(),
231            },
232            self.event_slot_of(self.clock.step),
233        )
234    }
235
236    pub(crate) fn busy(&self, work: &HostWork) -> bool {
237        self.observed(&self.live(), work).busy()
238    }
239
240    fn observed(&self, live: &Live, work: &HostWork) -> Activity {
241        match self.backend.measured_step {
242            None => Activity::BUSY,
243            Some(_) => Activity::of(&self.backend.measured, live, work),
244        }
245    }
246
247    fn gated(&mut self, live: &Live, work: &HostWork) -> Activity {
248        if self.backend.measured_step.is_none() {
249            return Activity::BUSY;
250        }
251        let liveness = Activity::of(&self.backend.measured, live, work);
252        let hold = self.backend.rest.gate(liveness.simulating());
253        liveness.held(hold)
254    }
255
256    pub(crate) fn frames(
257        &mut self,
258        live: &Live,
259        work: &HostWork,
260        params: StepParamsRecord,
261    ) -> StepFrames {
262        let liveness = self.gated(live, work);
263        let facts = StepFacts {
264            params,
265            counts: self.frame_counts(),
266        };
267        StepFrames::of(&facts, live, liveness)
268    }
269}