1use std::thread;
6use std::time::Duration;
7
8use euclid::{Point2D, Rect, RigidTransform3D, Size2D};
9use log::warn;
10use malloc_size_of_derive::MallocSizeOf;
11use profile_traits::generic_callback::GenericCallback as ProfileGenericCallback;
12use serde::{Deserialize, Serialize};
13use servo_base::generic_channel::{self, GenericReceiver, GenericSender};
14
15use crate::{
16 ContextId, DeviceAPI, Error, Event, Floor, Frame, FrameUpdateEvent, HitTestId, HitTestSource,
17 InputSource, LayerGrandManager, LayerId, LayerInit, Native, Viewport, Viewports,
18};
19
20static TIMEOUT: Duration = Duration::from_millis(5);
22
23#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize)]
25pub enum SessionMode {
26 Inline,
27 ImmersiveVR,
28 ImmersiveAR,
29}
30
31#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
33pub struct SessionInit {
34 pub required_features: Vec<String>,
35 pub optional_features: Vec<String>,
36 pub first_person_observer_view: bool,
40}
41
42impl SessionInit {
43 pub fn validate(&self, mode: SessionMode, supported: &[String]) -> Result<Vec<String>, Error> {
46 for f in &self.required_features {
47 if f == "viewer" || (f == "local" && mode != SessionMode::Inline) {
50 continue;
51 }
52
53 if !supported.contains(f) {
54 return Err(Error::UnsupportedFeature(f.into()));
55 }
56 }
57 let mut granted = self.required_features.clone();
58 for f in &self.optional_features {
59 if f == "viewer" ||
60 (f == "local" && mode != SessionMode::Inline) ||
61 supported.contains(f)
62 {
63 granted.push(f.clone());
64 }
65 }
66
67 Ok(granted)
68 }
69
70 pub fn feature_requested(&self, f: &str) -> bool {
71 self.required_features
72 .iter()
73 .chain(self.optional_features.iter())
74 .any(|x| *x == f)
75 }
76}
77
78#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize, MallocSizeOf)]
80pub enum EnvironmentBlendMode {
81 Opaque,
82 AlphaBlend,
83 Additive,
84}
85
86#[derive(Debug, Serialize, Deserialize)]
88enum SessionMsg {
89 CreateLayer(ContextId, LayerInit, GenericSender<Result<LayerId, Error>>),
90 DestroyLayer(ContextId, LayerId),
91 SetLayers(Vec<(ContextId, LayerId)>),
92 SetEventDest(ProfileGenericCallback<Event>),
93 SetFrameDest(ProfileGenericCallback<Frame>),
94 UpdateClipPlanes(f32, f32),
95 StartRenderLoop,
96 RenderAnimationFrame,
97 RequestHitTest(HitTestSource),
98 CancelHitTest(HitTestId),
99 UpdateFrameRate(f32, ProfileGenericCallback<f32>),
100 Quit,
101 GetBoundsGeometry(GenericSender<Option<Vec<Point2D<f32, Floor>>>>),
102}
103
104#[derive(Serialize, Deserialize, Clone)]
105pub struct Quitter {
106 sender: GenericSender<SessionMsg>,
107}
108
109impl Quitter {
110 pub fn quit(&self) {
111 let _ = self.sender.send(SessionMsg::Quit);
112 }
113}
114
115#[derive(Serialize, Deserialize, MallocSizeOf)]
119pub struct Session {
120 floor_transform: Option<RigidTransform3D<f32, Native, Floor>>,
121 viewports: Viewports,
122 sender: GenericSender<SessionMsg>,
123 environment_blend_mode: EnvironmentBlendMode,
124 initial_inputs: Vec<InputSource>,
125 granted_features: Vec<String>,
126 id: SessionId,
127 supported_frame_rates: Vec<f32>,
128}
129
130#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Deserialize, Serialize, MallocSizeOf)]
131pub struct SessionId(pub(crate) u32);
132
133impl Session {
134 pub fn id(&self) -> SessionId {
135 self.id
136 }
137
138 pub fn floor_transform(&self) -> Option<RigidTransform3D<f32, Native, Floor>> {
139 self.floor_transform
140 }
141
142 pub fn reference_space_bounds(&self) -> Option<Vec<Point2D<f32, Floor>>> {
143 let (sender, receiver) = generic_channel::channel()?;
144 let _ = self.sender.send(SessionMsg::GetBoundsGeometry(sender));
145 receiver.recv().ok()?
146 }
147
148 pub fn initial_inputs(&self) -> &[InputSource] {
149 &self.initial_inputs
150 }
151
152 pub fn environment_blend_mode(&self) -> EnvironmentBlendMode {
153 self.environment_blend_mode
154 }
155
156 pub fn viewports(&self) -> &[Rect<i32, Viewport>] {
157 &self.viewports.viewports
158 }
159
160 pub fn recommended_framebuffer_resolution(&self) -> Option<Size2D<i32, Viewport>> {
165 self.viewports()
166 .iter()
167 .fold(None::<Rect<_, _>>, |acc, vp| {
168 Some(acc.map(|a| a.union(vp)).unwrap_or(*vp))
169 })
170 .map(|rect| Size2D::new(rect.max_x(), rect.max_y()))
171 }
172
173 pub fn create_layer(&self, context_id: ContextId, init: LayerInit) -> Result<LayerId, Error> {
174 let Some((sender, receiver)) = generic_channel::channel() else {
175 return Err(Error::CommunicationError);
176 };
177 let _ = self
178 .sender
179 .send(SessionMsg::CreateLayer(context_id, init, sender));
180 receiver.recv().map_err(|_| Error::CommunicationError)?
181 }
182
183 pub fn destroy_layer(&self, context_id: ContextId, layer_id: LayerId) {
185 let _ = self
186 .sender
187 .send(SessionMsg::DestroyLayer(context_id, layer_id));
188 }
189
190 pub fn set_layers(&self, layers: Vec<(ContextId, LayerId)>) {
191 let _ = self.sender.send(SessionMsg::SetLayers(layers));
192 }
193
194 pub fn start_render_loop(&mut self) {
195 let _ = self.sender.send(SessionMsg::StartRenderLoop);
196 }
197
198 pub fn update_clip_planes(&mut self, near: f32, far: f32) {
199 let _ = self.sender.send(SessionMsg::UpdateClipPlanes(near, far));
200 }
201
202 pub fn set_event_dest(&mut self, dest: ProfileGenericCallback<Event>) {
203 let _ = self.sender.send(SessionMsg::SetEventDest(dest));
204 }
205
206 pub fn set_frame_dest(&mut self, dest: ProfileGenericCallback<Frame>) {
207 let _ = self.sender.send(SessionMsg::SetFrameDest(dest));
208 }
209
210 pub fn render_animation_frame(&mut self) {
211 let _ = self.sender.send(SessionMsg::RenderAnimationFrame);
212 }
213
214 pub fn end_session(&mut self) {
215 let _ = self.sender.send(SessionMsg::Quit);
216 }
217
218 pub fn apply_event(&mut self, event: FrameUpdateEvent) {
219 match event {
220 FrameUpdateEvent::UpdateFloorTransform(floor) => self.floor_transform = floor,
221 FrameUpdateEvent::UpdateViewports(vp) => self.viewports = vp,
222 FrameUpdateEvent::HitTestSourceAdded(_) => (),
223 }
224 }
225
226 pub fn granted_features(&self) -> &[String] {
227 &self.granted_features
228 }
229
230 pub fn request_hit_test(&self, source: HitTestSource) {
231 let _ = self.sender.send(SessionMsg::RequestHitTest(source));
232 }
233
234 pub fn cancel_hit_test(&self, id: HitTestId) {
235 let _ = self.sender.send(SessionMsg::CancelHitTest(id));
236 }
237
238 pub fn update_frame_rate(&mut self, rate: f32, sender: ProfileGenericCallback<f32>) {
239 let _ = self.sender.send(SessionMsg::UpdateFrameRate(rate, sender));
240 }
241
242 pub fn supported_frame_rates(&self) -> &[f32] {
243 &self.supported_frame_rates
244 }
245}
246
247#[derive(PartialEq)]
248enum RenderState {
249 NotInRenderLoop,
250 InRenderLoop,
251 PendingQuit,
252}
253
254pub struct SessionThread<Device> {
256 receiver: GenericReceiver<SessionMsg>,
257 sender: GenericSender<SessionMsg>,
258 layers: Vec<(ContextId, LayerId)>,
259 pending_layers: Option<Vec<(ContextId, LayerId)>>,
260 frame_count: u64,
261 frame_sender: Option<ProfileGenericCallback<Frame>>,
262 running: bool,
263 device: Device,
264 id: SessionId,
265 render_state: RenderState,
266}
267
268impl<Device> SessionThread<Device>
269where
270 Device: DeviceAPI,
271{
272 pub fn new(mut device: Device, id: SessionId) -> Result<Self, Error> {
273 let Some((sender, receiver)) = generic_channel::channel() else {
274 return Err(Error::CommunicationError);
275 };
276 device.set_quitter(Quitter {
277 sender: sender.clone(),
278 });
279 let frame_count = 0;
280 let running = true;
281 let layers = Vec::new();
282 let pending_layers = None;
283 Ok(SessionThread {
284 sender,
285 receiver,
286 device,
287 layers,
288 pending_layers,
289 frame_count,
290 frame_sender: None,
291 running,
292 id,
293 render_state: RenderState::NotInRenderLoop,
294 })
295 }
296
297 pub fn new_session(&mut self) -> Session {
298 let floor_transform = self.device.floor_transform();
299 let viewports = self.device.viewports();
300 let sender = self.sender.clone();
301 let initial_inputs = self.device.initial_inputs();
302 let environment_blend_mode = self.device.environment_blend_mode();
303 let granted_features = self.device.granted_features().into();
304 let supported_frame_rates = self.device.supported_frame_rates();
305 Session {
306 floor_transform,
307 viewports,
308 sender,
309 initial_inputs,
310 environment_blend_mode,
311 granted_features,
312 id: self.id,
313 supported_frame_rates,
314 }
315 }
316
317 pub fn run(&mut self) {
318 while let Ok(msg) = self.receiver.recv() {
319 if !self.handle_msg(msg) {
320 self.running = false;
321 break;
322 }
323 }
324 }
325
326 fn handle_msg(&mut self, msg: SessionMsg) -> bool {
327 log::debug!("processing {:?}", msg);
328 match msg {
329 SessionMsg::SetEventDest(dest) => {
330 self.device.set_event_dest(dest);
331 },
332 SessionMsg::SetFrameDest(dest) => {
333 self.frame_sender = Some(dest);
334 },
335 SessionMsg::RequestHitTest(source) => {
336 self.device.request_hit_test(source);
337 },
338 SessionMsg::CancelHitTest(id) => {
339 self.device.cancel_hit_test(id);
340 },
341 SessionMsg::CreateLayer(context_id, layer_init, sender) => {
342 let result = self.device.create_layer(context_id, layer_init);
343 let _ = sender.send(result);
344 },
345 SessionMsg::DestroyLayer(context_id, layer_id) => {
346 self.layers.retain(|&(_, other_id)| layer_id != other_id);
347 self.device.destroy_layer(context_id, layer_id);
348 },
349 SessionMsg::SetLayers(layers) => {
350 self.pending_layers = Some(layers);
351 },
352 SessionMsg::StartRenderLoop => {
353 if let Some(layers) = self.pending_layers.take() {
354 self.layers = layers;
355 }
356 let frame = match self.device.begin_animation_frame(&self.layers[..]) {
357 Some(frame) => frame,
358 None => {
359 warn!("Device stopped providing frames, exiting");
360 return false;
361 },
362 };
363 self.render_state = RenderState::InRenderLoop;
364 self.send_frame(frame);
365 },
366 SessionMsg::UpdateClipPlanes(near, far) => self.device.update_clip_planes(near, far),
367 SessionMsg::RenderAnimationFrame => {
368 self.frame_count += 1;
369
370 self.device.end_animation_frame(&self.layers[..]);
371
372 if self.render_state == RenderState::PendingQuit {
373 self.quit();
374 return false;
375 }
376
377 if let Some(layers) = self.pending_layers.take() {
378 self.layers = layers;
379 }
380 #[expect(unused_mut)]
381 let mut frame = match self.device.begin_animation_frame(&self.layers[..]) {
382 Some(frame) => frame,
383 None => {
384 warn!("Device stopped providing frames, exiting");
385 return false;
386 },
387 };
388
389 self.send_frame(frame);
390 },
391 SessionMsg::UpdateFrameRate(rate, sender) => {
392 let new_framerate = self.device.update_frame_rate(rate);
393 let _ = sender.send(new_framerate);
394 },
395 SessionMsg::Quit => {
396 if self.render_state == RenderState::NotInRenderLoop {
397 self.quit();
398 return false;
399 } else {
400 self.render_state = RenderState::PendingQuit;
401 }
402 },
403 SessionMsg::GetBoundsGeometry(sender) => {
404 let bounds = self.device.reference_space_bounds();
405 let _ = sender.send(bounds);
406 },
407 }
408 true
409 }
410
411 fn send_frame(&self, frame: Frame) {
412 if let Some(frame_sender) = &self.frame_sender {
413 let _ = frame_sender.send(frame);
414 }
415 }
416
417 fn quit(&mut self) {
418 self.render_state = RenderState::NotInRenderLoop;
419 self.device.quit();
420 }
421}
422
423pub trait MainThreadSession: 'static {
425 fn run_one_frame(&mut self);
426 fn running(&self) -> bool;
427}
428
429impl<Device> MainThreadSession for SessionThread<Device>
430where
431 Device: DeviceAPI,
432{
433 fn run_one_frame(&mut self) {
434 let frame_count = self.frame_count;
435 while frame_count == self.frame_count && self.running {
436 if let Ok(msg) = self.receiver.try_recv_timeout(TIMEOUT) {
437 self.running = self.handle_msg(msg);
438 } else {
439 break;
440 }
441 }
442 }
443
444 fn running(&self) -> bool {
445 self.running
446 }
447}
448
449pub struct SessionBuilder<'a, GL> {
451 sessions: &'a mut Vec<Box<dyn MainThreadSession>>,
452 layer_grand_manager: LayerGrandManager<GL>,
453 id: SessionId,
454}
455
456impl<'a, GL: 'static> SessionBuilder<'a, GL> {
457 pub fn id(&self) -> SessionId {
458 self.id
459 }
460
461 pub(crate) fn new(
462 sessions: &'a mut Vec<Box<dyn MainThreadSession>>,
463 layer_grand_manager: LayerGrandManager<GL>,
464 id: SessionId,
465 ) -> Self {
466 SessionBuilder {
467 sessions,
468 layer_grand_manager,
469 id,
470 }
471 }
472
473 pub fn spawn<Device, Factory>(self, factory: Factory) -> Result<Session, Error>
475 where
476 Factory: 'static + FnOnce(LayerGrandManager<GL>) -> Result<Device, Error> + Send,
477 Device: DeviceAPI,
478 {
479 let Some((acks, ackr)) = generic_channel::channel() else {
480 return Err(Error::CommunicationError);
481 };
482 let layer_grand_manager = self.layer_grand_manager;
483 let id = self.id;
484 thread::spawn(move || {
485 match factory(layer_grand_manager).and_then(|device| SessionThread::new(device, id)) {
486 Ok(mut thread) => {
487 let session = thread.new_session();
488 let _ = acks.send(Ok(session));
489 thread.run();
490 },
491 Err(err) => {
492 let _ = acks.send(Err(err));
493 },
494 }
495 });
496 ackr.recv().unwrap_or(Err(Error::CommunicationError))
497 }
498
499 pub fn run_on_main_thread<Device, Factory>(self, factory: Factory) -> Result<Session, Error>
501 where
502 Factory: 'static + FnOnce(LayerGrandManager<GL>) -> Result<Device, Error>,
503 Device: DeviceAPI,
504 {
505 let device = factory(self.layer_grand_manager)?;
506 let mut session_thread = SessionThread::new(device, self.id)?;
507 let session = session_thread.new_session();
508 self.sessions.push(Box::new(session_thread));
509 Ok(session)
510 }
511}