From 623507187b4e8edb65d0a7135be9473f63838a75 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Tue, 23 Apr 2019 10:16:04 -0700 Subject: [PATCH 01/11] Update webvr --- Cargo.lock | 16 ++++++++-------- components/webvr/Cargo.toml | 2 +- components/webvr_traits/Cargo.toml | 2 +- ports/glutin/Cargo.toml | 2 +- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a918e5d59cb..274b1a3da49 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3457,7 +3457,7 @@ dependencies = [ [[package]] name = "rust-webvr" -version = "0.10.4" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bindgen 0.49.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3470,13 +3470,13 @@ dependencies = [ "libloading 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "ovr-mobile-sys 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rust-webvr-api 0.10.4 (registry+https://github.com/rust-lang/crates.io-index)", + "rust-webvr-api 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "winit 0.18.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rust-webvr-api" -version = "0.10.4" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "android_injected_glue 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3810,7 +3810,7 @@ dependencies = [ "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "osmesa-src 0.1.0 (git+https://github.com/servo/osmesa-src)", "osmesa-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rust-webvr 0.10.4 (registry+https://github.com/rust-lang/crates.io-index)", + "rust-webvr 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "sig 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "tinyfiledialogs 3.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -5137,7 +5137,7 @@ dependencies = [ "ipc-channel 0.11.2 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "msg 0.0.1", - "rust-webvr 0.10.4 (registry+https://github.com/rust-lang/crates.io-index)", + "rust-webvr 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "script_traits 0.0.1", "servo_config 0.0.1", "webvr_traits 0.0.1", @@ -5149,7 +5149,7 @@ version = "0.0.1" dependencies = [ "ipc-channel 0.11.2 (registry+https://github.com/rust-lang/crates.io-index)", "msg 0.0.1", - "rust-webvr-api 0.10.4 (registry+https://github.com/rust-lang/crates.io-index)", + "rust-webvr-api 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -5647,8 +5647,8 @@ dependencies = [ "checksum regex-syntax 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "dcfd8681eebe297b81d98498869d4aae052137651ad7b96822f09ceb690d0a96" "checksum remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3488ba1b9a2084d38645c4c08276a1752dcbf2c7130d74f1569681ad5d2799c5" "checksum ron 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "da06feaa07f69125ab9ddc769b11de29090122170b402547f64b86fe16ebc399" -"checksum rust-webvr 0.10.4 (registry+https://github.com/rust-lang/crates.io-index)" = "dd268264db4808e78ad1738ce1ff10a8bd53fb5ba408f595763174ca4a6fb875" -"checksum rust-webvr-api 0.10.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1b2af5c6c86fb79e70b5a34daa3d488411225707c73dc5467c7da7c83d557daf" +"checksum rust-webvr 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e9c827417035beccd02f5e1dde7866c80662efafb8bcfe659f0082d10def4faa" +"checksum rust-webvr-api 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b5208a3b3f0b02abf17e66c0fe1e0cd3a4f5172c9bf6d1a3e1ac6338a3d218d3" "checksum rustc-demangle 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "3058a43ada2c2d0b92b3ae38007a2d0fa5e9db971be260e0171408a4ff471c95" "checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" "checksum rusttype 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b8eb11f5b0a98c8eca2fb1483f42646d8c340e83e46ab416f8a063a0fd0eeb20" diff --git a/components/webvr/Cargo.toml b/components/webvr/Cargo.toml index faca3eb57a6..f4d195d29fe 100644 --- a/components/webvr/Cargo.toml +++ b/components/webvr/Cargo.toml @@ -22,7 +22,7 @@ gleam = "0.6" ipc-channel = "0.11" log = "0.4" msg = {path = "../msg"} -rust-webvr = {version = "0.10.2", features = ["openvr", "vrexternal"]} +rust-webvr = {version = "=0.11.0", features = ["openvr", "vrexternal"]} script_traits = {path = "../script_traits"} servo_config = {path = "../config"} webvr_traits = {path = "../webvr_traits" } diff --git a/components/webvr_traits/Cargo.toml b/components/webvr_traits/Cargo.toml index 032729334f3..bf268053a9d 100644 --- a/components/webvr_traits/Cargo.toml +++ b/components/webvr_traits/Cargo.toml @@ -13,5 +13,5 @@ path = "lib.rs" [dependencies] ipc-channel = "0.11" msg = {path = "../msg"} -rust-webvr-api = {version = "0.10.3", features = ["ipc"]} +rust-webvr-api = {version = "=0.11.0", features = ["ipc"]} serde = "1.0" diff --git a/ports/glutin/Cargo.toml b/ports/glutin/Cargo.toml index 4edbef5fd85..3ef0c32fe0c 100644 --- a/ports/glutin/Cargo.toml +++ b/ports/glutin/Cargo.toml @@ -52,7 +52,7 @@ lazy_static = "1" libservo = {path = "../../components/servo"} libc = "0.2" log = "0.4" -rust-webvr = { version = "0.10.2", features = ["glwindow"] } +rust-webvr = { version = "=0.11.0", features = ["glwindow"] } tinyfiledialogs = "3.0" [target.'cfg(any(target_os = "linux", target_os = "windows"))'.dependencies] From c1a8605c3dbce636a605b805fe89cdf0ad1923be Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Tue, 23 Apr 2019 10:16:56 -0700 Subject: [PATCH 02/11] Allow webvr thread consumers to request input data --- components/canvas_traits/webgl.rs | 8 ++++++-- components/script/dom/vrdisplay.rs | 17 +++++++++++------ components/webvr/webvr_thread.rs | 19 ++++++++++++++++--- components/webvr_traits/lib.rs | 6 ++++++ 4 files changed, 39 insertions(+), 11 deletions(-) diff --git a/components/canvas_traits/webgl.rs b/components/canvas_traits/webgl.rs index 474ae4b603b..af88ca905aa 100644 --- a/components/canvas_traits/webgl.rs +++ b/components/canvas_traits/webgl.rs @@ -12,7 +12,7 @@ use std::fmt; use std::num::NonZeroU32; use std::ops::Deref; use webrender_api::{DocumentId, ImageKey, PipelineId}; -use webvr_traits::WebVRFutureFrameData; +use webvr_traits::WebVRPoseInformation; /// Helper function that creates a WebGL channel (WebGLSender, WebGLReceiver) to be used in WebGLCommands. pub use crate::webgl_channel::webgl_channel; @@ -508,9 +508,13 @@ pub enum WebVRCommand { /// Synchronize the pose information to be used in the frame. SyncPoses( WebVRDeviceId, + // near f64, + // far f64, - WebGLSender>, + // sync gamepads too + bool, + WebGLSender>, ), /// Submit the frame to a VR device using the specified texture coordinates. SubmitFrame(WebVRDeviceId, [f32; 4], [f32; 4]), diff --git a/components/script/dom/vrdisplay.rs b/components/script/dom/vrdisplay.rs index a8cb594a2b1..3ad1eff44eb 100644 --- a/components/script/dom/vrdisplay.rs +++ b/components/script/dom/vrdisplay.rs @@ -51,7 +51,7 @@ use std::mem; use std::ops::Deref; use std::rc::Rc; use std::thread; -use webvr_traits::{WebVRDisplayData, WebVRDisplayEvent, WebVRFrameData, WebVRFutureFrameData}; +use webvr_traits::{WebVRDisplayData, WebVRDisplayEvent, WebVRFrameData, WebVRPoseInformation}; use webvr_traits::{WebVRLayer, WebVRMsg}; #[dom_struct] @@ -86,7 +86,7 @@ pub struct VRDisplay { // Compositor VRFrameData synchonization frame_data_status: Cell, #[ignore_malloc_size_of = "closures are hard"] - frame_data_receiver: DomRefCell>>>, + frame_data_receiver: DomRefCell>>>, running_display_raf: Cell, paused: Cell, stopped_on_pause: Cell, @@ -726,8 +726,13 @@ impl VRDisplay { .unwrap(); // Run Sync Poses in parallell on Render thread - let msg = - WebVRCommand::SyncPoses(display_id, near, far, sync_sender.clone()); + let msg = WebVRCommand::SyncPoses( + display_id, + near, + far, + false, + sync_sender.clone(), + ); api_sender.send_vr(msg).unwrap(); } else { let _ = wakeup_receiver.recv(); @@ -808,8 +813,8 @@ impl VRDisplay { fn sync_frame_data(&self) { let status = if let Some(receiver) = self.frame_data_receiver.borrow().as_ref() { match receiver.recv().unwrap() { - Ok(future_data) => { - *self.frame_data.borrow_mut() = future_data.block(); + Ok(pose) => { + *self.frame_data.borrow_mut() = pose.frame.block(); VRFrameDataStatus::Synced }, Err(()) => VRFrameDataStatus::Exit, diff --git a/components/webvr/webvr_thread.rs b/components/webvr/webvr_thread.rs index e7803509c82..1077581f10c 100644 --- a/components/webvr/webvr_thread.rs +++ b/components/webvr/webvr_thread.rs @@ -16,7 +16,7 @@ use std::collections::hash_map::Entry; use std::collections::{HashMap, HashSet}; use std::{thread, time}; use webvr_traits::webvr::*; -use webvr_traits::{WebVRMsg, WebVRResult}; +use webvr_traits::{WebVRMsg, WebVRPoseInformation, WebVRResult}; /// WebVRThread owns native VRDisplays, handles their life cycle inside Servo and /// acts a doorman for untrusted VR requests from DOM Objects. These are the key components @@ -386,10 +386,23 @@ impl webgl::WebVRRenderHandler for WebVRCompositorHandler { unsafe { (*compositor.0).start_present(None) }; } }, - webgl::WebVRCommand::SyncPoses(compositor_id, near, far, sender) => { + webgl::WebVRCommand::SyncPoses(compositor_id, near, far, get_gamepads, sender) => { if let Some(compositor) = self.compositors.get(&compositor_id) { let pose = unsafe { (*compositor.0).future_frame_data(near, far) }; - let _ = sender.send(Ok(pose)); + let mut pose_information = WebVRPoseInformation { + frame: pose, + gamepads: vec![], + }; + if get_gamepads { + let gamepads = unsafe { (*compositor.0).fetch_gamepads() }; + if let Ok(gamepads) = gamepads { + for gamepad in gamepads { + let g = gamepad.borrow(); + pose_information.gamepads.push((g.id(), g.state())); + } + } + } + let _ = sender.send(Ok(pose_information)); } else { let _ = sender.send(Err(())); } diff --git a/components/webvr_traits/lib.rs b/components/webvr_traits/lib.rs index ab31436c136..f96fee056e7 100644 --- a/components/webvr_traits/lib.rs +++ b/components/webvr_traits/lib.rs @@ -30,3 +30,9 @@ pub use rust_webvr_api::VRLayer as WebVRLayer; pub use rust_webvr_api::VRMainThreadHeartbeat as WebVRMainThreadHeartbeat; pub use rust_webvr_api::VRPose as WebVRPose; pub use rust_webvr_api::VRStageParameters as WebVRStageParameters; + +#[derive(Deserialize, Serialize)] +pub struct WebVRPoseInformation { + pub frame: WebVRFutureFrameData, + pub gamepads: Vec<(u32, WebVRGamepadState)>, +} From 0f952c7ff8d4132c2a6eca9acf599788c1ec9c8c Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Mon, 29 Apr 2019 17:25:24 -0700 Subject: [PATCH 03/11] Add blank XRInputSource --- components/script/dom/mod.rs | 1 + .../script/dom/webidls/XRInputSource.webidl | 26 +++++++++++++++ components/script/dom/xrinputsource.rs | 33 +++++++++++++++++++ 3 files changed, 60 insertions(+) create mode 100644 components/script/dom/webidls/XRInputSource.webidl create mode 100644 components/script/dom/xrinputsource.rs diff --git a/components/script/dom/mod.rs b/components/script/dom/mod.rs index ff1688fb6c3..4e9f49e46f9 100644 --- a/components/script/dom/mod.rs +++ b/components/script/dom/mod.rs @@ -540,6 +540,7 @@ pub mod xmlhttprequestupload; pub mod xmlserializer; pub mod xr; pub mod xrframe; +pub mod xrinputsource; pub mod xrlayer; pub mod xrpose; pub mod xrreferencespace; diff --git a/components/script/dom/webidls/XRInputSource.webidl b/components/script/dom/webidls/XRInputSource.webidl new file mode 100644 index 00000000000..813d14e4615 --- /dev/null +++ b/components/script/dom/webidls/XRInputSource.webidl @@ -0,0 +1,26 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +// https://immersive-web.github.io/webxr/#xrinputsource-interface + +enum XRHandedness { + "none", + "left", + "right" +}; + +enum XRTargetRayMode { + "gaze", + "tracked-pointer", + "screen" +}; + +[SecureContext, Exposed=Window, Pref="dom.webxr.enabled"] +interface XRInputSource { + // [SameObject] readonly attribute XRHandedness handedness; + // [SameObject] readonly attribute XRTargetRayMode targetRayMode; + // [SameObject] readonly attribute XRSpace targetRaySpace; + // [SameObject] readonly attribute XRSpace? gripSpace; + // [SameObject] readonly attribute Gamepad? gamepad; +}; diff --git a/components/script/dom/xrinputsource.rs b/components/script/dom/xrinputsource.rs new file mode 100644 index 00000000000..1e0592f3c12 --- /dev/null +++ b/components/script/dom/xrinputsource.rs @@ -0,0 +1,33 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +use crate::dom::bindings::codegen::Bindings::XRInputSourceBinding; +use crate::dom::bindings::reflector::{Reflector, reflect_dom_object}; +use crate::dom::bindings::root::{Dom, DomRoot}; +use crate::dom::globalscope::GlobalScope; +use crate::dom::xrsession::XRSession; +use dom_struct::dom_struct; + +#[dom_struct] +pub struct XRInputSource { + reflector: Reflector, + session: Dom, +} + +impl XRInputSource { + pub fn new_inherited(session: &XRSession) -> XRInputSource { + XRInputSource { + reflector: Reflector::new(), + session: Dom::from_ref(session), + } + } + + pub fn new(global: &GlobalScope, session: &XRSession) -> DomRoot { + reflect_dom_object( + Box::new(XRInputSource::new_inherited(session)), + global, + XRInputSourceBinding::Wrap, + ) + } +} From f98143d60bf7065ca8c59bf610d60c2a6dee55e7 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Mon, 29 Apr 2019 18:16:18 -0700 Subject: [PATCH 04/11] Add GetGamepadsForDisplay message for initializing inputs --- components/webvr/webvr_thread.rs | 29 +++++++++++++++++++++++++ components/webvr_traits/webvr_traits.rs | 4 ++++ 2 files changed, 33 insertions(+) diff --git a/components/webvr/webvr_thread.rs b/components/webvr/webvr_thread.rs index 1077581f10c..e90ddbf7df5 100644 --- a/components/webvr/webvr_thread.rs +++ b/components/webvr/webvr_thread.rs @@ -128,6 +128,9 @@ impl WebVRThread { WebVRMsg::GetGamepads(synced_ids, sender) => { self.handle_get_gamepads(synced_ids, sender); }, + WebVRMsg::GetGamepadsForDisplay(display_id, sender) => { + self.handle_get_gamepads_for_display(display_id, sender); + }, WebVRMsg::Exit => break, } } @@ -251,6 +254,32 @@ impl WebVRThread { self.vr_compositor_chan.send(compositor).unwrap(); } + fn handle_get_gamepads_for_display( + &mut self, + display_id: u32, + sender: IpcSender>>, + ) { + match self.service.get_display(display_id) { + Some(display) => { + let gamepads = display.borrow_mut().fetch_gamepads(); + match gamepads { + Ok(gamepads) => { + let data = gamepads + .iter() + .map(|g| { + let g = g.borrow(); + (g.data(), g.state()) + }) + .collect(); + sender.send(Ok(data)).unwrap(); + }, + Err(e) => sender.send(Err(e)).unwrap(), + } + }, + None => sender.send(Err("Device not found".into())).unwrap(), + } + } + fn handle_get_gamepads( &mut self, synced_ids: Vec, diff --git a/components/webvr_traits/webvr_traits.rs b/components/webvr_traits/webvr_traits.rs index 0f6dd069867..d21e6c3ff16 100644 --- a/components/webvr_traits/webvr_traits.rs +++ b/components/webvr_traits/webvr_traits.rs @@ -30,5 +30,9 @@ pub enum WebVRMsg { Vec, IpcSender, VRGamepadState)>>>, ), + GetGamepadsForDisplay( + u32, + IpcSender>>, + ), Exit, } From 3a08e917e0c8501b4d56a31ae3ef6788743b4f9f Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Mon, 29 Apr 2019 18:32:48 -0700 Subject: [PATCH 05/11] Write method for initializing input sources --- components/script/dom/bindings/trace.rs | 4 +-- components/script/dom/vrdisplay.rs | 43 ++++++++++++++++++++++++- components/script/dom/xrinputsource.rs | 25 +++++++++++--- 3 files changed, 65 insertions(+), 7 deletions(-) diff --git a/components/script/dom/bindings/trace.rs b/components/script/dom/bindings/trace.rs index 56805e4d9fe..2132e487efb 100644 --- a/components/script/dom/bindings/trace.rs +++ b/components/script/dom/bindings/trace.rs @@ -138,7 +138,7 @@ use tendril::{StrTendril, TendrilSink}; use time::{Duration, Timespec}; use uuid::Uuid; use webrender_api::{DocumentId, ImageKey, RenderApiSender}; -use webvr_traits::WebVRGamepadHand; +use webvr_traits::{WebVRGamepadData, WebVRGamepadHand, WebVRGamepadState}; /// A trait to allow tracing (only) DOM objects. pub unsafe trait JSTraceable { @@ -478,7 +478,7 @@ unsafe_no_jsmanaged_fields!(WebGLVertexArrayId); unsafe_no_jsmanaged_fields!(WebGLVersion); unsafe_no_jsmanaged_fields!(WebGLSLVersion); unsafe_no_jsmanaged_fields!(MediaList); -unsafe_no_jsmanaged_fields!(WebVRGamepadHand); +unsafe_no_jsmanaged_fields!(WebVRGamepadData, WebVRGamepadState, WebVRGamepadHand); unsafe_no_jsmanaged_fields!(ScriptToConstellationChan); unsafe_no_jsmanaged_fields!(InteractiveMetrics); unsafe_no_jsmanaged_fields!(InteractiveWindow); diff --git a/components/script/dom/vrdisplay.rs b/components/script/dom/vrdisplay.rs index 3ad1eff44eb..c00d1c75e64 100644 --- a/components/script/dom/vrdisplay.rs +++ b/components/script/dom/vrdisplay.rs @@ -22,7 +22,7 @@ use crate::dom::bindings::inheritance::Castable; use crate::dom::bindings::num::Finite; use crate::dom::bindings::refcounted::{Trusted, TrustedPromise}; use crate::dom::bindings::reflector::{reflect_dom_object, DomObject}; -use crate::dom::bindings::root::{DomRoot, MutDom, MutNullableDom}; +use crate::dom::bindings::root::{Dom, DomRoot, MutDom, MutNullableDom}; use crate::dom::bindings::str::DOMString; use crate::dom::event::Event; use crate::dom::eventtarget::EventTarget; @@ -36,6 +36,7 @@ use crate::dom::vrpose::VRPose; use crate::dom::vrstageparameters::VRStageParameters; use crate::dom::webglrenderingcontext::WebGLRenderingContext; use crate::dom::xrframe::XRFrame; +use crate::dom::xrinputsource::XRInputSource; use crate::dom::xrsession::XRSession; use crate::dom::xrwebgllayer::XRWebGLLayer; use crate::script_runtime::CommonScriptMsg; @@ -47,6 +48,7 @@ use dom_struct::dom_struct; use ipc_channel::ipc::IpcSender; use profile_traits::ipc; use std::cell::Cell; +use std::collections::HashMap; use std::mem; use std::ops::Deref; use std::rc::Rc; @@ -92,6 +94,10 @@ pub struct VRDisplay { stopped_on_pause: Cell, /// Whether or not this is XR mode, and the session xr_session: MutNullableDom, + /// Have inputs been initialized? (i.e, has getInputSources() been called?) + /// XR only + initialized_inputs: Cell, + input_sources: DomRefCell>>, } unsafe_no_jsmanaged_fields!(WebVRDisplayData); @@ -164,6 +170,8 @@ impl VRDisplay { // When the VR Resume event is received and the flag is set, VR presentation automatically restarts. stopped_on_pause: Cell::new(false), xr_session: MutNullableDom::default(), + initialized_inputs: Cell::new(false), + input_sources: DomRefCell::new(HashMap::new()), } } @@ -914,6 +922,39 @@ impl VRDisplay { pair.1 = None; } } + + /// Initialize XRInputSources + fn initialize_inputs(&self) { + if self.initialized_inputs.get() { + return + } + self.initialized_inputs.set(true); + + let (sender, receiver) = ipc::channel(self.global().time_profiler_chan().clone()).unwrap(); + let display = self.display.borrow().display_id; + self.webvr_thread() + .send(WebVRMsg::GetGamepadsForDisplay(display, sender)) + .unwrap(); + match receiver.recv().unwrap() { + Ok(gamepads) => { + let global = self.global(); + let session = self + .xr_session + .get() + .expect("initialize_inputs called on a VR session"); + let roots: Vec<_> = gamepads + .into_iter() + .map(|g| (g.1.gamepad_id, XRInputSource::new(&global, &session, g.0, g.1))) + .collect(); + + let mut inputs = self.input_sources.borrow_mut(); + for (id, root) in &roots { + inputs.insert(*id, Dom::from_ref(&root)); + } + }, + Err(_) => {}, + } + } } // WebVR Spec: If the number of values in the leftBounds/rightBounds arrays diff --git a/components/script/dom/xrinputsource.rs b/components/script/dom/xrinputsource.rs index 1e0592f3c12..ca6ce47677f 100644 --- a/components/script/dom/xrinputsource.rs +++ b/components/script/dom/xrinputsource.rs @@ -2,30 +2,47 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ +use crate::dom::bindings::cell::DomRefCell; use crate::dom::bindings::codegen::Bindings::XRInputSourceBinding; -use crate::dom::bindings::reflector::{Reflector, reflect_dom_object}; +use crate::dom::bindings::reflector::{reflect_dom_object, Reflector}; use crate::dom::bindings::root::{Dom, DomRoot}; use crate::dom::globalscope::GlobalScope; use crate::dom::xrsession::XRSession; use dom_struct::dom_struct; +use webvr_traits::{WebVRGamepadData, WebVRGamepadState}; #[dom_struct] pub struct XRInputSource { reflector: Reflector, session: Dom, + #[ignore_malloc_size_of = "Defined in rust-webvr"] + data: WebVRGamepadData, + #[ignore_malloc_size_of = "Defined in rust-webvr"] + state: DomRefCell, } impl XRInputSource { - pub fn new_inherited(session: &XRSession) -> XRInputSource { + pub fn new_inherited( + session: &XRSession, + data: WebVRGamepadData, + state: WebVRGamepadState, + ) -> XRInputSource { XRInputSource { reflector: Reflector::new(), session: Dom::from_ref(session), + data, + state: DomRefCell::new(state), } } - pub fn new(global: &GlobalScope, session: &XRSession) -> DomRoot { + pub fn new( + global: &GlobalScope, + session: &XRSession, + data: WebVRGamepadData, + state: WebVRGamepadState, + ) -> DomRoot { reflect_dom_object( - Box::new(XRInputSource::new_inherited(session)), + Box::new(XRInputSource::new_inherited(session, data, state)), global, XRInputSourceBinding::Wrap, ) From 5c8132c379a2d5612d5c904c7fe65b54d7f8ec70 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Mon, 29 Apr 2019 19:15:27 -0700 Subject: [PATCH 06/11] Use initialized input sources in getInputSources() --- components/script/dom/vrdisplay.rs | 11 ++++++++++- components/script/dom/webidls/XRSession.webidl | 3 +++ components/script/dom/xrsession.rs | 6 ++++++ 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/components/script/dom/vrdisplay.rs b/components/script/dom/vrdisplay.rs index c00d1c75e64..1f7480e2ef0 100644 --- a/components/script/dom/vrdisplay.rs +++ b/components/script/dom/vrdisplay.rs @@ -926,7 +926,7 @@ impl VRDisplay { /// Initialize XRInputSources fn initialize_inputs(&self) { if self.initialized_inputs.get() { - return + return; } self.initialized_inputs.set(true); @@ -955,6 +955,15 @@ impl VRDisplay { Err(_) => {}, } } + + pub fn get_input_sources(&self) -> Vec> { + self.initialize_inputs(); + self.input_sources + .borrow() + .iter() + .map(|(_, x)| DomRoot::from_ref(&**x)) + .collect() + } } // WebVR Spec: If the number of values in the leftBounds/rightBounds arrays diff --git a/components/script/dom/webidls/XRSession.webidl b/components/script/dom/webidls/XRSession.webidl index f22918d469d..798a8f7b7ae 100644 --- a/components/script/dom/webidls/XRSession.webidl +++ b/components/script/dom/webidls/XRSession.webidl @@ -25,7 +25,10 @@ interface XRSession : EventTarget { // // Methods Promise requestReferenceSpace(XRReferenceSpaceOptions options); + // workaround until we have FrozenArray + // see https://github.com/servo/servo/issues/10427#issuecomment-449593626 // FrozenArray getInputSources(); + sequence getInputSources(); Promise updateRenderState(optional XRRenderStateInit state); long requestAnimationFrame(XRFrameRequestCallback callback); diff --git a/components/script/dom/xrsession.rs b/components/script/dom/xrsession.rs index 4b855cba4c8..67c7a10e36c 100644 --- a/components/script/dom/xrsession.rs +++ b/components/script/dom/xrsession.rs @@ -19,6 +19,7 @@ use crate::dom::eventtarget::EventTarget; use crate::dom::globalscope::GlobalScope; use crate::dom::promise::Promise; use crate::dom::vrdisplay::VRDisplay; +use crate::dom::xrinputsource::XRInputSource; use crate::dom::xrlayer::XRLayer; use crate::dom::xrreferencespace::XRReferenceSpace; use crate::dom::xrrenderstate::XRRenderState; @@ -153,4 +154,9 @@ impl XRSessionMethods for XRSession { p } + + /// https://immersive-web.github.io/webxr/#dom-xrsession-getinputsources + fn GetInputSources(&self) -> Vec> { + self.display.get_input_sources() + } } From b693af6a541dffb770d0e8daa53800ee20e3f70f Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Mon, 29 Apr 2019 20:07:59 -0700 Subject: [PATCH 07/11] Sync input source data every frame if necessary --- components/script/dom/vrdisplay.rs | 22 ++++++++++++++++++++-- components/script/dom/xrinputsource.rs | 4 ++++ 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/components/script/dom/vrdisplay.rs b/components/script/dom/vrdisplay.rs index 1f7480e2ef0..77817bae2fc 100644 --- a/components/script/dom/vrdisplay.rs +++ b/components/script/dom/vrdisplay.rs @@ -121,6 +121,8 @@ struct VRRAFUpdate { /// Number uniquely identifying the WebGL context /// so that we may setup/tear down VR compositors as things change context_id: usize, + /// Do we need input data? + needs_inputs: bool, } type VRRAFUpdateSender = Sender>; @@ -635,6 +637,7 @@ impl VRDisplay { depth_far: self.depth_far.get(), api_sender: self.api_sender(), context_id: self.context_id(), + needs_inputs: self.initialized_inputs.get(), } } @@ -698,6 +701,7 @@ impl VRDisplay { let (raf_sender, raf_receiver) = unbounded(); let (wakeup_sender, wakeup_receiver) = unbounded(); *self.raf_wakeup_sender.borrow_mut() = Some(wakeup_sender); + let mut needs_inputs = false; // The render loop at native headset frame rate is implemented using a dedicated thread. // Every loop iteration syncs pose data with the HMD, submits the pixels to the display and waits for Vsync. @@ -738,7 +742,7 @@ impl VRDisplay { display_id, near, far, - false, + needs_inputs, sync_sender.clone(), ); api_sender.send_vr(msg).unwrap(); @@ -765,6 +769,7 @@ impl VRDisplay { if let Ok(update) = raf_receiver.recv().unwrap() { near = update.depth_near; far = update.depth_far; + needs_inputs = update.needs_inputs; if update.context_id != context_id { if let Some(ref api_sender) = update.api_sender { api_sender @@ -823,6 +828,14 @@ impl VRDisplay { match receiver.recv().unwrap() { Ok(pose) => { *self.frame_data.borrow_mut() = pose.frame.block(); + if self.initialized_inputs.get() { + let inputs = self.input_sources.borrow(); + for (id, state) in pose.gamepads { + if let Some(input) = inputs.get(&id) { + input.update_state(state); + } + } + } VRFrameDataStatus::Synced }, Err(()) => VRFrameDataStatus::Exit, @@ -944,7 +957,12 @@ impl VRDisplay { .expect("initialize_inputs called on a VR session"); let roots: Vec<_> = gamepads .into_iter() - .map(|g| (g.1.gamepad_id, XRInputSource::new(&global, &session, g.0, g.1))) + .map(|g| { + ( + g.1.gamepad_id, + XRInputSource::new(&global, &session, g.0, g.1), + ) + }) .collect(); let mut inputs = self.input_sources.borrow_mut(); diff --git a/components/script/dom/xrinputsource.rs b/components/script/dom/xrinputsource.rs index ca6ce47677f..f79716028eb 100644 --- a/components/script/dom/xrinputsource.rs +++ b/components/script/dom/xrinputsource.rs @@ -47,4 +47,8 @@ impl XRInputSource { XRInputSourceBinding::Wrap, ) } + + pub fn update_state(&self, state: WebVRGamepadState) { + *self.state.borrow_mut() = state; + } } From e5716624d462d26fc840a1af124beaf482e26111 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Mon, 29 Apr 2019 20:15:18 -0700 Subject: [PATCH 08/11] Add XRInputSource.handedness --- .../script/dom/webidls/XRInputSource.webidl | 2 +- components/script/dom/xrinputsource.rs | 16 +++++++++++++++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/components/script/dom/webidls/XRInputSource.webidl b/components/script/dom/webidls/XRInputSource.webidl index 813d14e4615..9270ff50823 100644 --- a/components/script/dom/webidls/XRInputSource.webidl +++ b/components/script/dom/webidls/XRInputSource.webidl @@ -18,7 +18,7 @@ enum XRTargetRayMode { [SecureContext, Exposed=Window, Pref="dom.webxr.enabled"] interface XRInputSource { - // [SameObject] readonly attribute XRHandedness handedness; + readonly attribute XRHandedness handedness; // [SameObject] readonly attribute XRTargetRayMode targetRayMode; // [SameObject] readonly attribute XRSpace targetRaySpace; // [SameObject] readonly attribute XRSpace? gripSpace; diff --git a/components/script/dom/xrinputsource.rs b/components/script/dom/xrinputsource.rs index f79716028eb..dcb86a23622 100644 --- a/components/script/dom/xrinputsource.rs +++ b/components/script/dom/xrinputsource.rs @@ -4,12 +4,15 @@ use crate::dom::bindings::cell::DomRefCell; use crate::dom::bindings::codegen::Bindings::XRInputSourceBinding; +use crate::dom::bindings::codegen::Bindings::XRInputSourceBinding::{ + XRHandedness, XRInputSourceMethods, +}; use crate::dom::bindings::reflector::{reflect_dom_object, Reflector}; use crate::dom::bindings::root::{Dom, DomRoot}; use crate::dom::globalscope::GlobalScope; use crate::dom::xrsession::XRSession; use dom_struct::dom_struct; -use webvr_traits::{WebVRGamepadData, WebVRGamepadState}; +use webvr_traits::{WebVRGamepadData, WebVRGamepadHand, WebVRGamepadState}; #[dom_struct] pub struct XRInputSource { @@ -52,3 +55,14 @@ impl XRInputSource { *self.state.borrow_mut() = state; } } + +impl XRInputSourceMethods for XRInputSource { + /// https://immersive-web.github.io/webxr/#dom-xrinputsource-handedness + fn Handedness(&self) -> XRHandedness { + match self.data.hand { + WebVRGamepadHand::Unknown => XRHandedness::None, + WebVRGamepadHand::Left => XRHandedness::Left, + WebVRGamepadHand::Right => XRHandedness::Right, + } + } +} From d4a6a4987da86e363ccef6f3eaeeeee0cd8593aa Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Mon, 29 Apr 2019 20:27:07 -0700 Subject: [PATCH 09/11] Add XRInputSource.targetRaySpace --- .../script/dom/webidls/XRInputSource.webidl | 2 +- components/script/dom/xrinputsource.rs | 21 ++++++++-- components/script/dom/xrreferencespace.rs | 2 +- components/script/dom/xrspace.rs | 39 ++++++++++++++++--- .../script/dom/xrstationaryreferencespace.rs | 4 +- 5 files changed, 55 insertions(+), 13 deletions(-) diff --git a/components/script/dom/webidls/XRInputSource.webidl b/components/script/dom/webidls/XRInputSource.webidl index 9270ff50823..5ad1e48628f 100644 --- a/components/script/dom/webidls/XRInputSource.webidl +++ b/components/script/dom/webidls/XRInputSource.webidl @@ -20,7 +20,7 @@ enum XRTargetRayMode { interface XRInputSource { readonly attribute XRHandedness handedness; // [SameObject] readonly attribute XRTargetRayMode targetRayMode; - // [SameObject] readonly attribute XRSpace targetRaySpace; + [SameObject] readonly attribute XRSpace targetRaySpace; // [SameObject] readonly attribute XRSpace? gripSpace; // [SameObject] readonly attribute Gamepad? gamepad; }; diff --git a/components/script/dom/xrinputsource.rs b/components/script/dom/xrinputsource.rs index dcb86a23622..2b623864d56 100644 --- a/components/script/dom/xrinputsource.rs +++ b/components/script/dom/xrinputsource.rs @@ -7,12 +7,13 @@ use crate::dom::bindings::codegen::Bindings::XRInputSourceBinding; use crate::dom::bindings::codegen::Bindings::XRInputSourceBinding::{ XRHandedness, XRInputSourceMethods, }; -use crate::dom::bindings::reflector::{reflect_dom_object, Reflector}; -use crate::dom::bindings::root::{Dom, DomRoot}; +use crate::dom::bindings::reflector::{reflect_dom_object, DomObject, Reflector}; +use crate::dom::bindings::root::{Dom, DomRoot, MutNullableDom}; use crate::dom::globalscope::GlobalScope; use crate::dom::xrsession::XRSession; +use crate::dom::xrspace::XRSpace; use dom_struct::dom_struct; -use webvr_traits::{WebVRGamepadData, WebVRGamepadHand, WebVRGamepadState}; +use webvr_traits::{WebVRGamepadData, WebVRGamepadHand, WebVRGamepadState, WebVRPose}; #[dom_struct] pub struct XRInputSource { @@ -22,6 +23,7 @@ pub struct XRInputSource { data: WebVRGamepadData, #[ignore_malloc_size_of = "Defined in rust-webvr"] state: DomRefCell, + target_ray_space: MutNullableDom, } impl XRInputSource { @@ -35,6 +37,7 @@ impl XRInputSource { session: Dom::from_ref(session), data, state: DomRefCell::new(state), + target_ray_space: Default::default(), } } @@ -54,6 +57,10 @@ impl XRInputSource { pub fn update_state(&self, state: WebVRGamepadState) { *self.state.borrow_mut() = state; } + + pub fn pose(&self) -> WebVRPose { + self.state.borrow().pose + } } impl XRInputSourceMethods for XRInputSource { @@ -65,4 +72,12 @@ impl XRInputSourceMethods for XRInputSource { WebVRGamepadHand::Right => XRHandedness::Right, } } + + /// https://immersive-web.github.io/webxr/#dom-xrinputsource-targetrayspace + fn TargetRaySpace(&self) -> DomRoot { + self.target_ray_space.or_init(|| { + let global = self.global(); + XRSpace::new_inputspace(&global, &self.session, &self) + }) + } } diff --git a/components/script/dom/xrreferencespace.rs b/components/script/dom/xrreferencespace.rs index 664dc4f0e23..932f917b5a5 100644 --- a/components/script/dom/xrreferencespace.rs +++ b/components/script/dom/xrreferencespace.rs @@ -110,7 +110,7 @@ impl XRReferenceSpace { // non-subclassed XRReferenceSpaces exist, obtained via the "identity" // type. These are equivalent to the viewer pose and follow the headset // around - XRSpace::viewer_pose_from_frame_data(base_pose) + XRSpace::pose_to_transform(&base_pose.pose) } } } diff --git a/components/script/dom/xrspace.rs b/components/script/dom/xrspace.rs index 8948ac03c8e..30f9246c354 100644 --- a/components/script/dom/xrspace.rs +++ b/components/script/dom/xrspace.rs @@ -5,20 +5,22 @@ use crate::dom::bindings::codegen::Bindings::XRSpaceBinding; use crate::dom::bindings::inheritance::Castable; use crate::dom::bindings::reflector::reflect_dom_object; -use crate::dom::bindings::root::{Dom, DomRoot}; +use crate::dom::bindings::root::{Dom, DomRoot, MutNullableDom}; use crate::dom::eventtarget::EventTarget; use crate::dom::globalscope::GlobalScope; +use crate::dom::xrinputsource::XRInputSource; use crate::dom::xrreferencespace::XRReferenceSpace; use crate::dom::xrsession::XRSession; use dom_struct::dom_struct; use euclid::{RigidTransform3D, Rotation3D, Vector3D}; -use webvr_traits::WebVRFrameData; +use webvr_traits::{WebVRFrameData, WebVRPose}; #[dom_struct] pub struct XRSpace { eventtarget: EventTarget, session: Dom, is_viewerspace: bool, + input_source: MutNullableDom, } impl XRSpace { @@ -27,6 +29,7 @@ impl XRSpace { eventtarget: EventTarget::new_inherited(), session: Dom::from_ref(session), is_viewerspace: false, + input_source: Default::default(), } } @@ -35,6 +38,7 @@ impl XRSpace { eventtarget: EventTarget::new_inherited(), session: Dom::from_ref(session), is_viewerspace: true, + input_source: Default::default(), } } @@ -45,6 +49,27 @@ impl XRSpace { XRSpaceBinding::Wrap, ) } + + fn new_inputspace_inner(session: &XRSession, input: &XRInputSource) -> XRSpace { + XRSpace { + eventtarget: EventTarget::new_inherited(), + session: Dom::from_ref(session), + is_viewerspace: false, + input_source: MutNullableDom::new(Some(input)), + } + } + + pub fn new_inputspace( + global: &GlobalScope, + session: &XRSession, + input: &XRInputSource, + ) -> DomRoot { + reflect_dom_object( + Box::new(XRSpace::new_inputspace_inner(session, input)), + global, + XRSpaceBinding::Wrap, + ) + } } impl XRSpace { @@ -57,16 +82,18 @@ impl XRSpace { if let Some(reference) = self.downcast::() { reference.get_pose(base_pose) } else if self.is_viewerspace { - XRSpace::viewer_pose_from_frame_data(base_pose) + XRSpace::pose_to_transform(&base_pose.pose) + } else if let Some(source) = self.input_source.get() { + XRSpace::pose_to_transform(&source.pose()) } else { unreachable!() } } - pub fn viewer_pose_from_frame_data(data: &WebVRFrameData) -> RigidTransform3D { - let pos = data.pose.position.unwrap_or([0., 0., 0.]); + pub fn pose_to_transform(pose: &WebVRPose) -> RigidTransform3D { + let pos = pose.position.unwrap_or([0., 0., 0.]); let translation = Vector3D::new(pos[0] as f64, pos[1] as f64, pos[2] as f64); - let orient = data.pose.orientation.unwrap_or([0., 0., 0., 0.]); + let orient = pose.orientation.unwrap_or([0., 0., 0., 0.]); let rotation = Rotation3D::quaternion( orient[0] as f64, orient[1] as f64, diff --git a/components/script/dom/xrstationaryreferencespace.rs b/components/script/dom/xrstationaryreferencespace.rs index a867aa0d976..65a0aebb790 100644 --- a/components/script/dom/xrstationaryreferencespace.rs +++ b/components/script/dom/xrstationaryreferencespace.rs @@ -55,7 +55,7 @@ impl XRStationaryReferenceSpace { /// /// Does not apply originOffset, use get_viewer_pose on XRReferenceSpace instead pub fn get_unoffset_viewer_pose(&self, viewer_pose: &WebVRFrameData) -> RigidTransform3D { - let viewer_pose = XRSpace::viewer_pose_from_frame_data(viewer_pose); + let viewer_pose = XRSpace::pose_to_transform(&viewer_pose.pose); // 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) @@ -113,7 +113,7 @@ impl XRStationaryReferenceSpace { }, XRStationaryReferenceSpaceSubtype::Position_disabled => { // This space follows the user around, but does not mirror the user's orientation - let viewer_pose = XRSpace::viewer_pose_from_frame_data(viewer_pose); + let viewer_pose = XRSpace::pose_to_transform(&viewer_pose.pose); viewer_pose.translation.into() }, } From 0756923e526dca922296a8a27af92234cd2ed544 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Mon, 29 Apr 2019 20:59:52 -0700 Subject: [PATCH 10/11] Make viewerSpace [SameObject] --- components/script/dom/webidls/XRSession.webidl | 2 +- components/script/dom/xrsession.rs | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/components/script/dom/webidls/XRSession.webidl b/components/script/dom/webidls/XRSession.webidl index 798a8f7b7ae..0399f2d0bc1 100644 --- a/components/script/dom/webidls/XRSession.webidl +++ b/components/script/dom/webidls/XRSession.webidl @@ -20,7 +20,7 @@ interface XRSession : EventTarget { readonly attribute XREnvironmentBlendMode environmentBlendMode; readonly attribute XRRenderState renderState; - readonly attribute XRSpace viewerSpace; + [SameObject] readonly attribute XRSpace viewerSpace; // // Methods Promise requestReferenceSpace(XRReferenceSpaceOptions options); diff --git a/components/script/dom/xrsession.rs b/components/script/dom/xrsession.rs index 67c7a10e36c..5aab6341ca4 100644 --- a/components/script/dom/xrsession.rs +++ b/components/script/dom/xrsession.rs @@ -34,6 +34,7 @@ pub struct XRSession { display: Dom, base_layer: MutNullableDom, blend_mode: XREnvironmentBlendMode, + viewer_space: MutNullableDom, } impl XRSession { @@ -44,6 +45,7 @@ impl XRSession { base_layer: Default::default(), // we don't yet support any AR devices blend_mode: XREnvironmentBlendMode::Opaque, + viewer_space: Default::default(), } } @@ -87,7 +89,8 @@ impl XRSessionMethods for XRSession { // https://immersive-web.github.io/webxr/#dom-xrsession-viewerspace fn ViewerSpace(&self) -> DomRoot { - XRSpace::new_viewerspace(&self.global(), &self) + self.viewer_space + .or_init(|| XRSpace::new_viewerspace(&self.global(), &self)) } /// https://immersive-web.github.io/webxr/#dom-xrsession-requestanimationframe From f17f0664950b769e2e57dd7628463f9ad7e60699 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Fri, 3 May 2019 13:52:23 -0700 Subject: [PATCH 11/11] Fix orientation getter in XRRigidTransform --- components/script/dom/xrrigidtransform.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/script/dom/xrrigidtransform.rs b/components/script/dom/xrrigidtransform.rs index 969ec839292..a3b30a1eb0f 100644 --- a/components/script/dom/xrrigidtransform.rs +++ b/components/script/dom/xrrigidtransform.rs @@ -93,7 +93,7 @@ impl XRRigidTransformMethods for XRRigidTransform { } // https://immersive-web.github.io/webxr/#dom-xrrigidtransform-orientation fn Orientation(&self) -> DomRoot { - self.position.or_init(|| { + self.orientation.or_init(|| { let r = &self.transform.rotation; DOMPointReadOnly::new(&self.global(), r.i, r.j, r.k, r.r) })