mirror of
https://github.com/servo/servo.git
synced 2025-07-22 14:53:49 +01:00
Added first-cut implementation of XR layers
This commit is contained in:
parent
7ae11588dc
commit
fda8da0e9d
19 changed files with 585 additions and 15 deletions
|
@ -299,6 +299,9 @@ mod gen {
|
|||
test: bool,
|
||||
#[serde(default)]
|
||||
glwindow: bool,
|
||||
layers: {
|
||||
enabled: bool,
|
||||
}
|
||||
},
|
||||
worklet: {
|
||||
blockingsleep: {
|
||||
|
|
|
@ -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::*;
|
||||
|
|
63
components/script/dom/webidls/XRLayer.webidl
Normal file
63
components/script/dom/webidls/XRLayer.webidl
Normal 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;
|
||||
// };
|
18
components/script/dom/webidls/XRMediaBinding.webidl
Normal file
18
components/script/dom/webidls/XRMediaBinding.webidl
Normal 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;
|
||||
};
|
|
@ -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 {
|
||||
|
|
9
components/script/dom/webidls/XRSubImage.webidl
Normal file
9
components/script/dom/webidls/XRSubImage.webidl
Normal 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;
|
||||
};
|
44
components/script/dom/webidls/XRWebGLBinding.webidl
Normal file
44
components/script/dom/webidls/XRWebGLBinding.webidl
Normal 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"
|
||||
};
|
||||
|
11
components/script/dom/webidls/XRWebGLSubImage.webidl
Normal file
11
components/script/dom/webidls/XRWebGLSubImage.webidl
Normal 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;
|
||||
};
|
53
components/script/dom/xrlayer.rs
Normal file
53
components/script/dom/xrlayer.rs
Normal 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,
|
||||
}
|
||||
}
|
||||
}
|
35
components/script/dom/xrmediabinding.rs
Normal file
35
components/script/dom/xrmediabinding.rs
Normal 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)
|
||||
}
|
||||
}
|
|
@ -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 {
|
||||
|
|
|
@ -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(())
|
||||
}
|
||||
|
||||
|
|
23
components/script/dom/xrsubimage.rs
Normal file
23
components/script/dom/xrsubimage.rs
Normal 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)
|
||||
}
|
||||
}
|
109
components/script/dom/xrwebglbinding.rs
Normal file
109
components/script/dom/xrwebglbinding.rs
Normal 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),
|
||||
)
|
||||
}
|
||||
}
|
35
components/script/dom/xrwebglsubimage.rs
Normal file
35
components/script/dom/xrwebglsubimage.rs
Normal 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
|
||||
}
|
||||
}
|
|
@ -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,
|
||||
|
|
|
@ -14615,6 +14615,13 @@
|
|||
{}
|
||||
]
|
||||
],
|
||||
"layers.html": [
|
||||
"31f4b6bd51cfcca47666331857bd2bbdf84d2f5e",
|
||||
[
|
||||
null,
|
||||
{}
|
||||
]
|
||||
],
|
||||
"obtain_frame.html": [
|
||||
"74fda5bad43e8ea95552e65380e83952680e8469",
|
||||
[
|
||||
|
|
1
tests/wpt/mozilla/meta/webxr/layers.html.ini
Normal file
1
tests/wpt/mozilla/meta/webxr/layers.html.ini
Normal file
|
@ -0,0 +1 @@
|
|||
prefs: [dom.webxr.layers.enabled:true]
|
54
tests/wpt/mozilla/tests/webxr/layers.html
Normal file
54
tests/wpt/mozilla/tests/webxr/layers.html
Normal 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>
|
Loading…
Add table
Add a link
Reference in a new issue