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}