webxr_api/
registry.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5use 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}