From 90e87b97baa7bf9b57d72a562c98af3ed2b52e88 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Mon, 7 Jan 2019 15:24:26 -0800 Subject: [PATCH 1/3] Init XR present on XR::RequestSession() with empty context --- components/script/dom/vrdisplay.rs | 6 +++--- components/script/dom/xr.rs | 5 ++--- components/script/dom/xrsession.rs | 8 +++++--- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/components/script/dom/vrdisplay.rs b/components/script/dom/vrdisplay.rs index 896bd0d4f81..2115f7ef218 100644 --- a/components/script/dom/vrdisplay.rs +++ b/components/script/dom/vrdisplay.rs @@ -688,12 +688,12 @@ impl VRDisplay { // XR stuff // XXXManishearth eventually we should share as much logic as possible impl VRDisplay { - pub fn xr_present(&self, session: &XRSession, ctx: &WebGLRenderingContext) { + pub fn xr_present(&self, session: &XRSession, ctx: Option<&WebGLRenderingContext>) { let layer_bounds = WebVRLayer::default(); self.xr_session.set(Some(session)); if self.presenting.get() { *self.layer.borrow_mut() = layer_bounds; - self.layer_ctx.set(Some(&ctx)); + self.layer_ctx.set(ctx); return; } @@ -709,7 +709,7 @@ impl VRDisplay { if let Ok(()) = receiver.recv().unwrap() { *self.layer.borrow_mut() = layer_bounds; - self.layer_ctx.set(Some(&ctx)); + self.layer_ctx.set(ctx); self.init_present(); } } diff --git a/components/script/dom/xr.rs b/components/script/dom/xr.rs index dae63a4baca..a608d7e31a4 100644 --- a/components/script/dom/xr.rs +++ b/components/script/dom/xr.rs @@ -95,10 +95,9 @@ impl XRMethods for XR { } let session = XRSession::new(&self.global(), &displays[0]); + // XXXManishearth we should actually xr_present() here instead of + // in XRSession::new, and resolve a promise based on it promise.resolve_native(&session); - // whether or not we should initiate presentation is unclear - // https://github.com/immersive-web/webxr/issues/453 - promise } } diff --git a/components/script/dom/xrsession.rs b/components/script/dom/xrsession.rs index 449d4acf8fc..73814a386b2 100644 --- a/components/script/dom/xrsession.rs +++ b/components/script/dom/xrsession.rs @@ -37,11 +37,13 @@ impl XRSession { } pub fn new(global: &GlobalScope, display: &VRDisplay) -> DomRoot { - reflect_dom_object( + let ret = reflect_dom_object( Box::new(XRSession::new_inherited(display)), global, XRSessionBinding::Wrap, - ) + ); + ret.display.xr_present(&ret, None); + ret } } @@ -76,7 +78,7 @@ impl XRSessionMethods for XRSession { self.base_layer.set(layer); if let Some(layer) = layer { let layer = layer.downcast::().unwrap(); - self.display.xr_present(&self, &layer.Context()); + self.display.xr_present(&self, Some(&layer.Context())); } else { // steps unknown // https://github.com/immersive-web/webxr/issues/453 From 9ddbf68cb31e5407f3773922c2b9a4337eb83b48 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Mon, 7 Jan 2019 16:55:52 -0800 Subject: [PATCH 2/3] Make VR presentation code async; use for VRDisplay::RequestPresent --- components/script/dom/vrdisplay.rs | 89 +++++++++++++++++++----------- 1 file changed, 58 insertions(+), 31 deletions(-) diff --git a/components/script/dom/vrdisplay.rs b/components/script/dom/vrdisplay.rs index 2115f7ef218..e203a2779b7 100644 --- a/components/script/dom/vrdisplay.rs +++ b/components/script/dom/vrdisplay.rs @@ -15,7 +15,7 @@ use crate::dom::bindings::codegen::Bindings::WindowBinding::WindowMethods; use crate::dom::bindings::codegen::Bindings::XRSessionBinding::XRFrameRequestCallback; use crate::dom::bindings::inheritance::Castable; use crate::dom::bindings::num::Finite; -use crate::dom::bindings::refcounted::Trusted; +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::str::DOMString; @@ -34,7 +34,7 @@ use crate::dom::xrframe::XRFrame; use crate::dom::xrsession::XRSession; use crate::script_runtime::CommonScriptMsg; use crate::script_runtime::ScriptThreadEventCategory::WebVREvent; -use crate::task_source::TaskSourceName; +use crate::task_source::{TaskSource, TaskSourceName}; use canvas_traits::webgl::{webgl_channel, WebGLReceiver, WebVRCommand}; use crossbeam_channel::{unbounded, Sender}; use dom_struct::dom_struct; @@ -347,35 +347,8 @@ impl VRDisplayMethods for VRDisplay { }, }; - // WebVR spec: Repeat calls while already presenting will update the VRLayers being displayed. - if self.presenting.get() { - *self.layer.borrow_mut() = layer_bounds; - self.layer_ctx.set(Some(&layer_ctx)); - promise.resolve_native(&()); - return promise; - } - - // Request Present - let (sender, receiver) = ipc::channel(self.global().time_profiler_chan().clone()).unwrap(); - self.webvr_thread() - .send(WebVRMsg::RequestPresent( - self.global().pipeline_id(), - self.display.borrow().display_id, - sender, - )) - .unwrap(); - match receiver.recv().unwrap() { - Ok(()) => { - *self.layer.borrow_mut() = layer_bounds; - self.layer_ctx.set(Some(&layer_ctx)); - self.init_present(); - promise.resolve_native(&()); - }, - Err(e) => { - promise.reject_native(&e); - }, - } - + self.request_present(layer_bounds, Some(&layer_ctx), + promise.clone(), |p| p.resolve_native(&())); promise } @@ -464,6 +437,60 @@ impl VRDisplay { } } + pub fn request_present(&self, layer_bounds: WebVRLayer, + ctx: Option<&WebGLRenderingContext>, + promise: Rc, resolve: F) + where F: FnOnce(Rc) + Send + 'static { + // WebVR spec: Repeat calls while already presenting will update the VRLayers being displayed. + if self.presenting.get() { + *self.layer.borrow_mut() = layer_bounds; + self.layer_ctx.set(ctx); + resolve(promise); + return; + } + + // Request Present + let (sender, receiver) = ipc::channel(self.global().time_profiler_chan().clone()).unwrap(); + self.webvr_thread() + .send(WebVRMsg::RequestPresent( + self.global().pipeline_id(), + self.display.borrow().display_id, + sender, + )) + .unwrap(); + let promise = TrustedPromise::new(promise); + let this = Trusted::new(self); + let ctx = ctx.map(|c| Trusted::new(c)); + let global = self.global(); + let window = global.as_window(); + let (task_source, canceller) = window + .task_manager() + .dom_manipulation_task_source_with_canceller(); + thread::spawn(move || { + let recv = receiver.recv().unwrap(); + let _ = task_source.queue_with_canceller( + task!(vr_presenting: move || { + let this = this.root(); + let promise = promise.root(); + let ctx = ctx.map(|c| c.root()); + match recv { + Ok(()) => { + *this.layer.borrow_mut() = layer_bounds; + this.layer_ctx.set(ctx.as_ref().map(|c| &**c)); + this.init_present(); + resolve(promise); + }, + Err(e) => { + promise.reject_native(&e); + }, + } + }), + &canceller, + ); + + }); + } + pub fn handle_webvr_event(&self, event: &WebVRDisplayEvent) { match *event { WebVRDisplayEvent::Connect(ref display) => { From e2522d36ffa053b10296bbd1c16d60e502f1f452 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Mon, 7 Jan 2019 17:59:06 -0800 Subject: [PATCH 3/3] Use async VR presentation code for XRSession --- components/script/dom/vrdisplay.rs | 62 ++++++++++++++---------------- components/script/dom/xr.rs | 4 +- components/script/dom/xrsession.rs | 13 ++++--- 3 files changed, 37 insertions(+), 42 deletions(-) diff --git a/components/script/dom/vrdisplay.rs b/components/script/dom/vrdisplay.rs index e203a2779b7..6c4bea1568c 100644 --- a/components/script/dom/vrdisplay.rs +++ b/components/script/dom/vrdisplay.rs @@ -347,8 +347,9 @@ impl VRDisplayMethods for VRDisplay { }, }; - self.request_present(layer_bounds, Some(&layer_ctx), - promise.clone(), |p| p.resolve_native(&())); + self.request_present(layer_bounds, Some(&layer_ctx), Some(promise.clone()), |p| { + p.resolve_native(&()) + }); promise } @@ -437,15 +438,20 @@ impl VRDisplay { } } - pub fn request_present(&self, layer_bounds: WebVRLayer, - ctx: Option<&WebGLRenderingContext>, - promise: Rc, resolve: F) - where F: FnOnce(Rc) + Send + 'static { + pub fn request_present( + &self, + layer_bounds: WebVRLayer, + ctx: Option<&WebGLRenderingContext>, + promise: Option>, + resolve: F, + ) where + F: FnOnce(Rc) + Send + 'static, + { // WebVR spec: Repeat calls while already presenting will update the VRLayers being displayed. if self.presenting.get() { *self.layer.borrow_mut() = layer_bounds; self.layer_ctx.set(ctx); - resolve(promise); + promise.map(resolve); return; } @@ -458,7 +464,7 @@ impl VRDisplay { sender, )) .unwrap(); - let promise = TrustedPromise::new(promise); + let promise = promise.map(TrustedPromise::new); let this = Trusted::new(self); let ctx = ctx.map(|c| Trusted::new(c)); let global = self.global(); @@ -471,23 +477,22 @@ impl VRDisplay { let _ = task_source.queue_with_canceller( task!(vr_presenting: move || { let this = this.root(); - let promise = promise.root(); + let promise = promise.map(|p| p.root()); let ctx = ctx.map(|c| c.root()); match recv { Ok(()) => { *this.layer.borrow_mut() = layer_bounds; this.layer_ctx.set(ctx.as_ref().map(|c| &**c)); this.init_present(); - resolve(promise); + promise.map(resolve); }, Err(e) => { - promise.reject_native(&e); + promise.map(|p| p.reject_native(&e)); }, } }), &canceller, ); - }); } @@ -715,30 +720,19 @@ impl VRDisplay { // XR stuff // XXXManishearth eventually we should share as much logic as possible impl VRDisplay { - pub fn xr_present(&self, session: &XRSession, ctx: Option<&WebGLRenderingContext>) { + pub fn xr_present( + &self, + session: &XRSession, + ctx: Option<&WebGLRenderingContext>, + promise: Option>, + ) { let layer_bounds = WebVRLayer::default(); self.xr_session.set(Some(session)); - if self.presenting.get() { - *self.layer.borrow_mut() = layer_bounds; - self.layer_ctx.set(ctx); - return; - } - - // Request Present - let (sender, receiver) = ipc::channel(self.global().time_profiler_chan().clone()).unwrap(); - self.webvr_thread() - .send(WebVRMsg::RequestPresent( - self.global().pipeline_id(), - self.display.borrow().display_id, - sender, - )) - .unwrap(); - - if let Ok(()) = receiver.recv().unwrap() { - *self.layer.borrow_mut() = layer_bounds; - self.layer_ctx.set(ctx); - self.init_present(); - } + let session = Trusted::new(session); + self.request_present(layer_bounds, ctx, promise, move |p| { + let session = session.root(); + p.resolve_native(&session); + }); } pub fn xr_raf(&self, callback: Rc) -> u32 { diff --git a/components/script/dom/xr.rs b/components/script/dom/xr.rs index a608d7e31a4..3e18ee0d279 100644 --- a/components/script/dom/xr.rs +++ b/components/script/dom/xr.rs @@ -95,9 +95,7 @@ impl XRMethods for XR { } let session = XRSession::new(&self.global(), &displays[0]); - // XXXManishearth we should actually xr_present() here instead of - // in XRSession::new, and resolve a promise based on it - promise.resolve_native(&session); + session.xr_present(promise.clone()); promise } } diff --git a/components/script/dom/xrsession.rs b/components/script/dom/xrsession.rs index 73814a386b2..93837255f37 100644 --- a/components/script/dom/xrsession.rs +++ b/components/script/dom/xrsession.rs @@ -14,6 +14,7 @@ use crate::dom::bindings::reflector::reflect_dom_object; use crate::dom::bindings::root::{Dom, DomRoot, MutNullableDom}; use crate::dom::eventtarget::EventTarget; use crate::dom::globalscope::GlobalScope; +use crate::dom::promise::Promise; use crate::dom::vrdisplay::VRDisplay; use crate::dom::xrlayer::XRLayer; use crate::dom::xrwebgllayer::XRWebGLLayer; @@ -37,13 +38,15 @@ impl XRSession { } pub fn new(global: &GlobalScope, display: &VRDisplay) -> DomRoot { - let ret = reflect_dom_object( + reflect_dom_object( Box::new(XRSession::new_inherited(display)), global, XRSessionBinding::Wrap, - ); - ret.display.xr_present(&ret, None); - ret + ) + } + + pub fn xr_present(&self, p: Rc) { + self.display.xr_present(self, None, Some(p)); } } @@ -78,7 +81,7 @@ impl XRSessionMethods for XRSession { self.base_layer.set(layer); if let Some(layer) = layer { let layer = layer.downcast::().unwrap(); - self.display.xr_present(&self, Some(&layer.Context())); + self.display.xr_present(&self, Some(&layer.Context()), None); } else { // steps unknown // https://github.com/immersive-web/webxr/issues/453