Skip to main content

dynamis_broadphase/
lib.rs

1mod capacity;
2mod domain;
3mod streams;
4
5pub use capacity::{BroadphaseCapacity, BroadphaseInputs, Capacity};
6pub use domain::BroadphaseDomain;
7pub use streams::{
8    BroadphaseDemand, BroadphaseStream, BroadphaseStreams, entry_capacity, pair_capacity,
9    sort_capacity,
10};
11
12use dynamis_abi::COUNTER_ENTRIES;
13use dynamis_gpu::GpuContext;
14use dynamis_gpu::Resources;
15use dynamis_pass::{Schedule, Stage, domain_passes};
16use dynamis_shader::{GRID_INDEX, stream};
17use dynamis_sort::{RadixSort, SortChannels};
18use dynamis_state::StateStream;
19
20domain_passes!(BroadphasePasses, broadphase => &["entries", "soft_entries"]);
21
22#[derive(Clone, Copy, Debug, PartialEq, Eq)]
23pub struct BroadphaseFrame {
24    pub indexing: bool,
25}
26
27pub fn capacity(streams: &BroadphaseStreams) -> BroadphaseCapacity {
28    BroadphaseCapacity {
29        entries: streams.entry_keys.slots(),
30        pairs: streams.pair_major.slots(),
31    }
32}
33
34pub struct Broadphase {
35    passes: BroadphasePasses,
36    sort: RadixSort,
37    cell_pairs: Stage,
38    level_links: Stage,
39}
40
41impl Broadphase {
42    pub fn new(context: &GpuContext, streams: &impl Resources, passes: BroadphasePasses) -> Self {
43        Self {
44            passes,
45            sort: RadixSort::new(context, "grid sort", sort_capacity(streams)),
46            cell_pairs: Stage::build(
47                context,
48                "cell_pairs",
49                stream(
50                    context,
51                    include_str!("../shaders/cell_pairs.wgsl"),
52                    GRID_INDEX,
53                    "work",
54                    BroadphaseStream::EntryKeys,
55                ),
56                streams,
57                &[
58                    ("pair_major", BroadphaseStream::PairMajor.whole()),
59                    ("pair_minor", BroadphaseStream::PairMinor.whole()),
60                    ("entry_keys", BroadphaseStream::EntryKeys.whole()),
61                    ("entry_order", BroadphaseStream::EntryOrder.whole()),
62                    ("entries", BroadphaseStream::Entries.whole()),
63                    ("counters", StateStream::Counters.whole()),
64                ],
65                &[],
66            ),
67            level_links: Stage::build(
68                context,
69                "level_links",
70                stream(
71                    context,
72                    include_str!("../shaders/level_links.wgsl"),
73                    GRID_INDEX,
74                    "work",
75                    BroadphaseStream::EntryKeys,
76                ),
77                streams,
78                &[
79                    ("pair_major", BroadphaseStream::PairMajor.whole()),
80                    ("pair_minor", BroadphaseStream::PairMinor.whole()),
81                    ("entry_keys", BroadphaseStream::EntryKeys.whole()),
82                    ("entry_order", BroadphaseStream::EntryOrder.whole()),
83                    ("entries", BroadphaseStream::Entries.whole()),
84                    ("counters", StateStream::Counters.whole()),
85                ],
86                &[],
87            ),
88        }
89    }
90
91    pub fn sort_entries(
92        &self,
93        recorder: &mut dynamis_gpu::ComputeRecorder,
94        streams: &impl Resources,
95    ) {
96        let count = dynamis_state::counter(COUNTER_ENTRIES).resolve(streams);
97        let channels = SortChannels {
98            generation: streams.generation(),
99            count,
100            major: BroadphaseStream::EntryKeys.whole().resolve(streams),
101            minor: BroadphaseStream::SortDummy.whole().resolve(streams),
102            payload: BroadphaseStream::EntryOrder.whole().resolve(streams),
103            scratch_major: BroadphaseStream::SortScratchMajor.whole().resolve(streams),
104            scratch_minor: BroadphaseStream::SortScratchMinor.whole().resolve(streams),
105            scratch_payload: BroadphaseStream::SortScratchPayload
106                .whole()
107                .resolve(streams),
108        };
109        self.sort.sort(recorder, &channels, 4, 0);
110    }
111
112    pub fn record(
113        &self,
114        pass: u32,
115        schedule: &mut Schedule,
116        encoder: &mut wgpu::CommandEncoder,
117        streams: &impl Resources,
118        frame: BroadphaseFrame,
119    ) {
120        if pass != self.passes.broadphase || !frame.indexing {
121            return;
122        }
123        let mut index = schedule.open(encoder, pass);
124        self.sort_entries(&mut index, streams);
125        self.cell_pairs.record_stream(&mut index, streams);
126        self.level_links.record_stream(&mut index, streams);
127        drop(index);
128    }
129}