diff options
-rw-r--r-- | Cargo.lock | 4 | ||||
-rw-r--r-- | components/script/dom/bindings/trace.rs | 9 | ||||
-rw-r--r-- | components/script/dom/xrframe.rs | 14 | ||||
-rw-r--r-- | components/script/dom/xrreferencespace.rs | 71 | ||||
-rw-r--r-- | components/script/dom/xrsession.rs | 16 | ||||
-rw-r--r-- | components/script/dom/xrview.rs | 50 | ||||
-rw-r--r-- | components/script/dom/xrviewerpose.rs | 75 | ||||
-rw-r--r-- | components/script/dom/xrwebgllayer.rs | 34 | ||||
-rw-r--r-- | tests/wpt/metadata/webxr/xrSession_input_events_end.https.html.ini | 3 |
9 files changed, 143 insertions, 133 deletions
diff --git a/Cargo.lock b/Cargo.lock index 9a1379f83c6..190172ab40b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6484,7 +6484,7 @@ dependencies = [ [[package]] name = "webxr" version = "0.0.1" -source = "git+https://github.com/servo/webxr#51477cb33fdb3bf3d5cc8b5af9e547fad9d67319" +source = "git+https://github.com/servo/webxr#0d8d2affc4da259b88d251ab49c0bbcbe96acf4d" dependencies = [ "android_injected_glue", "bindgen", @@ -6507,7 +6507,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#0d8d2affc4da259b88d251ab49c0bbcbe96acf4d" dependencies = [ "euclid", "ipc-channel", diff --git a/components/script/dom/bindings/trace.rs b/components/script/dom/bindings/trace.rs index 976ca568e92..7534541a06d 100644 --- a/components/script/dom/bindings/trace.rs +++ b/components/script/dom/bindings/trace.rs @@ -163,7 +163,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); @@ -777,6 +777,13 @@ unsafe impl<Space> JSTraceable for Ray<Space> { } } +unsafe impl<Eye> JSTraceable for View<Eye> { + #[inline] + unsafe fn trace(&self, _trc: *mut JSTracer) { + // Do nothing + } +} + unsafe impl JSTraceable for StyleLocked<FontFaceRule> { 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..2381d4864d9 100644 --- a/components/script/dom/xrframe.rs +++ b/components/script/dom/xrframe.rs @@ -80,12 +80,22 @@ impl XRFrameMethods for XRFrame { return Err(Error::InvalidState); } - let pose = if let Some(pose) = reference.get_viewer_pose(&self.data) { + let to_base = if let Some(to_base) = reference.get_base_transform(&self.data) { + to_base + } 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))) + Ok(Some(XRViewerPose::new( + &self.global(), + &self.session, + to_base, + viewer_pose, + ))) } /// https://immersive-web.github.io/webxr/#dom-xrframe-getpose diff --git a/components/script/dom/xrreferencespace.rs b/components/script/dom/xrreferencespace.rs index 3d05a59564c..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<ApiViewerPose> { - 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<ApiViewerPose> { - // 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.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.transform?; - let native_to_floor = self - .upcast::<XRSpace>() - .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<BaseTransform> { + let pose = self.get_pose(base_pose)?; + Some(pose.inverse().cast_unit()) } /// Gets pose represented by this space @@ -171,7 +126,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/xrsession.rs b/components/script/dom/xrsession.rs index 5460df4fef1..ee7a865d280 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; @@ -476,17 +476,10 @@ impl XRSession { /// Constructs a View suitable for inline sessions using the inlineVerticalFieldOfView and canvas size pub fn inline_view(&self) -> View<Viewer> { 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()), } } @@ -816,11 +809,14 @@ impl XRSessionMethods for XRSession { // The pose of an object in native-space. Should never be exposed. pub type ApiPose = RigidTransform3D<f32, ApiSpace, webxr_api::Native>; -// The pose of the viewer in some api-space. -pub type ApiViewerPose = RigidTransform3D<f32, webxr_api::Viewer, ApiSpace>; // A transform between objects in some API-space pub type ApiRigidTransform = RigidTransform3D<f32, ApiSpace, ApiSpace>; +#[derive(Clone, Copy)] +pub struct BaseSpace; + +pub type BaseTransform = RigidTransform3D<f32, webxr_api::Native, BaseSpace>; + #[allow(unsafe_code)] pub fn cast_transform<T, U, V, W>( transform: RigidTransform3D<f32, T, U>, diff --git a/components/script/dom/xrview.rs b/components/script/dom/xrview.rs index 8aa0b0adc58..55cac600f6b 100644 --- a/components/script/dom/xrview.rs +++ b/components/script/dom/xrview.rs @@ -9,23 +9,24 @@ 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::View; +use webxr_api::{ApiSpace, View}; #[dom_struct] pub struct XRView { reflector_: Reflector, session: Dom<XRSession>, eye: XREye, + viewport_index: usize, #[ignore_malloc_size_of = "mozjs"] proj: Heap<*mut JSObject>, - #[ignore_malloc_size_of = "mozjs"] - view: Heap<*mut JSObject>, - proj_array: Vec<f32>, + #[ignore_malloc_size_of = "defined in rust-webxr"] + view: View<ApiSpace>, transform: Dom<XRRigidTransform>, } @@ -34,15 +35,16 @@ impl XRView { session: &XRSession, transform: &XRRigidTransform, eye: XREye, - proj_array: Vec<f32>, + viewport_index: usize, + view: View<ApiSpace>, ) -> XRView { XRView { reflector_: Reflector::new(), session: Dom::from_ref(session), eye, + viewport_index, proj: Heap::default(), - view: Heap::default(), - proj_array, + view, transform: Dom::from_ref(transform), } } @@ -52,37 +54,31 @@ impl XRView { session: &XRSession, view: &View<V>, eye: XREye, - pose: &ApiViewerPose, + viewport_index: usize, + to_base: &BaseTransform, ) -> DomRoot<XRView> { - // 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<f32, V, BaseSpace> = to_base.pre_transform(&view.transform); 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(), + viewport_index, + view.cast_unit(), )), global, - ); - - let cx = global.get_cx(); - create_typed_array(cx, &proj, &ret.proj); - ret + ) } pub fn session(&self) -> &XRSession { &self.session } + + pub fn viewport_index(&self) -> usize { + self.viewport_index + } } impl XRViewMethods for XRView { @@ -95,7 +91,9 @@ impl XRViewMethods for XRView { fn ProjectionMatrix(&self, _cx: JSContext) -> NonNull<JSObject> { 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() } diff --git a/components/script/dom/xrviewerpose.rs b/components/script/dom/xrviewerpose.rs index 6e1ebe6422a..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::Views; +use webxr_api::{Viewer, ViewerPose, Views}; #[dom_struct] pub struct XRViewerPose { @@ -38,32 +39,76 @@ impl XRViewerPose { pub fn new( global: &GlobalScope, session: &XRSession, - pose: ApiViewerPose, + to_base: BaseTransform, + viewer_pose: &ViewerPose, ) -> DomRoot<XRViewerPose> { let _ac = enter_realm(&*global); rooted_vec!(let mut views); - session.with_session(|s| match s.views() { + match &viewer_pose.views { Views::Inline => views.push(XRView::new( global, session, &session.inline_view(), XREye::None, - &pose, + 0, + &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, &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, + &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, &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, + &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, + &to_base, + )); }, - }); - let transform = XRRigidTransform::new(global, cast_transform(pose)); + }; + let transform: RigidTransform3D<f32, Viewer, BaseSpace> = + 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(); diff --git a/components/script/dom/xrwebgllayer.rs b/components/script/dom/xrwebgllayer.rs index 6bab886a0fd..f93c4c22bc2 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::{Rect, 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] @@ -115,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; @@ -241,21 +244,16 @@ impl XRWebGLLayerMethods for XRWebGLLayer { return None; } - let views = self.session.with_session(|s| s.views().clone()); + let index = view.viewport_index(); - 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, - }; + 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)) } 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 |