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