1use 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}