1use base::generic_channel::{self, GenericCallback, GenericReceiver, GenericSender};
6use embedder_traits::EventLoopWaker;
7use ipc_channel::ipc::IpcSender;
8use log::warn;
9use profile_traits::generic_callback::GenericCallback as ProfileGenericCallback;
10use serde::{Deserialize, Serialize};
11
12use crate::{
13 DiscoveryAPI, Error, Frame, GLTypes, LayerGrandManager, MainThreadSession, MockDeviceInit,
14 MockDeviceMsg, MockDiscoveryAPI, Session, SessionBuilder, SessionId, SessionInit, SessionMode,
15};
16
17#[derive(Clone, Serialize, Deserialize)]
18pub struct Registry {
19 sender: GenericSender<RegistryMsg>,
20 waker: MainThreadWakerImpl,
21}
22
23pub struct MainThreadRegistry<GL> {
24 discoveries: Vec<Box<dyn DiscoveryAPI<GL>>>,
25 sessions: Vec<Box<dyn MainThreadSession>>,
26 mocks: Vec<Box<dyn MockDiscoveryAPI<GL>>>,
27 sender: GenericSender<RegistryMsg>,
28 receiver: GenericReceiver<RegistryMsg>,
29 waker: MainThreadWakerImpl,
30 grand_manager: LayerGrandManager<GL>,
31 next_session_id: u32,
32}
33
34#[derive(Clone, Serialize, Deserialize)]
35struct MainThreadWakerImpl {
36 callback: GenericCallback<()>,
37}
38
39impl MainThreadWakerImpl {
40 fn new(waker: Box<dyn EventLoopWaker>) -> Result<MainThreadWakerImpl, Error> {
41 let callback =
42 GenericCallback::new(move |_| waker.wake()).expect("Could not construct callback");
43 Ok(MainThreadWakerImpl { callback })
44 }
45
46 fn wake(&self) {
47 let _ = self.callback.send(());
48 }
49}
50
51impl Registry {
52 pub fn supports_session(
53 &mut self,
54 mode: SessionMode,
55 dest: ProfileGenericCallback<Result<(), Error>>,
56 ) {
57 let _ = self.sender.send(RegistryMsg::SupportsSession(mode, dest));
58 self.waker.wake();
59 }
60
61 pub fn request_session(
62 &mut self,
63 mode: SessionMode,
64 init: SessionInit,
65 dest: IpcSender<Result<Session, Error>>,
66 animation_frame_handler: IpcSender<Frame>,
67 ) {
68 let _ = self.sender.send(RegistryMsg::RequestSession(
69 mode,
70 init,
71 dest,
72 animation_frame_handler,
73 ));
74 self.waker.wake();
75 }
76
77 pub fn simulate_device_connection(
78 &mut self,
79 init: MockDeviceInit,
80 dest: ProfileGenericCallback<Result<GenericSender<MockDeviceMsg>, Error>>,
81 ) {
82 let _ = self
83 .sender
84 .send(RegistryMsg::SimulateDeviceConnection(init, dest));
85 self.waker.wake();
86 }
87}
88
89impl<GL: 'static + GLTypes> MainThreadRegistry<GL> {
90 pub fn new(
91 waker: Box<dyn EventLoopWaker>,
92 grand_manager: LayerGrandManager<GL>,
93 ) -> Result<Self, Error> {
94 let Some((sender, receiver)) = generic_channel::channel() else {
95 return Err(Error::CommunicationError);
96 };
97 let discoveries = Vec::new();
98 let sessions = Vec::new();
99 let mocks = Vec::new();
100 let waker = MainThreadWakerImpl::new(waker)?;
101 Ok(MainThreadRegistry {
102 discoveries,
103 sessions,
104 mocks,
105 sender,
106 receiver,
107 waker,
108 grand_manager,
109 next_session_id: 0,
110 })
111 }
112
113 pub fn registry(&self) -> Registry {
114 Registry {
115 sender: self.sender.clone(),
116 waker: self.waker.clone(),
117 }
118 }
119
120 pub fn register<D>(&mut self, discovery: D)
121 where
122 D: DiscoveryAPI<GL>,
123 {
124 self.discoveries.push(Box::new(discovery));
125 }
126
127 pub fn register_mock<D>(&mut self, discovery: D)
128 where
129 D: MockDiscoveryAPI<GL>,
130 {
131 self.mocks.push(Box::new(discovery));
132 }
133
134 pub fn run_on_main_thread<S>(&mut self, session: S)
135 where
136 S: MainThreadSession,
137 {
138 self.sessions.push(Box::new(session));
139 }
140
141 pub fn run_one_frame(&mut self) {
142 while let Ok(msg) = self.receiver.try_recv() {
143 self.handle_msg(msg);
144 }
145 for session in &mut self.sessions {
146 session.run_one_frame();
147 }
148 self.sessions.retain(|session| session.running());
149 }
150
151 pub fn running(&self) -> bool {
152 self.sessions.iter().any(|session| session.running())
153 }
154
155 fn handle_msg(&mut self, msg: RegistryMsg) {
156 match msg {
157 RegistryMsg::SupportsSession(mode, dest) => {
158 let _ = dest.send(self.supports_session(mode));
159 },
160 RegistryMsg::RequestSession(mode, init, dest, raf_sender) => {
161 let _ = dest.send(self.request_session(mode, init, raf_sender));
162 },
163 RegistryMsg::SimulateDeviceConnection(init, dest) => {
164 let _ = dest.send(self.simulate_device_connection(init));
165 },
166 }
167 }
168
169 fn supports_session(&mut self, mode: SessionMode) -> Result<(), Error> {
170 for discovery in &self.discoveries {
171 if discovery.supports_session(mode) {
172 return Ok(());
173 }
174 }
175 Err(Error::NoMatchingDevice)
176 }
177
178 fn request_session(
179 &mut self,
180 mode: SessionMode,
181 init: SessionInit,
182 raf_sender: IpcSender<Frame>,
183 ) -> Result<Session, Error> {
184 for discovery in &mut self.discoveries {
185 if discovery.supports_session(mode) {
186 let raf_sender = raf_sender.clone();
187 let id = SessionId(self.next_session_id);
188 self.next_session_id += 1;
189 let xr = SessionBuilder::new(
190 &mut self.sessions,
191 raf_sender,
192 self.grand_manager.clone(),
193 id,
194 );
195 match discovery.request_session(mode, &init, xr) {
196 Ok(session) => return Ok(session),
197 Err(err) => warn!("XR device error {:?}", err),
198 }
199 }
200 }
201 warn!("no device could support the session");
202 Err(Error::NoMatchingDevice)
203 }
204
205 fn simulate_device_connection(
206 &mut self,
207 init: MockDeviceInit,
208 ) -> Result<GenericSender<MockDeviceMsg>, Error> {
209 for mock in &mut self.mocks {
210 let Some((sender, receiver)) = generic_channel::channel() else {
211 return Err(Error::CommunicationError);
212 };
213 if let Ok(discovery) = mock.simulate_device_connection(init.clone(), receiver) {
214 self.discoveries.insert(0, discovery);
215 return Ok(sender);
216 }
217 }
218 Err(Error::NoMatchingDevice)
219 }
220}
221
222#[derive(Serialize, Deserialize)]
223#[expect(clippy::large_enum_variant)]
224enum RegistryMsg {
225 RequestSession(
226 SessionMode,
227 SessionInit,
228 IpcSender<Result<Session, Error>>,
229 IpcSender<Frame>,
230 ),
231 SupportsSession(SessionMode, ProfileGenericCallback<Result<(), Error>>),
232 SimulateDeviceConnection(
233 MockDeviceInit,
234 ProfileGenericCallback<Result<GenericSender<MockDeviceMsg>, Error>>,
235 ),
236}