diff options
-rw-r--r-- | components/config/prefs.rs | 3 | ||||
-rw-r--r-- | components/script/dom/mod.rs | 9 | ||||
-rw-r--r-- | components/script/dom/webidls/XRLayer.webidl | 63 | ||||
-rw-r--r-- | components/script/dom/webidls/XRMediaBinding.webidl | 18 | ||||
-rw-r--r-- | components/script/dom/webidls/XRRenderState.webidl | 3 | ||||
-rw-r--r-- | components/script/dom/webidls/XRSubImage.webidl | 9 | ||||
-rw-r--r-- | components/script/dom/webidls/XRWebGLBinding.webidl | 44 | ||||
-rw-r--r-- | components/script/dom/webidls/XRWebGLSubImage.webidl | 11 | ||||
-rw-r--r-- | components/script/dom/xrlayer.rs | 53 | ||||
-rw-r--r-- | components/script/dom/xrmediabinding.rs | 35 | ||||
-rw-r--r-- | components/script/dom/xrrenderstate.rs | 63 | ||||
-rw-r--r-- | components/script/dom/xrsession.rs | 59 | ||||
-rw-r--r-- | components/script/dom/xrsubimage.rs | 23 | ||||
-rw-r--r-- | components/script/dom/xrwebglbinding.rs | 109 | ||||
-rw-r--r-- | components/script/dom/xrwebglsubimage.rs | 35 | ||||
-rw-r--r-- | resources/prefs.json | 1 | ||||
-rw-r--r-- | tests/wpt/mozilla/meta/MANIFEST.json | 7 | ||||
-rw-r--r-- | tests/wpt/mozilla/meta/webxr/layers.html.ini | 1 | ||||
-rw-r--r-- | tests/wpt/mozilla/tests/webxr/layers.html | 54 |
19 files changed, 585 insertions, 15 deletions
diff --git a/components/config/prefs.rs b/components/config/prefs.rs index c741aa4d0df..82f4d6a0057 100644 --- a/components/config/prefs.rs +++ b/components/config/prefs.rs @@ -299,6 +299,9 @@ mod gen { test: bool, #[serde(default)] glwindow: bool, + layers: { + enabled: bool, + } }, worklet: { blockingsleep: { diff --git a/components/script/dom/mod.rs b/components/script/dom/mod.rs index dcc9af258cd..9ae4274a194 100644 --- a/components/script/dom/mod.rs +++ b/components/script/dom/mod.rs @@ -535,9 +535,8 @@ pub mod videotracklist; pub mod virtualmethods; pub mod vttcue; pub mod vttregion; -pub mod webgl_extensions; -pub use self::webgl_extensions::ext::*; pub mod webgl2renderingcontext; +pub mod webgl_extensions; pub mod webgl_validations; pub mod webglactiveinfo; pub mod webglbuffer; @@ -577,6 +576,8 @@ pub mod xrinputsource; pub mod xrinputsourcearray; pub mod xrinputsourceevent; pub mod xrinputsourceschangeevent; +pub mod xrlayer; +pub mod xrmediabinding; pub mod xrpose; pub mod xrreferencespace; pub mod xrrenderstate; @@ -584,9 +585,13 @@ pub mod xrrigidtransform; pub mod xrsession; pub mod xrsessionevent; pub mod xrspace; +pub mod xrsubimage; pub mod xrsystem; pub mod xrtest; pub mod xrview; pub mod xrviewerpose; pub mod xrviewport; +pub mod xrwebglbinding; pub mod xrwebgllayer; +pub mod xrwebglsubimage; +pub use self::webgl_extensions::ext::*; diff --git a/components/script/dom/webidls/XRLayer.webidl b/components/script/dom/webidls/XRLayer.webidl new file mode 100644 index 00000000000..eb967abf091 --- /dev/null +++ b/components/script/dom/webidls/XRLayer.webidl @@ -0,0 +1,63 @@ +/* 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/layers/#xrlayertype +[SecureContext, Exposed=Window, Pref="dom.webxr.layers.enabled"] +interface XRLayer { + readonly attribute unsigned long pixelWidth; + readonly attribute unsigned long pixelHeight; + +// attribute boolean blendTextureSourceAlpha; +// attribute boolean chromaticAberrationCorrection; + + void destroy(); +}; +// +// TODO: Implement the layer types +// +// [SecureContext, Exposed=Window, Pref="dom.webxr.enabled"] +// interface XRProjectionLayer : XRLayer { +// readonly attribute boolean ignoreDepthValues; +// }; +// +// [SecureContext, Exposed=Window, Pref="dom.webxr.layers.enabled"] +// interface XRQuadLayer : XRLayer { +// readonly attribute XRLayerLayout layout; +// attribute XRRigidTransform transform; +// +// attribute float width; +// attribute float height; +// }; +// +// [SecureContext, Exposed=Window, Pref="dom.webxr.layers.enabled"] +// interface XRCylinderLayer : XRLayer { +// readonly attribute XRLayerLayout layout; +// attribute XRReferenceSpace referenceSpace; +// +// attribute XRRigidTransform transform; +// attribute float radius; +// attribute float centralAngle; +// attribute float aspectRatio; +// }; +// +// [SecureContext, Exposed=Window, Pref="dom.webxr.layers.enabled"] +// interface XREquirectLayer : XRLayer { +// readonly attribute XRLayerLayout layout; +// attribute XRReferenceSpace referenceSpace; +// +// attribute XRRigidTransform transform; +// attribute float radius; +// attribute float scaleX; +// attribute float scaleY; +// attribute float biasX; +// attribute float biasY; +// }; +// +// [SecureContext, Exposed=Window, Pref="dom.webxr.layers.enabled"] +// interface XRCubeLayer : XRLayer { +// readonly attribute XRLayerLayout layout; +// attribute XRReferenceSpace referenceSpace; +// +// attribute DOMPoint orientation; +// }; diff --git a/components/script/dom/webidls/XRMediaBinding.webidl b/components/script/dom/webidls/XRMediaBinding.webidl new file mode 100644 index 00000000000..9ea40de56a4 --- /dev/null +++ b/components/script/dom/webidls/XRMediaBinding.webidl @@ -0,0 +1,18 @@ +/* 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/layers/#xrmediabindingtype +[SecureContext, Exposed=Window, Pref="dom.webxr.layers.enabled"] +interface XRMediaBinding { + constructor(XRSession session); + +// XRQuadLayer createQuadVideoLayer(HTMLVideoElement video, optional XRMediaLayerInit init = {}); +// XRCylinderLayer createCylinderVideoLayer(HTMLVideoElement video, optional XRMediaLayerInit init = {}); +// XREquirectLayer createEquirectVideoLayer(HTMLVideoElement video, optional XRMediaLayerInit init = {}); +}; + +dictionary XRMediaLayerInit { + XRLayerLayout layout = "mono"; + boolean invertStereo = false; +}; diff --git a/components/script/dom/webidls/XRRenderState.webidl b/components/script/dom/webidls/XRRenderState.webidl index e361ced6597..708df1f20eb 100644 --- a/components/script/dom/webidls/XRRenderState.webidl +++ b/components/script/dom/webidls/XRRenderState.webidl @@ -2,6 +2,8 @@ * 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/. */ +typedef (XRWebGLLayer or XRLayer) XRGenericLayer; + // https://immersive-web.github.io/webxr/#xrrenderstate-interface dictionary XRRenderStateInit { @@ -9,6 +11,7 @@ dictionary XRRenderStateInit { double depthFar; double inlineVerticalFieldOfView; XRWebGLLayer baseLayer; + sequence<XRGenericLayer> layers; }; [SecureContext, Exposed=Window, Pref="dom.webxr.enabled"] interface XRRenderState { diff --git a/components/script/dom/webidls/XRSubImage.webidl b/components/script/dom/webidls/XRSubImage.webidl new file mode 100644 index 00000000000..9dbbd089928 --- /dev/null +++ b/components/script/dom/webidls/XRSubImage.webidl @@ -0,0 +1,9 @@ +/* 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/layers/#xrsubimagetype +[SecureContext, Exposed=Window, Pref="dom.webxr.layers.enabled"] +interface XRSubImage { + readonly attribute XRViewport viewport; +}; diff --git a/components/script/dom/webidls/XRWebGLBinding.webidl b/components/script/dom/webidls/XRWebGLBinding.webidl new file mode 100644 index 00000000000..08617561b36 --- /dev/null +++ b/components/script/dom/webidls/XRWebGLBinding.webidl @@ -0,0 +1,44 @@ +/* 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/layers/#XRWebGLBindingtype +[SecureContext, Exposed=Window, Pref="dom.webxr.layers.enabled"] +interface XRWebGLBinding { + constructor(XRSession session, XRWebGLRenderingContext context); + +// readonly attribute double nativeProjectionScaleFactor; + +// XRProjectionLayer createProjectionLayer(GLenum textureTarget, optional XRProjectionLayerInit init = {}); +// XRQuadLayer createQuadLayer(GLenum textureTarget, XRLayerInit init); +// XRCylinderLayer createCylinderLayer(GLenum textureTarget, XRLayerInit init); +// XREquirectLayer createEquirectLayer(GLenum textureTarget, XRLayerInit init); +// XRCubeLayer createCubeLayer(XRLayerInit init); + + XRWebGLSubImage? getSubImage(XRLayer layer, XRFrame frame); // for mono layers + XRWebGLSubImage? getViewSubImage(XRLayer layer, XRView view); // for stereo layers +}; + +dictionary XRProjectionLayerInit { + boolean depth = true; + boolean stencil = false; + boolean alpha = true; + double scaleFactor = 1.0; +}; + +dictionary XRLayerInit { + required unsigned long pixelWidth; + required unsigned long pixelHeight; + XRLayerLayout layout = "mono"; + boolean depth = false; // This is a change from typical WebGL initialization, but feels appropriate. + boolean stencil = false; + boolean alpha = true; +}; + +enum XRLayerLayout { + "mono", + "stereo", + "stereo-left-right", + "stereo-top-bottom" +}; + diff --git a/components/script/dom/webidls/XRWebGLSubImage.webidl b/components/script/dom/webidls/XRWebGLSubImage.webidl new file mode 100644 index 00000000000..f25552d533e --- /dev/null +++ b/components/script/dom/webidls/XRWebGLSubImage.webidl @@ -0,0 +1,11 @@ +/* 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/layers/#xrwebglsubimagetype +[SecureContext, Exposed=Window, Pref="dom.webxr.layers.enabled"] +interface XRWebGLSubImage : XRSubImage { + readonly attribute WebGLTexture colorTexture; + readonly attribute WebGLTexture? depthStencilTexture; + readonly attribute unsigned long? imageIndex; +}; diff --git a/components/script/dom/xrlayer.rs b/components/script/dom/xrlayer.rs new file mode 100644 index 00000000000..e70cdb5085a --- /dev/null +++ b/components/script/dom/xrlayer.rs @@ -0,0 +1,53 @@ +/* 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::XRLayerBinding::XRLayerBinding::XRLayerMethods; +use crate::dom::bindings::reflector::Reflector; +use crate::dom::bindings::root::Dom; +use crate::dom::webglrenderingcontext::WebGLRenderingContext; +use crate::dom::xrsession::XRSession; +use dom_struct::dom_struct; +use euclid::Size2D; +use webxr_api::Viewport; + +#[dom_struct] +pub struct XRLayer { + reflector: Reflector, + session: Dom<XRSession>, + context: Dom<WebGLRenderingContext>, + size: Size2D<u32, Viewport>, +} + +impl XRLayerMethods for XRLayer { + /// https://immersive-web.github.io/layers/#dom-xrlayer-pixelwidth + fn PixelWidth(&self) -> u32 { + self.size.width + } + + /// https://immersive-web.github.io/layers/#dom-xrlayer-pixelheight + fn PixelHeight(&self) -> u32 { + self.size.height + } + + /// https://immersive-web.github.io/layers/#dom-xrlayer-destroy + fn Destroy(&self) { + // TODO: Implement this + } +} + +impl XRLayer { + #[allow(dead_code)] + pub fn new_inherited( + session: &XRSession, + context: &WebGLRenderingContext, + size: Size2D<u32, Viewport>, + ) -> XRLayer { + XRLayer { + reflector: Reflector::new(), + session: Dom::from_ref(session), + context: Dom::from_ref(context), + size: size, + } + } +} diff --git a/components/script/dom/xrmediabinding.rs b/components/script/dom/xrmediabinding.rs new file mode 100644 index 00000000000..b0b6a0ac69c --- /dev/null +++ b/components/script/dom/xrmediabinding.rs @@ -0,0 +1,35 @@ +/* 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::reflector::reflect_dom_object; +use crate::dom::bindings::reflector::Reflector; +use crate::dom::bindings::root::Dom; +use crate::dom::bindings::root::DomRoot; +use crate::dom::window::Window; +use crate::dom::xrsession::XRSession; +use dom_struct::dom_struct; + +#[dom_struct] +pub struct XRMediaBinding { + reflector: Reflector, + session: Dom<XRSession>, +} + +impl XRMediaBinding { + pub fn new_inherited(session: &XRSession) -> XRMediaBinding { + XRMediaBinding { + reflector: Reflector::new(), + session: Dom::from_ref(session), + } + } + + pub fn new(global: &Window, session: &XRSession) -> DomRoot<XRMediaBinding> { + reflect_dom_object(Box::new(XRMediaBinding::new_inherited(session)), global) + } + + #[allow(non_snake_case)] + pub fn Constructor(global: &Window, session: &XRSession) -> DomRoot<XRMediaBinding> { + XRMediaBinding::new(global, session) + } +} diff --git a/components/script/dom/xrrenderstate.rs b/components/script/dom/xrrenderstate.rs index 199e029ee7d..d174af531d0 100644 --- a/components/script/dom/xrrenderstate.rs +++ b/components/script/dom/xrrenderstate.rs @@ -2,15 +2,18 @@ * 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::XRRenderStateBinding::XRRenderStateMethods; +use crate::dom::bindings::codegen::UnionTypes::XRWebGLLayerOrXRLayer as RootedXRWebGLLayerOrXRLayer; use crate::dom::bindings::num::Finite; use crate::dom::bindings::reflector::{reflect_dom_object, DomObject, Reflector}; -use crate::dom::bindings::root::{DomRoot, MutNullableDom}; +use crate::dom::bindings::root::{Dom, DomRoot, MutNullableDom}; use crate::dom::globalscope::GlobalScope; +use crate::dom::xrlayer::XRLayer; use crate::dom::xrwebgllayer::XRWebGLLayer; - use dom_struct::dom_struct; use std::cell::Cell; +use webxr_api::SwapChainId; #[dom_struct] pub struct XRRenderState { @@ -19,6 +22,42 @@ pub struct XRRenderState { depth_far: Cell<f64>, inline_vertical_fov: Cell<Option<f64>>, layer: MutNullableDom<XRWebGLLayer>, + layers: DomRefCell<Vec<XRWebGLLayerOrXRLayer>>, +} + +#[unrooted_must_root_lint::must_root] +#[derive(Clone, JSTraceable, MallocSizeOf)] +pub enum XRWebGLLayerOrXRLayer { + XRWebGLLayer(Dom<XRWebGLLayer>), + XRLayer(Dom<XRLayer>), +} + +impl XRWebGLLayerOrXRLayer { + #[allow(unrooted_must_root)] + fn from_ref(layer: &RootedXRWebGLLayerOrXRLayer) -> XRWebGLLayerOrXRLayer { + match layer { + RootedXRWebGLLayerOrXRLayer::XRWebGLLayer(ref layer) => { + XRWebGLLayerOrXRLayer::XRWebGLLayer(Dom::from_ref(layer)) + }, + RootedXRWebGLLayerOrXRLayer::XRLayer(ref layer) => { + XRWebGLLayerOrXRLayer::XRLayer(Dom::from_ref(layer)) + }, + } + } + + pub fn swap_chain_id(&self) -> Option<SwapChainId> { + match self { + XRWebGLLayerOrXRLayer::XRWebGLLayer(layer) => Some(layer.swap_chain_id()), + XRWebGLLayerOrXRLayer::XRLayer(_) => None, + } + } + + pub fn swap_buffers(&self) { + match self { + XRWebGLLayerOrXRLayer::XRWebGLLayer(layer) => layer.swap_buffers(), + XRWebGLLayerOrXRLayer::XRLayer(_) => (), + } + } } impl XRRenderState { @@ -27,13 +66,16 @@ impl XRRenderState { depth_far: f64, inline_vertical_fov: Option<f64>, layer: Option<&XRWebGLLayer>, + layers: &[XRWebGLLayerOrXRLayer], ) -> XRRenderState { + debug_assert!(layer.is_none() || layers.is_empty()); XRRenderState { reflector_: Reflector::new(), depth_near: Cell::new(depth_near), depth_far: Cell::new(depth_far), inline_vertical_fov: Cell::new(inline_vertical_fov), layer: MutNullableDom::new(layer), + layers: DomRefCell::new(layers.iter().cloned().collect()), } } @@ -43,6 +85,7 @@ impl XRRenderState { depth_far: f64, inline_vertical_fov: Option<f64>, layer: Option<&XRWebGLLayer>, + layers: &[XRWebGLLayerOrXRLayer], ) -> DomRoot<XRRenderState> { reflect_dom_object( Box::new(XRRenderState::new_inherited( @@ -50,18 +93,21 @@ impl XRRenderState { depth_far, inline_vertical_fov, layer, + layers, )), global, ) } pub fn clone_object(&self) -> DomRoot<Self> { + let layers = self.layers.borrow(); XRRenderState::new( &self.global(), self.depth_near.get(), self.depth_far.get(), self.inline_vertical_fov.get(), self.layer.get().as_ref().map(|x| &**x), + &layers, ) } @@ -78,6 +124,19 @@ impl XRRenderState { pub fn set_layer(&self, layer: Option<&XRWebGLLayer>) { self.layer.set(layer) } + pub fn set_layers(&self, layers: &[RootedXRWebGLLayerOrXRLayer]) { + *self.layers.borrow_mut() = layers.iter().map(XRWebGLLayerOrXRLayer::from_ref).collect(); + } + pub fn with_layers<F, R>(&self, f: F) -> R + where + F: FnOnce(&[XRWebGLLayerOrXRLayer]) -> R, + { + let layers = self.layers.borrow(); + f(&*layers) + } + pub fn has_layer(&self) -> bool { + self.layer.get().is_some() || !self.layers.borrow().is_empty() + } } impl XRRenderStateMethods for XRRenderState { diff --git a/components/script/dom/xrsession.rs b/components/script/dom/xrsession.rs index 3396ca669c1..53e6c492b68 100644 --- a/components/script/dom/xrsession.rs +++ b/components/script/dom/xrsession.rs @@ -31,7 +31,6 @@ use crate::dom::xrreferencespace::XRReferenceSpace; use crate::dom::xrrenderstate::XRRenderState; use crate::dom::xrsessionevent::XRSessionEvent; use crate::dom::xrspace::XRSpace; -use crate::dom::xrwebgllayer::XRWebGLLayer; use crate::realms::InRealm; use crate::task_source::TaskSource; use dom_struct::dom_struct; @@ -52,7 +51,6 @@ use webxr_api::{ #[dom_struct] pub struct XRSession { eventtarget: EventTarget, - base_layer: MutNullableDom<XRWebGLLayer>, blend_mode: XREnvironmentBlendMode, mode: XRSessionMode, visibility_state: Cell<XRVisibilityState>, @@ -88,7 +86,6 @@ impl XRSession { ) -> XRSession { XRSession { eventtarget: EventTarget::new_inherited(), - base_layer: Default::default(), blend_mode: session.environment_blend_mode().into(), mode, visibility_state: Cell::new(XRVisibilityState::Visible), @@ -119,7 +116,7 @@ impl XRSession { } else { None }; - let render_state = XRRenderState::new(global, 0.1, 1000.0, ivfov, None); + let render_state = XRRenderState::new(global, 0.1, 1000.0, ivfov, None, &[]); let input_sources = XRInputSourceArray::new(global); let ret = reflect_dom_object( Box::new(XRSession::new_inherited( @@ -355,7 +352,14 @@ impl XRSession { // Step 6-7: XXXManishearth handle inlineVerticalFieldOfView if self.is_immersive() { - let swap_chain_id = pending.GetBaseLayer().map(|layer| layer.swap_chain_id()); + let swap_chain_id = pending + .GetBaseLayer() + .map(|layer| layer.swap_chain_id()) + .or_else(|| { + self.active_render_state.get().with_layers(|layers| { + layers.get(0).and_then(|layer| layer.swap_chain_id()) + }) + }); self.session.borrow_mut().set_swap_chain(swap_chain_id); } else { self.update_inline_projection_matrix() @@ -367,10 +371,9 @@ impl XRSession { } // Step 2 - let base_layer = match self.active_render_state.get().GetBaseLayer() { - Some(layer) => layer, - None => return, - }; + if !self.active_render_state.get().has_layer() { + return; + } // Step 3: XXXManishearth handle inline session @@ -395,7 +398,15 @@ impl XRSession { frame.set_active(false); if self.is_immersive() { - base_layer.swap_buffers(); + if let Some(base_layer) = self.active_render_state.get().GetBaseLayer() { + base_layer.swap_buffers(); + } else { + self.active_render_state.get().with_layers(|layers| { + for layer in layers { + layer.swap_buffers(); + } + }); + } self.session.borrow_mut().render_animation_frame(); } else { self.session.borrow_mut().start_render_loop(); @@ -513,6 +524,23 @@ impl XRSessionMethods for XRSession { return Err(Error::InvalidState); } + // TODO: add spec link for this step once XR layers has settled down + // https://immersive-web.github.io/layers/ + if init.baseLayer.is_some() && init.layers.is_some() { + return Err(Error::InvalidState); + } + + // TODO: add spec link for this step once XR layers has settled down + // https://immersive-web.github.io/layers/ + if init + .layers + .as_ref() + .map(|layers| layers.is_empty()) + .unwrap_or(false) + { + return Err(Error::InvalidState); + } + let pending = self .pending_render_state .or_init(|| self.active_render_state.get().clone_object()); @@ -546,7 +574,8 @@ impl XRSessionMethods for XRSession { pending.set_inline_vertical_fov(fov); } if let Some(ref layer) = init.baseLayer { - pending.set_layer(Some(&layer)) + pending.set_layer(Some(&layer)); + pending.set_layers(&[]); } if init.depthFar.is_some() || init.depthNear.is_some() { @@ -554,6 +583,14 @@ impl XRSessionMethods for XRSession { .borrow_mut() .update_clip_planes(*pending.DepthNear() as f32, *pending.DepthFar() as f32); } + + // TODO: add spec link for this step once XR layers has settled down + // https://immersive-web.github.io/layers/ + if let Some(ref layers) = init.layers { + pending.set_layer(None); + pending.set_layers(layers); + } + Ok(()) } diff --git a/components/script/dom/xrsubimage.rs b/components/script/dom/xrsubimage.rs new file mode 100644 index 00000000000..2be59d48d3b --- /dev/null +++ b/components/script/dom/xrsubimage.rs @@ -0,0 +1,23 @@ +/* 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::XRSubImageBinding::XRSubImageBinding::XRSubImageMethods; +use crate::dom::bindings::reflector::Reflector; +use crate::dom::bindings::root::Dom; +use crate::dom::bindings::root::DomRoot; +use crate::dom::xrviewport::XRViewport; +use dom_struct::dom_struct; + +#[dom_struct] +pub struct XRSubImage { + reflector: Reflector, + viewport: Dom<XRViewport>, +} + +impl XRSubImageMethods for XRSubImage { + /// https://immersive-web.github.io/layers/#dom-xrsubimage-viewport + fn Viewport(&self) -> DomRoot<XRViewport> { + DomRoot::from_ref(&self.viewport) + } +} diff --git a/components/script/dom/xrwebglbinding.rs b/components/script/dom/xrwebglbinding.rs new file mode 100644 index 00000000000..27435aa3ddc --- /dev/null +++ b/components/script/dom/xrwebglbinding.rs @@ -0,0 +1,109 @@ +/* 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::XRWebGLBindingBinding::XRWebGLBindingBinding::XRWebGLBindingMethods; +use crate::dom::bindings::codegen::UnionTypes::WebGLRenderingContextOrWebGL2RenderingContext as RootedWebGLRenderingContextOrWebGL2RenderingContext; +use crate::dom::bindings::reflector::reflect_dom_object; +use crate::dom::bindings::reflector::Reflector; +use crate::dom::bindings::root::Dom; +use crate::dom::bindings::root::DomRoot; +use crate::dom::webgl2renderingcontext::WebGL2RenderingContext; +use crate::dom::webglrenderingcontext::WebGLRenderingContext; +use crate::dom::window::Window; +use crate::dom::xrframe::XRFrame; +use crate::dom::xrlayer::XRLayer; +use crate::dom::xrsession::XRSession; +use crate::dom::xrview::XRView; +use crate::dom::xrwebglsubimage::XRWebGLSubImage; +use dom_struct::dom_struct; + +#[dom_struct] +pub struct XRWebGLBinding { + reflector: Reflector, + session: Dom<XRSession>, + context: WebGLRenderingContextOrWebGL2RenderingContext, +} + +// TODO: Should this live somewhere else? +#[unrooted_must_root_lint::must_root] +#[derive(Clone, JSTraceable, MallocSizeOf)] +pub enum WebGLRenderingContextOrWebGL2RenderingContext { + WebGLRenderingContext(Dom<WebGLRenderingContext>), + WebGL2RenderingContext(Dom<WebGL2RenderingContext>), +} + +impl WebGLRenderingContextOrWebGL2RenderingContext { + #[allow(unrooted_must_root)] + fn from_ref( + context: &RootedWebGLRenderingContextOrWebGL2RenderingContext, + ) -> WebGLRenderingContextOrWebGL2RenderingContext { + match context { + RootedWebGLRenderingContextOrWebGL2RenderingContext::WebGLRenderingContext( + ref context, + ) => WebGLRenderingContextOrWebGL2RenderingContext::WebGLRenderingContext( + Dom::from_ref(context), + ), + RootedWebGLRenderingContextOrWebGL2RenderingContext::WebGL2RenderingContext( + ref context, + ) => WebGLRenderingContextOrWebGL2RenderingContext::WebGL2RenderingContext( + Dom::from_ref(context), + ), + } + } +} + +impl XRWebGLBindingMethods for XRWebGLBinding { + /// https://immersive-web.github.io/layers/#dom-xrwebglbinding-getsubimage + fn GetSubImage(&self, _layer: &XRLayer, _frame: &XRFrame) -> Option<DomRoot<XRWebGLSubImage>> { + // TODO: Implement this + None + } + + /// https://immersive-web.github.io/layers/#dom-xrwebglbinding-getviewsubimage + fn GetViewSubImage( + &self, + _layer: &XRLayer, + _view: &XRView, + ) -> Option<DomRoot<XRWebGLSubImage>> { + // TODO: Implement this + None + } +} + +impl XRWebGLBinding { + pub fn new_inherited( + session: &XRSession, + context: &WebGLRenderingContextOrWebGL2RenderingContext, + ) -> XRWebGLBinding { + XRWebGLBinding { + reflector: Reflector::new(), + session: Dom::from_ref(session), + context: context.clone(), + } + } + + pub fn new( + global: &Window, + session: &XRSession, + context: &WebGLRenderingContextOrWebGL2RenderingContext, + ) -> DomRoot<XRWebGLBinding> { + reflect_dom_object( + Box::new(XRWebGLBinding::new_inherited(session, context)), + global, + ) + } + + #[allow(non_snake_case)] + pub fn Constructor( + global: &Window, + session: &XRSession, + context: RootedWebGLRenderingContextOrWebGL2RenderingContext, + ) -> DomRoot<XRWebGLBinding> { + XRWebGLBinding::new( + global, + session, + &WebGLRenderingContextOrWebGL2RenderingContext::from_ref(&context), + ) + } +} diff --git a/components/script/dom/xrwebglsubimage.rs b/components/script/dom/xrwebglsubimage.rs new file mode 100644 index 00000000000..0331d36c4c2 --- /dev/null +++ b/components/script/dom/xrwebglsubimage.rs @@ -0,0 +1,35 @@ +/* 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::XRWebGLSubImageBinding::XRWebGLSubImageBinding::XRWebGLSubImageMethods; +use crate::dom::bindings::root::Dom; +use crate::dom::bindings::root::DomRoot; +use crate::dom::webgltexture::WebGLTexture; +use crate::dom::xrsubimage::XRSubImage; +use dom_struct::dom_struct; + +#[dom_struct] +pub struct XRWebGLSubImage { + xr_sub_image: XRSubImage, + color_texture: Dom<WebGLTexture>, + depth_stencil_texture: Option<Dom<WebGLTexture>>, + image_index: Option<u32>, +} + +impl XRWebGLSubImageMethods for XRWebGLSubImage { + /// https://immersive-web.github.io/layers/#dom-xrwebglsubimage-colortexture + fn ColorTexture(&self) -> DomRoot<WebGLTexture> { + DomRoot::from_ref(&self.color_texture) + } + + /// https://immersive-web.github.io/layers/#dom-xrwebglsubimage-depthstenciltexture + fn GetDepthStencilTexture(&self) -> Option<DomRoot<WebGLTexture>> { + self.depth_stencil_texture.as_deref().map(DomRoot::from_ref) + } + + /// https://immersive-web.github.io/layers/#dom-xrwebglsubimage-imageindex + fn GetImageIndex(&self) -> Option<u32> { + self.image_index + } +} diff --git a/resources/prefs.json b/resources/prefs.json index 985899e6554..9e0f6d95b5d 100644 --- a/resources/prefs.json +++ b/resources/prefs.json @@ -34,6 +34,7 @@ "dom.webvtt.enabled": false, "dom.webxr.enabled": true, "dom.webxr.glwindow": true, + "dom.webxr.layers.enabled": false, "dom.webxr.test": false, "dom.worklet.timeout_ms": 10, "gfx.subpixel-text-antialiasing.enabled": true, diff --git a/tests/wpt/mozilla/meta/MANIFEST.json b/tests/wpt/mozilla/meta/MANIFEST.json index f68c2ac1e00..43a57321277 100644 --- a/tests/wpt/mozilla/meta/MANIFEST.json +++ b/tests/wpt/mozilla/meta/MANIFEST.json @@ -14615,6 +14615,13 @@ {} ] ], + "layers.html": [ + "31f4b6bd51cfcca47666331857bd2bbdf84d2f5e", + [ + null, + {} + ] + ], "obtain_frame.html": [ "74fda5bad43e8ea95552e65380e83952680e8469", [ diff --git a/tests/wpt/mozilla/meta/webxr/layers.html.ini b/tests/wpt/mozilla/meta/webxr/layers.html.ini new file mode 100644 index 00000000000..72e1e4fc0b2 --- /dev/null +++ b/tests/wpt/mozilla/meta/webxr/layers.html.ini @@ -0,0 +1 @@ +prefs: [dom.webxr.layers.enabled:true] diff --git a/tests/wpt/mozilla/tests/webxr/layers.html b/tests/wpt/mozilla/tests/webxr/layers.html new file mode 100644 index 00000000000..31f4b6bd51c --- /dev/null +++ b/tests/wpt/mozilla/tests/webxr/layers.html @@ -0,0 +1,54 @@ +<html> + <head> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <script src="./resources/webxr-util.js"></script> + </head> + <body> + <canvas id="canvas" width="640" height="480"></canvas> + + <script> + let canvas = document.getElementById("canvas"); + let gl = canvas.getContext('webgl'); + promise_test(async function() { + let mock = await navigator.xr.test.simulateDeviceConnection({ + supportsImmersive: true, + views: TEST_VIEWS, + viewerOrigin: {position: [0.5, 0.1, 0.1], orientation: [1, 0, 0, 1] } + }); + let sessionPromise; + navigator.xr.test.simulateUserActivation(() => { + sessionPromise = navigator.xr.requestSession("immersive-vr"); + }); + let session = await sessionPromise; + let glLayerFactory = new XRWebGLBinding(session, gl); + let layer = new XRWebGLLayer(session, gl); + assert_class_string(glLayerFactory, "XRWebGLBinding", "glLayerFactory is an XRWebGLBinding object"); + + session.updateRenderState({ layers: [layer] }); + await new Promise(resolve => { + session.requestAnimationFrame((time, frame) => resolve(frame)); + }); + assert_equals(session.renderState.baseLayer, null, "Setting layers shouldn't set baseLayer"); + + session.updateRenderState({ baseLayer: layer }); + await new Promise(resolve => { + session.requestAnimationFrame((time, frame) => resolve(frame)); + }); + assert_equals(session.renderState.baseLayer, layer, "Setting baseLayer should set baseLayer"); + + session.updateRenderState({ layers: [layer] }); + await new Promise(resolve => { + session.requestAnimationFrame((time, frame) => resolve(frame)); + }); + assert_equals(session.renderState.baseLayer, null, "Setting layers should unset baseLayer"); + + assert_throws_dom( + "InvalidStateError", + () => { session.updateRenderState({ layers: [layer], baseLayer: layer }); }, + "Setting both baseLayer and layers should fail" + ); + }); + </script> + </body> +</html> |