From d681909b28c347d435b7f4dfee4a6a3814bcec38 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Thu, 5 Dec 2019 13:08:03 -0800 Subject: [PATCH 1/9] Bump webxr --- Cargo.lock | 4 ++-- components/script/dom/xrviewerpose.rs | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1d33fbf85da..90c660a1f70 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6391,7 +6391,7 @@ dependencies = [ [[package]] name = "webxr" version = "0.0.1" -source = "git+https://github.com/servo/webxr#e44552df536a6f424d58ccd068aa0301fee5fa1e" +source = "git+https://github.com/servo/webxr#29f4f1f28695553c45d6c020172048c0035c49ed" dependencies = [ "bindgen", "euclid", @@ -6411,7 +6411,7 @@ dependencies = [ [[package]] name = "webxr-api" version = "0.0.1" -source = "git+https://github.com/servo/webxr#e44552df536a6f424d58ccd068aa0301fee5fa1e" +source = "git+https://github.com/servo/webxr#29f4f1f28695553c45d6c020172048c0035c49ed" dependencies = [ "euclid", "ipc-channel", diff --git a/components/script/dom/xrviewerpose.rs b/components/script/dom/xrviewerpose.rs index 8ebabc0781f..1a5aacd0c91 100644 --- a/components/script/dom/xrviewerpose.rs +++ b/components/script/dom/xrviewerpose.rs @@ -42,6 +42,7 @@ impl XRViewerPose { ) -> DomRoot { rooted_vec!(let mut views); session.with_session(|s| match s.views() { + Views::Inline => unimplemented!(), Views::Mono(view) => { views.push(XRView::new(global, session, &view, XREye::None, &pose)) }, From 2066a5509a69a6ad4a1c5d1c03d0e4f0415ee338 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Thu, 5 Dec 2019 13:29:21 -0800 Subject: [PATCH 2/9] Allow constructing inline sessions --- components/script/dom/xr.rs | 37 ++++++++++++++++++++++-------- components/script/dom/xrsession.rs | 7 +++++- 2 files changed, 33 insertions(+), 11 deletions(-) diff --git a/components/script/dom/xr.rs b/components/script/dom/xr.rs index a916d7a8267..4f5a90e89c4 100644 --- a/components/script/dom/xr.rs +++ b/components/script/dom/xr.rs @@ -42,6 +42,7 @@ pub struct XR { gamepads: DomRefCell>>, pending_immersive_session: Cell, active_immersive_session: MutNullableDom, + active_inline_sessions: DomRefCell>>, test: MutNullableDom, } @@ -53,6 +54,7 @@ impl XR { gamepads: DomRefCell::new(Vec::new()), pending_immersive_session: Cell::new(false), active_immersive_session: Default::default(), + active_inline_sessions: DomRefCell::new(Vec::new()), test: Default::default(), } } @@ -86,7 +88,9 @@ impl XR { self.active_immersive_session.set(None); } } - // XXXManishearth when we support inline sessions we should remove them too + self.active_inline_sessions + .borrow_mut() + .retain(|sess| Dom::from_ref(&**sess) != Dom::from_ref(session)); } } @@ -163,12 +167,14 @@ impl XRMethods for XR { return promise; } - if self.pending_or_active_session() { - promise.reject_error(Error::InvalidState); - return promise; - } + if mode != XRSessionMode::Inline { + if self.pending_or_active_session() { + promise.reject_error(Error::InvalidState); + return promise; + } - self.set_pending(); + self.set_pending(); + } let promise = Promise::new_in_current_compartment(&self.global(), comp); let mut trusted = Some(TrustedPromise::new(promise.clone())); @@ -193,7 +199,7 @@ impl XRMethods for XR { }; let _ = task_source.queue_with_canceller( task!(request_session: move || { - this.root().session_obtained(message, trusted.root()); + this.root().session_obtained(message, trusted.root(), mode); }), &canceller, ); @@ -211,7 +217,12 @@ impl XRMethods for XR { } impl XR { - fn session_obtained(&self, response: Result, promise: Rc) { + fn session_obtained( + &self, + response: Result, + promise: Rc, + mode: XRSessionMode, + ) { let session = match response { Ok(session) => session, Err(_) => { @@ -220,8 +231,14 @@ impl XR { }, }; - let session = XRSession::new(&self.global(), session); - self.set_active_immersive_session(&session); + let session = XRSession::new(&self.global(), session, mode); + if mode == XRSessionMode::Inline { + self.active_inline_sessions + .borrow_mut() + .push(Dom::from_ref(&*session)); + } else { + self.set_active_immersive_session(&session); + } promise.resolve_native(&session); } diff --git a/components/script/dom/xrsession.rs b/components/script/dom/xrsession.rs index 438705853f6..64f90d38118 100644 --- a/components/script/dom/xrsession.rs +++ b/components/script/dom/xrsession.rs @@ -8,6 +8,7 @@ use crate::dom::bindings::cell::DomRefCell; use crate::dom::bindings::codegen::Bindings::NavigatorBinding::NavigatorBinding::NavigatorMethods; use crate::dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::WebGLRenderingContextMethods; use crate::dom::bindings::codegen::Bindings::WindowBinding::WindowBinding::WindowMethods; +use crate::dom::bindings::codegen::Bindings::XRBinding::XRSessionMode; use crate::dom::bindings::codegen::Bindings::XRReferenceSpaceBinding::XRReferenceSpaceType; use crate::dom::bindings::codegen::Bindings::XRRenderStateBinding::XRRenderStateInit; use crate::dom::bindings::codegen::Bindings::XRRenderStateBinding::XRRenderStateMethods; @@ -56,6 +57,7 @@ pub struct XRSession { eventtarget: EventTarget, base_layer: MutNullableDom, blend_mode: XREnvironmentBlendMode, + mode: XRSessionMode, visibility_state: Cell, viewer_space: MutNullableDom, #[ignore_malloc_size_of = "defined in webxr"] @@ -85,11 +87,13 @@ impl XRSession { session: Session, render_state: &XRRenderState, input_sources: &XRInputSourceArray, + mode: XRSessionMode, ) -> XRSession { XRSession { eventtarget: EventTarget::new_inherited(), base_layer: Default::default(), blend_mode: session.environment_blend_mode().into(), + mode, visibility_state: Cell::new(XRVisibilityState::Visible), viewer_space: Default::default(), session: DomRefCell::new(session), @@ -107,7 +111,7 @@ impl XRSession { } } - pub fn new(global: &GlobalScope, session: Session) -> DomRoot { + pub fn new(global: &GlobalScope, session: Session, mode: XRSessionMode) -> DomRoot { let render_state = XRRenderState::new(global, 0.1, 1000.0, None); let input_sources = XRInputSourceArray::new(global); let ret = reflect_dom_object( @@ -115,6 +119,7 @@ impl XRSession { session, &render_state, &input_sources, + mode, )), global, XRSessionBinding::Wrap, From a64e02a4517b04365678ea983cec1a645db0e461 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Thu, 5 Dec 2019 13:41:15 -0800 Subject: [PATCH 3/9] Add inlineVerticalFieldOfView support --- .../script/dom/webidls/XRRenderState.webidl | 2 ++ components/script/dom/xrrenderstate.rs | 20 ++++++++++++++++++- components/script/dom/xrsession.rs | 14 ++++++++----- 3 files changed, 30 insertions(+), 6 deletions(-) diff --git a/components/script/dom/webidls/XRRenderState.webidl b/components/script/dom/webidls/XRRenderState.webidl index 01d7fd39191..29d0232b21d 100644 --- a/components/script/dom/webidls/XRRenderState.webidl +++ b/components/script/dom/webidls/XRRenderState.webidl @@ -7,11 +7,13 @@ dictionary XRRenderStateInit { double depthNear; double depthFar; + double inlineVerticalFieldOfView; XRWebGLLayer baseLayer; }; [SecureContext, Exposed=Window, Pref="dom.webxr.enabled"] interface XRRenderState { readonly attribute double depthNear; readonly attribute double depthFar; + readonly attribute double inlineVerticalFieldOfView; readonly attribute XRWebGLLayer? baseLayer; }; diff --git a/components/script/dom/xrrenderstate.rs b/components/script/dom/xrrenderstate.rs index 2aba4e46493..bbaf41385ab 100644 --- a/components/script/dom/xrrenderstate.rs +++ b/components/script/dom/xrrenderstate.rs @@ -17,6 +17,7 @@ pub struct XRRenderState { reflector_: Reflector, depth_near: Cell, depth_far: Cell, + inline_vertical_fov: Cell, layer: MutNullableDom, } @@ -24,12 +25,14 @@ impl XRRenderState { pub fn new_inherited( depth_near: f64, depth_far: f64, + inline_vertical_fov: f64, layer: Option<&XRWebGLLayer>, ) -> XRRenderState { XRRenderState { reflector_: Reflector::new(), depth_near: Cell::new(depth_near), depth_far: Cell::new(depth_far), + inline_vertical_fov: Cell::new(inline_vertical_fov), layer: MutNullableDom::new(layer), } } @@ -38,10 +41,16 @@ impl XRRenderState { global: &GlobalScope, depth_near: f64, depth_far: f64, + inline_vertical_fov: f64, layer: Option<&XRWebGLLayer>, ) -> DomRoot { reflect_dom_object( - Box::new(XRRenderState::new_inherited(depth_near, depth_far, layer)), + Box::new(XRRenderState::new_inherited( + depth_near, + depth_far, + inline_vertical_fov, + layer, + )), global, XRRenderStateBinding::Wrap, ) @@ -52,6 +61,7 @@ impl XRRenderState { &self.global(), self.depth_near.get(), self.depth_far.get(), + self.inline_vertical_fov.get(), self.layer.get().as_ref().map(|x| &**x), ) } @@ -62,6 +72,9 @@ impl XRRenderState { pub fn set_depth_far(&self, depth: f64) { self.depth_far.set(depth) } + pub fn set_inline_vertical_fov(&self, fov: f64) { + self.inline_vertical_fov.set(fov) + } pub fn set_layer(&self, layer: Option<&XRWebGLLayer>) { self.layer.set(layer) } @@ -78,6 +91,11 @@ impl XRRenderStateMethods for XRRenderState { Finite::wrap(self.depth_far.get()) } + /// https://immersive-web.github.io/webxr/#dom-xrrenderstate-inlineverticalfieldofview + fn InlineVerticalFieldOfView(&self) -> Finite { + Finite::wrap(self.inline_vertical_fov.get()) + } + /// https://immersive-web.github.io/webxr/#dom-xrrenderstate-baselayer fn GetBaseLayer(&self) -> Option> { self.layer.get() diff --git a/components/script/dom/xrsession.rs b/components/script/dom/xrsession.rs index 64f90d38118..d2b31b692e1 100644 --- a/components/script/dom/xrsession.rs +++ b/components/script/dom/xrsession.rs @@ -112,7 +112,8 @@ impl XRSession { } pub fn new(global: &GlobalScope, session: Session, mode: XRSessionMode) -> DomRoot { - let render_state = XRRenderState::new(global, 0.1, 1000.0, None); + use std::f64::consts::FRAC_PI_2; + let render_state = XRRenderState::new(global, 0.1, 1000.0, FRAC_PI_2, None); let input_sources = XRInputSourceArray::new(global); let ret = reflect_dom_object( Box::new(XRSession::new_inherited( @@ -399,9 +400,10 @@ impl XRSessionMethods for XRSession { } } - // XXXManishearth step 4: - // If newState’s inlineVerticalFieldOfView is set and session is an - // immersive session, throw an InvalidStateError and abort these steps. + // Step 4: + if init.inlineVerticalFieldOfView.is_some() { + return Err(Error::InvalidState); + } let pending = self .pending_render_state @@ -412,6 +414,9 @@ impl XRSessionMethods for XRSession { if let Some(far) = init.depthFar { pending.set_depth_far(*far); } + if let Some(fov) = init.inlineVerticalFieldOfView { + pending.set_inline_vertical_fov(*fov); + } if let Some(ref layer) = init.baseLayer { pending.set_layer(Some(&layer)) } @@ -421,7 +426,6 @@ impl XRSessionMethods for XRSession { .borrow_mut() .update_clip_planes(*pending.DepthNear() as f32, *pending.DepthFar() as f32); } - // XXXManishearth handle inlineVerticalFieldOfView Ok(()) } From a1c1a16e9818cff45f2fba24ba2f71651de9ff6d Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Thu, 5 Dec 2019 14:28:13 -0800 Subject: [PATCH 4/9] Add inline support to XRWebGLLayer --- .../script/dom/webidls/XRWebGLLayer.webidl | 2 +- components/script/dom/xrwebgllayer.rs | 46 +++++++++++-------- 2 files changed, 27 insertions(+), 21 deletions(-) diff --git a/components/script/dom/webidls/XRWebGLLayer.webidl b/components/script/dom/webidls/XRWebGLLayer.webidl index 40091ccc73e..dd2420dd13a 100644 --- a/components/script/dom/webidls/XRWebGLLayer.webidl +++ b/components/script/dom/webidls/XRWebGLLayer.webidl @@ -30,7 +30,7 @@ interface XRWebGLLayer { readonly attribute boolean stencil; readonly attribute boolean alpha; - readonly attribute WebGLFramebuffer framebuffer; + readonly attribute WebGLFramebuffer? framebuffer; readonly attribute unsigned long framebufferWidth; readonly attribute unsigned long framebufferHeight; diff --git a/components/script/dom/xrwebgllayer.rs b/components/script/dom/xrwebgllayer.rs index 44bc10868b6..2d39a47286b 100644 --- a/components/script/dom/xrwebgllayer.rs +++ b/components/script/dom/xrwebgllayer.rs @@ -20,6 +20,7 @@ use crate::dom::xrview::XRView; use crate::dom::xrviewport::XRViewport; use canvas_traits::webgl::WebGLFramebufferId; use dom_struct::dom_struct; +use euclid::default::Size2D; use std::convert::TryInto; use webxr_api::SwapChainId as WebXRSwapChainId; use webxr_api::Views; @@ -35,7 +36,8 @@ pub struct XRWebGLLayer { swap_chain_id: WebXRSwapChainId, context: Dom, session: Dom, - framebuffer: Dom, + /// If none, this is an inline session (the composition disabled flag is true) + framebuffer: Option>, } impl XRWebGLLayer { @@ -44,7 +46,7 @@ impl XRWebGLLayer { session: &XRSession, context: &WebGLRenderingContext, init: &XRWebGLLayerInit, - framebuffer: &WebGLFramebuffer, + framebuffer: Option<&WebGLFramebuffer>, ) -> XRWebGLLayer { XRWebGLLayer { reflector_: Reflector::new(), @@ -55,7 +57,7 @@ impl XRWebGLLayer { swap_chain_id, context: Dom::from_ref(context), session: Dom::from_ref(session), - framebuffer: Dom::from_ref(framebuffer), + framebuffer: framebuffer.map(Dom::from_ref), } } @@ -65,7 +67,7 @@ impl XRWebGLLayer { session: &XRSession, context: &WebGLRenderingContext, init: &XRWebGLLayerInit, - framebuffer: &WebGLFramebuffer, + framebuffer: Option<&WebGLFramebuffer>, ) -> DomRoot { reflect_dom_object( Box::new(XRWebGLLayer::new_inherited( @@ -115,7 +117,7 @@ impl XRWebGLLayer { session, context, init, - &framebuffer, + Some(&framebuffer), )) } @@ -128,10 +130,24 @@ impl XRWebGLLayer { } pub fn swap_buffers(&self) { - if let WebGLFramebufferId::Opaque(id) = self.framebuffer.id() { + if let WebGLFramebufferId::Opaque(id) = self + .framebuffer + .as_ref() + .expect("Must have framebuffer") + .id() + { self.context.swap_buffers(Some(id)); } } + + fn size(&self) -> Size2D { + if let Some(framebuffer) = self.framebuffer { + let size = framebuffer.size().unwrap_or((0, 0)); + Size2D::new(size.0, size.1) + } else { + self.context.Canvas().get_size() + } + } } impl XRWebGLLayerMethods for XRWebGLLayer { @@ -161,28 +177,18 @@ impl XRWebGLLayerMethods for XRWebGLLayer { } /// https://immersive-web.github.io/webxr/#dom-xrwebgllayer-framebuffer - fn Framebuffer(&self) -> DomRoot { - DomRoot::from_ref(&self.framebuffer) + fn GetFramebuffer(&self) -> Option> { + self.framebuffer.as_ref().map(|x| DomRoot::from_ref(&**x)) } /// https://immersive-web.github.io/webxr/#dom-xrwebgllayer-framebufferwidth fn FramebufferWidth(&self) -> u32 { - self.framebuffer - .size() - .unwrap_or((0, 0)) - .0 - .try_into() - .unwrap_or(0) + self.size().width.try_into().unwrap_or(0) } /// https://immersive-web.github.io/webxr/#dom-xrwebgllayer-framebufferheight fn FramebufferHeight(&self) -> u32 { - self.framebuffer - .size() - .unwrap_or((0, 0)) - .1 - .try_into() - .unwrap_or(0) + self.size().height.try_into().unwrap_or(0) } /// https://immersive-web.github.io/webxr/#dom-xrwebgllayer-getviewport From 8aaa8493a799771d4250fe5692ec413b6fc2d942 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Thu, 5 Dec 2019 15:08:09 -0800 Subject: [PATCH 5/9] Give inline sessions the correct projection matrices --- components/script/dom/bindings/trace.rs | 18 ++++++- components/script/dom/xrsession.rs | 66 ++++++++++++++++++++++--- components/script/dom/xrviewerpose.rs | 8 ++- components/script/dom/xrwebgllayer.rs | 43 ++++++++++------ 4 files changed, 108 insertions(+), 27 deletions(-) diff --git a/components/script/dom/bindings/trace.rs b/components/script/dom/bindings/trace.rs index e8818d316ac..9dad0da9cd3 100644 --- a/components/script/dom/bindings/trace.rs +++ b/components/script/dom/bindings/trace.rs @@ -61,7 +61,7 @@ use cssparser::RGBA; use devtools_traits::{CSSError, TimelineMarkerType, WorkerId}; use embedder_traits::{EventLoopWaker, MediaMetadata}; use encoding_rs::{Decoder, Encoding}; -use euclid::default::{Point2D, Rect, Rotation3D, Transform2D, Transform3D}; +use euclid::default::{Point2D, Rect, Rotation3D, Transform2D}; use euclid::Length as EuclidLength; use html5ever::buffer_queue::BufferQueue; use html5ever::{LocalName, Namespace, Prefix, QualName}; @@ -534,7 +534,7 @@ unsafe_no_jsmanaged_fields!(Mutex); unsafe_no_jsmanaged_fields!(ResourceFetchTiming); unsafe_no_jsmanaged_fields!(Timespec); unsafe_no_jsmanaged_fields!(HTMLMediaElementFetchContext); -unsafe_no_jsmanaged_fields!(Rotation3D, Transform2D, Transform3D); +unsafe_no_jsmanaged_fields!(Rotation3D, Transform2D); unsafe_no_jsmanaged_fields!(Point2D, Rect); unsafe_no_jsmanaged_fields!(Rect); unsafe_no_jsmanaged_fields!(CascadeData); @@ -665,6 +665,20 @@ unsafe impl JSTraceable for euclid::RigidTransform3D { } } +unsafe impl JSTraceable for euclid::Transform3D { + #[inline] + unsafe fn trace(&self, _trc: *mut JSTracer) { + // Do nothing + } +} + +unsafe impl JSTraceable for euclid::Transform3D { + #[inline] + unsafe fn trace(&self, _trc: *mut JSTracer) { + // Do nothing + } +} + unsafe impl JSTraceable for EuclidLength { #[inline] unsafe fn trace(&self, _trc: *mut JSTracer) { diff --git a/components/script/dom/xrsession.rs b/components/script/dom/xrsession.rs index d2b31b692e1..1ffe7ff77c3 100644 --- a/components/script/dom/xrsession.rs +++ b/components/script/dom/xrsession.rs @@ -40,7 +40,7 @@ use crate::dom::xrspace::XRSpace; use crate::dom::xrwebgllayer::XRWebGLLayer; use crate::task_source::TaskSource; use dom_struct::dom_struct; -use euclid::RigidTransform3D; +use euclid::{Rect, RigidTransform3D, Transform3D}; use ipc_channel::ipc::IpcSender; use ipc_channel::router::ROUTER; use profile_traits::ipc; @@ -48,8 +48,8 @@ use std::cell::Cell; use std::mem; use std::rc::Rc; use webxr_api::{ - self, EnvironmentBlendMode, Event as XREvent, Frame, SelectEvent, SelectKind, Session, - Visibility, + self, util, Display, EnvironmentBlendMode, Event as XREvent, Frame, SelectEvent, SelectKind, + Session, View, Viewer, Visibility, }; #[dom_struct] @@ -65,6 +65,8 @@ pub struct XRSession { frame_requested: Cell, pending_render_state: MutNullableDom, active_render_state: MutDom, + /// Cached projection matrix for inline sessions + inline_projection_matrix: DomRefCell>, next_raf_id: Cell, #[ignore_malloc_size_of = "closures are hard"] @@ -100,6 +102,7 @@ impl XRSession { frame_requested: Cell::new(false), pending_render_state: MutNullableDom::new(None), active_render_state: MutDom::new(render_state), + inline_projection_matrix: Default::default(), next_raf_id: Cell::new(0), raf_callback_list: DomRefCell::new(vec![]), @@ -140,6 +143,10 @@ impl XRSession { self.ended.get() } + pub fn is_immersive(&self) -> bool { + self.mode != XRSessionMode::Inline + } + fn setup_raf_loop(&self) { assert!( self.raf_sender.borrow().is_none(), @@ -304,9 +311,12 @@ impl XRSession { self.active_render_state.set(&pending); // Step 6-7: XXXManishearth handle inlineVerticalFieldOfView - // XXXManishearth handle inline sessions and composition disabled flag - let swap_chain_id = pending.GetBaseLayer().map(|layer| layer.swap_chain_id()); - self.session.borrow_mut().set_swap_chain(swap_chain_id); + if self.is_immersive() { + let swap_chain_id = pending.GetBaseLayer().map(|layer| layer.swap_chain_id()); + self.session.borrow_mut().set_swap_chain(swap_chain_id); + } else { + self.update_inline_projection_matrix() + } } for event in frame.events.drain(..) { @@ -339,8 +349,10 @@ impl XRSession { self.outside_raf.set(true); frame.set_active(false); - base_layer.swap_buffers(); - self.session.borrow_mut().render_animation_frame(); + if self.is_immersive() { + base_layer.swap_buffers(); + self.session.borrow_mut().render_animation_frame(); + } self.request_new_xr_frame(); // If the canvas element is attached to the DOM, it is now dirty, @@ -351,6 +363,44 @@ impl XRSession { .upcast::() .dirty(NodeDamage::OtherNodeDamage); } + + fn update_inline_projection_matrix(&self) { + debug_assert!(!self.is_immersive()); + let render_state = self.active_render_state.get(); + let size = if let Some(base) = render_state.GetBaseLayer() { + base.size() + } else { + return; + }; + let mut clip_planes = util::ClipPlanes::default(); + let near = *render_state.DepthNear() as f32; + let far = *render_state.DepthFar() as f32; + clip_planes.update(near, far); + let top = *render_state.InlineVerticalFieldOfView() / 2.; + let top = near * top.tan() as f32; + let bottom = top; + let left = top * size.width as f32 / size.height as f32; + let right = left; + let matrix = util::frustum_to_projection_matrix(left, right, top, bottom, clip_planes); + *self.inline_projection_matrix.borrow_mut() = matrix; + } + + /// Constructs a View suitable for inline sessions using the inlineVerticalFieldOfView and canvas size + pub fn inline_view(&self) -> View { + debug_assert!(!self.is_immersive()); + let size = self + .active_render_state + .get() + .GetBaseLayer() + .expect("Must never construct views when base layer is not set") + .size(); + View { + // Inline views have no offset + transform: RigidTransform3D::identity(), + projection: *self.inline_projection_matrix.borrow(), + viewport: Rect::from_size(size.to_i32()), + } + } } impl XRSessionMethods for XRSession { diff --git a/components/script/dom/xrviewerpose.rs b/components/script/dom/xrviewerpose.rs index 1a5aacd0c91..0e64613294b 100644 --- a/components/script/dom/xrviewerpose.rs +++ b/components/script/dom/xrviewerpose.rs @@ -42,7 +42,13 @@ impl XRViewerPose { ) -> DomRoot { rooted_vec!(let mut views); session.with_session(|s| match s.views() { - Views::Inline => unimplemented!(), + Views::Inline => views.push(XRView::new( + global, + session, + &session.inline_view(), + XREye::None, + &pose, + )), Views::Mono(view) => { views.push(XRView::new(global, session, &view, XREye::None, &pose)) }, diff --git a/components/script/dom/xrwebgllayer.rs b/components/script/dom/xrwebgllayer.rs index 2d39a47286b..752e2ea384a 100644 --- a/components/script/dom/xrwebgllayer.rs +++ b/components/script/dom/xrwebgllayer.rs @@ -20,10 +20,10 @@ use crate::dom::xrview::XRView; use crate::dom::xrviewport::XRViewport; use canvas_traits::webgl::WebGLFramebufferId; use dom_struct::dom_struct; -use euclid::default::Size2D; +use euclid::Size2D; use std::convert::TryInto; use webxr_api::SwapChainId as WebXRSwapChainId; -use webxr_api::Views; +use webxr_api::{Viewport, Views}; #[dom_struct] pub struct XRWebGLLayer { @@ -33,7 +33,7 @@ pub struct XRWebGLLayer { stencil: bool, alpha: bool, #[ignore_malloc_size_of = "ids don't malloc"] - swap_chain_id: WebXRSwapChainId, + swap_chain_id: Option, context: Dom, session: Dom, /// If none, this is an inline session (the composition disabled flag is true) @@ -42,7 +42,7 @@ pub struct XRWebGLLayer { impl XRWebGLLayer { pub fn new_inherited( - swap_chain_id: WebXRSwapChainId, + swap_chain_id: Option, session: &XRSession, context: &WebGLRenderingContext, init: &XRWebGLLayerInit, @@ -63,7 +63,7 @@ impl XRWebGLLayer { pub fn new( global: &GlobalScope, - swap_chain_id: WebXRSwapChainId, + swap_chain_id: Option, session: &XRSession, context: &WebGLRenderingContext, init: &XRWebGLLayerInit, @@ -89,6 +89,7 @@ impl XRWebGLLayer { context: &WebGLRenderingContext, init: &XRWebGLLayerInit, ) -> Fallible> { + let framebuffer; // Step 2 if session.is_ended() { return Err(Error::InvalidState); @@ -97,9 +98,15 @@ impl XRWebGLLayer { // XXXManishearth step 4: check XR compat flag for immersive sessions // Step 9.2. "Initialize layer’s framebuffer to a new opaque framebuffer created with context." - let size = session.with_session(|session| session.recommended_framebuffer_resolution()); - let (swap_chain_id, framebuffer) = - WebGLFramebuffer::maybe_new_webxr(session, context, size).ok_or(Error::Operation)?; + let (swap_chain_id, framebuffer) = if session.is_immersive() { + let size = session.with_session(|session| session.recommended_framebuffer_resolution()); + let (swap_chain_id, fb) = WebGLFramebuffer::maybe_new_webxr(session, context, size) + .ok_or(Error::Operation)?; + framebuffer = fb; + (Some(swap_chain_id), Some(&*framebuffer)) + } else { + (None, None) + }; // Step 9.3. "Allocate and initialize resources compatible with session’s XR device, // including GPU accessible memory buffers, as required to support the compositing of layer." @@ -117,12 +124,13 @@ impl XRWebGLLayer { session, context, init, - Some(&framebuffer), + framebuffer, )) } pub fn swap_chain_id(&self) -> WebXRSwapChainId { self.swap_chain_id + .expect("swap_chain_id must not be called for inline sessions") } pub fn session(&self) -> &XRSession { @@ -133,19 +141,22 @@ impl XRWebGLLayer { if let WebGLFramebufferId::Opaque(id) = self .framebuffer .as_ref() - .expect("Must have framebuffer") + .expect("swap_buffers must not be called for inline sessions") .id() { self.context.swap_buffers(Some(id)); } } - fn size(&self) -> Size2D { - if let Some(framebuffer) = self.framebuffer { + pub fn size(&self) -> Size2D { + if let Some(framebuffer) = self.framebuffer.as_ref() { let size = framebuffer.size().unwrap_or((0, 0)); - Size2D::new(size.0, size.1) + Size2D::new( + size.0.try_into().unwrap_or(0), + size.1.try_into().unwrap_or(0), + ) } else { - self.context.Canvas().get_size() + Size2D::from_untyped(self.context.Canvas().get_size()) } } } @@ -183,12 +194,12 @@ impl XRWebGLLayerMethods for XRWebGLLayer { /// https://immersive-web.github.io/webxr/#dom-xrwebgllayer-framebufferwidth fn FramebufferWidth(&self) -> u32 { - self.size().width.try_into().unwrap_or(0) + self.size().width } /// https://immersive-web.github.io/webxr/#dom-xrwebgllayer-framebufferheight fn FramebufferHeight(&self) -> u32 { - self.size().height.try_into().unwrap_or(0) + self.size().height } /// https://immersive-web.github.io/webxr/#dom-xrwebgllayer-getviewport From d46cbb2083bfe2222eeb2c885422ae76eefc52c5 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Thu, 5 Dec 2019 15:52:29 -0800 Subject: [PATCH 6/9] Allow simulating multiple immersive-capable devices --- components/script/dom/xrtest.rs | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/components/script/dom/xrtest.rs b/components/script/dom/xrtest.rs index 05d608b46a4..b40807b25d5 100644 --- a/components/script/dom/xrtest.rs +++ b/components/script/dom/xrtest.rs @@ -25,14 +25,12 @@ use euclid::RigidTransform3D; use ipc_channel::ipc::IpcSender; use ipc_channel::router::ROUTER; use profile_traits::ipc; -use std::cell::Cell; use std::rc::Rc; use webxr_api::{self, Error as XRError, MockDeviceInit, MockDeviceMsg}; #[dom_struct] pub struct XRTest { reflector: Reflector, - session_started: Cell, devices_connected: DomRefCell>>, } @@ -40,7 +38,6 @@ impl XRTest { pub fn new_inherited() -> XRTest { XRTest { reflector: Reflector::new(), - session_started: Cell::new(false), devices_connected: DomRefCell::new(vec![]), } } @@ -76,11 +73,6 @@ impl XRTestMethods for XRTest { fn SimulateDeviceConnection(&self, init: &FakeXRDeviceInit) -> Rc { let p = Promise::new(&self.global()); - if !init.supportsImmersive || self.session_started.get() { - p.reject_native(&()); - return p; - } - let origin = if let Some(ref o) = init.viewerOrigin { match get_origin(&o) { Ok(origin) => origin, @@ -121,8 +113,6 @@ impl XRTestMethods for XRTest { floor_origin, }; - self.session_started.set(true); - let global = self.global(); let window = global.as_window(); let this = Trusted::new(self); From 51af3be468ae017e6697439be213ae2b7202faf5 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Tue, 10 Dec 2019 14:40:07 -0800 Subject: [PATCH 7/9] Don't attempt to wait for session ending when it has already ended See https://github.com/immersive-web/webxr/pull/939 --- components/script/dom/xrsession.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/components/script/dom/xrsession.rs b/components/script/dom/xrsession.rs index 1ffe7ff77c3..bab52ab326f 100644 --- a/components/script/dom/xrsession.rs +++ b/components/script/dom/xrsession.rs @@ -540,6 +540,19 @@ impl XRSessionMethods for XRSession { fn End(&self) -> Rc { let global = self.global(); let p = Promise::new(&global); + if self.ended.get() && self.end_promises.borrow().is_empty() { + // If the session has completely ended and all end promises have been resolved, + // don't queue up more end promises + // + // We need to check for end_promises being empty because `ended` is set + // before everything has been completely shut down, and we do not want to + // prematurely resolve the promise then + // + // However, if end_promises is empty, then all end() promises have already resolved, + // so the session has completely shut down and we should not queue up more promises + p.resolve_native(&()); + return p; + } self.end_promises.borrow_mut().push(p.clone()); // This is duplicated in event_callback since this should // happen ASAP for end() but can happen later if the device From 9167f1f235a47b85fd6ac1ec9cdf42ef07098970 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Thu, 5 Dec 2019 16:39:46 -0800 Subject: [PATCH 8/9] Update WPT expectations --- .../webxr/idlharness.https.window.js.ini | 4 +-- ...ce_requestSession_immersive.https.html.ini | 7 ----- ...estSession_optionalFeatures.https.html.ini | 9 ------- .../webxr/xrFrame_getPose.https.html.ini | 4 --- .../webxr/xrFrame_lifetime.https.html.ini | 4 --- .../webxr/xrSession_end.https.html.ini | 4 --- ...imationFrame_callback_calls.https.html.ini | 4 --- ...estAnimationFrame_timestamp.https.html.ini | 3 ++- ...uestReferenceSpace_features.https.html.ini | 27 ------------------- ...ssion_viewer_referenceSpace.https.html.ini | 4 --- .../metadata/webxr/xrView_eyes.https.html.ini | 4 --- .../xrView_oneframeupdate.https.html.ini | 2 +- ...bGLLayer_opaque_framebuffer.https.html.ini | 4 --- 13 files changed, 4 insertions(+), 76 deletions(-) delete mode 100644 tests/wpt/metadata/webxr/xrDevice_requestSession_immersive.https.html.ini delete mode 100644 tests/wpt/metadata/webxr/xrFrame_getPose.https.html.ini delete mode 100644 tests/wpt/metadata/webxr/xrFrame_lifetime.https.html.ini delete mode 100644 tests/wpt/metadata/webxr/xrSession_end.https.html.ini delete mode 100644 tests/wpt/metadata/webxr/xrSession_requestAnimationFrame_callback_calls.https.html.ini delete mode 100644 tests/wpt/metadata/webxr/xrSession_viewer_referenceSpace.https.html.ini delete mode 100644 tests/wpt/metadata/webxr/xrView_eyes.https.html.ini delete mode 100644 tests/wpt/metadata/webxr/xrWebGLLayer_opaque_framebuffer.https.html.ini diff --git a/tests/wpt/metadata/webxr/idlharness.https.window.js.ini b/tests/wpt/metadata/webxr/idlharness.https.window.js.ini index d65bfccb3a4..a1d256fabfd 100644 --- a/tests/wpt/metadata/webxr/idlharness.https.window.js.ini +++ b/tests/wpt/metadata/webxr/idlharness.https.window.js.ini @@ -107,9 +107,6 @@ [XRReferenceSpace interface: attribute onreset] expected: FAIL - [XRRenderState interface: attribute inlineVerticalFieldOfView] - expected: FAIL - [XRRay interface: attribute origin] expected: FAIL @@ -169,3 +166,4 @@ [WebGLRenderingContext includes WebGLRenderingContextBase: member names are unique] expected: FAIL + diff --git a/tests/wpt/metadata/webxr/xrDevice_requestSession_immersive.https.html.ini b/tests/wpt/metadata/webxr/xrDevice_requestSession_immersive.https.html.ini deleted file mode 100644 index 0d5790999bb..00000000000 --- a/tests/wpt/metadata/webxr/xrDevice_requestSession_immersive.https.html.ini +++ /dev/null @@ -1,7 +0,0 @@ -[xrDevice_requestSession_immersive.https.html] - [Tests requestSession ignores unknown optionalFeatures] - expected: FAIL - - [Tests requestSession accepts XRSessionInit dictionary] - expected: FAIL - diff --git a/tests/wpt/metadata/webxr/xrDevice_requestSession_optionalFeatures.https.html.ini b/tests/wpt/metadata/webxr/xrDevice_requestSession_optionalFeatures.https.html.ini index b20c9fe3f68..4e60af060a6 100644 --- a/tests/wpt/metadata/webxr/xrDevice_requestSession_optionalFeatures.https.html.ini +++ b/tests/wpt/metadata/webxr/xrDevice_requestSession_optionalFeatures.https.html.ini @@ -2,12 +2,3 @@ [Tests requestSession ignores unknown optionalFeatures] expected: FAIL - [Tests requestSession accepts XRSessionInit dictionary with empty feature lists] - expected: FAIL - - [Tests requestSession ignores unknown objects in optionalFeatures] - expected: FAIL - - [Tests requestSession ignores unknown strings in optionalFeatures] - expected: FAIL - diff --git a/tests/wpt/metadata/webxr/xrFrame_getPose.https.html.ini b/tests/wpt/metadata/webxr/xrFrame_getPose.https.html.ini deleted file mode 100644 index 5d8e04f7e44..00000000000 --- a/tests/wpt/metadata/webxr/xrFrame_getPose.https.html.ini +++ /dev/null @@ -1,4 +0,0 @@ -[xrFrame_getPose.https.html] - [XRFrame.getPose works for non-immersive sessions] - expected: FAIL - diff --git a/tests/wpt/metadata/webxr/xrFrame_lifetime.https.html.ini b/tests/wpt/metadata/webxr/xrFrame_lifetime.https.html.ini deleted file mode 100644 index d49c6a61b71..00000000000 --- a/tests/wpt/metadata/webxr/xrFrame_lifetime.https.html.ini +++ /dev/null @@ -1,4 +0,0 @@ -[xrFrame_lifetime.https.html] - [XRFrame methods throw exceptions outside of the requestAnimationFrame callback for non-immersive sessions] - expected: FAIL - diff --git a/tests/wpt/metadata/webxr/xrSession_end.https.html.ini b/tests/wpt/metadata/webxr/xrSession_end.https.html.ini deleted file mode 100644 index edfc5ae795a..00000000000 --- a/tests/wpt/metadata/webxr/xrSession_end.https.html.ini +++ /dev/null @@ -1,4 +0,0 @@ -[xrSession_end.https.html] - [end event fires when non-immersive session ends] - expected: FAIL - diff --git a/tests/wpt/metadata/webxr/xrSession_requestAnimationFrame_callback_calls.https.html.ini b/tests/wpt/metadata/webxr/xrSession_requestAnimationFrame_callback_calls.https.html.ini deleted file mode 100644 index 66ba580e143..00000000000 --- a/tests/wpt/metadata/webxr/xrSession_requestAnimationFrame_callback_calls.https.html.ini +++ /dev/null @@ -1,4 +0,0 @@ -[xrSession_requestAnimationFrame_callback_calls.https.html] - [XRSession requestAnimationFrame calls the provided callback a non-immersive session] - expected: FAIL - diff --git a/tests/wpt/metadata/webxr/xrSession_requestAnimationFrame_timestamp.https.html.ini b/tests/wpt/metadata/webxr/xrSession_requestAnimationFrame_timestamp.https.html.ini index 85fce01757f..426ad2894ad 100644 --- a/tests/wpt/metadata/webxr/xrSession_requestAnimationFrame_timestamp.https.html.ini +++ b/tests/wpt/metadata/webxr/xrSession_requestAnimationFrame_timestamp.https.html.ini @@ -1,7 +1,8 @@ [xrSession_requestAnimationFrame_timestamp.https.html] + expected: TIMEOUT [XRFrame getViewerPose updates on the next frame for immersive] expected: FAIL [XRFrame getViewerPose updates on the next frame for non-immersive] - expected: FAIL + expected: TIMEOUT diff --git a/tests/wpt/metadata/webxr/xrSession_requestReferenceSpace_features.https.html.ini b/tests/wpt/metadata/webxr/xrSession_requestReferenceSpace_features.https.html.ini index 4f55ce35584..42ddb3aa092 100644 --- a/tests/wpt/metadata/webxr/xrSession_requestReferenceSpace_features.https.html.ini +++ b/tests/wpt/metadata/webxr/xrSession_requestReferenceSpace_features.https.html.ini @@ -1,34 +1,7 @@ [xrSession_requestReferenceSpace_features.https.html] - [Non-immersive session rejects unbounded space even when requested] - expected: FAIL - - [Immersive session supports local space by default] - expected: FAIL - - [Non-immersive session supports local-floor space when required] - expected: FAIL - [Immersive session rejects local-floor space if not requested] expected: FAIL - [Immersive session supports local-floor space when required] - expected: FAIL - - [Non-immersive session rejects bounded-floor space even when requested] - expected: FAIL - - [Non-immersive session supports local space when optional] - expected: FAIL - - [Immersive session supports local-floor space when optional] - expected: FAIL - - [Non-immersive session supports local space when required] - expected: FAIL - [Non-immersive session rejects local space if not requested] expected: FAIL - [Immersive session supports viewer space by default] - expected: FAIL - diff --git a/tests/wpt/metadata/webxr/xrSession_viewer_referenceSpace.https.html.ini b/tests/wpt/metadata/webxr/xrSession_viewer_referenceSpace.https.html.ini deleted file mode 100644 index 47ad34657e1..00000000000 --- a/tests/wpt/metadata/webxr/xrSession_viewer_referenceSpace.https.html.ini +++ /dev/null @@ -1,4 +0,0 @@ -[xrSession_viewer_referenceSpace.https.html] - [Identity reference space provides correct poses for immersive sessions] - expected: FAIL - diff --git a/tests/wpt/metadata/webxr/xrView_eyes.https.html.ini b/tests/wpt/metadata/webxr/xrView_eyes.https.html.ini deleted file mode 100644 index 57017470684..00000000000 --- a/tests/wpt/metadata/webxr/xrView_eyes.https.html.ini +++ /dev/null @@ -1,4 +0,0 @@ -[xrView_eyes.https.html] - [XRView.eye is correct for non-immersive sessions] - expected: FAIL - diff --git a/tests/wpt/metadata/webxr/xrView_oneframeupdate.https.html.ini b/tests/wpt/metadata/webxr/xrView_oneframeupdate.https.html.ini index dfeec8ff525..1146c9d7979 100644 --- a/tests/wpt/metadata/webxr/xrView_oneframeupdate.https.html.ini +++ b/tests/wpt/metadata/webxr/xrView_oneframeupdate.https.html.ini @@ -1,5 +1,5 @@ [xrView_oneframeupdate.https.html] - expected: ERROR + expected: TIMEOUT [XRView projection matrices update near and far depths on the next frame] expected: TIMEOUT diff --git a/tests/wpt/metadata/webxr/xrWebGLLayer_opaque_framebuffer.https.html.ini b/tests/wpt/metadata/webxr/xrWebGLLayer_opaque_framebuffer.https.html.ini deleted file mode 100644 index 1513198ae52..00000000000 --- a/tests/wpt/metadata/webxr/xrWebGLLayer_opaque_framebuffer.https.html.ini +++ /dev/null @@ -1,4 +0,0 @@ -[xrWebGLLayer_opaque_framebuffer.https.html] - [Ensure that the framebuffer given by the WebGL layer is opaque for non-immersive] - expected: FAIL - From f58fd8617e273af96f9db3cdcff4e52ec674f053 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Wed, 11 Dec 2019 07:44:18 -0800 Subject: [PATCH 9/9] Add t.step_func() to oneframeupdate test --- tests/wpt/metadata/MANIFEST.json | 2 +- tests/wpt/metadata/webxr/xrView_oneframeupdate.https.html.ini | 3 +-- .../web-platform-tests/webxr/xrView_oneframeupdate.https.html | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/tests/wpt/metadata/MANIFEST.json b/tests/wpt/metadata/MANIFEST.json index 3081e9d40de..36f9d65acef 100644 --- a/tests/wpt/metadata/MANIFEST.json +++ b/tests/wpt/metadata/MANIFEST.json @@ -727424,7 +727424,7 @@ "testharness" ], "webxr/xrView_oneframeupdate.https.html": [ - "8edb2c0b265f18479644f312f91478d6029e3cd5", + "438d3dbaa36a14d6850adf83e3279e23c00157a4", "testharness" ], "webxr/xrView_sameObject.https.html": [ diff --git a/tests/wpt/metadata/webxr/xrView_oneframeupdate.https.html.ini b/tests/wpt/metadata/webxr/xrView_oneframeupdate.https.html.ini index 1146c9d7979..cdfe879fb87 100644 --- a/tests/wpt/metadata/webxr/xrView_oneframeupdate.https.html.ini +++ b/tests/wpt/metadata/webxr/xrView_oneframeupdate.https.html.ini @@ -1,5 +1,4 @@ [xrView_oneframeupdate.https.html] - expected: TIMEOUT [XRView projection matrices update near and far depths on the next frame] - expected: TIMEOUT + expected: FAIL diff --git a/tests/wpt/web-platform-tests/webxr/xrView_oneframeupdate.https.html b/tests/wpt/web-platform-tests/webxr/xrView_oneframeupdate.https.html index 8edb2c0b265..438d3dbaa36 100644 --- a/tests/wpt/web-platform-tests/webxr/xrView_oneframeupdate.https.html +++ b/tests/wpt/web-platform-tests/webxr/xrView_oneframeupdate.https.html @@ -76,7 +76,7 @@ let testFunction = function(session, fakeDeviceController, t) { counter++; } - session.requestAnimationFrame(onFrame); + session.requestAnimationFrame(t.step_func(onFrame)); })); };