1mod capacity;
2mod ccd;
3mod commands;
4mod commit;
5mod domain;
6mod entries;
7mod integrate;
8mod islands;
9mod live;
10mod narrowphase;
11mod solver;
12mod sort;
13mod streams;
14
15use dynamis_abi::{FrameCounts, StepParamsRecord};
16use dynamis_gpu::Resources;
17
18const IDENTITY: &[&str] = &[include_str!("../shaders/identity.wgsl")];
19const CONTACT: &[&str] = &[
20 include_str!("../shaders/identity.wgsl"),
21 include_str!("../shaders/events.wgsl"),
22];
23
24#[derive(Clone, Copy, Debug, PartialEq, Eq)]
25pub struct RigidShape {
26 pub island_rounds: u32,
27 pub body_row_words: u32,
28 pub body_id_words: u32,
29 pub collider_slot_words: u32,
30}
31
32impl RigidShape {
33 pub fn of(counts: &FrameCounts) -> Self {
34 Self {
35 island_rounds: propagation_rounds(counts.dynamic_bodies),
36 body_row_words: dynamis_sort::key_words(counts.bodies.max(1)),
37 body_id_words: dynamis_sort::key_words(counts.body_ids.max(1)),
38 collider_slot_words: dynamis_sort::key_words(counts.colliders.max(1)),
39 }
40 }
41}
42
43fn propagation_rounds(bodies: u32) -> u32 {
44 bodies.max(2).ilog2() + 1
45}
46
47#[derive(Clone, Copy, Debug)]
48pub struct RigidFrame {
49 pub params: StepParamsRecord,
50 pub shape: RigidShape,
51 pub query_count: u32,
52 pub observed_count: u32,
53 pub simulating: bool,
54 pub indexing: bool,
55 pub ccd: bool,
56}
57
58use commands::Commands;
59use commit::Commit;
60use dynamis_gpu::GpuContext;
61use dynamis_pass::{Schedule, domain_passes};
62use dynamis_sort::RadixSort;
63use entries::Entries;
64use integrate::Integrate;
65use islands::Islands;
66use islands::Sleep;
67use live::Live;
68use narrowphase::Narrowphase;
69use solver::Solver;
70
71pub use capacity::{Capacity, RigidCapacity, RigidInputs, capacity};
72pub use ccd::{Ccd, CcdPasses};
73pub use domain::{RigidDomain, RigidDomainPasses, RigidDomainRuntime, RigidWork};
74pub use streams::{RigidDemand, RigidStream, RigidStreams, event_capacity, sort_capacity};
75
76domain_passes!(
77 RigidPasses,
78 commands => &[],
79 prepare => &["commands"],
80 entries => &["prepare", "soft_bounds"],
81 narrowphase => &["broadphase"],
82 islands => &["narrowphase"],
83 wake => &["islands"],
84 live => &["wake"],
85 solver_prepare => &["live"],
86 substeps => &["solver_prepare"],
87);
88
89domain_passes!(
90 RigidResolutionPasses,
91 sleep => &["soft_apply"],
92 commit => &["sleep"],
93 resting_gather => &["commit"],
94 resting_index => &["resting_gather"],
95);
96
97pub struct Rigid {
98 passes: RigidPasses,
99 resolution: RigidResolutionPasses,
100 commands: Commands,
101 integrate: Integrate,
102 entries: Entries,
103 narrowphase: Narrowphase,
104 islands: Islands,
105 sleep: Sleep,
106 live: Live,
107 solver: Solver,
108 commit: Commit,
109 sort: RadixSort,
110}
111
112impl Rigid {
113 pub fn new(
114 context: &GpuContext,
115 streams: &impl Resources,
116 passes: RigidPasses,
117 resolution: RigidResolutionPasses,
118 ) -> Self {
119 Self {
120 passes,
121 resolution,
122 commands: Commands::build(context, streams),
123 integrate: Integrate::build(context, streams),
124 entries: Entries::build(context, streams),
125 narrowphase: Narrowphase::build(context, streams),
126 islands: Islands::build(context, streams),
127 sleep: Sleep::build(context, streams),
128 live: Live::build(context, streams),
129 solver: Solver::build(context, streams),
130 commit: Commit::build(context, streams),
131 sort: RadixSort::new(context, "rigid sort", sort_capacity(streams)),
132 }
133 }
134
135 pub fn record(
136 &self,
137 pass: u32,
138 schedule: &mut Schedule,
139 encoder: &mut wgpu::CommandEncoder,
140 streams: &impl Resources,
141 frame: &RigidFrame,
142 ) {
143 let simulating = frame.simulating;
144 let indexing = frame.indexing;
145 if pass == self.passes.commands {
146 let mut commands = schedule.open(encoder, pass);
147 self.commands.record(&mut commands, streams, frame);
148 drop(commands);
149 } else if pass == self.passes.prepare {
150 if !indexing {
151 return;
152 }
153 let mut prepare = schedule.open(encoder, pass);
154 self.integrate
155 .record(&mut prepare, streams, frame, &self.sort);
156 drop(prepare);
157 } else if pass == self.passes.entries {
158 if !indexing {
159 return;
160 }
161 let mut entries = schedule.open(encoder, pass);
162 self.entries.record(&mut entries, streams, frame);
163 drop(entries);
164 } else if pass == self.passes.narrowphase {
165 if !simulating {
166 return;
167 }
168 let mut narrowphase = schedule.open(encoder, pass);
169 self.narrowphase
170 .record(&mut narrowphase, streams, frame, &self.sort);
171 drop(narrowphase);
172 } else if pass == self.passes.islands {
173 if !simulating {
174 return;
175 }
176 let mut islands = schedule.open(encoder, pass);
177 self.islands.record(&mut islands, streams, frame);
178 drop(islands);
179 } else if pass == self.passes.wake {
180 if !simulating {
181 return;
182 }
183 let mut wake = schedule.open(encoder, pass);
184 self.islands.record_wake(&mut wake, streams, frame);
185 drop(wake);
186 } else if pass == self.passes.live {
187 if !simulating {
188 return;
189 }
190 let mut live = schedule.open(encoder, pass);
191 self.live.record(&mut live, streams, frame);
192 drop(live);
193 } else if pass == self.passes.solver_prepare {
194 if !simulating {
195 return;
196 }
197 let mut prepare = schedule.open(encoder, pass);
198 self.solver.record_prepare(&mut prepare, streams, frame);
199 drop(prepare);
200 } else if pass == self.passes.substeps {
201 if !simulating {
202 return;
203 }
204 let mut substeps = schedule.open(encoder, pass);
205 self.solver.record_topology(&mut substeps, streams);
206 for substep in 0..frame.params.substeps {
207 self.integrate.record_substep(&mut substeps, streams);
208 if substep == 0 {
209 self.solver.record_warm(&mut substeps, streams);
210 }
211 self.solver.record_iterations(&mut substeps, streams, frame);
212 self.integrate
213 .record_substep_advance(&mut substeps, streams);
214 self.solver
215 .record_position_iterations(&mut substeps, streams, frame);
216 }
217 drop(substeps);
218 } else if pass == self.resolution.sleep {
219 if !simulating {
220 return;
221 }
222 let mut sleep = schedule.open(encoder, pass);
223 self.sleep.record(&mut sleep, streams, frame);
224 drop(sleep);
225 } else if pass == self.resolution.commit {
226 let mut commit = schedule.open(encoder, pass);
227 self.commit.record(&mut commit, streams, frame);
228 drop(commit);
229 } else if pass == self.resolution.resting_gather {
230 if !simulating {
231 return;
232 }
233 let mut gather = schedule.open(encoder, pass);
234 self.commit.record_gather(&mut gather, streams);
235 drop(gather);
236 } else if pass == self.resolution.resting_index {
237 if !simulating {
238 return;
239 }
240 let mut index = schedule.open(encoder, pass);
241 self.commit
242 .record_index(&mut index, streams, frame, &self.sort);
243 drop(index);
244 }
245 }
246
247 pub fn record_query_commands(
248 &self,
249 recorder: &mut dynamis_gpu::ComputeRecorder,
250 streams: &impl Resources,
251 frame: &RigidFrame,
252 ) {
253 self.commands.record_moves(recorder, streams, frame);
254 self.commands.record_edits(recorder, streams, frame);
255 self.commands.reset(recorder, streams);
256 self.integrate.record_broadphase(recorder, streams, frame);
257 self.entries.record(recorder, streams, frame);
258 }
259
260 pub fn record_query_flush(
261 &self,
262 recorder: &mut dynamis_gpu::ComputeRecorder,
263 streams: &impl Resources,
264 frame: &RigidFrame,
265 ) {
266 self.commit.record_query(recorder, streams, frame);
267 }
268}