diff options
-rw-r--r-- | components/script/dom/webglframebuffer.rs | 7 | ||||
-rw-r--r-- | components/script/dom/webidls/XRLayer.webidl | 71 | ||||
-rw-r--r-- | components/script/dom/webidls/XRLayerEvent.webidl | 15 | ||||
-rw-r--r-- | components/script/dom/webidls/XRMediaBinding.webidl | 1 | ||||
-rw-r--r-- | components/script/dom/webidls/XRRenderState.webidl | 10 | ||||
-rw-r--r-- | components/script/dom/webidls/XRSubImage.webidl | 2 | ||||
-rw-r--r-- | components/script/dom/webidls/XRWebGLBinding.webidl | 61 | ||||
-rw-r--r-- | components/script/dom/webidls/XRWebGLLayer.webidl | 8 | ||||
-rw-r--r-- | components/script/dom/xrlayer.rs | 54 | ||||
-rw-r--r-- | components/script/dom/xrrenderstate.rs | 86 | ||||
-rw-r--r-- | components/script/dom/xrsession.rs | 121 | ||||
-rw-r--r-- | components/script/dom/xrwebglbinding.rs | 93 | ||||
-rw-r--r-- | components/script/dom/xrwebgllayer.rs | 90 | ||||
-rw-r--r-- | tests/wpt/metadata/webxr/idlharness.https.window.js.ini | 24 | ||||
-rw-r--r-- | tests/wpt/mozilla/meta/MANIFEST.json | 4 | ||||
-rw-r--r-- | tests/wpt/mozilla/tests/mozilla/interfaces.html | 1 | ||||
-rw-r--r-- | tests/wpt/mozilla/tests/webxr/layers.html | 4 |
17 files changed, 289 insertions, 363 deletions
diff --git a/components/script/dom/webglframebuffer.rs b/components/script/dom/webglframebuffer.rs index a0d8025a131..9539ac90507 100644 --- a/components/script/dom/webglframebuffer.rs +++ b/components/script/dom/webglframebuffer.rs @@ -5,7 +5,6 @@ // https://www.khronos.org/registry/webgl/specs/latest/1.0/webgl.idl use crate::dom::bindings::cell::DomRefCell; use crate::dom::bindings::codegen::Bindings::WebGL2RenderingContextBinding::WebGL2RenderingContextConstants as constants; -use crate::dom::bindings::codegen::Bindings::XRWebGLLayerBinding::XRWebGLRenderingContext; use crate::dom::bindings::inheritance::Castable; use crate::dom::bindings::reflector::{reflect_dom_object, DomObject}; use crate::dom::bindings::root::{Dom, DomRoot, MutNullableDom}; @@ -141,13 +140,9 @@ impl WebGLFramebuffer { // https://github.com/servo/servo/issues/24498 pub fn maybe_new_webxr( session: &XRSession, - context: &XRWebGLRenderingContext, + context: &WebGLRenderingContext, size: Size2D<i32, Viewport>, ) -> Option<DomRoot<Self>> { - let context = match context { - XRWebGLRenderingContext::WebGLRenderingContext(ref ctx) => DomRoot::from_ref(&**ctx), - XRWebGLRenderingContext::WebGL2RenderingContext(ref ctx) => ctx.base_context(), - }; let framebuffer = Self::maybe_new(&*context)?; framebuffer.size.set(Some((size.width, size.height))); framebuffer.status.set(constants::FRAMEBUFFER_COMPLETE); diff --git a/components/script/dom/webidls/XRLayer.webidl b/components/script/dom/webidls/XRLayer.webidl index d78e220b5f5..60e314316dd 100644 --- a/components/script/dom/webidls/XRLayer.webidl +++ b/components/script/dom/webidls/XRLayer.webidl @@ -2,59 +2,74 @@ * 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 { -// attribute boolean blendTextureSourceAlpha; -// attribute boolean chromaticAberrationCorrection; +// https://immersive-web.github.io/webxr/#xrlayer +[SecureContext, Exposed=Window, Pref="dom.webxr.enabled"] +interface XRLayer : EventTarget {}; - void destroy(); -}; -// // TODO: Implement the layer types // -// [SecureContext, Exposed=Window, Pref="dom.webxr.enabled"] -// interface XRProjectionLayer : XRLayer { +// [SecureContext, Exposed=Window, Pref="dom.webxr.layers.enabled"] +// interface XRCompositionLayer : XRLayer { +// readonly attribute XRLayerLayout layout; +// +// attribute boolean blendTextureSourceAlpha; +// attribute boolean? chromaticAberrationCorrection; +// attribute float? fixedFoveation; +// +// readonly attribute boolean needsRedraw; +// +// void destroy(); +// }; +// +// [SecureContext, Exposed=Window, Pref="dom.webxr.layers.enabled"] +// interface XRProjectionLayer : XRCompositionLayer { // readonly attribute boolean ignoreDepthValues; // }; // // [SecureContext, Exposed=Window, Pref="dom.webxr.layers.enabled"] -// interface XRQuadLayer : XRLayer { -// readonly attribute XRLayerLayout layout; +// interface XRQuadLayer : XRCompositionLayer { +// attribute XRSpace space; // attribute XRRigidTransform transform; // // attribute float width; // attribute float height; +// +// // Events +// attribute EventHandler onredraw; // }; // // [SecureContext, Exposed=Window, Pref="dom.webxr.layers.enabled"] -// interface XRCylinderLayer : XRLayer { -// readonly attribute XRLayerLayout layout; -// attribute XRReferenceSpace referenceSpace; -// +// interface XRCylinderLayer : XRCompositionLayer { +// attribute XRSpace space; // attribute XRRigidTransform transform; +// // attribute float radius; // attribute float centralAngle; // attribute float aspectRatio; +// +// // Events +// attribute EventHandler onredraw; // }; // // [SecureContext, Exposed=Window, Pref="dom.webxr.layers.enabled"] -// interface XREquirectLayer : XRLayer { -// readonly attribute XRLayerLayout layout; -// attribute XRReferenceSpace referenceSpace; -// +// interface XREquirectLayer : XRCompositionLayer { +// attribute XRSpace space; // attribute XRRigidTransform transform; +// // attribute float radius; -// attribute float scaleX; -// attribute float scaleY; -// attribute float biasX; -// attribute float biasY; +// attribute float centralHorizontalAngle; +// attribute float upperVerticalAngle; +// attribute float lowerVerticalAngle; +// +// // Events +// attribute EventHandler onredraw; // }; // // [SecureContext, Exposed=Window, Pref="dom.webxr.layers.enabled"] -// interface XRCubeLayer : XRLayer { -// readonly attribute XRLayerLayout layout; -// attribute XRReferenceSpace referenceSpace; +// interface XRCubeLayer : XRCompositionLayer { +// attribute XRSpace space; +// attribute DOMPointReadOnly orientation; // -// attribute DOMPoint orientation; +// // Events +// attribute EventHandler onredraw; // }; diff --git a/components/script/dom/webidls/XRLayerEvent.webidl b/components/script/dom/webidls/XRLayerEvent.webidl new file mode 100644 index 00000000000..c90b9bfb27b --- /dev/null +++ b/components/script/dom/webidls/XRLayerEvent.webidl @@ -0,0 +1,15 @@ +/* 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/#xrlayerevent-interface + +// [SecureContext, Exposed=Window] +// interface XRLayerEvent : Event { +// constructor(DOMString type, XRLayerEventInit eventInitDict); +// [SameObject] readonly attribute XRLayer layer; +// }; + +dictionary XRLayerEventInit : EventInit { + required XRLayer layer; +}; diff --git a/components/script/dom/webidls/XRMediaBinding.webidl b/components/script/dom/webidls/XRMediaBinding.webidl index 9ea40de56a4..226e0653b33 100644 --- a/components/script/dom/webidls/XRMediaBinding.webidl +++ b/components/script/dom/webidls/XRMediaBinding.webidl @@ -13,6 +13,7 @@ interface XRMediaBinding { }; dictionary XRMediaLayerInit { + required XRSpace space; XRLayerLayout layout = "mono"; boolean invertStereo = false; }; diff --git a/components/script/dom/webidls/XRRenderState.webidl b/components/script/dom/webidls/XRRenderState.webidl index 708df1f20eb..52c72511923 100644 --- a/components/script/dom/webidls/XRRenderState.webidl +++ b/components/script/dom/webidls/XRRenderState.webidl @@ -2,16 +2,14 @@ * 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 { double depthNear; double depthFar; double inlineVerticalFieldOfView; - XRWebGLLayer baseLayer; - sequence<XRGenericLayer> layers; + XRWebGLLayer? baseLayer; + sequence<XRLayer>? layers; }; [SecureContext, Exposed=Window, Pref="dom.webxr.enabled"] interface XRRenderState { @@ -19,4 +17,8 @@ dictionary XRRenderStateInit { readonly attribute double depthFar; readonly attribute double? inlineVerticalFieldOfView; readonly attribute XRWebGLLayer? baseLayer; + + // https://immersive-web.github.io/layers/#xrrenderstatechanges + // workaround until we have FrozenArray + readonly attribute /* FrozenArray<XRLayer> */ any layers; }; diff --git a/components/script/dom/webidls/XRSubImage.webidl b/components/script/dom/webidls/XRSubImage.webidl index 9dbbd089928..c96067fab17 100644 --- a/components/script/dom/webidls/XRSubImage.webidl +++ b/components/script/dom/webidls/XRSubImage.webidl @@ -5,5 +5,5 @@ // https://immersive-web.github.io/layers/#xrsubimagetype [SecureContext, Exposed=Window, Pref="dom.webxr.layers.enabled"] interface XRSubImage { - readonly attribute XRViewport viewport; + [SameObject] readonly attribute XRViewport viewport; }; diff --git a/components/script/dom/webidls/XRWebGLBinding.webidl b/components/script/dom/webidls/XRWebGLBinding.webidl index 08617561b36..c57b59b7afc 100644 --- a/components/script/dom/webidls/XRWebGLBinding.webidl +++ b/components/script/dom/webidls/XRWebGLBinding.webidl @@ -9,14 +9,18 @@ interface XRWebGLBinding { // 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); +// XRProjectionLayer createProjectionLayer(XRTextureType textureType, +// optional XRProjectionLayerInit init); +// XRQuadLayer createQuadLayer(XRTextureType textureType, +// optional XRQuadLayerInit init); +// XRCylinderLayer createCylinderLayer(XRTextureType textureType, +// optional XRCylinderLayerInit init); +// XREquirectLayer createEquirectLayer(XRTextureType textureType, +// optional XREquirectLayerInit init); +// XRCubeLayer createCubeLayer(optional XRCubeLayerInit init); - XRWebGLSubImage? getSubImage(XRLayer layer, XRFrame frame); // for mono layers - XRWebGLSubImage? getViewSubImage(XRLayer layer, XRView view); // for stereo layers +// XRWebGLSubImage getSubImage(XRCompositionLayer layer, XRFrame frame, optional XREye eye = "none"); +// XRWebGLSubImage getViewSubImage(XRProjectionLayer layer, XRView view); }; dictionary XRProjectionLayerInit { @@ -26,19 +30,54 @@ dictionary XRProjectionLayerInit { double scaleFactor = 1.0; }; +dictionary XRQuadLayerInit : XRLayerInit { + XRRigidTransform? transform; + float width = 1.0; + float height = 1.0; + boolean isStatic = false; +}; + +dictionary XRCylinderLayerInit : XRLayerInit { + XRRigidTransform? transform; + float radius = 2.0; + float centralAngle = 0.78539; + float aspectRatio = 2.0; + boolean isStatic = false; +}; + +dictionary XREquirectLayerInit : XRLayerInit { + XRRigidTransform? transform; + float radius = 0; + float centralHorizontalAngle = 6.28318; + float upperVerticalAngle = 1.570795; + float lowerVerticalAngle = -1.570795; + boolean isStatic = false; +}; + +dictionary XRCubeLayerInit : XRLayerInit { + DOMPointReadOnly? orientation; + boolean isStatic = false; +}; + dictionary XRLayerInit { - required unsigned long pixelWidth; - required unsigned long pixelHeight; + required XRSpace space; + required unsigned long viewPixelWidth; + required unsigned long viewPixelHeight; XRLayerLayout layout = "mono"; - boolean depth = false; // This is a change from typical WebGL initialization, but feels appropriate. + boolean depth = false; boolean stencil = false; boolean alpha = true; }; +enum XRTextureType { + "texture", + "texture-array" +}; + enum XRLayerLayout { + "default", "mono", "stereo", "stereo-left-right", "stereo-top-bottom" }; - diff --git a/components/script/dom/webidls/XRWebGLLayer.webidl b/components/script/dom/webidls/XRWebGLLayer.webidl index db3d3b7b917..87d2dc4dccb 100644 --- a/components/script/dom/webidls/XRWebGLLayer.webidl +++ b/components/script/dom/webidls/XRWebGLLayer.webidl @@ -17,19 +17,19 @@ dictionary XRWebGLLayerInit { }; [SecureContext, Exposed=Window, Pref="dom.webxr.enabled"] -interface XRWebGLLayer { +interface XRWebGLLayer: XRLayer { [Throws] constructor(XRSession session, XRWebGLRenderingContext context, optional XRWebGLLayerInit layerInit = {}); - // // Attributes + // Attributes readonly attribute boolean antialias; readonly attribute boolean ignoreDepthValues; - readonly attribute WebGLFramebuffer? framebuffer; + [SameObject] readonly attribute WebGLFramebuffer? framebuffer; readonly attribute unsigned long framebufferWidth; readonly attribute unsigned long framebufferHeight; - // // Methods + // Methods XRViewport? getViewport(XRView view); // // Static Methods diff --git a/components/script/dom/xrlayer.rs b/components/script/dom/xrlayer.rs index b55df545e37..7328609d89f 100644 --- a/components/script/dom/xrlayer.rs +++ b/components/script/dom/xrlayer.rs @@ -2,30 +2,26 @@ * 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::inheritance::Castable; use crate::dom::bindings::root::Dom; +use crate::dom::eventtarget::EventTarget; use crate::dom::webglrenderingcontext::WebGLRenderingContext; use crate::dom::xrframe::XRFrame; use crate::dom::xrsession::XRSession; +use crate::dom::xrwebgllayer::XRWebGLLayer; use canvas_traits::webgl::WebGLContextId; use dom_struct::dom_struct; use webxr_api::LayerId; #[dom_struct] pub struct XRLayer { - reflector: Reflector, + event_target: EventTarget, session: Dom<XRSession>, context: Dom<WebGLRenderingContext>, - #[ignore_malloc_size_of = "Layers don't heap-allocate"] - layer_id: LayerId, -} - -impl XRLayerMethods for XRLayer { - /// https://immersive-web.github.io/layers/#dom-xrlayer-destroy - fn Destroy(&self) { - // TODO: Implement this - } + /// If none, the session is inline (the composition disabled flag is true) + /// and this is a XRWebGLLayer. + #[ignore_malloc_size_of = "Layer ids don't heap-allocate"] + layer_id: Option<LayerId>, } impl XRLayer { @@ -33,17 +29,17 @@ impl XRLayer { pub fn new_inherited( session: &XRSession, context: &WebGLRenderingContext, - layer_id: LayerId, + layer_id: Option<LayerId>, ) -> XRLayer { XRLayer { - reflector: Reflector::new(), + event_target: EventTarget::new_inherited(), session: Dom::from_ref(session), context: Dom::from_ref(context), layer_id, } } - pub(crate) fn layer_id(&self) -> LayerId { + pub(crate) fn layer_id(&self) -> Option<LayerId> { self.layer_id } @@ -51,13 +47,29 @@ impl XRLayer { self.context.context_id() } - pub fn begin_frame(&self, _frame: &XRFrame) -> Option<()> { - // TODO: Implement this - None + pub(crate) fn context(&self) -> &WebGLRenderingContext { + &self.context + } + + pub(crate) fn session(&self) -> &XRSession { + &self.session } - pub fn end_frame(&self, _frame: &XRFrame) -> Option<()> { - // TODO: Implement this - None + pub fn begin_frame(&self, frame: &XRFrame) -> Option<()> { + // TODO: Implement this for other layer types + if let Some(this) = self.downcast::<XRWebGLLayer>() { + this.begin_frame(frame) + } else { + unimplemented!() + } + } + + pub fn end_frame(&self, frame: &XRFrame) -> Option<()> { + // TODO: Implement this for other layer types + if let Some(this) = self.downcast::<XRWebGLLayer>() { + this.end_frame(frame) + } else { + unimplemented!() + } } } diff --git a/components/script/dom/xrrenderstate.rs b/components/script/dom/xrrenderstate.rs index 10ab1ba661f..71e6d873814 100644 --- a/components/script/dom/xrrenderstate.rs +++ b/components/script/dom/xrrenderstate.rs @@ -4,17 +4,18 @@ 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::{Dom, DomRoot, MutNullableDom}; +use crate::dom::bindings::root::Dom; +use crate::dom::bindings::root::{DomRoot, MutNullableDom}; +use crate::dom::bindings::utils::to_frozen_array; use crate::dom::globalscope::GlobalScope; use crate::dom::xrlayer::XRLayer; use crate::dom::xrwebgllayer::XRWebGLLayer; -use canvas_traits::webgl::WebGLContextId; +use crate::script_runtime::JSContext; use dom_struct::dom_struct; +use js::jsval::JSVal; use std::cell::Cell; -use webxr_api::LayerId; use webxr_api::SubImages; #[dom_struct] @@ -24,51 +25,7 @@ pub struct XRRenderState { depth_far: Cell<f64>, inline_vertical_fov: Cell<Option<f64>>, base_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(crate) fn layer_id(&self) -> Option<LayerId> { - match self { - XRWebGLLayerOrXRLayer::XRWebGLLayer(ref layer) => layer.layer_id(), - XRWebGLLayerOrXRLayer::XRLayer(ref layer) => Some(layer.layer_id()), - } - } -} - -impl RootedXRWebGLLayerOrXRLayer { - pub(crate) fn layer_id(&self) -> Option<LayerId> { - match self { - RootedXRWebGLLayerOrXRLayer::XRWebGLLayer(ref layer) => layer.layer_id(), - RootedXRWebGLLayerOrXRLayer::XRLayer(ref layer) => Some(layer.layer_id()), - } - } - - pub(crate) fn context_id(&self) -> WebGLContextId { - match self { - RootedXRWebGLLayerOrXRLayer::XRWebGLLayer(ref layer) => layer.context_id(), - RootedXRWebGLLayerOrXRLayer::XRLayer(ref layer) => layer.context_id(), - } - } + layers: DomRefCell<Vec<Dom<XRLayer>>>, } impl XRRenderState { @@ -77,7 +34,7 @@ impl XRRenderState { depth_far: f64, inline_vertical_fov: Option<f64>, layer: Option<&XRWebGLLayer>, - layers: &[XRWebGLLayerOrXRLayer], + layers: Vec<&XRLayer>, ) -> XRRenderState { debug_assert!(layer.is_none() || layers.is_empty()); XRRenderState { @@ -86,7 +43,12 @@ impl XRRenderState { depth_far: Cell::new(depth_far), inline_vertical_fov: Cell::new(inline_vertical_fov), base_layer: MutNullableDom::new(layer), - layers: DomRefCell::new(layers.iter().cloned().collect()), + layers: DomRefCell::new( + layers + .into_iter() + .map(|layer| Dom::from_ref(layer)) + .collect(), + ), } } @@ -96,7 +58,7 @@ impl XRRenderState { depth_far: f64, inline_vertical_fov: Option<f64>, layer: Option<&XRWebGLLayer>, - layers: &[XRWebGLLayerOrXRLayer], + layers: Vec<&XRLayer>, ) -> DomRoot<XRRenderState> { reflect_dom_object( Box::new(XRRenderState::new_inherited( @@ -111,14 +73,13 @@ impl XRRenderState { } 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.base_layer.get().as_ref().map(|x| &**x), - &layers, + self.layers.borrow().iter().map(|x| &**x).collect(), ) } @@ -135,12 +96,15 @@ impl XRRenderState { pub fn set_base_layer(&self, layer: Option<&XRWebGLLayer>) { self.base_layer.set(layer) } - pub fn set_layers(&self, layers: &[RootedXRWebGLLayerOrXRLayer]) { - *self.layers.borrow_mut() = layers.iter().map(XRWebGLLayerOrXRLayer::from_ref).collect(); + pub fn set_layers(&self, layers: Vec<&XRLayer>) { + *self.layers.borrow_mut() = layers + .into_iter() + .map(|layer| Dom::from_ref(layer)) + .collect(); } pub fn with_layers<F, R>(&self, f: F) -> R where - F: FnOnce(&[XRWebGLLayerOrXRLayer]) -> R, + F: FnOnce(&[Dom<XRLayer>]) -> R, { let layers = self.layers.borrow(); f(&*layers) @@ -187,4 +151,12 @@ impl XRRenderStateMethods for XRRenderState { fn GetBaseLayer(&self) -> Option<DomRoot<XRWebGLLayer>> { self.base_layer.get() } + + /// https://immersive-web.github.io/layers/#dom-xrrenderstate-layers + fn Layers(&self, cx: JSContext) -> JSVal { + // TODO: cache this array? + let layers = self.layers.borrow(); + let layers: Vec<&XRLayer> = layers.iter().map(|x| &**x).collect(); + to_frozen_array(&layers[..], cx) + } } diff --git a/components/script/dom/xrsession.rs b/components/script/dom/xrsession.rs index 87dcf19f622..1655328ec5a 100644 --- a/components/script/dom/xrsession.rs +++ b/components/script/dom/xrsession.rs @@ -16,7 +16,6 @@ use crate::dom::bindings::codegen::Bindings::XRSessionBinding::XRFrameRequestCal use crate::dom::bindings::codegen::Bindings::XRSessionBinding::XRSessionMethods; use crate::dom::bindings::codegen::Bindings::XRSessionBinding::XRVisibilityState; use crate::dom::bindings::codegen::Bindings::XRSystemBinding::XRSessionMode; -use crate::dom::bindings::codegen::Bindings::XRWebGLLayerBinding::XRWebGLRenderingContext; use crate::dom::bindings::error::{Error, ErrorResult}; use crate::dom::bindings::inheritance::Castable; use crate::dom::bindings::refcounted::Trusted; @@ -33,7 +32,6 @@ use crate::dom::xrinputsourcearray::XRInputSourceArray; use crate::dom::xrinputsourceevent::XRInputSourceEvent; use crate::dom::xrreferencespace::XRReferenceSpace; use crate::dom::xrrenderstate::XRRenderState; -use crate::dom::xrrenderstate::XRWebGLLayerOrXRLayer; use crate::dom::xrsessionevent::XRSessionEvent; use crate::dom::xrspace::XRSpace; use crate::realms::InRealm; @@ -133,7 +131,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, Vec::new()); let input_sources = XRInputSourceArray::new(global); let ret = reflect_dom_object( Box::new(XRSession::new_inherited( @@ -495,12 +493,7 @@ impl XRSession { pub fn dirty_layers(&self) { if let Some(layer) = self.RenderState().GetBaseLayer() { - match layer.context() { - XRWebGLRenderingContext::WebGLRenderingContext(c) => c.mark_as_dirty(), - XRWebGLRenderingContext::WebGL2RenderingContext(c) => { - c.base_context().mark_as_dirty() - }, - } + layer.context().mark_as_dirty(); } } @@ -511,14 +504,7 @@ impl XRSession { } self.active_render_state.get().with_layers(|layers| { for layer in layers { - match layer { - XRWebGLLayerOrXRLayer::XRWebGLLayer(layer) => { - layer.begin_frame(frame); - }, - XRWebGLLayerOrXRLayer::XRLayer(layer) => { - layer.begin_frame(frame); - }, - } + layer.begin_frame(frame); } }); } @@ -530,14 +516,7 @@ impl XRSession { } self.active_render_state.get().with_layers(|layers| { for layer in layers { - match layer { - XRWebGLLayerOrXRLayer::XRWebGLLayer(layer) => { - layer.end_frame(frame); - }, - XRWebGLLayerOrXRLayer::XRLayer(layer) => { - layer.end_frame(frame); - }, - } + layer.end_frame(frame); } }); } @@ -612,7 +591,7 @@ impl XRSessionMethods for XRSession { return Err(Error::InvalidState); } // Step 3: - if let Some(ref layer) = init.baseLayer { + if let Some(Some(ref layer)) = init.baseLayer { if Dom::from_ref(layer.session()) != Dom::from_ref(self) { return Err(Error::InvalidState); } @@ -623,26 +602,67 @@ 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); + // https://immersive-web.github.io/layers/#updaterenderstatechanges + // Step 1. + // TODO: support the `layers' feature. + let session_created_with_layers_enabled = false; + if init.baseLayer.is_some() { + if session_created_with_layers_enabled { + return Err(Error::NotSupported); + } + // https://github.com/immersive-web/layers/issues/189 + if init.layers.is_some() { + return Err(Error::Type(String::from( + "Cannot set WebXR layers and baseLayer", + ))); + } } - // 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); + if let Some(Some(ref layers)) = init.layers { + // Step 2 + for layer in layers { + let count = layers + .iter() + .filter(|other| other.layer_id() == layer.layer_id()) + .count(); + if count > 1 { + return Err(Error::Type(String::from("Duplicate entry in WebXR layers"))); + } + } + + // Step 3 + for layer in layers { + if layer.session() != self { + return Err(Error::Type(String::from( + "Layer from different session in WebXR layers", + ))); + } + } } + // Step 4-5 let pending = self .pending_render_state .or_init(|| self.active_render_state.get().clone_object()); + + // Step 6 + if let Some(ref layers) = init.layers { + let layers = layers.as_deref().unwrap_or_default(); + pending.set_base_layer(None); + pending.set_layers(layers.iter().map(|x| &**x).collect()); + let layers = layers + .iter() + .filter_map(|layer| { + let context_id = WebXRContextId::from(layer.context_id()); + let layer_id = layer.layer_id()?; + Some((context_id, layer_id)) + }) + .collect(); + self.session.borrow_mut().set_layers(layers); + } + + // End of https://immersive-web.github.io/layers/#updaterenderstatechanges + if let Some(near) = init.depthNear { let mut near = *near; // Step 8 from #apply-the-pending-render-state @@ -673,9 +693,10 @@ impl XRSessionMethods for XRSession { pending.set_inline_vertical_fov(fov); } if let Some(ref layer) = init.baseLayer { - pending.set_base_layer(Some(&layer)); - pending.set_layers(&[]); - let layers = std::iter::once(layer) + pending.set_base_layer(layer.as_deref()); + pending.set_layers(Vec::new()); + let layers = layer + .iter() .filter_map(|layer| { let context_id = WebXRContextId::from(layer.context_id()); let layer_id = layer.layer_id()?; @@ -691,22 +712,6 @@ impl XRSessionMethods for XRSession { .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_base_layer(None); - pending.set_layers(layers); - let layers = layers - .iter() - .filter_map(|layer| { - let context_id = WebXRContextId::from(layer.context_id()); - let layer_id = layer.layer_id()?; - Some((context_id, layer_id)) - }) - .collect(); - self.session.borrow_mut().set_layers(layers); - } - Ok(()) } diff --git a/components/script/dom/xrwebglbinding.rs b/components/script/dom/xrwebglbinding.rs index 4f5efaa3cf7..a0c4846074b 100644 --- a/components/script/dom/xrwebglbinding.rs +++ b/components/script/dom/xrwebglbinding.rs @@ -2,105 +2,36 @@ * 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::codegen::UnionTypes::WebGLRenderingContextOrWebGL2RenderingContext; 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 canvas_traits::webgl::WebGLContextId; 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 RootedWebGLRenderingContextOrWebGL2RenderingContext { - pub(crate) fn context_id(&self) -> WebGLContextId { - match self { - RootedWebGLRenderingContextOrWebGL2RenderingContext::WebGLRenderingContext( - ref context, - ) => context.context_id(), - RootedWebGLRenderingContextOrWebGL2RenderingContext::WebGL2RenderingContext( - ref context, - ) => context.base_context().context_id(), - } - } -} - -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 - } + context: Dom<WebGLRenderingContext>, } impl XRWebGLBinding { - pub fn new_inherited( - session: &XRSession, - context: &WebGLRenderingContextOrWebGL2RenderingContext, - ) -> XRWebGLBinding { + pub fn new_inherited(session: &XRSession, context: &WebGLRenderingContext) -> XRWebGLBinding { XRWebGLBinding { reflector: Reflector::new(), session: Dom::from_ref(session), - context: context.clone(), + context: Dom::from_ref(context), } } pub fn new( global: &Window, session: &XRSession, - context: &WebGLRenderingContextOrWebGL2RenderingContext, + context: &WebGLRenderingContext, ) -> DomRoot<XRWebGLBinding> { reflect_dom_object( Box::new(XRWebGLBinding::new_inherited(session, context)), @@ -112,12 +43,14 @@ impl XRWebGLBinding { pub fn Constructor( global: &Window, session: &XRSession, - context: RootedWebGLRenderingContextOrWebGL2RenderingContext, + context: WebGLRenderingContextOrWebGL2RenderingContext, ) -> DomRoot<XRWebGLBinding> { - XRWebGLBinding::new( - global, - session, - &WebGLRenderingContextOrWebGL2RenderingContext::from_ref(&context), - ) + let context = match context { + WebGLRenderingContextOrWebGL2RenderingContext::WebGLRenderingContext(ctx) => ctx, + WebGLRenderingContextOrWebGL2RenderingContext::WebGL2RenderingContext(ctx) => { + ctx.base_context() + }, + }; + XRWebGLBinding::new(global, session, &context) } } diff --git a/components/script/dom/xrwebgllayer.rs b/components/script/dom/xrwebgllayer.rs index 539c96770f3..7f0a7883961 100644 --- a/components/script/dom/xrwebgllayer.rs +++ b/components/script/dom/xrwebgllayer.rs @@ -2,30 +2,29 @@ * 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::inheritance::Castable; use crate::dom::bindings::codegen::Bindings::WebGL2RenderingContextBinding::WebGL2RenderingContextConstants as constants; use crate::dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::WebGLRenderingContextMethods; -use crate::dom::bindings::codegen::Bindings::WebGL2RenderingContextBinding::WebGL2RenderingContextBinding::WebGL2RenderingContextMethods; use crate::dom::bindings::codegen::Bindings::XRWebGLLayerBinding::XRWebGLLayerInit; use crate::dom::bindings::codegen::Bindings::XRWebGLLayerBinding::XRWebGLLayerMethods; use crate::dom::bindings::codegen::Bindings::XRWebGLLayerBinding::XRWebGLRenderingContext; use crate::dom::bindings::error::Error; use crate::dom::bindings::error::Fallible; -use crate::dom::bindings::reflector::{reflect_dom_object, DomObject, Reflector}; +use crate::dom::bindings::inheritance::Castable; +use crate::dom::bindings::reflector::{reflect_dom_object, DomObject}; use crate::dom::bindings::root::{Dom, DomRoot}; use crate::dom::globalscope::GlobalScope; use crate::dom::webglframebuffer::WebGLFramebuffer; use crate::dom::webglobject::WebGLObject; -use crate::dom::webgltexture::WebGLTexture; use crate::dom::webglrenderingcontext::WebGLRenderingContext; -use crate::dom::webgl2renderingcontext::WebGL2RenderingContext; +use crate::dom::webgltexture::WebGLTexture; 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::xrviewport::XRViewport; -use canvas_traits::webgl::WebGLContextId; use canvas_traits::webgl::WebGLCommand; +use canvas_traits::webgl::WebGLContextId; use canvas_traits::webgl::WebGLTextureId; use dom_struct::dom_struct; use euclid::{Rect, Size2D}; @@ -35,22 +34,6 @@ use webxr_api::LayerId; use webxr_api::LayerInit; use webxr_api::Viewport; -#[derive(JSTraceable, MallocSizeOf)] -#[unrooted_must_root_lint::must_root] -pub enum RenderingContext { - WebGL1(Dom<WebGLRenderingContext>), - WebGL2(Dom<WebGL2RenderingContext>), -} - -impl RenderingContext { - fn context_id(&self) -> WebGLContextId { - match self { - RenderingContext::WebGL1(ref ctx) => ctx.context_id(), - RenderingContext::WebGL2(ref ctx) => ctx.base_context().context_id(), - } - } -} - impl<'a> From<&'a XRWebGLLayerInit> for LayerInit { fn from(init: &'a XRWebGLLayerInit) -> LayerInit { LayerInit::WebGLLayer { @@ -66,46 +49,31 @@ impl<'a> From<&'a XRWebGLLayerInit> for LayerInit { #[dom_struct] pub struct XRWebGLLayer { - reflector_: Reflector, + xr_layer: XRLayer, antialias: bool, depth: bool, stencil: bool, alpha: bool, ignore_depth_values: bool, - context: RenderingContext, - session: Dom<XRSession>, /// If none, this is an inline session (the composition disabled flag is true) framebuffer: Option<Dom<WebGLFramebuffer>>, - /// If none, this is an inline session (the composition disabled flag is true) - #[ignore_malloc_size_of = "Layer ids don't heap-allocate"] - layer_id: Option<LayerId>, } impl XRWebGLLayer { pub fn new_inherited( session: &XRSession, - context: XRWebGLRenderingContext, + context: &WebGLRenderingContext, init: &XRWebGLLayerInit, framebuffer: Option<&WebGLFramebuffer>, layer_id: Option<LayerId>, ) -> XRWebGLLayer { XRWebGLLayer { - reflector_: Reflector::new(), + xr_layer: XRLayer::new_inherited(session, context, layer_id), antialias: init.antialias, depth: init.depth, stencil: init.stencil, alpha: init.alpha, ignore_depth_values: init.ignoreDepthValues, - layer_id, - context: match context { - XRWebGLRenderingContext::WebGLRenderingContext(ctx) => { - RenderingContext::WebGL1(Dom::from_ref(&*ctx)) - }, - XRWebGLRenderingContext::WebGL2RenderingContext(ctx) => { - RenderingContext::WebGL2(Dom::from_ref(&*ctx)) - }, - }, - session: Dom::from_ref(session), framebuffer: framebuffer.map(Dom::from_ref), } } @@ -113,7 +81,7 @@ impl XRWebGLLayer { pub fn new( global: &GlobalScope, session: &XRSession, - context: XRWebGLRenderingContext, + context: &WebGLRenderingContext, init: &XRWebGLLayerInit, framebuffer: Option<&WebGLFramebuffer>, layer_id: Option<LayerId>, @@ -138,6 +106,11 @@ impl XRWebGLLayer { context: XRWebGLRenderingContext, init: &XRWebGLLayerInit, ) -> Fallible<DomRoot<Self>> { + let context = match context { + XRWebGLRenderingContext::WebGLRenderingContext(ctx) => ctx, + XRWebGLRenderingContext::WebGL2RenderingContext(ctx) => ctx.base_context(), + }; + // Step 2 if session.is_ended() { return Err(Error::InvalidState); @@ -169,16 +142,13 @@ impl XRWebGLLayer { }; // Ensure that we finish setting up this layer before continuing. - match context { - XRWebGLRenderingContext::WebGLRenderingContext(ref ctx) => ctx.Finish(), - XRWebGLRenderingContext::WebGL2RenderingContext(ref ctx) => ctx.Finish(), - } + context.Finish(); // Step 10. "Return layer." Ok(XRWebGLLayer::new( &global.global(), session, - context, + &context, init, framebuffer.as_deref(), layer_id, @@ -186,15 +156,15 @@ impl XRWebGLLayer { } pub fn layer_id(&self) -> Option<LayerId> { - self.layer_id + self.xr_layer.layer_id() } pub fn context_id(&self) -> WebGLContextId { - self.context.context_id() + self.xr_layer.context_id() } pub fn session(&self) -> &XRSession { - &self.session + &self.xr_layer.session() } pub fn size(&self) -> Size2D<u32, Viewport> { @@ -205,10 +175,7 @@ impl XRWebGLLayer { size.1.try_into().unwrap_or(0), ) } else { - let size = match self.context { - RenderingContext::WebGL1(ref ctx) => ctx.Canvas().get_size(), - RenderingContext::WebGL2(ref ctx) => ctx.base_context().Canvas().get_size(), - }; + let size = self.context().Canvas().get_size(); Size2D::from_untyped(size) } } @@ -225,7 +192,7 @@ impl XRWebGLLayer { debug!("XRWebGLLayer begin frame"); let framebuffer = self.framebuffer.as_ref()?; let context = framebuffer.upcast::<WebGLObject>().context(); - let sub_images = frame.get_sub_images(self.layer_id?)?; + let sub_images = frame.get_sub_images(self.layer_id()?)?; // TODO: Cache this texture let color_texture_id = WebGLTextureId::maybe_new(sub_images.sub_image.as_ref()?.color_texture)?; @@ -306,15 +273,8 @@ impl XRWebGLLayer { Some(()) } - pub(crate) fn context(&self) -> XRWebGLRenderingContext { - match self.context { - RenderingContext::WebGL1(ref ctx) => { - XRWebGLRenderingContext::WebGLRenderingContext(DomRoot::from_ref(&**ctx)) - }, - RenderingContext::WebGL2(ref ctx) => { - XRWebGLRenderingContext::WebGL2RenderingContext(DomRoot::from_ref(&**ctx)) - }, - } + pub(crate) fn context(&self) -> &WebGLRenderingContext { + self.xr_layer.context() } } @@ -346,13 +306,13 @@ impl XRWebGLLayerMethods for XRWebGLLayer { /// https://immersive-web.github.io/webxr/#dom-xrwebgllayer-getviewport fn GetViewport(&self, view: &XRView) -> Option<DomRoot<XRViewport>> { - if self.session != view.session() { + if self.session() != view.session() { return None; } let index = view.viewport_index(); - let viewport = self.session.with_session(|s| { + let viewport = self.session().with_session(|s| { // Inline sssions if s.viewports().is_empty() { Rect::from_size(self.size().to_i32()) diff --git a/tests/wpt/metadata/webxr/idlharness.https.window.js.ini b/tests/wpt/metadata/webxr/idlharness.https.window.js.ini index 5aea7e10f11..066806ce962 100644 --- a/tests/wpt/metadata/webxr/idlharness.https.window.js.ini +++ b/tests/wpt/metadata/webxr/idlharness.https.window.js.ini @@ -329,30 +329,6 @@ [Stringification of xrInputSourceArray] expected: FAIL - [XRLayer interface: existence and properties of interface prototype object] - expected: FAIL - - [XRLayer interface: existence and properties of interface object] - expected: FAIL - - [XRLayer interface object name] - expected: FAIL - - [XRLayer interface: existence and properties of interface prototype object's "constructor" property] - expected: FAIL - - [XRWebGLLayer interface: existence and properties of interface object] - expected: FAIL - - [XRWebGLLayer interface: existence and properties of interface prototype object] - expected: FAIL - - [XRLayer interface object length] - expected: FAIL - - [XRLayer interface: existence and properties of interface prototype object's @@unscopables property] - expected: FAIL - [XRSession interface: xrSession must inherit property "cancelAnimationFrame(unsigned long)" with the proper type] expected: FAIL diff --git a/tests/wpt/mozilla/meta/MANIFEST.json b/tests/wpt/mozilla/meta/MANIFEST.json index f5bcd405ee8..efd06ac5803 100644 --- a/tests/wpt/mozilla/meta/MANIFEST.json +++ b/tests/wpt/mozilla/meta/MANIFEST.json @@ -13959,7 +13959,7 @@ ] ], "interfaces.html": [ - "d988b7939f83cef16a51a4ae5502ed029f31df99", + "b58b16ca333f9e00afade02c2ac60689ee7eef3a", [ null, {} @@ -14719,7 +14719,7 @@ ] ], "layers.html": [ - "49821d7661f92bc9cf22232d3fcb391c2cdc7295", + "f64cc1f30f469351b83cd1c12a0584b1db5317a7", [ null, {} diff --git a/tests/wpt/mozilla/tests/mozilla/interfaces.html b/tests/wpt/mozilla/tests/mozilla/interfaces.html index d988b7939f8..b58b16ca333 100644 --- a/tests/wpt/mozilla/tests/mozilla/interfaces.html +++ b/tests/wpt/mozilla/tests/mozilla/interfaces.html @@ -276,6 +276,7 @@ test_interfaces([ "XRInputSource", "XRInputSourceArray", "XRInputSourceEvent", + "XRLayer", "XRPose", "XRReferenceSpace", "XRRay", diff --git a/tests/wpt/mozilla/tests/webxr/layers.html b/tests/wpt/mozilla/tests/webxr/layers.html index 49821d7661f..f64cc1f30f4 100644 --- a/tests/wpt/mozilla/tests/webxr/layers.html +++ b/tests/wpt/mozilla/tests/webxr/layers.html @@ -43,8 +43,8 @@ }); assert_equals(session.renderState.baseLayer, null, "Setting layers should unset baseLayer"); - assert_throws_dom( - "InvalidStateError", + assert_throws_js( + TypeError, () => { session.updateRenderState({ layers: [layer], baseLayer: layer }); }, "Setting both baseLayer and layers should fail" ); |