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