Added first-cut implementation of XR layers

This commit is contained in:
Alan Jeffrey 2020-04-08 17:35:20 -05:00
parent 7ae11588dc
commit fda8da0e9d
19 changed files with 585 additions and 15 deletions

View file

@ -299,6 +299,9 @@ mod gen {
test: bool,
#[serde(default)]
glwindow: bool,
layers: {
enabled: bool,
}
},
worklet: {
blockingsleep: {

View file

@ -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::*;

View file

@ -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;
// };

View file

@ -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;
};

View file

@ -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 {

View file

@ -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;
};

View file

@ -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"
};

View file

@ -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;
};

View file

@ -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,
}
}
}

View file

@ -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)
}
}

View file

@ -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 {

View file

@ -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(())
}

View file

@ -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)
}
}

View file

@ -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),
)
}
}

View file

@ -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
}
}

View file

@ -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,

View file

@ -14615,6 +14615,13 @@
{}
]
],
"layers.html": [
"31f4b6bd51cfcca47666331857bd2bbdf84d2f5e",
[
null,
{}
]
],
"obtain_frame.html": [
"74fda5bad43e8ea95552e65380e83952680e8469",
[

View file

@ -0,0 +1 @@
prefs: [dom.webxr.layers.enabled:true]

View file

@ -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>