Skip to main content

dynamis_rigid/
lib.rs

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}