From 708824700fa97847cd9c420fa5e87603eb4f7e34 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Wed, 13 May 2020 13:48:41 -0700 Subject: [PATCH 1/5] Make views a per-frame deal --- Cargo.lock | 4 ++-- components/script/dom/bindings/trace.rs | 9 +++++++- components/script/dom/xrframe.rs | 7 +++++- components/script/dom/xrview.rs | 14 +++++++---- components/script/dom/xrviewerpose.rs | 5 ++-- components/script/dom/xrwebgllayer.rs | 23 +++---------------- .../xrSession_input_events_end.https.html.ini | 3 +-- 7 files changed, 33 insertions(+), 32 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c6664024cb1..c49dbd308c8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6471,7 +6471,7 @@ dependencies = [ [[package]] name = "webxr" version = "0.0.1" -source = "git+https://github.com/servo/webxr#51477cb33fdb3bf3d5cc8b5af9e547fad9d67319" +source = "git+https://github.com/servo/webxr#133663f06f9f0fdffeb046b03ce12205b8515847" dependencies = [ "android_injected_glue", "bindgen", @@ -6494,7 +6494,7 @@ dependencies = [ [[package]] name = "webxr-api" version = "0.0.1" -source = "git+https://github.com/servo/webxr#51477cb33fdb3bf3d5cc8b5af9e547fad9d67319" +source = "git+https://github.com/servo/webxr#133663f06f9f0fdffeb046b03ce12205b8515847" dependencies = [ "euclid", "ipc-channel", diff --git a/components/script/dom/bindings/trace.rs b/components/script/dom/bindings/trace.rs index 26db47233f9..e15c657a1e3 100644 --- a/components/script/dom/bindings/trace.rs +++ b/components/script/dom/bindings/trace.rs @@ -162,7 +162,7 @@ use webgpu::{ }; use webrender_api::{DocumentId, ImageKey}; use webxr_api::SwapChainId as WebXRSwapChainId; -use webxr_api::{Finger, Hand, Ray}; +use webxr_api::{Finger, Hand, Ray, View}; unsafe_no_jsmanaged_fields!(Tm); @@ -775,6 +775,13 @@ unsafe impl JSTraceable for Ray { } } +unsafe impl JSTraceable for View { + #[inline] + unsafe fn trace(&self, _trc: *mut JSTracer) { + // Do nothing + } +} + unsafe impl JSTraceable for StyleLocked { unsafe fn trace(&self, _trc: *mut JSTracer) { // Do nothing. diff --git a/components/script/dom/xrframe.rs b/components/script/dom/xrframe.rs index 1526a1c387c..68896b21de6 100644 --- a/components/script/dom/xrframe.rs +++ b/components/script/dom/xrframe.rs @@ -85,7 +85,12 @@ impl XRFrameMethods for XRFrame { } else { return Ok(None); }; - Ok(Some(XRViewerPose::new(&self.global(), &self.session, pose))) + Ok(Some(XRViewerPose::new( + &self.global(), + &self.session, + pose, + &self.data.views, + ))) } /// https://immersive-web.github.io/webxr/#dom-xrframe-getpose diff --git a/components/script/dom/xrview.rs b/components/script/dom/xrview.rs index 8aa0b0adc58..17760d72b1a 100644 --- a/components/script/dom/xrview.rs +++ b/components/script/dom/xrview.rs @@ -14,7 +14,7 @@ use crate::script_runtime::JSContext; use dom_struct::dom_struct; use js::jsapi::{Heap, JSObject}; use std::ptr::NonNull; -use webxr_api::View; +use webxr_api::{ApiSpace, View}; #[dom_struct] pub struct XRView { @@ -23,8 +23,8 @@ pub struct XRView { eye: XREye, #[ignore_malloc_size_of = "mozjs"] proj: Heap<*mut JSObject>, - #[ignore_malloc_size_of = "mozjs"] - view: Heap<*mut JSObject>, + #[ignore_malloc_size_of = "defined in rust-webxr"] + view: View, proj_array: Vec, transform: Dom, } @@ -35,18 +35,23 @@ impl XRView { transform: &XRRigidTransform, eye: XREye, proj_array: Vec, + view: View, ) -> XRView { XRView { reflector_: Reflector::new(), session: Dom::from_ref(session), eye, proj: Heap::default(), - view: Heap::default(), proj_array, + view, transform: Dom::from_ref(transform), } } + pub fn view(&self) -> &View { + &self.view + } + pub fn new( global: &GlobalScope, session: &XRSession, @@ -71,6 +76,7 @@ impl XRView { &transform, eye, (&proj).to_vec(), + view.cast_unit(), )), global, ); diff --git a/components/script/dom/xrviewerpose.rs b/components/script/dom/xrviewerpose.rs index 6e1ebe6422a..ee36e3ff472 100644 --- a/components/script/dom/xrviewerpose.rs +++ b/components/script/dom/xrviewerpose.rs @@ -39,10 +39,11 @@ impl XRViewerPose { global: &GlobalScope, session: &XRSession, pose: ApiViewerPose, + frame_views: &Views, ) -> DomRoot { let _ac = enter_realm(&*global); rooted_vec!(let mut views); - session.with_session(|s| match s.views() { + match frame_views { Views::Inline => views.push(XRView::new( global, session, @@ -62,7 +63,7 @@ impl XRViewerPose { views.push(XRView::new(global, session, &right, XREye::Right, &pose)); views.push(XRView::new(global, session, &third_eye, XREye::None, &pose)); }, - }); + }; let transform = XRRigidTransform::new(global, cast_transform(pose)); let pose = reflect_dom_object(Box::new(XRViewerPose::new_inherited(&transform)), global); diff --git a/components/script/dom/xrwebgllayer.rs b/components/script/dom/xrwebgllayer.rs index 6bab886a0fd..ae1252aa02c 100644 --- a/components/script/dom/xrwebgllayer.rs +++ b/components/script/dom/xrwebgllayer.rs @@ -4,7 +4,6 @@ use crate::dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::WebGLRenderingContextMethods; use crate::dom::bindings::codegen::Bindings::WebGL2RenderingContextBinding::WebGL2RenderingContextBinding::WebGL2RenderingContextMethods; -use crate::dom::bindings::codegen::Bindings::XRViewBinding::{XREye, XRViewMethods}; use crate::dom::bindings::codegen::Bindings::XRWebGLLayerBinding::XRWebGLLayerInit; use crate::dom::bindings::codegen::Bindings::XRWebGLLayerBinding::XRWebGLLayerMethods; use crate::dom::bindings::codegen::Bindings::XRWebGLLayerBinding::XRWebGLRenderingContext; @@ -22,10 +21,10 @@ use crate::dom::xrview::XRView; use crate::dom::xrviewport::XRViewport; use canvas_traits::webgl::WebGLFramebufferId; use dom_struct::dom_struct; -use euclid::{Point2D, Rect, Size2D}; +use euclid::Size2D; use std::convert::TryInto; use webxr_api::SwapChainId as WebXRSwapChainId; -use webxr_api::{Viewport, Views}; +use webxr_api::Viewport; #[derive(JSTraceable, MallocSizeOf)] #[unrooted_must_root_lint::must_root] @@ -241,22 +240,6 @@ impl XRWebGLLayerMethods for XRWebGLLayer { return None; } - let views = self.session.with_session(|s| s.views().clone()); - - let viewport = match (view.Eye(), views) { - (XREye::None, Views::Inline) => { - let origin = Point2D::new(0, 0); - Rect::new(origin, self.size().cast()) - }, - (XREye::None, Views::Mono(view)) => view.viewport, - (XREye::None, Views::StereoCapture(_, _, view)) => view.viewport, - (XREye::Left, Views::Stereo(view, _)) => view.viewport, - (XREye::Left, Views::StereoCapture(view, _, _)) => view.viewport, - (XREye::Right, Views::Stereo(_, view)) => view.viewport, - (XREye::Right, Views::StereoCapture(_, view, _)) => view.viewport, - _ => return None, - }; - - Some(XRViewport::new(&self.global(), viewport)) + Some(XRViewport::new(&self.global(), view.view().viewport)) } } diff --git a/tests/wpt/metadata/webxr/xrSession_input_events_end.https.html.ini b/tests/wpt/metadata/webxr/xrSession_input_events_end.https.html.ini index 1d6cd17924d..739e7b4c112 100644 --- a/tests/wpt/metadata/webxr/xrSession_input_events_end.https.html.ini +++ b/tests/wpt/metadata/webxr/xrSession_input_events_end.https.html.ini @@ -1,5 +1,4 @@ [xrSession_input_events_end.https.html] - expected: TIMEOUT [Calling end during an input callback stops processing at the right time] - expected: TIMEOUT + expected: FAIL From eaad692c0beb8538967fe35632bda9323ab4efbc Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Wed, 13 May 2020 14:14:06 -0700 Subject: [PATCH 2/5] Use cached projection matrix --- components/script/dom/xrview.rs | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/components/script/dom/xrview.rs b/components/script/dom/xrview.rs index 17760d72b1a..b33c56cb1b4 100644 --- a/components/script/dom/xrview.rs +++ b/components/script/dom/xrview.rs @@ -25,7 +25,6 @@ pub struct XRView { proj: Heap<*mut JSObject>, #[ignore_malloc_size_of = "defined in rust-webxr"] view: View, - proj_array: Vec, transform: Dom, } @@ -34,7 +33,6 @@ impl XRView { session: &XRSession, transform: &XRRigidTransform, eye: XREye, - proj_array: Vec, view: View, ) -> XRView { XRView { @@ -42,7 +40,6 @@ impl XRView { session: Dom::from_ref(session), eye, proj: Heap::default(), - proj_array, view, transform: Dom::from_ref(transform), } @@ -68,22 +65,15 @@ impl XRView { let transform = pose.pre_transform(&offset); let transform = XRRigidTransform::new(global, cast_transform(transform)); - // row_major since euclid uses row vectors - let proj = view.projection.to_row_major_array(); - let ret = reflect_dom_object( + reflect_dom_object( Box::new(XRView::new_inherited( session, &transform, eye, - (&proj).to_vec(), view.cast_unit(), )), global, - ); - - let cx = global.get_cx(); - create_typed_array(cx, &proj, &ret.proj); - ret + ) } pub fn session(&self) -> &XRSession { @@ -101,7 +91,9 @@ impl XRViewMethods for XRView { fn ProjectionMatrix(&self, _cx: JSContext) -> NonNull { if self.proj.get().is_null() { let cx = self.global().get_cx(); - create_typed_array(cx, &self.proj_array, &self.proj); + // row_major since euclid uses row vectors + let proj = self.view.projection.to_row_major_array(); + create_typed_array(cx, &proj, &self.proj); } NonNull::new(self.proj.get()).unwrap() } From 794624b42b82e549b1992ec41d7fd830a563ba0e Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Thu, 14 May 2020 11:18:34 -0700 Subject: [PATCH 3/5] Move viewports to being per-session, not per-frame --- Cargo.lock | 4 ++-- components/script/dom/xrsession.rs | 9 +-------- components/script/dom/xrview.rs | 13 +++++++++---- components/script/dom/xrviewerpose.rs | 20 ++++++++++++++------ components/script/dom/xrwebgllayer.rs | 21 ++++++++++++++++++--- 5 files changed, 44 insertions(+), 23 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c49dbd308c8..ee77709da88 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6471,7 +6471,7 @@ dependencies = [ [[package]] name = "webxr" version = "0.0.1" -source = "git+https://github.com/servo/webxr#133663f06f9f0fdffeb046b03ce12205b8515847" +source = "git+https://github.com/servo/webxr#a73b150f1e1a946fd90bd1ccf0056e35c3eef0d2" dependencies = [ "android_injected_glue", "bindgen", @@ -6494,7 +6494,7 @@ dependencies = [ [[package]] name = "webxr-api" version = "0.0.1" -source = "git+https://github.com/servo/webxr#133663f06f9f0fdffeb046b03ce12205b8515847" +source = "git+https://github.com/servo/webxr#a73b150f1e1a946fd90bd1ccf0056e35c3eef0d2" dependencies = [ "euclid", "ipc-channel", diff --git a/components/script/dom/xrsession.rs b/components/script/dom/xrsession.rs index 2ef47361f92..879dff7b662 100644 --- a/components/script/dom/xrsession.rs +++ b/components/script/dom/xrsession.rs @@ -40,7 +40,7 @@ use crate::dom::xrspace::XRSpace; use crate::realms::InRealm; use crate::task_source::TaskSource; use dom_struct::dom_struct; -use euclid::{Rect, RigidTransform3D, Transform3D, Vector3D}; +use euclid::{RigidTransform3D, Transform3D, Vector3D}; use ipc_channel::ipc::IpcReceiver; use ipc_channel::router::ROUTER; use metrics::ToMs; @@ -463,17 +463,10 @@ impl XRSession { /// 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()), } } diff --git a/components/script/dom/xrview.rs b/components/script/dom/xrview.rs index b33c56cb1b4..4ec37a7b6b0 100644 --- a/components/script/dom/xrview.rs +++ b/components/script/dom/xrview.rs @@ -21,6 +21,7 @@ pub struct XRView { reflector_: Reflector, session: Dom, eye: XREye, + viewport_index: usize, #[ignore_malloc_size_of = "mozjs"] proj: Heap<*mut JSObject>, #[ignore_malloc_size_of = "defined in rust-webxr"] @@ -33,27 +34,26 @@ impl XRView { session: &XRSession, transform: &XRRigidTransform, eye: XREye, + viewport_index: usize, view: View, ) -> XRView { XRView { reflector_: Reflector::new(), session: Dom::from_ref(session), eye, + viewport_index, proj: Heap::default(), view, transform: Dom::from_ref(transform), } } - pub fn view(&self) -> &View { - &self.view - } - pub fn new( global: &GlobalScope, session: &XRSession, view: &View, eye: XREye, + viewport_index: usize, pose: &ApiViewerPose, ) -> DomRoot { // XXXManishearth compute and cache projection matrices on the Display @@ -70,6 +70,7 @@ impl XRView { session, &transform, eye, + viewport_index, view.cast_unit(), )), global, @@ -79,6 +80,10 @@ impl XRView { pub fn session(&self) -> &XRSession { &self.session } + + pub fn viewport_index(&self) -> usize { + self.viewport_index + } } impl XRViewMethods for XRView { diff --git a/components/script/dom/xrviewerpose.rs b/components/script/dom/xrviewerpose.rs index ee36e3ff472..b55129b8daf 100644 --- a/components/script/dom/xrviewerpose.rs +++ b/components/script/dom/xrviewerpose.rs @@ -49,19 +49,27 @@ impl XRViewerPose { session, &session.inline_view(), XREye::None, + 0, &pose, )), Views::Mono(view) => { - views.push(XRView::new(global, session, &view, XREye::None, &pose)) + views.push(XRView::new(global, session, &view, XREye::None, 0, &pose)) }, Views::Stereo(left, right) => { - views.push(XRView::new(global, session, &left, XREye::Left, &pose)); - views.push(XRView::new(global, session, &right, XREye::Right, &pose)); + views.push(XRView::new(global, session, &left, XREye::Left, 0, &pose)); + views.push(XRView::new(global, session, &right, XREye::Right, 1, &pose)); }, Views::StereoCapture(left, right, third_eye) => { - views.push(XRView::new(global, session, &left, XREye::Left, &pose)); - views.push(XRView::new(global, session, &right, XREye::Right, &pose)); - views.push(XRView::new(global, session, &third_eye, XREye::None, &pose)); + views.push(XRView::new(global, session, &left, XREye::Left, 0, &pose)); + views.push(XRView::new(global, session, &right, XREye::Right, 1, &pose)); + views.push(XRView::new( + global, + session, + &third_eye, + XREye::None, + 2, + &pose, + )); }, }; let transform = XRRigidTransform::new(global, cast_transform(pose)); diff --git a/components/script/dom/xrwebgllayer.rs b/components/script/dom/xrwebgllayer.rs index ae1252aa02c..f93c4c22bc2 100644 --- a/components/script/dom/xrwebgllayer.rs +++ b/components/script/dom/xrwebgllayer.rs @@ -21,7 +21,7 @@ use crate::dom::xrview::XRView; use crate::dom::xrviewport::XRViewport; use canvas_traits::webgl::WebGLFramebufferId; use dom_struct::dom_struct; -use euclid::Size2D; +use euclid::{Rect, Size2D}; use std::convert::TryInto; use webxr_api::SwapChainId as WebXRSwapChainId; use webxr_api::Viewport; @@ -114,7 +114,11 @@ impl XRWebGLLayer { // Step 9.2. "Initialize layer’s framebuffer to a new opaque framebuffer created with context." let (swap_chain_id, framebuffer) = if session.is_immersive() { - let size = session.with_session(|session| session.recommended_framebuffer_resolution()); + let size = session.with_session(|session| { + session + .recommended_framebuffer_resolution() + .expect("immersive session must have viewports") + }); let (swap_chain_id, fb) = WebGLFramebuffer::maybe_new_webxr(session, &context, size) .ok_or(Error::Operation)?; framebuffer = fb; @@ -240,6 +244,17 @@ impl XRWebGLLayerMethods for XRWebGLLayer { return None; } - Some(XRViewport::new(&self.global(), view.view().viewport)) + let index = view.viewport_index(); + + let viewport = self.session.with_session(|s| { + // Inline sssions + if s.viewports().is_empty() { + Rect::from_size(self.size().to_i32()) + } else { + s.viewports()[index] + } + }); + + Some(XRViewport::new(&self.global(), viewport)) } } From a97dcd9ad6c895d61974317f7ba77f6b6fb48282 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Thu, 14 May 2020 12:00:02 -0700 Subject: [PATCH 4/5] Update to use webxr_api::ViewerPose --- Cargo.lock | 4 ++-- components/script/dom/xrframe.rs | 7 ++++++- components/script/dom/xrreferencespace.rs | 8 +++++--- components/script/dom/xrviewerpose.rs | 6 +++--- 4 files changed, 16 insertions(+), 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ee77709da88..5bca4f79fd1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6471,7 +6471,7 @@ dependencies = [ [[package]] name = "webxr" version = "0.0.1" -source = "git+https://github.com/servo/webxr#a73b150f1e1a946fd90bd1ccf0056e35c3eef0d2" +source = "git+https://github.com/servo/webxr#3f754a11eb3e9771f6020ec5a25ae94ed1e11f07" dependencies = [ "android_injected_glue", "bindgen", @@ -6494,7 +6494,7 @@ dependencies = [ [[package]] name = "webxr-api" version = "0.0.1" -source = "git+https://github.com/servo/webxr#a73b150f1e1a946fd90bd1ccf0056e35c3eef0d2" +source = "git+https://github.com/servo/webxr#3f754a11eb3e9771f6020ec5a25ae94ed1e11f07" dependencies = [ "euclid", "ipc-channel", diff --git a/components/script/dom/xrframe.rs b/components/script/dom/xrframe.rs index 68896b21de6..fbb6890baf3 100644 --- a/components/script/dom/xrframe.rs +++ b/components/script/dom/xrframe.rs @@ -85,11 +85,16 @@ impl XRFrameMethods for XRFrame { } else { return Ok(None); }; + let viewer_pose = if let Some(pose) = self.data.pose.as_ref() { + pose + } else { + return Ok(None); + }; Ok(Some(XRViewerPose::new( &self.global(), &self.session, pose, - &self.data.views, + viewer_pose, ))) } diff --git a/components/script/dom/xrreferencespace.rs b/components/script/dom/xrreferencespace.rs index 3d05a59564c..0936b33fe6d 100644 --- a/components/script/dom/xrreferencespace.rs +++ b/components/script/dom/xrreferencespace.rs @@ -113,7 +113,7 @@ impl XRReferenceSpace { // get_viewer_pose(eye_level) = get_pose(eye_level).inverse() * get_pose(viewer_space) // = I * viewer_pose // = viewer_pose - let viewer_pose: ApiViewerPose = cast_transform(base_pose.transform?); + let viewer_pose: ApiViewerPose = cast_transform(base_pose.pose.as_ref()?.transform); // we get viewer poses in eye-level space by default Some(viewer_pose) @@ -122,7 +122,7 @@ impl XRReferenceSpace { // get_viewer_pose(floor_level) = get_pose(floor_level).inverse() * get_pose(viewer_space) // = floor_to_native.inverse() * viewer_pose // = native_to_floor * viewer_pose - let viewer_pose = base_pose.transform?; + let viewer_pose = base_pose.pose.as_ref()?.transform; let native_to_floor = self .upcast::() .session() @@ -171,7 +171,9 @@ impl XRReferenceSpace { .with_session(|s| s.floor_transform())?; Some(cast_transform(native_to_floor.inverse())) }, - XRReferenceSpaceType::Viewer => base_pose.transform.map(cast_transform), + XRReferenceSpaceType::Viewer => { + Some(cast_transform(base_pose.pose.as_ref()?.transform)) + }, _ => unimplemented!(), } } diff --git a/components/script/dom/xrviewerpose.rs b/components/script/dom/xrviewerpose.rs index b55129b8daf..10c212c5ada 100644 --- a/components/script/dom/xrviewerpose.rs +++ b/components/script/dom/xrviewerpose.rs @@ -17,7 +17,7 @@ use dom_struct::dom_struct; use js::conversions::ToJSValConvertible; use js::jsapi::Heap; use js::jsval::{JSVal, UndefinedValue}; -use webxr_api::Views; +use webxr_api::{ViewerPose, Views}; #[dom_struct] pub struct XRViewerPose { @@ -39,11 +39,11 @@ impl XRViewerPose { global: &GlobalScope, session: &XRSession, pose: ApiViewerPose, - frame_views: &Views, + viewer_pose: &ViewerPose, ) -> DomRoot { let _ac = enter_realm(&*global); rooted_vec!(let mut views); - match frame_views { + match &viewer_pose.views { Views::Inline => views.push(XRView::new( global, session, From d627476893cae7a243e234a289683eea99109b20 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Sat, 16 May 2020 21:49:44 -0700 Subject: [PATCH 5/5] Update to treat view transforms as native-relative --- Cargo.lock | 4 +- components/script/dom/xrframe.rs | 6 +- components/script/dom/xrreferencespace.rs | 67 ++++------------------- components/script/dom/xrsession.rs | 7 ++- components/script/dom/xrview.rs | 13 ++--- components/script/dom/xrviewerpose.rs | 62 ++++++++++++++++----- 6 files changed, 74 insertions(+), 85 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5bca4f79fd1..01e99beb5d0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6471,7 +6471,7 @@ dependencies = [ [[package]] name = "webxr" version = "0.0.1" -source = "git+https://github.com/servo/webxr#3f754a11eb3e9771f6020ec5a25ae94ed1e11f07" +source = "git+https://github.com/servo/webxr#0d8d2affc4da259b88d251ab49c0bbcbe96acf4d" dependencies = [ "android_injected_glue", "bindgen", @@ -6494,7 +6494,7 @@ dependencies = [ [[package]] name = "webxr-api" version = "0.0.1" -source = "git+https://github.com/servo/webxr#3f754a11eb3e9771f6020ec5a25ae94ed1e11f07" +source = "git+https://github.com/servo/webxr#0d8d2affc4da259b88d251ab49c0bbcbe96acf4d" dependencies = [ "euclid", "ipc-channel", diff --git a/components/script/dom/xrframe.rs b/components/script/dom/xrframe.rs index fbb6890baf3..2381d4864d9 100644 --- a/components/script/dom/xrframe.rs +++ b/components/script/dom/xrframe.rs @@ -80,8 +80,8 @@ impl XRFrameMethods for XRFrame { return Err(Error::InvalidState); } - let pose = if let Some(pose) = reference.get_viewer_pose(&self.data) { - pose + let to_base = if let Some(to_base) = reference.get_base_transform(&self.data) { + to_base } else { return Ok(None); }; @@ -93,7 +93,7 @@ impl XRFrameMethods for XRFrame { Ok(Some(XRViewerPose::new( &self.global(), &self.session, - pose, + to_base, viewer_pose, ))) } diff --git a/components/script/dom/xrreferencespace.rs b/components/script/dom/xrreferencespace.rs index 0936b33fe6d..fb4f890e766 100644 --- a/components/script/dom/xrreferencespace.rs +++ b/components/script/dom/xrreferencespace.rs @@ -9,11 +9,11 @@ use crate::dom::bindings::reflector::{reflect_dom_object, DomObject}; use crate::dom::bindings::root::{Dom, DomRoot}; use crate::dom::globalscope::GlobalScope; use crate::dom::xrrigidtransform::XRRigidTransform; -use crate::dom::xrsession::{cast_transform, ApiPose, ApiViewerPose, XRSession}; +use crate::dom::xrsession::{cast_transform, ApiPose, BaseTransform, XRSession}; use crate::dom::xrspace::XRSpace; use dom_struct::dom_struct; use euclid::RigidTransform3D; -use webxr_api::{BaseSpace, Frame, Space}; +use webxr_api::{self, Frame, Space}; #[dom_struct] pub struct XRReferenceSpace { @@ -60,9 +60,9 @@ impl XRReferenceSpace { pub fn space(&self) -> Space { let base = match self.ty { - XRReferenceSpaceType::Local => BaseSpace::Local, - XRReferenceSpaceType::Viewer => BaseSpace::Viewer, - XRReferenceSpaceType::Local_floor => BaseSpace::Floor, + XRReferenceSpaceType::Local => webxr_api::BaseSpace::Local, + XRReferenceSpaceType::Viewer => webxr_api::BaseSpace::Viewer, + XRReferenceSpaceType::Local_floor => webxr_api::BaseSpace::Floor, _ => panic!("unsupported reference space found"), }; let offset = self.offset.transform(); @@ -85,58 +85,13 @@ impl XRReferenceSpaceMethods for XRReferenceSpace { } impl XRReferenceSpace { - /// Gets pose of the viewer with respect to this space + /// Get a transform that can be used to locate the base space /// - /// This is equivalent to `get_pose(self).inverse() * get_pose(viewerSpace)` (in column vector notation), - /// however we specialize it to be efficient - pub fn get_viewer_pose(&self, base_pose: &Frame) -> Option { - let pose = self.get_unoffset_viewer_pose(base_pose)?; - // in column-vector notation, - // get_viewer_pose(space) = get_pose(space).inverse() * get_pose(viewer_space) - // = (get_unoffset_pose(space) * offset).inverse() * get_pose(viewer_space) - // = offset.inverse() * get_unoffset_pose(space).inverse() * get_pose(viewer_space) - // = offset.inverse() * get_unoffset_viewer_pose(space) - let offset = self.offset.transform(); - let inverse = offset.inverse(); - Some(inverse.pre_transform(&pose)) - } - - /// Gets pose of the viewer with respect to this space - /// - /// Does not apply originOffset, use get_viewer_pose instead if you need it - pub fn get_unoffset_viewer_pose(&self, base_pose: &Frame) -> Option { - // all math is in column-vector notation - // we use the following equation to verify correctness here: - // get_viewer_pose(space) = get_pose(space).inverse() * get_pose(viewer_space) - match self.ty { - XRReferenceSpaceType::Local => { - // get_viewer_pose(eye_level) = get_pose(eye_level).inverse() * get_pose(viewer_space) - // = I * viewer_pose - // = viewer_pose - let viewer_pose: ApiViewerPose = cast_transform(base_pose.pose.as_ref()?.transform); - - // we get viewer poses in eye-level space by default - Some(viewer_pose) - }, - XRReferenceSpaceType::Local_floor => { - // get_viewer_pose(floor_level) = get_pose(floor_level).inverse() * get_pose(viewer_space) - // = floor_to_native.inverse() * viewer_pose - // = native_to_floor * viewer_pose - let viewer_pose = base_pose.pose.as_ref()?.transform; - let native_to_floor = self - .upcast::() - .session() - .with_session(|s| s.floor_transform())?; - - Some(cast_transform(native_to_floor.pre_transform(&viewer_pose))) - }, - XRReferenceSpaceType::Viewer => { - // This reference space follows the viewer around, so the viewer is - // always at an identity transform with respect to it - Some(RigidTransform3D::identity()) - }, - _ => unimplemented!(), - } + /// This is equivalent to `get_pose(self).inverse()` (in column vector notation), + /// but with better types + pub fn get_base_transform(&self, base_pose: &Frame) -> Option { + let pose = self.get_pose(base_pose)?; + Some(pose.inverse().cast_unit()) } /// Gets pose represented by this space diff --git a/components/script/dom/xrsession.rs b/components/script/dom/xrsession.rs index 879dff7b662..3b27b21222d 100644 --- a/components/script/dom/xrsession.rs +++ b/components/script/dom/xrsession.rs @@ -791,11 +791,14 @@ impl XRSessionMethods for XRSession { // The pose of an object in native-space. Should never be exposed. pub type ApiPose = RigidTransform3D; -// The pose of the viewer in some api-space. -pub type ApiViewerPose = RigidTransform3D; // A transform between objects in some API-space pub type ApiRigidTransform = RigidTransform3D; +#[derive(Clone, Copy)] +pub struct BaseSpace; + +pub type BaseTransform = RigidTransform3D; + #[allow(unsafe_code)] pub fn cast_transform( transform: RigidTransform3D, diff --git a/components/script/dom/xrview.rs b/components/script/dom/xrview.rs index 4ec37a7b6b0..55cac600f6b 100644 --- a/components/script/dom/xrview.rs +++ b/components/script/dom/xrview.rs @@ -9,9 +9,10 @@ use crate::dom::bindings::root::{Dom, DomRoot}; use crate::dom::bindings::utils::create_typed_array; use crate::dom::globalscope::GlobalScope; use crate::dom::xrrigidtransform::XRRigidTransform; -use crate::dom::xrsession::{cast_transform, ApiViewerPose, XRSession}; +use crate::dom::xrsession::{cast_transform, BaseSpace, BaseTransform, XRSession}; use crate::script_runtime::JSContext; use dom_struct::dom_struct; +use euclid::RigidTransform3D; use js::jsapi::{Heap, JSObject}; use std::ptr::NonNull; use webxr_api::{ApiSpace, View}; @@ -54,15 +55,9 @@ impl XRView { view: &View, eye: XREye, viewport_index: usize, - pose: &ApiViewerPose, + to_base: &BaseTransform, ) -> DomRoot { - // XXXManishearth compute and cache projection matrices on the Display - - // this transform is the pose of the viewer in the eye space, i.e. it is the transform - // from the viewer space to the eye space. We invert it to get the pose of the eye in the viewer space. - let offset = view.transform.inverse(); - - let transform = pose.pre_transform(&offset); + let transform: RigidTransform3D = to_base.pre_transform(&view.transform); let transform = XRRigidTransform::new(global, cast_transform(transform)); reflect_dom_object( diff --git a/components/script/dom/xrviewerpose.rs b/components/script/dom/xrviewerpose.rs index 10c212c5ada..d88eb7ec9c9 100644 --- a/components/script/dom/xrviewerpose.rs +++ b/components/script/dom/xrviewerpose.rs @@ -9,15 +9,16 @@ use crate::dom::bindings::root::DomRoot; use crate::dom::globalscope::GlobalScope; use crate::dom::xrpose::XRPose; use crate::dom::xrrigidtransform::XRRigidTransform; -use crate::dom::xrsession::{cast_transform, ApiViewerPose, XRSession}; +use crate::dom::xrsession::{cast_transform, BaseSpace, BaseTransform, XRSession}; use crate::dom::xrview::XRView; use crate::realms::enter_realm; use crate::script_runtime::JSContext; use dom_struct::dom_struct; +use euclid::RigidTransform3D; use js::conversions::ToJSValConvertible; use js::jsapi::Heap; use js::jsval::{JSVal, UndefinedValue}; -use webxr_api::{ViewerPose, Views}; +use webxr_api::{Viewer, ViewerPose, Views}; #[dom_struct] pub struct XRViewerPose { @@ -38,7 +39,7 @@ impl XRViewerPose { pub fn new( global: &GlobalScope, session: &XRSession, - pose: ApiViewerPose, + to_base: BaseTransform, viewer_pose: &ViewerPose, ) -> DomRoot { let _ac = enter_realm(&*global); @@ -50,29 +51,64 @@ impl XRViewerPose { &session.inline_view(), XREye::None, 0, - &pose, + &to_base, + )), + Views::Mono(view) => views.push(XRView::new( + global, + session, + &view, + XREye::None, + 0, + &to_base, )), - Views::Mono(view) => { - views.push(XRView::new(global, session, &view, XREye::None, 0, &pose)) - }, Views::Stereo(left, right) => { - views.push(XRView::new(global, session, &left, XREye::Left, 0, &pose)); - views.push(XRView::new(global, session, &right, XREye::Right, 1, &pose)); + views.push(XRView::new( + global, + session, + &left, + XREye::Left, + 0, + &to_base, + )); + views.push(XRView::new( + global, + session, + &right, + XREye::Right, + 1, + &to_base, + )); }, Views::StereoCapture(left, right, third_eye) => { - views.push(XRView::new(global, session, &left, XREye::Left, 0, &pose)); - views.push(XRView::new(global, session, &right, XREye::Right, 1, &pose)); + views.push(XRView::new( + global, + session, + &left, + XREye::Left, + 0, + &to_base, + )); + views.push(XRView::new( + global, + session, + &right, + XREye::Right, + 1, + &to_base, + )); views.push(XRView::new( global, session, &third_eye, XREye::None, 2, - &pose, + &to_base, )); }, }; - let transform = XRRigidTransform::new(global, cast_transform(pose)); + let transform: RigidTransform3D = + to_base.pre_transform(&viewer_pose.transform); + let transform = XRRigidTransform::new(global, cast_transform(transform)); let pose = reflect_dom_object(Box::new(XRViewerPose::new_inherited(&transform)), global); let cx = global.get_cx();