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}