Skip to main content

dynamis_world/
event.rs

1use super::World;
2use dynamis_abi::{COUNTER_EVENTS, ContactEventRecord};
3use dynamis_gpu::EVENT_SLOTS;
4use dynamis_model::{BodyHandle, ContactEvent, ContactEventKind};
5use std::collections::VecDeque;
6use std::mem::size_of;
7
8pub(crate) struct Events {
9    pub(crate) contact: Vec<ContactEvent>,
10    pub(crate) due: VecDeque<(u64, u32)>,
11    pub(crate) sink: Option<Box<dyn FnMut(ContactEvent)>>,
12}
13
14impl Events {
15    pub(crate) fn new() -> Self {
16        Self {
17            contact: Vec::new(),
18            due: VecDeque::new(),
19            sink: None,
20        }
21    }
22}
23
24impl World {
25    pub fn drain_events(&mut self) -> Vec<ContactEvent> {
26        self.backend.gpu.assert_alive();
27        self.collect_readbacks();
28        self.sync_events();
29        std::mem::take(&mut self.events.contact)
30    }
31
32    pub fn set_event_sink(&mut self, sink: Option<Box<dyn FnMut(ContactEvent)>>) {
33        self.events.sink = sink;
34    }
35
36    pub(crate) fn note_events_due(&mut self, step: u64) {
37        let count = self.backend.measured[COUNTER_EVENTS];
38        if count > 0 {
39            self.events.due.push_back((step, count));
40        }
41    }
42
43    pub(crate) fn copy_events(&mut self, encoder: &mut dynamis_gpu::SubmissionEncoder) {
44        while let Some((step, count)) = self.events.due.pop_front() {
45            assert!(
46                self.clock.step <= step + EVENT_SLOTS as u64,
47                "event segment for step {step} was overwritten before step {} could copy it",
48                self.clock.step
49            );
50            let segment = self.backend.streams.rigid.events.size() / EVENT_SLOTS as u64;
51            let offset = (step % EVENT_SLOTS as u64) * segment;
52            let bytes = (count as u64 * size_of::<ContactEventRecord>() as u64).min(segment);
53            let displaced = self.backend.readback.events.enqueue(
54                encoder,
55                self.backend.streams.rigid.events.buffer(),
56                offset,
57                bytes,
58                step,
59            );
60            if let Some((_, bytes)) = displaced {
61                self.consume_events(&bytes);
62            }
63        }
64    }
65
66    pub(crate) fn sync_events(&mut self) {
67        if self.events.due.is_empty() {
68            return;
69        }
70        let device = self.backend.gpu.device().clone();
71        let mut encoder = dynamis_gpu::SubmissionEncoder::new(&device, "dynamis event readback");
72        self.copy_events(&mut encoder);
73        self.submit(encoder);
74        for (_, bytes) in self.backend.readback.events.drain() {
75            self.consume_events(&bytes);
76        }
77    }
78
79    pub(crate) fn consume_events(&mut self, bytes: &[u8]) {
80        let records = dynamis_abi::decode::<ContactEventRecord>(bytes);
81        let count = records.len();
82        let mut fresh = Vec::with_capacity(count);
83        for record in &records[..count] {
84            let kind = match record.kind {
85                dynamis_abi::EVENT_BEGIN => ContactEventKind::Begin,
86                dynamis_abi::EVENT_END => ContactEventKind::End,
87                dynamis_abi::EVENT_PERSIST => ContactEventKind::Persist,
88                other => panic!("GPU event record has an invalid kind {other}"),
89            };
90            fresh.push(ContactEvent {
91                kind,
92                first: BodyHandle {
93                    id: record.first_id,
94                    generation: record.first_generation,
95                },
96                second: BodyHandle {
97                    id: record.second_id,
98                    generation: record.second_generation,
99                },
100                sensor: record.sensor == 1,
101                point: record.point,
102                normal: record.normal,
103            });
104        }
105        if let Some(sink) = self.events.sink.as_mut() {
106            for event in fresh.iter().copied() {
107                sink(event);
108            }
109        }
110        self.events.contact.extend(fresh);
111    }
112}