Skip to main content

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