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