Auto merge of #22911 - Manishearth:xr-spec-fixes, r=jdm

Some XR spec fixes

Tie in some concepts that were previously left out of the
implementation.

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/22911)
<!-- Reviewable:end -->
This commit is contained in:
bors-servo 2019-02-19 11:09:22 -05:00 committed by GitHub
commit cc8a9fa928
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 69 additions and 10 deletions

View file

@ -4,6 +4,7 @@
use crate::dom::bindings::callback::ExceptionHandling; use crate::dom::bindings::callback::ExceptionHandling;
use crate::dom::bindings::cell::DomRefCell; use crate::dom::bindings::cell::DomRefCell;
use crate::dom::bindings::codegen::Bindings::NavigatorBinding::NavigatorMethods;
use crate::dom::bindings::codegen::Bindings::PerformanceBinding::PerformanceMethods; use crate::dom::bindings::codegen::Bindings::PerformanceBinding::PerformanceMethods;
use crate::dom::bindings::codegen::Bindings::VRDisplayBinding; use crate::dom::bindings::codegen::Bindings::VRDisplayBinding;
use crate::dom::bindings::codegen::Bindings::VRDisplayBinding::VRDisplayMethods; use crate::dom::bindings::codegen::Bindings::VRDisplayBinding::VRDisplayMethods;
@ -13,6 +14,7 @@ use crate::dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::WebGL
use crate::dom::bindings::codegen::Bindings::WindowBinding::FrameRequestCallback; use crate::dom::bindings::codegen::Bindings::WindowBinding::FrameRequestCallback;
use crate::dom::bindings::codegen::Bindings::WindowBinding::WindowMethods; use crate::dom::bindings::codegen::Bindings::WindowBinding::WindowMethods;
use crate::dom::bindings::codegen::Bindings::XRSessionBinding::XRFrameRequestCallback; use crate::dom::bindings::codegen::Bindings::XRSessionBinding::XRFrameRequestCallback;
use crate::dom::bindings::error::Error;
use crate::dom::bindings::inheritance::Castable; use crate::dom::bindings::inheritance::Castable;
use crate::dom::bindings::num::Finite; use crate::dom::bindings::num::Finite;
use crate::dom::bindings::refcounted::{Trusted, TrustedPromise}; use crate::dom::bindings::refcounted::{Trusted, TrustedPromise};
@ -347,6 +349,24 @@ impl VRDisplayMethods for VRDisplay {
}, },
}; };
// WebVR spec: Repeat calls while already presenting will update the VRLayers being displayed.
if self.presenting.get() {
*self.layer.borrow_mut() = layer_bounds;
self.layer_ctx.set(Some(&layer_ctx));
promise.resolve_native(&());
return promise;
}
let xr = self.global().as_window().Navigator().Xr();
if xr.pending_or_active_session() {
// WebVR spec doesn't mandate anything here, however
// the WebXR spec expects there to be only one immersive XR session at a time,
// and WebVR is deprecated
promise.reject_error(Error::InvalidState);
return promise;
}
self.request_present(layer_bounds, Some(&layer_ctx), Some(promise.clone()), |p| { self.request_present(layer_bounds, Some(&layer_ctx), Some(promise.clone()), |p| {
p.resolve_native(&()) p.resolve_native(&())
}); });
@ -447,14 +467,6 @@ impl VRDisplay {
) where ) where
F: FnOnce(Rc<Promise>) + Send + 'static, F: FnOnce(Rc<Promise>) + Send + 'static,
{ {
// WebVR spec: Repeat calls while already presenting will update the VRLayers being displayed.
if self.presenting.get() {
*self.layer.borrow_mut() = layer_bounds;
self.layer_ctx.set(ctx);
promise.map(resolve);
return;
}
// Request Present // Request Present
let (sender, receiver) = ipc::channel(self.global().time_profiler_chan().clone()).unwrap(); let (sender, receiver) = ipc::channel(self.global().time_profiler_chan().clone()).unwrap();
self.webvr_thread() self.webvr_thread()
@ -557,6 +569,8 @@ impl VRDisplay {
fn init_present(&self) { fn init_present(&self) {
self.presenting.set(true); self.presenting.set(true);
let xr = self.global().as_window().Navigator().Xr();
xr.set_active_immersive_session(&self);
let (sync_sender, sync_receiver) = webgl_channel().unwrap(); let (sync_sender, sync_receiver) = webgl_channel().unwrap();
*self.frame_data_receiver.borrow_mut() = Some(sync_receiver); *self.frame_data_receiver.borrow_mut() = Some(sync_receiver);
@ -623,6 +637,8 @@ impl VRDisplay {
fn stop_present(&self) { fn stop_present(&self) {
self.presenting.set(false); self.presenting.set(false);
let xr = self.global().as_window().Navigator().Xr();
xr.deactivate_session();
*self.frame_data_receiver.borrow_mut() = None; *self.frame_data_receiver.borrow_mut() = None;
let api_sender = self.layer_ctx.get().unwrap().webgl_sender(); let api_sender = self.layer_ctx.get().unwrap().webgl_sender();

View file

@ -17,7 +17,7 @@ interface XRSession : EventTarget {
// // Attributes // // Attributes
readonly attribute XRSessionMode mode; readonly attribute XRSessionMode mode;
// readonly attribute XRPresentationContext outputContext; // readonly attribute XRPresentationContext outputContext;
// readonly attribute XREnvironmentBlendMode environmentBlendMode; readonly attribute XREnvironmentBlendMode environmentBlendMode;
attribute double depthNear; attribute double depthNear;
attribute double depthFar; attribute double depthFar;

View file

@ -10,7 +10,7 @@ use crate::dom::bindings::codegen::Bindings::XRBinding::{XRMethods, XRSessionMod
use crate::dom::bindings::error::Error; use crate::dom::bindings::error::Error;
use crate::dom::bindings::inheritance::Castable; use crate::dom::bindings::inheritance::Castable;
use crate::dom::bindings::reflector::{reflect_dom_object, DomObject}; use crate::dom::bindings::reflector::{reflect_dom_object, DomObject};
use crate::dom::bindings::root::{Dom, DomRoot}; use crate::dom::bindings::root::{Dom, DomRoot, MutNullableDom};
use crate::dom::event::Event; use crate::dom::event::Event;
use crate::dom::eventtarget::EventTarget; use crate::dom::eventtarget::EventTarget;
use crate::dom::gamepad::Gamepad; use crate::dom::gamepad::Gamepad;
@ -23,6 +23,7 @@ use crate::dom::xrsession::XRSession;
use dom_struct::dom_struct; use dom_struct::dom_struct;
use ipc_channel::ipc::IpcSender; use ipc_channel::ipc::IpcSender;
use profile_traits::ipc; use profile_traits::ipc;
use std::cell::Cell;
use std::rc::Rc; use std::rc::Rc;
use webvr_traits::{WebVRDisplayData, WebVRDisplayEvent, WebVREvent, WebVRMsg}; use webvr_traits::{WebVRDisplayData, WebVRDisplayEvent, WebVREvent, WebVRMsg};
use webvr_traits::{WebVRGamepadData, WebVRGamepadEvent, WebVRGamepadState}; use webvr_traits::{WebVRGamepadData, WebVRGamepadEvent, WebVRGamepadState};
@ -32,6 +33,8 @@ pub struct XR {
eventtarget: EventTarget, eventtarget: EventTarget,
displays: DomRefCell<Vec<Dom<VRDisplay>>>, displays: DomRefCell<Vec<Dom<VRDisplay>>>,
gamepads: DomRefCell<Vec<Dom<Gamepad>>>, gamepads: DomRefCell<Vec<Dom<Gamepad>>>,
pending_immersive_session: Cell<bool>,
active_immersive_session: MutNullableDom<VRDisplay>,
} }
impl XR { impl XR {
@ -40,6 +43,8 @@ impl XR {
eventtarget: EventTarget::new_inherited(), eventtarget: EventTarget::new_inherited(),
displays: DomRefCell::new(Vec::new()), displays: DomRefCell::new(Vec::new()),
gamepads: DomRefCell::new(Vec::new()), gamepads: DomRefCell::new(Vec::new()),
pending_immersive_session: Cell::new(false),
active_immersive_session: Default::default(),
} }
} }
@ -48,6 +53,26 @@ impl XR {
root.register(); root.register();
root root
} }
pub fn pending_or_active_session(&self) -> bool {
self.pending_immersive_session.get() || self.active_immersive_session.get().is_some()
}
pub fn set_pending(&self) {
self.pending_immersive_session.set(true)
}
pub fn set_active_immersive_session(&self, session: &VRDisplay) {
// XXXManishearth when we support non-immersive (inline) sessions we should
// ensure they never reach these codepaths
self.pending_immersive_session.set(false);
self.active_immersive_session.set(Some(session))
}
pub fn deactivate_session(&self) {
self.pending_immersive_session.set(false);
self.active_immersive_session.set(None)
}
} }
impl Drop for XR { impl Drop for XR {
@ -79,6 +104,13 @@ impl XRMethods for XR {
return promise; return promise;
} }
if self.pending_or_active_session() {
promise.reject_error(Error::InvalidState);
return promise;
}
// we set pending immersive session to true further down
// to handle rejections in a cleaner way
let displays = self.get_displays(); let displays = self.get_displays();
let displays = match displays { let displays = match displays {
@ -94,6 +126,8 @@ impl XRMethods for XR {
promise.reject_error(Error::Security); promise.reject_error(Error::Security);
} }
self.set_pending();
let session = XRSession::new(&self.global(), &displays[0]); let session = XRSession::new(&self.global(), &displays[0]);
session.xr_present(promise.clone()); session.xr_present(promise.clone());
promise promise

View file

@ -5,6 +5,7 @@
use crate::dom::bindings::codegen::Bindings::VRDisplayBinding::VRDisplayMethods; use crate::dom::bindings::codegen::Bindings::VRDisplayBinding::VRDisplayMethods;
use crate::dom::bindings::codegen::Bindings::XRBinding::XRSessionMode; use crate::dom::bindings::codegen::Bindings::XRBinding::XRSessionMode;
use crate::dom::bindings::codegen::Bindings::XRSessionBinding; use crate::dom::bindings::codegen::Bindings::XRSessionBinding;
use crate::dom::bindings::codegen::Bindings::XRSessionBinding::XREnvironmentBlendMode;
use crate::dom::bindings::codegen::Bindings::XRSessionBinding::XRFrameRequestCallback; use crate::dom::bindings::codegen::Bindings::XRSessionBinding::XRFrameRequestCallback;
use crate::dom::bindings::codegen::Bindings::XRSessionBinding::XRSessionMethods; use crate::dom::bindings::codegen::Bindings::XRSessionBinding::XRSessionMethods;
use crate::dom::bindings::codegen::Bindings::XRWebGLLayerBinding::XRWebGLLayerMethods; use crate::dom::bindings::codegen::Bindings::XRWebGLLayerBinding::XRWebGLLayerMethods;
@ -26,6 +27,7 @@ pub struct XRSession {
eventtarget: EventTarget, eventtarget: EventTarget,
display: Dom<VRDisplay>, display: Dom<VRDisplay>,
base_layer: MutNullableDom<XRLayer>, base_layer: MutNullableDom<XRLayer>,
blend_mode: XREnvironmentBlendMode,
} }
impl XRSession { impl XRSession {
@ -34,6 +36,8 @@ impl XRSession {
eventtarget: EventTarget::new_inherited(), eventtarget: EventTarget::new_inherited(),
display: Dom::from_ref(display), display: Dom::from_ref(display),
base_layer: Default::default(), base_layer: Default::default(),
// we don't yet support any AR devices
blend_mode: XREnvironmentBlendMode::Opaque,
} }
} }
@ -102,4 +106,9 @@ impl XRSessionMethods for XRSession {
fn CancelAnimationFrame(&self, frame: i32) { fn CancelAnimationFrame(&self, frame: i32) {
self.display.xr_cancel_raf(frame) self.display.xr_cancel_raf(frame)
} }
/// https://immersive-web.github.io/webxr/#dom-xrsession-environmentblendmode
fn EnvironmentBlendMode(&self) -> XREnvironmentBlendMode {
self.blend_mode
}
} }