Finish the integration of webxr into the Cargo workspace (#35229)

- Run `cargo fmt` on `webxr` and `webxr-api`
- Fix clippy warnings in the existing `webxr` code
- Integrate the new crates into the workspace
- Expose `webxr` via the libservo API rather than requiring embedders to
  depend on it explicitly.

Signed-off-by: Martin Robinson <mrobinson@igalia.com>
This commit is contained in:
Martin Robinson 2025-01-31 17:41:57 +01:00 committed by GitHub
parent a4c6c205d2
commit 5466c27f6f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
41 changed files with 448 additions and 649 deletions

2
Cargo.lock generated
View file

@ -6884,7 +6884,6 @@ dependencies = [
"tracing-subscriber", "tracing-subscriber",
"url", "url",
"vergen-git2", "vergen-git2",
"webxr",
"windows-sys 0.59.0", "windows-sys 0.59.0",
"winit", "winit",
"winres", "winres",
@ -8605,6 +8604,7 @@ dependencies = [
"ipc-channel", "ipc-channel",
"log", "log",
"serde", "serde",
"time 0.3.37",
] ]
[[package]] [[package]]

View file

@ -97,6 +97,7 @@ net_traits = { path = "components/shared/net" }
nix = "0.29" nix = "0.29"
num-traits = "0.2" num-traits = "0.2"
num_cpus = "1.1.0" num_cpus = "1.1.0"
openxr = "0.19"
parking_lot = "0.12" parking_lot = "0.12"
percent-encoding = "2.3" percent-encoding = "2.3"
proc-macro2 = "1" proc-macro2 = "1"
@ -105,6 +106,7 @@ quote = "1"
rand = "0.8" rand = "0.8"
rand_core = "0.6" rand_core = "0.6"
rand_isaac = "0.3" rand_isaac = "0.3"
raw-window-handle = "0.6"
rayon = "1" rayon = "1"
regex = "1.11" regex = "1.11"
rustls = { version = "0.23", default-features = false, features = ["logging", "std", "tls12"] } rustls = { version = "0.23", default-features = false, features = ["logging", "std", "tls12"] }
@ -159,8 +161,9 @@ webpki-roots = "0.26"
webrender = { git = "https://github.com/servo/webrender", branch = "0.65", features = ["capture"] } webrender = { git = "https://github.com/servo/webrender", branch = "0.65", features = ["capture"] }
webrender_api = { git = "https://github.com/servo/webrender", branch = "0.65" } webrender_api = { git = "https://github.com/servo/webrender", branch = "0.65" }
webrender_traits = { path = "components/shared/webrender" } webrender_traits = { path = "components/shared/webrender" }
webxr = { git = "https://github.com/servo/webxr" } webxr-api = { path = "components/shared/webxr" }
webxr-api = { git = "https://github.com/servo/webxr" } winapi = "0.3"
wio = "0.2"
wgpu-core = { git = "https://github.com/gfx-rs/wgpu", rev = "d8e7ab1ad13f2bf2f9702401d1bc625e26b1c2e6" } wgpu-core = { git = "https://github.com/gfx-rs/wgpu", rev = "d8e7ab1ad13f2bf2f9702401d1bc625e26b1c2e6" }
wgpu-types = { git = "https://github.com/gfx-rs/wgpu", rev = "d8e7ab1ad13f2bf2f9702401d1bc625e26b1c2e6" } wgpu-types = { git = "https://github.com/gfx-rs/wgpu", rev = "d8e7ab1ad13f2bf2f9702401d1bc625e26b1c2e6" }
windows-sys = "0.59" windows-sys = "0.59"
@ -230,7 +233,3 @@ codegen-units = 1
# #
# [patch."https://github.com/servo/<repository>"] # [patch."https://github.com/servo/<repository>"]
# <crate> = { path = "/path/to/local/checkout" } # <crate> = { path = "/path/to/local/checkout" }
[patch."https://github.com/servo/webxr"]
webxr = { path = "components/webxr" }
webxr-api = { path = "components/shared/webxr" }

View file

@ -43,5 +43,5 @@ unicode-script = { workspace = true }
webrender = { workspace = true } webrender = { workspace = true }
webrender_api = { workspace = true } webrender_api = { workspace = true }
webrender_traits = { workspace = true } webrender_traits = { workspace = true }
webxr = { workspace = true, features = ["ipc"], optional = true } webxr = { path = "../webxr", features = ["ipc"], optional = true }
webxr-api = { workspace = true, features = ["ipc"], optional = true } webxr-api = { workspace = true, features = ["ipc"], optional = true }

View file

@ -42,7 +42,7 @@ tracing = { workspace = true, optional = true }
webrender = { workspace = true } webrender = { workspace = true }
webrender_api = { workspace = true } webrender_api = { workspace = true }
webrender_traits = { workspace = true } webrender_traits = { workspace = true }
webxr = { workspace = true, optional = true } webxr = { path = "../webxr", optional = true }
[dev-dependencies] [dev-dependencies]
surfman = { workspace = true } surfman = { workspace = true }

View file

@ -95,18 +95,22 @@ webgpu = { path = "../webgpu" }
webrender = { workspace = true } webrender = { workspace = true }
webrender_api = { workspace = true } webrender_api = { workspace = true }
webrender_traits = { workspace = true } webrender_traits = { workspace = true }
webxr = { workspace = true, optional = true }
webxr-api = { workspace = true, optional = true } webxr-api = { workspace = true, optional = true }
[target.'cfg(any(target_os = "android", target_env = "ohos"))'.dependencies] [target.'cfg(any(target_os = "android", target_env = "ohos"))'.dependencies]
surfman = { workspace = true, features = ["sm-angle-default"] } surfman = { workspace = true, features = ["sm-angle-default"] }
webxr = { path = "../webxr", optional = true }
[target.'cfg(not(any(target_os = "android", target_env = "ohos")))'.dependencies] [target.'cfg(not(any(target_os = "android", target_env = "ohos")))'.dependencies]
surfman = { workspace = true, features = ["sm-x11", "sm-raw-window-handle-06"] } surfman = { workspace = true, features = ["sm-x11", "sm-raw-window-handle-06"] }
webxr = { path = "../webxr", features = ["ipc", "glwindow", "headless"] }
[target.'cfg(all(not(target_os = "windows"), not(target_os = "ios"), not(target_os = "android"), not(target_env = "ohos"), not(target_arch = "arm"), not(target_arch = "aarch64")))'.dependencies] [target.'cfg(all(not(target_os = "windows"), not(target_os = "ios"), not(target_os = "android"), not(target_env = "ohos"), not(target_arch = "arm"), not(target_arch = "aarch64")))'.dependencies]
gaol = "0.2.1" gaol = "0.2.1"
[target.'cfg(target_os = "windows")'.dependencies]
webxr = { path = "../webxr", features = ["ipc", "glwindow", "headless", "openxr-api"] }
[dev-dependencies] [dev-dependencies]
libservo = { path = ".", features = ["tracing"] } libservo = { path = ".", features = ["tracing"] }
rustls = { version = "0.23", default-features = false, features = ["aws-lc-rs"] } rustls = { version = "0.23", default-features = false, features = ["aws-lc-rs"] }

View file

@ -106,6 +106,8 @@ use webrender_traits::{
CrossProcessCompositorApi, WebrenderExternalImageHandlers, WebrenderExternalImageRegistry, CrossProcessCompositorApi, WebrenderExternalImageHandlers, WebrenderExternalImageRegistry,
WebrenderImageHandlerType, WebrenderImageHandlerType,
}; };
#[cfg(feature = "webxr")]
pub use webxr;
pub use { pub use {
background_hang_monitor, base, bluetooth, bluetooth_traits, canvas, canvas_traits, compositing, background_hang_monitor, base, bluetooth, bluetooth_traits, canvas, canvas_traits, compositing,
devtools, devtools_traits, euclid, fonts, ipc_channel, layout_thread_2020, media, net, devtools, devtools_traits, euclid, fonts, ipc_channel, layout_thread_2020, media, net,

View file

@ -1,14 +1,12 @@
[package] [package]
name = "webxr-api" name = "webxr-api"
version = "0.0.1" version.workspace = true
authors = ["The Servo Project Developers"] authors.workspace = true
edition = "2018" license.workspace = true
edition.workspace = true
homepage = "https://github.com/servo/webxr" publish.workspace = true
repository = "https://github.com/servo/webxr" rust-version.workspace = true
keywords = ["ar", "headset", "openxr", "vr", "webxr"] keywords = ["ar", "headset", "openxr", "vr", "webxr"]
license = "MPL-2.0"
description = '''A safe Rust API that provides a way to interact with description = '''A safe Rust API that provides a way to interact with
virtual reality and augmented reality devices and integration with OpenXR. virtual reality and augmented reality devices and integration with OpenXR.
The API is inspired by the WebXR Device API (https://www.w3.org/TR/webxr/) The API is inspired by the WebXR Device API (https://www.w3.org/TR/webxr/)
@ -21,8 +19,8 @@ path = "lib.rs"
ipc = ["serde", "ipc-channel", "euclid/serde"] ipc = ["serde", "ipc-channel", "euclid/serde"]
[dependencies] [dependencies]
euclid = "0.22" euclid = { workspace = true }
ipc-channel = { version = "0.19", optional = true } ipc-channel = { workspace = true, optional = true }
log = "0.4" log = { workspace = true }
serde = { version = "1.0", optional = true } serde = { workspace = true, optional = true }
time = { version = "0.1", optional = true } time_03 = { workspace = true, optional = true }

View file

@ -4,28 +4,14 @@
//! Traits to be implemented by backends //! Traits to be implemented by backends
use crate::ContextId;
use crate::EnvironmentBlendMode;
use crate::Error;
use crate::Event;
use crate::Floor;
use crate::Frame;
use crate::HitTestId;
use crate::HitTestSource;
use crate::InputSource;
use crate::LayerId;
use crate::LayerInit;
use crate::Native;
use crate::Quitter;
use crate::Sender;
use crate::Session;
use crate::SessionBuilder;
use crate::SessionInit;
use crate::SessionMode;
use crate::Viewports;
use euclid::{Point2D, RigidTransform3D}; use euclid::{Point2D, RigidTransform3D};
use crate::{
ContextId, EnvironmentBlendMode, Error, Event, Floor, Frame, HitTestId, HitTestSource,
InputSource, LayerId, LayerInit, Native, Quitter, Sender, Session, SessionBuilder, SessionInit,
SessionMode, Viewports,
};
/// A trait for discovering XR devices /// A trait for discovering XR devices
pub trait DiscoveryAPI<GL>: 'static { pub trait DiscoveryAPI<GL>: 'static {
fn request_session( fn request_session(
@ -105,10 +91,10 @@ impl<GL: 'static> DiscoveryAPI<GL> for Box<dyn DiscoveryAPI<GL>> {
init: &SessionInit, init: &SessionInit,
xr: SessionBuilder<GL>, xr: SessionBuilder<GL>,
) -> Result<Session, Error> { ) -> Result<Session, Error> {
(&mut **self).request_session(mode, init, xr) (**self).request_session(mode, init, xr)
} }
fn supports_session(&self, mode: SessionMode) -> bool { fn supports_session(&self, mode: SessionMode) -> bool {
(&**self).supports_session(mode) (**self).supports_session(mode)
} }
} }

View file

@ -4,18 +4,13 @@
use euclid::RigidTransform3D; use euclid::RigidTransform3D;
use crate::ApiSpace; use crate::{
use crate::BaseSpace; ApiSpace, BaseSpace, Frame, InputFrame, InputId, InputSource, SelectEvent, SelectKind, Sender,
use crate::Frame; };
use crate::InputFrame;
use crate::InputId;
use crate::InputSource;
use crate::SelectEvent;
use crate::SelectKind;
use crate::Sender;
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
#[cfg_attr(feature = "ipc", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "ipc", derive(serde::Serialize, serde::Deserialize))]
#[allow(clippy::large_enum_variant)]
pub enum Event { pub enum Event {
/// Input source connected /// Input source connected
AddInput(InputSource), AddInput(InputSource),
@ -35,7 +30,7 @@ pub enum Event {
ReferenceSpaceChanged(BaseSpace, RigidTransform3D<f32, ApiSpace, ApiSpace>), ReferenceSpaceChanged(BaseSpace, RigidTransform3D<f32, ApiSpace, ApiSpace>),
} }
#[derive(Copy, Clone, Debug)] #[derive(Clone, Copy, Debug)]
#[cfg_attr(feature = "ipc", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "ipc", derive(serde::Serialize, serde::Deserialize))]
pub enum Visibility { pub enum Visibility {
/// Session fully displayed to user /// Session fully displayed to user
@ -65,7 +60,7 @@ impl EventBuffer {
EventBuffer::Buffered(ref mut events) => events.push(event), EventBuffer::Buffered(ref mut events) => events.push(event),
EventBuffer::Sink(ref dest) => { EventBuffer::Sink(ref dest) => {
let _ = dest.send(event); let _ = dest.send(event);
} },
} }
} }

View file

@ -2,20 +2,14 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * 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/. */ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use crate::Floor;
use crate::HitTestId;
use crate::HitTestResult;
use crate::InputFrame;
use crate::Native;
use crate::SubImages;
use crate::Viewer;
use crate::Viewports;
use crate::Views;
use euclid::RigidTransform3D; use euclid::RigidTransform3D;
use crate::{
Floor, HitTestId, HitTestResult, InputFrame, Native, SubImages, Viewer, Viewports, Views,
};
/// The per-frame data that is provided by the device. /// The per-frame data that is provided by the device.
/// https://www.w3.org/TR/webxr/#xrframe /// <https://www.w3.org/TR/webxr/#xrframe>
// TODO: other fields? // TODO: other fields?
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
#[cfg_attr(feature = "ipc", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "ipc", derive(serde::Serialize, serde::Deserialize))]

View file

@ -1,7 +1,12 @@
use crate::Native; /* 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 euclid::RigidTransform3D; use euclid::RigidTransform3D;
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] use crate::Native;
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
#[cfg_attr(feature = "ipc", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "ipc", derive(serde::Serialize, serde::Deserialize))]
pub struct HandSpace; pub struct HandSpace;
@ -29,7 +34,7 @@ pub struct Finger<J> {
pub phalanx_tip: Option<J>, pub phalanx_tip: Option<J>,
} }
#[derive(Copy, Clone, Debug)] #[derive(Clone, Copy, Debug)]
#[cfg_attr(feature = "ipc", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "ipc", derive(serde::Serialize, serde::Deserialize))]
pub struct JointFrame { pub struct JointFrame {
pub pose: RigidTransform3D<f32, HandSpace, Native>, pub pose: RigidTransform3D<f32, HandSpace, Native>,
@ -97,7 +102,7 @@ impl<J> Finger<J> {
} }
} }
#[derive(Copy, Clone, Debug, PartialEq, Eq)] #[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[cfg_attr(feature = "ipc", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "ipc", derive(serde::Serialize, serde::Deserialize))]
pub enum FingerJoint { pub enum FingerJoint {
Metacarpal, Metacarpal,
@ -107,7 +112,7 @@ pub enum FingerJoint {
PhalanxTip, PhalanxTip,
} }
#[derive(Copy, Clone, Debug, PartialEq, Eq)] #[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[cfg_attr(feature = "ipc", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "ipc", derive(serde::Serialize, serde::Deserialize))]
pub enum Joint { pub enum Joint {
Wrist, Wrist,

View file

@ -1,16 +1,16 @@
use crate::ApiSpace; /* This Source Code Form is subject to the terms of the Mozilla Public
use crate::Native; * License, v. 2.0. If a copy of the MPL was not distributed with this
use crate::Space; * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use euclid::Point3D;
use euclid::RigidTransform3D;
use euclid::Rotation3D;
use euclid::Vector3D;
use std::f32::EPSILON;
use std::iter::FromIterator; use std::iter::FromIterator;
use euclid::{Point3D, RigidTransform3D, Rotation3D, Vector3D};
use crate::{ApiSpace, Native, Space};
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug)]
#[cfg_attr(feature = "ipc", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "ipc", derive(serde::Serialize, serde::Deserialize))]
/// https://immersive-web.github.io/hit-test/#xrray /// <https://immersive-web.github.io/hit-test/#xrray>
pub struct Ray<Space> { pub struct Ray<Space> {
/// The origin of the ray /// The origin of the ray
pub origin: Vector3D<f32, Space>, pub origin: Vector3D<f32, Space>,
@ -20,16 +20,16 @@ pub struct Ray<Space> {
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug)]
#[cfg_attr(feature = "ipc", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "ipc", derive(serde::Serialize, serde::Deserialize))]
/// https://immersive-web.github.io/hit-test/#enumdef-xrhittesttrackabletype /// <https://immersive-web.github.io/hit-test/#enumdef-xrhittesttrackabletype>
pub enum EntityType { pub enum EntityType {
Point, Point,
Plane, Plane,
Mesh, Mesh,
} }
#[derive(Copy, Clone, Debug)] #[derive(Clone, Copy, Debug)]
#[cfg_attr(feature = "ipc", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "ipc", derive(serde::Serialize, serde::Deserialize))]
/// https://immersive-web.github.io/hit-test/#dictdef-xrhittestoptionsinit /// <https://immersive-web.github.io/hit-test/#dictdef-xrhittestoptionsinit>
pub struct HitTestSource { pub struct HitTestSource {
pub id: HitTestId, pub id: HitTestId,
pub space: Space, pub space: Space,
@ -37,11 +37,11 @@ pub struct HitTestSource {
pub types: EntityTypes, pub types: EntityTypes,
} }
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
#[cfg_attr(feature = "ipc", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "ipc", derive(serde::Serialize, serde::Deserialize))]
pub struct HitTestId(pub u32); pub struct HitTestId(pub u32);
#[derive(Copy, Clone, Debug, Default)] #[derive(Clone, Copy, Debug, Default)]
#[cfg_attr(feature = "ipc", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "ipc", derive(serde::Serialize, serde::Deserialize))]
/// Vec<EntityType>, but better /// Vec<EntityType>, but better
pub struct EntityTypes { pub struct EntityTypes {
@ -50,7 +50,7 @@ pub struct EntityTypes {
pub mesh: bool, pub mesh: bool,
} }
#[derive(Copy, Clone, Debug)] #[derive(Clone, Copy, Debug)]
#[cfg_attr(feature = "ipc", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "ipc", derive(serde::Serialize, serde::Deserialize))]
pub struct HitTestResult { pub struct HitTestResult {
pub id: HitTestId, pub id: HitTestId,
@ -62,7 +62,7 @@ pub struct HitTestResult {
/// The coordinate space of a hit test result /// The coordinate space of a hit test result
pub struct HitTestSpace; pub struct HitTestSpace;
#[derive(Copy, Clone, Debug)] #[derive(Clone, Copy, Debug)]
#[cfg_attr(feature = "ipc", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "ipc", derive(serde::Serialize, serde::Deserialize))]
pub struct Triangle { pub struct Triangle {
pub first: Point3D<f32, Native>, pub first: Point3D<f32, Native>,
@ -101,7 +101,7 @@ impl FromIterator<EntityType> for EntityTypes {
} }
impl Triangle { impl Triangle {
/// https://en.wikipedia.org/wiki/M%C3%B6ller%E2%80%93Trumbore_intersection_algorithm /// <https://en.wikipedia.org/wiki/M%C3%B6ller%E2%80%93Trumbore_intersection_algorithm>
pub fn intersect( pub fn intersect(
self, self,
ray: Ray<Native>, ray: Ray<Native>,
@ -117,7 +117,7 @@ impl Triangle {
let h = ray.direction.cross(edge2); let h = ray.direction.cross(edge2);
let a = edge1.dot(h); let a = edge1.dot(h);
if a > -EPSILON && a < EPSILON { if a > -f32::EPSILON && a < f32::EPSILON {
// ray is parallel to triangle // ray is parallel to triangle
return None; return None;
} }
@ -129,7 +129,7 @@ impl Triangle {
// barycentric coordinate of intersection point u // barycentric coordinate of intersection point u
let u = f * s.dot(h); let u = f * s.dot(h);
// barycentric coordinates have range (0, 1) // barycentric coordinates have range (0, 1)
if u < 0. || u > 1. { if !(0. ..=1.).contains(&u) {
// the intersection is outside the triangle // the intersection is outside the triangle
return None; return None;
} }
@ -147,7 +147,7 @@ impl Triangle {
let t = f * edge2.dot(q); let t = f * edge2.dot(q);
if t > EPSILON { if t > f32::EPSILON {
let origin = ray.origin + ray.direction * t; let origin = ray.origin + ray.direction * t;
// this is not part of the Möller-Trumbore algorithm, the hit test spec // this is not part of the Möller-Trumbore algorithm, the hit test spec
@ -156,7 +156,7 @@ impl Triangle {
let normal = edge1.cross(edge2).normalize(); let normal = edge1.cross(edge2).normalize();
let y = Vector3D::new(0., 1., 0.); let y = Vector3D::new(0., 1., 0.);
let dot = normal.dot(y); let dot = normal.dot(y);
let rotation = if dot > -EPSILON && dot < EPSILON { let rotation = if dot > -f32::EPSILON && dot < f32::EPSILON {
// vectors are parallel, return the vector itself // vectors are parallel, return the vector itself
// XXXManishearth it's possible for the vectors to be // XXXManishearth it's possible for the vectors to be
// antiparallel, unclear if normals need to be flipped // antiparallel, unclear if normals need to be flipped

View file

@ -2,18 +2,15 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * 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/. */ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use crate::Hand;
use crate::Input;
use crate::JointFrame;
use crate::Native;
use euclid::RigidTransform3D; use euclid::RigidTransform3D;
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] use crate::{Hand, Input, JointFrame, Native};
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
#[cfg_attr(feature = "ipc", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "ipc", derive(serde::Serialize, serde::Deserialize))]
pub struct InputId(pub u32); pub struct InputId(pub u32);
#[derive(Copy, Clone, Debug)] #[derive(Clone, Copy, Debug)]
#[cfg_attr(feature = "ipc", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "ipc", derive(serde::Serialize, serde::Deserialize))]
pub enum Handedness { pub enum Handedness {
None, None,
@ -21,7 +18,7 @@ pub enum Handedness {
Right, Right,
} }
#[derive(Copy, Clone, Debug)] #[derive(Clone, Copy, Debug)]
#[cfg_attr(feature = "ipc", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "ipc", derive(serde::Serialize, serde::Deserialize))]
pub enum TargetRayMode { pub enum TargetRayMode {
Gaze, Gaze,
@ -55,7 +52,7 @@ pub struct InputFrame {
pub input_changed: bool, pub input_changed: bool,
} }
#[derive(Copy, Clone, Debug, PartialEq, Eq)] #[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[cfg_attr(feature = "ipc", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "ipc", derive(serde::Serialize, serde::Deserialize))]
pub enum SelectEvent { pub enum SelectEvent {
/// Selection started /// Selection started
@ -66,7 +63,7 @@ pub enum SelectEvent {
Select, Select,
} }
#[derive(Copy, Clone, Debug, PartialEq, Eq)] #[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[cfg_attr(feature = "ipc", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "ipc", derive(serde::Serialize, serde::Deserialize))]
pub enum SelectKind { pub enum SelectKind {
Select, Select,

View file

@ -2,16 +2,12 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * 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/. */ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use crate::Error;
use crate::Viewport;
use crate::Viewports;
use euclid::Rect;
use euclid::Size2D;
use std::fmt::Debug; use std::fmt::Debug;
use std::sync::atomic::AtomicUsize; use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::atomic::Ordering;
use euclid::{Rect, Size2D};
use crate::{Error, Viewport, Viewports};
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
#[cfg_attr(feature = "ipc", derive(Deserialize, Serialize))] #[cfg_attr(feature = "ipc", derive(Deserialize, Serialize))]
@ -165,12 +161,14 @@ impl LayerManager {
impl Drop for LayerManager { impl Drop for LayerManager {
fn drop(&mut self) { fn drop(&mut self) {
log::debug!("Dropping LayerManager"); log::debug!("Dropping LayerManager");
for (context_id, layer_id) in self.0.layers().to_vec() { let layers: Vec<_> = self.0.layers().to_vec();
for (context_id, layer_id) in layers.into_iter() {
self.destroy_layer(context_id, layer_id); self.destroy_layer(context_id, layer_id);
} }
} }
} }
#[allow(clippy::type_complexity)]
pub struct LayerManagerFactory<GL: GLTypes>( pub struct LayerManagerFactory<GL: GLTypes>(
Box< Box<
dyn Send dyn Send
@ -213,16 +211,16 @@ pub struct LayerId(usize);
static NEXT_LAYER_ID: AtomicUsize = AtomicUsize::new(0); static NEXT_LAYER_ID: AtomicUsize = AtomicUsize::new(0);
impl LayerId { impl Default for LayerId {
pub fn new() -> LayerId { fn default() -> Self {
LayerId(NEXT_LAYER_ID.fetch_add(1, Ordering::SeqCst)) LayerId(NEXT_LAYER_ID.fetch_add(1, Ordering::SeqCst))
} }
} }
#[derive(Copy, Clone, Debug)] #[derive(Clone, Copy, Debug)]
#[cfg_attr(feature = "ipc", derive(Deserialize, Serialize))] #[cfg_attr(feature = "ipc", derive(Deserialize, Serialize))]
pub enum LayerInit { pub enum LayerInit {
// https://www.w3.org/TR/webxr/#dictdef-xrwebgllayerinit /// <https://www.w3.org/TR/webxr/#dictdef-xrwebgllayerinit>
WebGLLayer { WebGLLayer {
antialias: bool, antialias: bool,
depth: bool, depth: bool,
@ -231,7 +229,7 @@ pub enum LayerInit {
ignore_depth_values: bool, ignore_depth_values: bool,
framebuffer_scale_factor: f32, framebuffer_scale_factor: f32,
}, },
// https://immersive-web.github.io/layers/#xrprojectionlayerinittype /// <https://immersive-web.github.io/layers/#xrprojectionlayerinittype>
ProjectionLayer { ProjectionLayer {
depth: bool, depth: bool,
stencil: bool, stencil: bool,
@ -247,8 +245,8 @@ impl LayerInit {
LayerInit::WebGLLayer { LayerInit::WebGLLayer {
framebuffer_scale_factor: scale, framebuffer_scale_factor: scale,
.. ..
} } |
| LayerInit::ProjectionLayer { LayerInit::ProjectionLayer {
scale_factor: scale, scale_factor: scale,
.. ..
} => { } => {
@ -258,13 +256,13 @@ impl LayerInit {
.fold(Rect::zero(), |acc, view| acc.union(view)) .fold(Rect::zero(), |acc, view| acc.union(view))
.size; .size;
(native_size.to_f32() * *scale).to_i32() (native_size.to_f32() * *scale).to_i32()
} },
} }
} }
} }
/// https://immersive-web.github.io/layers/#enumdef-xrlayerlayout /// <https://immersive-web.github.io/layers/#enumdef-xrlayerlayout>
#[derive(Copy, Clone, Debug)] #[derive(Clone, Copy, Debug)]
#[cfg_attr(feature = "ipc", derive(Deserialize, Serialize))] #[cfg_attr(feature = "ipc", derive(Deserialize, Serialize))]
pub enum LayerLayout { pub enum LayerLayout {
// TODO: Default // TODO: Default
@ -284,7 +282,7 @@ pub struct SubImages {
pub view_sub_images: Vec<SubImage>, pub view_sub_images: Vec<SubImage>,
} }
/// https://immersive-web.github.io/layers/#xrsubimagetype /// <https://immersive-web.github.io/layers/#xrsubimagetype>
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
#[cfg_attr(feature = "ipc", derive(Deserialize, Serialize))] #[cfg_attr(feature = "ipc", derive(Deserialize, Serialize))]
pub struct SubImage { pub struct SubImage {

View file

@ -19,130 +19,48 @@ mod space;
pub mod util; pub mod util;
mod view; mod view;
pub use device::DeviceAPI;
pub use device::DiscoveryAPI;
pub use error::Error;
pub use events::Event;
pub use events::EventBuffer;
pub use events::Visibility;
pub use frame::Frame;
pub use frame::FrameUpdateEvent;
pub use frame::ViewerPose;
pub use hand::Finger;
pub use hand::FingerJoint;
pub use hand::Hand;
pub use hand::HandSpace;
pub use hand::Joint;
pub use hand::JointFrame;
pub use hittest::EntityType;
pub use hittest::EntityTypes;
pub use hittest::HitTestId;
pub use hittest::HitTestResult;
pub use hittest::HitTestSource;
pub use hittest::HitTestSpace;
pub use hittest::Ray;
pub use hittest::Triangle;
pub use input::Handedness;
pub use input::InputFrame;
pub use input::InputId;
pub use input::InputSource;
pub use input::SelectEvent;
pub use input::SelectKind;
pub use input::TargetRayMode;
pub use layer::ContextId;
pub use layer::GLContexts;
pub use layer::GLTypes;
pub use layer::LayerGrandManager;
pub use layer::LayerGrandManagerAPI;
pub use layer::LayerId;
pub use layer::LayerInit;
pub use layer::LayerLayout;
pub use layer::LayerManager;
pub use layer::LayerManagerAPI;
pub use layer::LayerManagerFactory;
pub use layer::SubImage;
pub use layer::SubImages;
pub use mock::MockButton;
pub use mock::MockButtonType;
pub use mock::MockDeviceInit;
pub use mock::MockDeviceMsg;
pub use mock::MockDiscoveryAPI;
pub use mock::MockInputInit;
pub use mock::MockInputMsg;
pub use mock::MockRegion;
pub use mock::MockViewInit;
pub use mock::MockViewsInit;
pub use mock::MockWorld;
pub use registry::MainThreadRegistry;
pub use registry::MainThreadWaker;
pub use registry::Registry;
pub use session::EnvironmentBlendMode;
pub use session::MainThreadSession;
pub use session::Quitter;
pub use session::Session;
pub use session::SessionBuilder;
pub use session::SessionId;
pub use session::SessionInit;
pub use session::SessionMode;
pub use session::SessionThread;
pub use space::ApiSpace;
pub use space::BaseSpace;
pub use space::Space;
pub use view::Capture;
pub use view::CubeBack;
pub use view::CubeBottom;
pub use view::CubeLeft;
pub use view::CubeRight;
pub use view::CubeTop;
pub use view::Display;
pub use view::Floor;
pub use view::Input;
pub use view::LeftEye;
pub use view::Native;
pub use view::RightEye;
pub use view::SomeEye;
pub use view::View;
pub use view::Viewer;
pub use view::Viewport;
pub use view::Viewports;
pub use view::Views;
pub use view::CUBE_BACK;
pub use view::CUBE_BOTTOM;
pub use view::CUBE_LEFT;
pub use view::CUBE_RIGHT;
pub use view::CUBE_TOP;
pub use view::LEFT_EYE;
pub use view::RIGHT_EYE;
pub use view::VIEWER;
#[cfg(feature = "ipc")]
use std::thread;
use std::time::Duration;
#[cfg(feature = "ipc")]
pub use ipc_channel::ipc::IpcSender as Sender;
#[cfg(feature = "ipc")]
pub use ipc_channel::ipc::IpcReceiver as Receiver;
#[cfg(feature = "ipc")]
pub use ipc_channel::ipc::channel;
#[cfg(not(feature = "ipc"))] #[cfg(not(feature = "ipc"))]
pub use std::sync::mpsc::{Receiver, RecvTimeoutError, Sender}; pub use std::sync::mpsc::{Receiver, RecvTimeoutError, Sender};
#[cfg(feature = "ipc")]
use std::thread;
use std::time::Duration;
pub use device::{DeviceAPI, DiscoveryAPI};
pub use error::Error;
pub use events::{Event, EventBuffer, Visibility};
pub use frame::{Frame, FrameUpdateEvent, ViewerPose};
pub use hand::{Finger, FingerJoint, Hand, HandSpace, Joint, JointFrame};
pub use hittest::{
EntityType, EntityTypes, HitTestId, HitTestResult, HitTestSource, HitTestSpace, Ray, Triangle,
};
pub use input::{
Handedness, InputFrame, InputId, InputSource, SelectEvent, SelectKind, TargetRayMode,
};
#[cfg(feature = "ipc")]
pub use ipc_channel::ipc::channel;
#[cfg(feature = "ipc")]
pub use ipc_channel::ipc::IpcReceiver as Receiver;
#[cfg(feature = "ipc")]
pub use ipc_channel::ipc::IpcSender as Sender;
pub use layer::{
ContextId, GLContexts, GLTypes, LayerGrandManager, LayerGrandManagerAPI, LayerId, LayerInit,
LayerLayout, LayerManager, LayerManagerAPI, LayerManagerFactory, SubImage, SubImages,
};
pub use mock::{
MockButton, MockButtonType, MockDeviceInit, MockDeviceMsg, MockDiscoveryAPI, MockInputInit,
MockInputMsg, MockRegion, MockViewInit, MockViewsInit, MockWorld,
};
pub use registry::{MainThreadRegistry, MainThreadWaker, Registry};
pub use session::{
EnvironmentBlendMode, MainThreadSession, Quitter, Session, SessionBuilder, SessionId,
SessionInit, SessionMode, SessionThread,
};
pub use space::{ApiSpace, BaseSpace, Space};
pub use view::{
Capture, CubeBack, CubeBottom, CubeLeft, CubeRight, CubeTop, Display, Floor, Input, LeftEye,
Native, RightEye, SomeEye, View, Viewer, Viewport, Viewports, Views, CUBE_BACK, CUBE_BOTTOM,
CUBE_LEFT, CUBE_RIGHT, CUBE_TOP, LEFT_EYE, RIGHT_EYE, VIEWER,
};
#[cfg(not(feature = "ipc"))] #[cfg(not(feature = "ipc"))]
pub fn channel<T>() -> Result<(Sender<T>, Receiver<T>), ()> { pub fn channel<T>() -> Result<(Sender<T>, Receiver<T>), ()> {
@ -169,7 +87,7 @@ where
return Ok(msg); return Ok(msg);
} }
thread::sleep(delay); thread::sleep(delay);
delay = delay * 2; delay *= 2;
} }
receiver.try_recv() receiver.try_recv()
} }

View file

@ -2,33 +2,16 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * 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/. */ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use crate::DiscoveryAPI;
use crate::Display;
use crate::EntityType;
use crate::Error;
use crate::Floor;
use crate::Handedness;
use crate::Input;
use crate::InputId;
use crate::InputSource;
use crate::LeftEye;
use crate::Native;
use crate::Receiver;
use crate::RightEye;
use crate::SelectEvent;
use crate::SelectKind;
use crate::Sender;
use crate::TargetRayMode;
use crate::Triangle;
use crate::Viewer;
use crate::Viewport;
use crate::Visibility;
use euclid::{Point2D, Rect, RigidTransform3D, Transform3D}; use euclid::{Point2D, Rect, RigidTransform3D, Transform3D};
#[cfg(feature = "ipc")] #[cfg(feature = "ipc")]
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::{
DiscoveryAPI, Display, EntityType, Error, Floor, Handedness, Input, InputId, InputSource,
LeftEye, Native, Receiver, RightEye, SelectEvent, SelectKind, Sender, TargetRayMode, Triangle,
Viewer, Viewport, Visibility,
};
/// A trait for discovering mock XR devices /// A trait for discovering mock XR devices
pub trait MockDiscoveryAPI<GL>: 'static { pub trait MockDiscoveryAPI<GL>: 'static {
fn simulate_device_connection( fn simulate_device_connection(
@ -103,7 +86,7 @@ pub enum MockInputMsg {
SetGripOrigin(Option<RigidTransform3D<f32, Input, Native>>), SetGripOrigin(Option<RigidTransform3D<f32, Input, Native>>),
/// Note: SelectEvent::Select here refers to a complete Select event, /// Note: SelectEvent::Select here refers to a complete Select event,
/// not just the end event, i.e. it refers to /// not just the end event, i.e. it refers to
/// https://immersive-web.github.io/webxr-test-api/#dom-fakexrinputcontroller-simulateselect /// <https://immersive-web.github.io/webxr-test-api/#dom-fakexrinputcontroller-simulateselect>
TriggerSelect(SelectKind, SelectEvent), TriggerSelect(SelectKind, SelectEvent),
Disconnect, Disconnect,
Reconnect, Reconnect,

View file

@ -2,28 +2,16 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * 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/. */ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use crate::DiscoveryAPI;
use crate::Error;
use crate::Frame;
use crate::GLTypes;
use crate::LayerGrandManager;
use crate::MainThreadSession;
use crate::MockDeviceInit;
use crate::MockDeviceMsg;
use crate::MockDiscoveryAPI;
use crate::Receiver;
use crate::Sender;
use crate::Session;
use crate::SessionBuilder;
use crate::SessionId;
use crate::SessionInit;
use crate::SessionMode;
use log::warn; use log::warn;
#[cfg(feature = "ipc")] #[cfg(feature = "ipc")]
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::{
DiscoveryAPI, Error, Frame, GLTypes, LayerGrandManager, MainThreadSession, MockDeviceInit,
MockDeviceMsg, MockDiscoveryAPI, Receiver, Sender, Session, SessionBuilder, SessionId,
SessionInit, SessionMode,
};
#[derive(Clone)] #[derive(Clone)]
#[cfg_attr(feature = "ipc", derive(Serialize, Deserialize))] #[cfg_attr(feature = "ipc", derive(Serialize, Deserialize))]
pub struct Registry { pub struct Registry {
@ -188,13 +176,13 @@ impl<GL: 'static + GLTypes> MainThreadRegistry<GL> {
match msg { match msg {
RegistryMsg::SupportsSession(mode, dest) => { RegistryMsg::SupportsSession(mode, dest) => {
let _ = dest.send(self.supports_session(mode)); let _ = dest.send(self.supports_session(mode));
} },
RegistryMsg::RequestSession(mode, init, dest, raf_sender) => { RegistryMsg::RequestSession(mode, init, dest, raf_sender) => {
let _ = dest.send(self.request_session(mode, init, raf_sender)); let _ = dest.send(self.request_session(mode, init, raf_sender));
} },
RegistryMsg::SimulateDeviceConnection(init, dest) => { RegistryMsg::SimulateDeviceConnection(init, dest) => {
let _ = dest.send(self.simulate_device_connection(init)); let _ = dest.send(self.simulate_device_connection(init));
} },
} }
} }
@ -250,6 +238,7 @@ impl<GL: 'static + GLTypes> MainThreadRegistry<GL> {
} }
#[cfg_attr(feature = "ipc", derive(Serialize, Deserialize))] #[cfg_attr(feature = "ipc", derive(Serialize, Deserialize))]
#[allow(clippy::large_enum_variant)]
enum RegistryMsg { enum RegistryMsg {
RequestSession( RequestSession(
SessionMode, SessionMode,

View file

@ -2,43 +2,24 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * 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/. */ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use crate::channel;
use crate::ContextId;
use crate::DeviceAPI;
use crate::Error;
use crate::Event;
use crate::Floor;
use crate::Frame;
use crate::FrameUpdateEvent;
use crate::HitTestId;
use crate::HitTestSource;
use crate::InputSource;
use crate::LayerGrandManager;
use crate::LayerId;
use crate::LayerInit;
use crate::Native;
use crate::Receiver;
use crate::Sender;
use crate::Viewport;
use crate::Viewports;
use euclid::Point2D;
use euclid::Rect;
use euclid::RigidTransform3D;
use euclid::Size2D;
use log::warn;
use std::thread; use std::thread;
use std::time::Duration; use std::time::Duration;
use euclid::{Point2D, Rect, RigidTransform3D, Size2D};
use log::warn;
#[cfg(feature = "ipc")] #[cfg(feature = "ipc")]
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::{
channel, ContextId, DeviceAPI, Error, Event, Floor, Frame, FrameUpdateEvent, HitTestId,
HitTestSource, InputSource, LayerGrandManager, LayerId, LayerInit, Native, Receiver, Sender,
Viewport, Viewports,
};
// How long to wait for an rAF. // How long to wait for an rAF.
static TIMEOUT: Duration = Duration::from_millis(5); static TIMEOUT: Duration = Duration::from_millis(5);
/// https://www.w3.org/TR/webxr/#xrsessionmode-enum /// <https://www.w3.org/TR/webxr/#xrsessionmode-enum>
#[derive(Clone, Copy, Debug, Eq, PartialEq)] #[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[cfg_attr(feature = "ipc", derive(Serialize, Deserialize))] #[cfg_attr(feature = "ipc", derive(Serialize, Deserialize))]
pub enum SessionMode { pub enum SessionMode {
@ -47,7 +28,7 @@ pub enum SessionMode {
ImmersiveAR, ImmersiveAR,
} }
/// https://immersive-web.github.io/webxr/#dictdef-xrsessioninit /// <https://immersive-web.github.io/webxr/#dictdef-xrsessioninit>
#[derive(Clone, Debug, Eq, PartialEq)] #[derive(Clone, Debug, Eq, PartialEq)]
#[cfg_attr(feature = "ipc", derive(Serialize, Deserialize))] #[cfg_attr(feature = "ipc", derive(Serialize, Deserialize))]
pub struct SessionInit { pub struct SessionInit {
@ -76,9 +57,9 @@ impl SessionInit {
} }
let mut granted = self.required_features.clone(); let mut granted = self.required_features.clone();
for f in &self.optional_features { for f in &self.optional_features {
if f == "viewer" if f == "viewer" ||
|| (f == "local" && mode != SessionMode::Inline) (f == "local" && mode != SessionMode::Inline) ||
|| supported.contains(f) supported.contains(f)
{ {
granted.push(f.clone()); granted.push(f.clone());
} }
@ -91,12 +72,11 @@ impl SessionInit {
self.required_features self.required_features
.iter() .iter()
.chain(self.optional_features.iter()) .chain(self.optional_features.iter())
.find(|x| *x == f) .any(|x| *x == f)
.is_some()
} }
} }
/// https://immersive-web.github.io/webxr-ar-module/#xrenvironmentblendmode-enum /// <https://immersive-web.github.io/webxr-ar-module/#xrenvironmentblendmode-enum>
#[derive(Clone, Copy, Debug, Eq, PartialEq)] #[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[cfg_attr(feature = "ipc", derive(Serialize, Deserialize))] #[cfg_attr(feature = "ipc", derive(Serialize, Deserialize))]
pub enum EnvironmentBlendMode { pub enum EnvironmentBlendMode {
@ -137,7 +117,7 @@ impl Quitter {
/// An object that represents an XR session. /// An object that represents an XR session.
/// This is owned by the content thread. /// This is owned by the content thread.
/// https://www.w3.org/TR/webxr/#xrsession-interface /// <https://www.w3.org/TR/webxr/#xrsession-interface>
#[cfg_attr(feature = "ipc", derive(Serialize, Deserialize))] #[cfg_attr(feature = "ipc", derive(Serialize, Deserialize))]
pub struct Session { pub struct Session {
floor_transform: Option<RigidTransform3D<f32, Native, Floor>>, floor_transform: Option<RigidTransform3D<f32, Native, Floor>>,
@ -160,7 +140,7 @@ impl Session {
} }
pub fn floor_transform(&self) -> Option<RigidTransform3D<f32, Native, Floor>> { pub fn floor_transform(&self) -> Option<RigidTransform3D<f32, Native, Floor>> {
self.floor_transform.clone() self.floor_transform
} }
pub fn reference_space_bounds(&self) -> Option<Vec<Point2D<f32, Floor>>> { pub fn reference_space_bounds(&self) -> Option<Vec<Point2D<f32, Floor>>> {
@ -182,7 +162,7 @@ impl Session {
} }
/// A resolution large enough to contain all the viewports. /// A resolution large enough to contain all the viewports.
/// https://immersive-web.github.io/webxr/#recommended-webgl-framebuffer-resolution /// <https://immersive-web.github.io/webxr/#recommended-webgl-framebuffer-resolution>
/// ///
/// Returns None if the session is inline /// Returns None if the session is inline
pub fn recommended_framebuffer_resolution(&self) -> Option<Size2D<i32, Viewport>> { pub fn recommended_framebuffer_resolution(&self) -> Option<Size2D<i32, Viewport>> {
@ -335,15 +315,11 @@ where
} }
pub fn run(&mut self) { pub fn run(&mut self) {
loop { while let Ok(msg) = self.receiver.recv() {
if let Ok(msg) = self.receiver.recv() {
if !self.handle_msg(msg) { if !self.handle_msg(msg) {
self.running = false; self.running = false;
break; break;
} }
} else {
break;
}
} }
} }
@ -352,24 +328,24 @@ where
match msg { match msg {
SessionMsg::SetEventDest(dest) => { SessionMsg::SetEventDest(dest) => {
self.device.set_event_dest(dest); self.device.set_event_dest(dest);
} },
SessionMsg::RequestHitTest(source) => { SessionMsg::RequestHitTest(source) => {
self.device.request_hit_test(source); self.device.request_hit_test(source);
} },
SessionMsg::CancelHitTest(id) => { SessionMsg::CancelHitTest(id) => {
self.device.cancel_hit_test(id); self.device.cancel_hit_test(id);
} },
SessionMsg::CreateLayer(context_id, layer_init, sender) => { SessionMsg::CreateLayer(context_id, layer_init, sender) => {
let result = self.device.create_layer(context_id, layer_init); let result = self.device.create_layer(context_id, layer_init);
let _ = sender.send(result); let _ = sender.send(result);
} },
SessionMsg::DestroyLayer(context_id, layer_id) => { SessionMsg::DestroyLayer(context_id, layer_id) => {
self.layers.retain(|&(_, other_id)| layer_id != other_id); self.layers.retain(|&(_, other_id)| layer_id != other_id);
self.device.destroy_layer(context_id, layer_id); self.device.destroy_layer(context_id, layer_id);
} },
SessionMsg::SetLayers(layers) => { SessionMsg::SetLayers(layers) => {
self.pending_layers = Some(layers); self.pending_layers = Some(layers);
} },
SessionMsg::StartRenderLoop => { SessionMsg::StartRenderLoop => {
if let Some(layers) = self.pending_layers.take() { if let Some(layers) = self.pending_layers.take() {
self.layers = layers; self.layers = layers;
@ -379,11 +355,11 @@ where
None => { None => {
warn!("Device stopped providing frames, exiting"); warn!("Device stopped providing frames, exiting");
return false; return false;
} },
}; };
self.render_state = RenderState::InRenderLoop; self.render_state = RenderState::InRenderLoop;
let _ = self.frame_sender.send(frame); let _ = self.frame_sender.send(frame);
} },
SessionMsg::UpdateClipPlanes(near, far) => self.device.update_clip_planes(near, far), SessionMsg::UpdateClipPlanes(near, far) => self.device.update_clip_planes(near, far),
SessionMsg::RenderAnimationFrame => { SessionMsg::RenderAnimationFrame => {
self.frame_count += 1; self.frame_count += 1;
@ -404,15 +380,15 @@ where
None => { None => {
warn!("Device stopped providing frames, exiting"); warn!("Device stopped providing frames, exiting");
return false; return false;
} },
}; };
let _ = self.frame_sender.send(frame); let _ = self.frame_sender.send(frame);
} },
SessionMsg::UpdateFrameRate(rate, sender) => { SessionMsg::UpdateFrameRate(rate, sender) => {
let new_framerate = self.device.update_frame_rate(rate); let new_framerate = self.device.update_frame_rate(rate);
let _ = sender.send(new_framerate); let _ = sender.send(new_framerate);
} },
SessionMsg::Quit => { SessionMsg::Quit => {
if self.render_state == RenderState::NotInRenderLoop { if self.render_state == RenderState::NotInRenderLoop {
self.quit(); self.quit();
@ -420,11 +396,11 @@ where
} else { } else {
self.render_state = RenderState::PendingQuit; self.render_state = RenderState::PendingQuit;
} }
} },
SessionMsg::GetBoundsGeometry(sender) => { SessionMsg::GetBoundsGeometry(sender) => {
let bounds = self.device.reference_space_bounds(); let bounds = self.device.reference_space_bounds();
let _ = sender.send(bounds); let _ = sender.send(bounds);
} },
} }
true true
} }
@ -506,10 +482,10 @@ impl<'a, GL: 'static> SessionBuilder<'a, GL> {
let session = thread.new_session(); let session = thread.new_session();
let _ = acks.send(Ok(session)); let _ = acks.send(Ok(session));
thread.run(); thread.run();
} },
Err(err) => { Err(err) => {
let _ = acks.send(Err(err)); let _ = acks.send(Err(err));
} },
} }
}); });
ackr.recv().unwrap_or(Err(Error::CommunicationError)) ackr.recv().unwrap_or(Err(Error::CommunicationError))

View file

@ -1,7 +1,11 @@
use crate::InputId; /* This Source Code Form is subject to the terms of the Mozilla Public
use crate::Joint; * 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 euclid::RigidTransform3D; use euclid::RigidTransform3D;
use crate::{InputId, Joint};
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug)]
#[cfg_attr(feature = "ipc", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "ipc", derive(serde::Serialize, serde::Deserialize))]
/// A stand-in type for "the space isn't statically known since /// A stand-in type for "the space isn't statically known since

View file

@ -1,8 +1,11 @@
use crate::FrameUpdateEvent; /* This Source Code Form is subject to the terms of the Mozilla Public
use crate::HitTestId; * License, v. 2.0. If a copy of the MPL was not distributed with this
use crate::HitTestSource; * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use euclid::Transform3D; use euclid::Transform3D;
use crate::{FrameUpdateEvent, HitTestId, HitTestSource};
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug)]
#[cfg_attr(feature = "ipc", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "ipc", derive(serde::Serialize, serde::Deserialize))]
pub struct ClipPlanes { pub struct ClipPlanes {

View file

@ -4,35 +4,32 @@
//! This crate uses `euclid`'s typed units, and exposes different coordinate spaces. //! This crate uses `euclid`'s typed units, and exposes different coordinate spaces.
use euclid::Rect; use std::marker::PhantomData;
use euclid::RigidTransform3D;
use euclid::Transform3D;
use euclid::{Rect, RigidTransform3D, Transform3D};
#[cfg(feature = "ipc")] #[cfg(feature = "ipc")]
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::marker::PhantomData;
/// The coordinate space of the viewer /// The coordinate space of the viewer
/// https://immersive-web.github.io/webxr/#dom-xrreferencespacetype-viewer /// <https://immersive-web.github.io/webxr/#dom-xrreferencespacetype-viewer>
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug)]
#[cfg_attr(feature = "ipc", derive(Serialize, Deserialize))] #[cfg_attr(feature = "ipc", derive(Serialize, Deserialize))]
pub enum Viewer {} pub enum Viewer {}
/// The coordinate space of the floor /// The coordinate space of the floor
/// https://immersive-web.github.io/webxr/#dom-xrreferencespacetype-local-floor /// <https://immersive-web.github.io/webxr/#dom-xrreferencespacetype-local-floor>
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug)]
#[cfg_attr(feature = "ipc", derive(Serialize, Deserialize))] #[cfg_attr(feature = "ipc", derive(Serialize, Deserialize))]
pub enum Floor {} pub enum Floor {}
/// The coordinate space of the left eye /// The coordinate space of the left eye
/// https://immersive-web.github.io/webxr/#dom-xreye-left /// <https://immersive-web.github.io/webxr/#dom-xreye-left>
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug)]
#[cfg_attr(feature = "ipc", derive(Serialize, Deserialize))] #[cfg_attr(feature = "ipc", derive(Serialize, Deserialize))]
pub enum LeftEye {} pub enum LeftEye {}
/// The coordinate space of the right eye /// The coordinate space of the right eye
/// https://immersive-web.github.io/webxr/#dom-xreye-right /// <https://immersive-web.github.io/webxr/#dom-xreye-right>
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug)]
#[cfg_attr(feature = "ipc", derive(Serialize, Deserialize))] #[cfg_attr(feature = "ipc", derive(Serialize, Deserialize))]
pub enum RightEye {} pub enum RightEye {}
@ -115,7 +112,7 @@ pub enum Capture {}
/// its projection onto its display. /// its projection onto its display.
/// For stereo displays, we have a `View<LeftEye>` and a `View<RightEye>`. /// For stereo displays, we have a `View<LeftEye>` and a `View<RightEye>`.
/// For mono displays, we hagve a `View<Viewer>` /// For mono displays, we hagve a `View<Viewer>`
/// https://immersive-web.github.io/webxr/#xrview /// <https://immersive-web.github.io/webxr/#xrview>
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
#[cfg_attr(feature = "ipc", derive(Serialize, Deserialize))] #[cfg_attr(feature = "ipc", derive(Serialize, Deserialize))]
pub struct View<Eye> { pub struct View<Eye> {
@ -144,6 +141,7 @@ impl<Eye> View<Eye> {
/// Whether a device is mono or stereo, and the views it supports. /// Whether a device is mono or stereo, and the views it supports.
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
#[cfg_attr(feature = "ipc", derive(Serialize, Deserialize))] #[cfg_attr(feature = "ipc", derive(Serialize, Deserialize))]
#[allow(clippy::large_enum_variant)]
pub enum Views { pub enum Views {
/// Mono view for inline VR, viewport and projection matrices are calculated by client /// Mono view for inline VR, viewport and projection matrices are calculated by client
Inline, Inline,

View file

@ -1,14 +1,12 @@
[package] [package]
name = "webxr" name = "webxr"
version = "0.0.1" version.workspace = true
authors = ["The Servo Project Developers"] authors.workspace = true
edition = "2018" license.workspace = true
edition.workspace = true
homepage = "https://github.com/servo/webxr" publish.workspace = true
repository = "https://github.com/servo/webxr" rust-version.workspace = true
keywords = ["ar", "headset", "openxr", "vr", "webxr"] keywords = ["ar", "headset", "openxr", "vr", "webxr"]
license = "MPL-2.0"
description = '''A safe Rust API that provides a way to interact with description = '''A safe Rust API that provides a way to interact with
virtual reality and augmented reality devices and integration with OpenXR. virtual reality and augmented reality devices and integration with OpenXR.
The API is inspired by the WebXR Device API (https://www.w3.org/TR/webxr/) The API is inspired by the WebXR Device API (https://www.w3.org/TR/webxr/)
@ -27,23 +25,16 @@ ipc = ["webxr-api/ipc", "serde"]
openxr-api = ["angle", "openxr", "winapi", "wio", "surfman/sm-angle-default"] openxr-api = ["angle", "openxr", "winapi", "wio", "surfman/sm-angle-default"]
[dependencies] [dependencies]
webxr-api = { path = "../shared/webxr" } webxr-api = { workspace = true }
crossbeam-channel = "0.5" crossbeam-channel = { workspace = true }
euclid = "0.22" euclid = { workspace = true }
log = "0.4.6" log = { workspace = true }
openxr = { version = "0.19", optional = true } openxr = { workspace = true, optional = true }
serde = { version = "1.0", optional = true } serde = { workspace = true, optional = true }
glow = "0.16" glow = { workspace = true }
raw-window-handle = "0.6" raw-window-handle = { workspace = true }
surfman = { git = "https://github.com/servo/surfman", rev = "300789ddbda45c89e9165c31118bf1c4c07f89f6", features = [ surfman = { workspace = true, features = ["chains", "sm-raw-window-handle-06"] }
"chains",
"sm-raw-window-handle-06",
] }
[target.'cfg(target_os = "windows")'.dependencies] [target.'cfg(target_os = "windows")'.dependencies]
winapi = { version = "0.3", features = [ winapi = { workspace = true, features = ["dxgi", "d3d11", "winerror"], optional = true }
"dxgi", wio = { workspace = true, optional = true }
"d3d11",
"winerror",
], optional = true }
wio = { version = "0.2", optional = true }

View file

@ -2,16 +2,15 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * 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/. */ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use crate::SurfmanGL;
use glow as gl;
use glow::Context as Gl;
use glow::HasContext;
use std::collections::HashMap; use std::collections::HashMap;
use std::num::NonZero; use std::num::NonZero;
use glow as gl;
use glow::{Context as Gl, HasContext};
use surfman::Device as SurfmanDevice; use surfman::Device as SurfmanDevice;
use webxr_api::ContextId; use webxr_api::{ContextId, GLContexts, LayerId};
use webxr_api::GLContexts;
use webxr_api::LayerId; use crate::SurfmanGL;
pub(crate) fn framebuffer(framebuffer: u32) -> Option<gl::NativeFramebuffer> { pub(crate) fn framebuffer(framebuffer: u32) -> Option<gl::NativeFramebuffer> {
NonZero::new(framebuffer).map(gl::NativeFramebuffer) NonZero::new(framebuffer).map(gl::NativeFramebuffer)
@ -93,6 +92,7 @@ impl GlClearer {
}) })
} }
#[allow(clippy::too_many_arguments)]
pub(crate) fn clear( pub(crate) fn clear(
&mut self, &mut self,
device: &mut SurfmanDevice, device: &mut SurfmanDevice,
@ -114,8 +114,6 @@ impl GlClearer {
let mut clear_color = [0., 0., 0., 0.]; let mut clear_color = [0., 0., 0., 0.];
let mut clear_depth = [0.]; let mut clear_depth = [0.];
let mut clear_stencil = [0]; let mut clear_stencil = [0];
let color_mask;
let depth_mask;
let mut stencil_mask = [0]; let mut stencil_mask = [0];
let scissor_enabled = gl.is_enabled(gl::SCISSOR_TEST); let scissor_enabled = gl.is_enabled(gl::SCISSOR_TEST);
let rasterizer_enabled = gl.is_enabled(gl::RASTERIZER_DISCARD); let rasterizer_enabled = gl.is_enabled(gl::RASTERIZER_DISCARD);
@ -125,9 +123,9 @@ impl GlClearer {
gl.get_parameter_f32_slice(gl::COLOR_CLEAR_VALUE, &mut clear_color[..]); gl.get_parameter_f32_slice(gl::COLOR_CLEAR_VALUE, &mut clear_color[..]);
gl.get_parameter_f32_slice(gl::DEPTH_CLEAR_VALUE, &mut clear_depth[..]); gl.get_parameter_f32_slice(gl::DEPTH_CLEAR_VALUE, &mut clear_depth[..]);
gl.get_parameter_i32_slice(gl::STENCIL_CLEAR_VALUE, &mut clear_stencil[..]); gl.get_parameter_i32_slice(gl::STENCIL_CLEAR_VALUE, &mut clear_stencil[..]);
depth_mask = gl.get_parameter_bool(gl::DEPTH_WRITEMASK); let depth_mask = gl.get_parameter_bool(gl::DEPTH_WRITEMASK);
gl.get_parameter_i32_slice(gl::STENCIL_WRITEMASK, &mut stencil_mask[..]); gl.get_parameter_i32_slice(gl::STENCIL_WRITEMASK, &mut stencil_mask[..]);
color_mask = gl.get_parameter_bool_array::<4>(gl::COLOR_WRITEMASK); let color_mask = gl.get_parameter_bool_array::<4>(gl::COLOR_WRITEMASK);
// Clear it // Clear it
gl.bind_framebuffer(gl::FRAMEBUFFER, fbo); gl.bind_framebuffer(gl::FRAMEBUFFER, fbo);

View file

@ -2,16 +2,15 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * 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/. */ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use crate::gl_utils::framebuffer;
use crate::{SurfmanGL, SurfmanLayerManager};
use core::slice; use core::slice;
use std::num::NonZeroU32;
use std::rc::Rc;
use euclid::{ use euclid::{
Angle, Point2D, Rect, RigidTransform3D, Rotation3D, Size2D, Transform3D, UnknownUnit, Vector3D, Angle, Point2D, Rect, RigidTransform3D, Rotation3D, Size2D, Transform3D, UnknownUnit, Vector3D,
}; };
use glow::{self as gl, Context as Gl, HasContext}; use glow::{self as gl, Context as Gl, HasContext};
use raw_window_handle::DisplayHandle; use raw_window_handle::DisplayHandle;
use std::num::NonZeroU32;
use std::rc::Rc;
use surfman::chains::{PreserveBuffer, SwapChain, SwapChainAPI, SwapChains, SwapChainsAPI}; use surfman::chains::{PreserveBuffer, SwapChain, SwapChainAPI, SwapChains, SwapChainsAPI};
use surfman::{ use surfman::{
Adapter, Connection, Context as SurfmanContext, ContextAttributeFlags, ContextAttributes, Adapter, Connection, Context as SurfmanContext, ContextAttributeFlags, ContextAttributes,
@ -26,6 +25,9 @@ use webxr_api::{
VIEWER, VIEWER,
}; };
use crate::gl_utils::framebuffer;
use crate::{SurfmanGL, SurfmanLayerManager};
// How far off the ground are the viewer's eyes? // How far off the ground are the viewer's eyes?
const HEIGHT: f32 = 1.0; const HEIGHT: f32 = 1.0;
@ -55,7 +57,7 @@ pub trait GlWindow {
fn display_handle(&self) -> DisplayHandle; fn display_handle(&self) -> DisplayHandle;
} }
#[derive(Copy, Clone, Debug, Eq, PartialEq)] #[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum GlWindowMode { pub enum GlWindowMode {
Blit, Blit,
StereoLeftRight, StereoLeftRight,
@ -80,9 +82,9 @@ impl GlWindowDiscovery {
pub fn new(window: Rc<dyn GlWindow>) -> GlWindowDiscovery { pub fn new(window: Rc<dyn GlWindow>) -> GlWindowDiscovery {
let connection = Connection::from_display_handle(window.display_handle()).unwrap(); let connection = Connection::from_display_handle(window.display_handle()).unwrap();
let adapter = connection.create_adapter().unwrap(); let adapter = connection.create_adapter().unwrap();
let flags = ContextAttributeFlags::ALPHA let flags = ContextAttributeFlags::ALPHA |
| ContextAttributeFlags::DEPTH ContextAttributeFlags::DEPTH |
| ContextAttributeFlags::STENCIL; ContextAttributeFlags::STENCIL;
let version = match connection.gl_api() { let version = match connection.gl_api() {
GLApi::GLES => GLVersion { major: 3, minor: 0 }, GLApi::GLES => GLVersion { major: 3, minor: 0 },
GLApi::GL => GLVersion { major: 3, minor: 2 }, GLApi::GL => GLVersion { major: 3, minor: 2 },
@ -108,7 +110,7 @@ impl DiscoveryAPI<SurfmanGL> for GlWindowDiscovery {
let granted_features = init.validate(mode, &["local-floor".into()])?; let granted_features = init.validate(mode, &["local-floor".into()])?;
let connection = self.connection.clone(); let connection = self.connection.clone();
let adapter = self.adapter.clone(); let adapter = self.adapter.clone();
let context_attributes = self.context_attributes.clone(); let context_attributes = self.context_attributes;
let window = self.window.clone(); let window = self.window.clone();
xr.run_on_main_thread(move |grand_manager| { xr.run_on_main_thread(move |grand_manager| {
GlWindowDevice::new( GlWindowDevice::new(
@ -155,6 +157,7 @@ impl DeviceAPI for GlWindowDevice {
fn viewports(&self) -> Viewports { fn viewports(&self) -> Viewports {
let size = self.viewport_size(); let size = self.viewport_size();
let viewports = match self.window.get_mode() { let viewports = match self.window.get_mode() {
#[allow(clippy::erasing_op, clippy::identity_op)]
GlWindowMode::Cubemap | GlWindowMode::Spherical => vec![ GlWindowMode::Cubemap | GlWindowMode::Spherical => vec![
Rect::new(Point2D::new(size.width * 1, size.height * 1), size), Rect::new(Point2D::new(size.width * 1, size.height * 1), size),
Rect::new(Point2D::new(size.width * 0, size.height * 1), size), Rect::new(Point2D::new(size.width * 0, size.height * 1), size),
@ -168,7 +171,7 @@ impl DeviceAPI for GlWindowDevice {
Rect::new(Point2D::default(), size), Rect::new(Point2D::default(), size),
Rect::new(Point2D::new(size.width, 0), size), Rect::new(Point2D::new(size.width, 0), size),
] ]
} },
}; };
Viewports { viewports } Viewports { viewports }
} }
@ -282,7 +285,7 @@ impl DeviceAPI for GlWindowDevice {
target_swap_chain target_swap_chain
.swap_buffers(&mut self.device, &mut self.context, PreserveBuffer::No) .swap_buffers(&mut self.device, &mut self.context, PreserveBuffer::No)
.unwrap(); .unwrap();
} },
None => { None => {
// Rendering to a native widget // Rendering to a native widget
let mut surface = self let mut surface = self
@ -296,7 +299,7 @@ impl DeviceAPI for GlWindowDevice {
self.device self.device
.bind_surface_to_context(&mut self.context, surface) .bind_surface_to_context(&mut self.context, surface)
.unwrap(); .unwrap();
} },
} }
debug_assert_eq!(unsafe { self.gl.get_error() }, gl::NO_ERROR); debug_assert_eq!(unsafe { self.gl.get_error() }, gl::NO_ERROR);
@ -377,11 +380,11 @@ impl GlWindowDevice {
.bind_surface_to_context(&mut context, surface) .bind_surface_to_context(&mut context, surface)
.unwrap(); .unwrap();
None None
} },
GlWindowRenderTarget::SwapChain(target_swap_chain) => { GlWindowRenderTarget::SwapChain(target_swap_chain) => {
debug_assert!(target_swap_chain.is_attached()); debug_assert!(target_swap_chain.is_attached());
Some(target_swap_chain) Some(target_swap_chain)
} },
}; };
let read_fbo = unsafe { gl.create_framebuffer().ok() }; let read_fbo = unsafe { gl.create_framebuffer().ok() };
@ -496,20 +499,20 @@ impl GlWindowDevice {
// (The wasted pixels are on the right of the left eye and vice versa.) // (The wasted pixels are on the right of the left eye and vice versa.)
let wasted_pixels = (INTER_PUPILLARY_DISTANCE / PIXELS_PER_METRE) as i32; let wasted_pixels = (INTER_PUPILLARY_DISTANCE / PIXELS_PER_METRE) as i32;
Size2D::new(window_size.width + wasted_pixels, window_size.height) Size2D::new(window_size.width + wasted_pixels, window_size.height)
} },
GlWindowMode::Cubemap => { GlWindowMode::Cubemap => {
// Cubemap viewports should be square // Cubemap viewports should be square
let size = 1.max(window_size.width / 3).max(window_size.height / 2); let size = 1.max(window_size.width / 3).max(window_size.height / 2);
Size2D::new(size, size) Size2D::new(size, size)
} },
GlWindowMode::Spherical => { GlWindowMode::Spherical => {
// Cubemap viewports should be square // Cubemap viewports should be square
let size = 1.max(window_size.width / 2).max(window_size.height); let size = 1.max(window_size.width / 2).max(window_size.height);
Size2D::new(size, size) Size2D::new(size, size)
} },
GlWindowMode::StereoLeftRight | GlWindowMode::Blit => { GlWindowMode::StereoLeftRight | GlWindowMode::Blit => {
Size2D::new(window_size.width / 2, window_size.height) Size2D::new(window_size.width / 2, window_size.height)
} },
} }
} }
@ -525,7 +528,7 @@ impl GlWindowDevice {
), ),
GlWindowMode::Blit | GlWindowMode::StereoLeftRight | GlWindowMode::StereoRedCyan => { GlWindowMode::Blit | GlWindowMode::StereoLeftRight | GlWindowMode::StereoRedCyan => {
Views::Stereo(self.view(viewer, LEFT_EYE), self.view(viewer, RIGHT_EYE)) Views::Stereo(self.view(viewer, LEFT_EYE), self.view(viewer, RIGHT_EYE))
} },
} }
} }
@ -583,7 +586,7 @@ impl GlWindowDevice {
GlWindowMode::Spherical | GlWindowMode::Cubemap => Angle::degrees(45.0), GlWindowMode::Spherical | GlWindowMode::Cubemap => Angle::degrees(45.0),
GlWindowMode::Blit | GlWindowMode::StereoLeftRight | GlWindowMode::StereoRedCyan => { GlWindowMode::Blit | GlWindowMode::StereoLeftRight | GlWindowMode::StereoRedCyan => {
Angle::degrees(FOV_UP) Angle::degrees(FOV_UP)
} },
}; };
let f = 1.0 / fov_up.radians.tan(); let f = 1.0 / fov_up.radians.tan();
let nf = 1.0 / (near - far); let nf = 1.0 / (near - far);
@ -723,13 +726,13 @@ impl GlWindowShader {
let (vertex_source, fragment_source) = match mode { let (vertex_source, fragment_source) = match mode {
GlWindowMode::Blit => { GlWindowMode::Blit => {
return None; return None;
} },
GlWindowMode::StereoLeftRight | GlWindowMode::Cubemap => { GlWindowMode::StereoLeftRight | GlWindowMode::Cubemap => {
(PASSTHROUGH_VERTEX_SHADER, PASSTHROUGH_FRAGMENT_SHADER) (PASSTHROUGH_VERTEX_SHADER, PASSTHROUGH_FRAGMENT_SHADER)
} },
GlWindowMode::StereoRedCyan => { GlWindowMode::StereoRedCyan => {
(ANAGLYPH_VERTEX_SHADER, ANAGLYPH_RED_CYAN_FRAGMENT_SHADER) (ANAGLYPH_VERTEX_SHADER, ANAGLYPH_RED_CYAN_FRAGMENT_SHADER)
} },
GlWindowMode::Spherical => (SPHERICAL_VERTEX_SHADER, SPHERICAL_FRAGMENT_SHADER), GlWindowMode::Spherical => (SPHERICAL_VERTEX_SHADER, SPHERICAL_FRAGMENT_SHADER),
}; };
@ -839,17 +842,15 @@ impl GlWindowShader {
match self.mode { match self.mode {
GlWindowMode::StereoRedCyan => { GlWindowMode::StereoRedCyan => {
let wasted = 1.0 let wasted = 1.0 -
- (texture_size.width as f32 / viewport_size.width as f32) (texture_size.width as f32 / viewport_size.width as f32).clamp(0.0, 1.0);
.max(0.0)
.min(1.0);
let wasted_location = self.gl.get_uniform_location(self.program, "wasted"); let wasted_location = self.gl.get_uniform_location(self.program, "wasted");
self.gl.uniform_1_f32(wasted_location.as_ref(), wasted); self.gl.uniform_1_f32(wasted_location.as_ref(), wasted);
} },
GlWindowMode::Blit GlWindowMode::Blit |
| GlWindowMode::Cubemap GlWindowMode::Cubemap |
| GlWindowMode::Spherical GlWindowMode::Spherical |
| GlWindowMode::StereoLeftRight => {} GlWindowMode::StereoLeftRight => {},
} }
self.gl self.gl

View file

@ -2,11 +2,10 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * 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/. */ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use crate::SurfmanGL;
use crate::SurfmanLayerManager;
use euclid::{Point2D, RigidTransform3D};
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
use std::thread; use std::thread;
use euclid::{Point2D, RigidTransform3D};
use surfman::chains::SwapChains; use surfman::chains::SwapChains;
use webxr_api::util::{self, ClipPlanes, HitTestList}; use webxr_api::util::{self, ClipPlanes, HitTestList};
use webxr_api::{ use webxr_api::{
@ -18,6 +17,9 @@ use webxr_api::{
SessionMode, Space, SubImages, View, Viewer, ViewerPose, Viewports, Views, SessionMode, Space, SubImages, View, Viewer, ViewerPose, Viewports, Views,
}; };
use crate::{SurfmanGL, SurfmanLayerManager};
#[derive(Default)]
pub struct HeadlessMockDiscovery {} pub struct HeadlessMockDiscovery {}
struct HeadlessDiscovery { struct HeadlessDiscovery {
@ -74,7 +76,7 @@ impl MockDiscoveryAPI<SurfmanGL> for HeadlessMockDiscovery {
init: MockDeviceInit, init: MockDeviceInit,
receiver: Receiver<MockDeviceMsg>, receiver: Receiver<MockDeviceMsg>,
) -> Result<Box<dyn DiscoveryAPI<SurfmanGL>>, Error> { ) -> Result<Box<dyn DiscoveryAPI<SurfmanGL>>, Error> {
let viewer_origin = init.viewer_origin.clone(); let viewer_origin = init.viewer_origin;
let floor_transform = init.floor_origin.map(|f| f.inverse()); let floor_transform = init.floor_origin.map(|f| f.inverse());
let views = init.views.clone(); let views = init.views.clone();
let data = HeadlessDeviceData { let data = HeadlessDeviceData {
@ -209,7 +211,7 @@ impl HeadlessDevice {
impl DeviceAPI for HeadlessDevice { impl DeviceAPI for HeadlessDevice {
fn floor_transform(&self) -> Option<RigidTransform3D<f32, Native, Floor>> { fn floor_transform(&self) -> Option<RigidTransform3D<f32, Native, Floor>> {
self.data.lock().unwrap().floor_transform.clone() self.data.lock().unwrap().floor_transform
} }
fn viewports(&self) -> Viewports { fn viewports(&self) -> Viewports {
@ -264,9 +266,9 @@ impl DeviceAPI for HeadlessDevice {
} }
if data.needs_floor_update { if data.needs_floor_update {
frame.events.push(FrameUpdateEvent::UpdateFloorTransform( frame
data.floor_transform.clone(), .events
)); .push(FrameUpdateEvent::UpdateFloorTransform(data.floor_transform));
data.needs_floor_update = false; data.needs_floor_update = false;
} }
Some(frame) Some(frame)
@ -315,12 +317,6 @@ impl DeviceAPI for HeadlessDevice {
} }
} }
impl HeadlessMockDiscovery {
pub fn new() -> HeadlessMockDiscovery {
HeadlessMockDiscovery {}
}
}
macro_rules! with_all_sessions { macro_rules! with_all_sessions {
($self:ident, |$s:ident| $e:expr) => { ($self:ident, |$s:ident| $e:expr) => {
for $s in &mut $self.sessions { for $s in &mut $self.sessions {
@ -401,20 +397,20 @@ impl HeadlessDeviceData {
MockDeviceMsg::ClearWorld => self.world = None, MockDeviceMsg::ClearWorld => self.world = None,
MockDeviceMsg::SetViewerOrigin(viewer_origin) => { MockDeviceMsg::SetViewerOrigin(viewer_origin) => {
self.viewer_origin = viewer_origin; self.viewer_origin = viewer_origin;
} },
MockDeviceMsg::SetFloorOrigin(floor_origin) => { MockDeviceMsg::SetFloorOrigin(floor_origin) => {
self.floor_transform = floor_origin.map(|f| f.inverse()); self.floor_transform = floor_origin.map(|f| f.inverse());
self.needs_floor_update = true; self.needs_floor_update = true;
} },
MockDeviceMsg::SetViews(views) => { MockDeviceMsg::SetViews(views) => {
self.views = views; self.views = views;
with_all_sessions!(self, |s| { with_all_sessions!(self, |s| {
s.needs_vp_update = true; s.needs_vp_update = true;
}) })
} },
MockDeviceMsg::VisibilityChange(v) => { MockDeviceMsg::VisibilityChange(v) => {
with_all_sessions!(self, |s| s.events.callback(Event::VisibilityChange(v))) with_all_sessions!(self, |s| s.events.callback(Event::VisibilityChange(v)))
} },
MockDeviceMsg::AddInputSource(init) => { MockDeviceMsg::AddInputSource(init) => {
self.inputs.push(InputInfo { self.inputs.push(InputInfo {
source: init.source.clone(), source: init.source.clone(),
@ -427,7 +423,7 @@ impl HeadlessDeviceData {
with_all_sessions!(self, |s| s with_all_sessions!(self, |s| s
.events .events
.callback(Event::AddInput(init.source.clone()))) .callback(Event::AddInput(init.source.clone())))
} },
MockDeviceMsg::MessageInputSource(id, msg) => { MockDeviceMsg::MessageInputSource(id, msg) => {
if let Some(ref mut input) = self.inputs.iter_mut().find(|i| i.source.id == id) { if let Some(ref mut input) = self.inputs.iter_mut().find(|i| i.source.id == id) {
match msg { match msg {
@ -437,21 +433,21 @@ impl HeadlessDeviceData {
s.events s.events
.callback(Event::UpdateInput(id, input.source.clone())) .callback(Event::UpdateInput(id, input.source.clone()))
}); });
} },
MockInputMsg::SetProfiles(p) => { MockInputMsg::SetProfiles(p) => {
input.source.profiles = p; input.source.profiles = p;
with_all_sessions!(self, |s| { with_all_sessions!(self, |s| {
s.events s.events
.callback(Event::UpdateInput(id, input.source.clone())) .callback(Event::UpdateInput(id, input.source.clone()))
}); });
} },
MockInputMsg::SetTargetRayMode(t) => { MockInputMsg::SetTargetRayMode(t) => {
input.source.target_ray_mode = t; input.source.target_ray_mode = t;
with_all_sessions!(self, |s| { with_all_sessions!(self, |s| {
s.events s.events
.callback(Event::UpdateInput(id, input.source.clone())) .callback(Event::UpdateInput(id, input.source.clone()))
}); });
} },
MockInputMsg::SetPointerOrigin(p) => input.pointer = p, MockInputMsg::SetPointerOrigin(p) => input.pointer = p,
MockInputMsg::SetGripOrigin(p) => input.grip = p, MockInputMsg::SetGripOrigin(p) => input.grip = p,
MockInputMsg::TriggerSelect(kind, event) => { MockInputMsg::TriggerSelect(kind, event) => {
@ -463,20 +459,20 @@ impl HeadlessDeviceData {
match event { match event {
SelectEvent::Start => { SelectEvent::Start => {
self.trigger_select(id, kind, event); self.trigger_select(id, kind, event);
} },
SelectEvent::End => { SelectEvent::End => {
if clicking { if clicking {
self.trigger_select(id, kind, SelectEvent::Select); self.trigger_select(id, kind, SelectEvent::Select);
} else { } else {
self.trigger_select(id, kind, SelectEvent::End); self.trigger_select(id, kind, SelectEvent::End);
} }
} },
SelectEvent::Select => { SelectEvent::Select => {
self.trigger_select(id, kind, SelectEvent::Start); self.trigger_select(id, kind, SelectEvent::Start);
self.trigger_select(id, kind, SelectEvent::Select); self.trigger_select(id, kind, SelectEvent::Select);
},
} }
} },
}
MockInputMsg::Disconnect => { MockInputMsg::Disconnect => {
if input.active { if input.active {
with_all_sessions!(self, |s| s with_all_sessions!(self, |s| s
@ -485,7 +481,7 @@ impl HeadlessDeviceData {
input.active = false; input.active = false;
input.clicking = false; input.clicking = false;
} }
} },
MockInputMsg::Reconnect => { MockInputMsg::Reconnect => {
if !input.active { if !input.active {
with_all_sessions!(self, |s| s with_all_sessions!(self, |s| s
@ -493,14 +489,14 @@ impl HeadlessDeviceData {
.callback(Event::AddInput(input.source.clone()))); .callback(Event::AddInput(input.source.clone())));
input.active = true; input.active = true;
} }
} },
MockInputMsg::SetSupportedButtons(buttons) => { MockInputMsg::SetSupportedButtons(buttons) => {
input.buttons = buttons; input.buttons = buttons;
with_all_sessions!(self, |s| s.events.callback(Event::UpdateInput( with_all_sessions!(self, |s| s.events.callback(Event::UpdateInput(
input.source.id, input.source.id,
input.source.clone() input.source.clone()
))); )));
} },
MockInputMsg::UpdateButtonState(state) => { MockInputMsg::UpdateButtonState(state) => {
if let Some(button) = input if let Some(button) = input
.buttons .buttons
@ -509,26 +505,26 @@ impl HeadlessDeviceData {
{ {
*button = state; *button = state;
} }
},
} }
} }
} },
}
MockDeviceMsg::Disconnect(s) => { MockDeviceMsg::Disconnect(s) => {
self.disconnected = true; self.disconnected = true;
with_all_sessions!(self, |s| s.quitter.as_ref().map(|q| q.quit())); with_all_sessions!(self, |s| s.quitter.as_ref().map(|q| q.quit()));
// notify the client that we're done disconnecting // notify the client that we're done disconnecting
let _ = s.send(()); let _ = s.send(());
return false; return false;
} },
MockDeviceMsg::SetBoundsGeometry(g) => { MockDeviceMsg::SetBoundsGeometry(g) => {
self.bounds_geometry = g; self.bounds_geometry = g;
} },
MockDeviceMsg::SimulateResetPose => { MockDeviceMsg::SimulateResetPose => {
with_all_sessions!(self, |s| s.events.callback(Event::ReferenceSpaceChanged( with_all_sessions!(self, |s| s.events.callback(Event::ReferenceSpaceChanged(
BaseSpace::Local, BaseSpace::Local,
RigidTransform3D::identity() RigidTransform3D::identity()
))); )));
} },
} }
true true
} }

View file

@ -14,8 +14,7 @@ pub mod headless;
pub mod openxr; pub mod openxr;
pub mod surfman_layer_manager; pub mod surfman_layer_manager;
pub use surfman_layer_manager::SurfmanGL; pub use surfman_layer_manager::{SurfmanGL, SurfmanLayerManager};
pub use surfman_layer_manager::SurfmanLayerManager;
pub type MainThreadRegistry = webxr_api::MainThreadRegistry<surfman_layer_manager::SurfmanGL>; pub type MainThreadRegistry = webxr_api::MainThreadRegistry<surfman_layer_manager::SurfmanGL>;
pub type Discovery = Box<dyn webxr_api::DiscoveryAPI<SurfmanGL>>; pub type Discovery = Box<dyn webxr_api::DiscoveryAPI<SurfmanGL>>;

View file

@ -1,9 +1,12 @@
/* 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 euclid::{Size2D, UnknownUnit}; use euclid::{Size2D, UnknownUnit};
use openxr::{ExtensionSet, FrameStream, FrameWaiter, Graphics, Instance, Session, SystemId}; use openxr::{ExtensionSet, FrameStream, FrameWaiter, Graphics, Instance, Session, SystemId};
use surfman::Context as SurfmanContext; use surfman::{
use surfman::Device as SurfmanDevice; Context as SurfmanContext, Device as SurfmanDevice, Error as SurfmanError, SurfaceTexture,
use surfman::Error as SurfmanError; };
use surfman::SurfaceTexture;
use webxr_api::Error; use webxr_api::Error;
pub enum GraphicsProvider {} pub enum GraphicsProvider {}

View file

@ -1,3 +1,7 @@
/* 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 std::{mem, ptr}; use std::{mem, ptr};
use euclid::{Size2D, UnknownUnit}; use euclid::{Size2D, UnknownUnit};
@ -6,11 +10,10 @@ use openxr::d3d::{Requirements, SessionCreateInfoD3D11, D3D11};
use openxr::{ use openxr::{
ExtensionSet, FormFactor, FrameStream, FrameWaiter, Graphics, Instance, Session, SystemId, ExtensionSet, FormFactor, FrameStream, FrameWaiter, Graphics, Instance, Session, SystemId,
}; };
use surfman::Adapter as SurfmanAdapter; use surfman::{
use surfman::Context as SurfmanContext; Adapter as SurfmanAdapter, Context as SurfmanContext, Device as SurfmanDevice,
use surfman::Device as SurfmanDevice; Error as SurfmanError, SurfaceTexture,
use surfman::Error as SurfmanError; };
use surfman::SurfaceTexture;
use webxr_api::Error; use webxr_api::Error;
use winapi::shared::winerror::{DXGI_ERROR_NOT_FOUND, S_OK}; use winapi::shared::winerror::{DXGI_ERROR_NOT_FOUND, S_OK};
use winapi::shared::{dxgi, dxgiformat}; use winapi::shared::{dxgi, dxgiformat};
@ -40,7 +43,7 @@ impl GraphicsProviderMethods<D3D11> for GraphicsProvider {
//dxgiformat::DXGI_FORMAT_R8G8B8A8_UNORM => return *format, //dxgiformat::DXGI_FORMAT_R8G8B8A8_UNORM => return *format,
f => { f => {
warn!("Backend requested unsupported format {:?}", f); warn!("Backend requested unsupported format {:?}", f);
} },
} }
} }
@ -116,8 +119,8 @@ fn get_matching_adapter(
let result = adapter.GetDesc1(&mut adapter_desc); let result = adapter.GetDesc1(&mut adapter_desc);
assert_eq!(result, S_OK); assert_eq!(result, S_OK);
let adapter_luid = &adapter_desc.AdapterLuid; let adapter_luid = &adapter_desc.AdapterLuid;
if adapter_luid.LowPart == requirements.adapter_luid.LowPart if adapter_luid.LowPart == requirements.adapter_luid.LowPart &&
&& adapter_luid.HighPart == requirements.adapter_luid.HighPart adapter_luid.HighPart == requirements.adapter_luid.HighPart
{ {
return Ok(adapter); return Ok(adapter);
} }

View file

@ -1,3 +1,7 @@
/* 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 std::ffi::c_void; use std::ffi::c_void;
use std::mem::MaybeUninit; use std::mem::MaybeUninit;
@ -12,22 +16,13 @@ use openxr::{
HandJointLocation, HandTracker, HandTrackingAimFlagsFB, Instance, Path, Posef, Session, Space, HandJointLocation, HandTracker, HandTrackingAimFlagsFB, Instance, Path, Posef, Session, Space,
SpaceLocationFlags, HAND_JOINT_COUNT, SpaceLocationFlags, HAND_JOINT_COUNT,
}; };
use webxr_api::Finger; use webxr_api::{
use webxr_api::Hand; Finger, Hand, Handedness, Input, InputFrame, InputId, InputSource, JointFrame, Native,
use webxr_api::Handedness; SelectEvent, TargetRayMode, Viewer,
use webxr_api::Input; };
use webxr_api::InputFrame;
use webxr_api::InputId;
use webxr_api::InputSource;
use webxr_api::JointFrame;
use webxr_api::Native;
use webxr_api::SelectEvent;
use webxr_api::TargetRayMode;
use webxr_api::Viewer;
use super::interaction_profiles::InteractionProfile; use super::interaction_profiles::InteractionProfile;
use super::IDENTITY_POSE; use super::IDENTITY_POSE;
use crate::ext_string; use crate::ext_string;
use crate::openxr::interaction_profiles::INTERACTION_PROFILES; use crate::openxr::interaction_profiles::INTERACTION_PROFILES;
@ -54,7 +49,7 @@ macro_rules! bind_inputs {
}; };
} }
#[derive(Copy, Clone, Debug, PartialEq, Eq)] #[derive(Clone, Copy, Debug, Eq, PartialEq)]
enum ClickState { enum ClickState {
Clicking, Clicking,
Done, Done,
@ -95,15 +90,15 @@ impl ClickState {
*self = ClickState::Done; *self = ClickState::Done;
// Cancel the select, we're showing a menu // Cancel the select, we're showing a menu
Some(SelectEvent::End) Some(SelectEvent::End)
} },
(true, ClickState::Done) => { (true, ClickState::Done) => {
*self = ClickState::Clicking; *self = ClickState::Clicking;
Some(SelectEvent::Start) Some(SelectEvent::Start)
} },
(false, ClickState::Clicking) => { (false, ClickState::Clicking) => {
*self = ClickState::Done; *self = ClickState::Done;
Some(SelectEvent::Select) Some(SelectEvent::Select)
} },
_ => None, _ => None,
} }
} else if *self == ClickState::Clicking { } else if *self == ClickState::Clicking {
@ -506,7 +501,7 @@ impl OpenXRInput {
let (button_values, buttons_changed) = { let (button_values, buttons_changed) = {
let mut changed = false; let mut changed = false;
let mut values = Vec::<f32>::new(); let mut values = Vec::<f32>::new();
let mut sync_buttons = |actions: &Vec<Action<f32>>| { let mut sync_buttons = |actions: &[Action<f32>]| {
let buttons = actions let buttons = actions
.iter() .iter()
.map(|action| { .map(|action| {
@ -678,7 +673,7 @@ fn locate_hand<G: Graphics>(
openxr::sys::Result::SUCCESS if location_info.is_active.into() => { openxr::sys::Result::SUCCESS if location_info.is_active.into() => {
aim_state.replace(state.assume_init()); aim_state.replace(state.assume_init());
Some(locations.assume_init()) Some(locations.assume_init())
} },
_ => None, _ => None,
}, },
) )

View file

@ -1,15 +1,16 @@
use openxr::{ /* This Source Code Form is subject to the terms of the Mozilla Public
sys::{ * 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 openxr::sys::{
BD_CONTROLLER_INTERACTION_EXTENSION_NAME, EXT_HAND_INTERACTION_EXTENSION_NAME, BD_CONTROLLER_INTERACTION_EXTENSION_NAME, EXT_HAND_INTERACTION_EXTENSION_NAME,
EXT_HP_MIXED_REALITY_CONTROLLER_EXTENSION_NAME, EXT_HP_MIXED_REALITY_CONTROLLER_EXTENSION_NAME, EXT_SAMSUNG_ODYSSEY_CONTROLLER_EXTENSION_NAME,
EXT_SAMSUNG_ODYSSEY_CONTROLLER_EXTENSION_NAME, FB_HAND_TRACKING_AIM_EXTENSION_NAME, FB_HAND_TRACKING_AIM_EXTENSION_NAME, FB_TOUCH_CONTROLLER_PRO_EXTENSION_NAME,
FB_TOUCH_CONTROLLER_PRO_EXTENSION_NAME,
HTC_VIVE_COSMOS_CONTROLLER_INTERACTION_EXTENSION_NAME, HTC_VIVE_COSMOS_CONTROLLER_INTERACTION_EXTENSION_NAME,
HTC_VIVE_FOCUS3_CONTROLLER_INTERACTION_EXTENSION_NAME, HTC_VIVE_FOCUS3_CONTROLLER_INTERACTION_EXTENSION_NAME,
META_TOUCH_CONTROLLER_PLUS_EXTENSION_NAME, ML_ML2_CONTROLLER_INTERACTION_EXTENSION_NAME, META_TOUCH_CONTROLLER_PLUS_EXTENSION_NAME, ML_ML2_CONTROLLER_INTERACTION_EXTENSION_NAME,
},
ExtensionSet,
}; };
use openxr::ExtensionSet;
#[macro_export] #[macro_export]
macro_rules! ext_string { macro_rules! ext_string {

View file

@ -1,16 +1,16 @@
use crate::gl_utils::GlClearer; /* This Source Code Form is subject to the terms of the Mozilla Public
use crate::SurfmanGL; * 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 euclid::Box2D; use std::collections::HashMap;
use euclid::Point2D; use std::num::NonZeroU32;
use euclid::Rect; use std::ops::Deref;
use euclid::RigidTransform3D; use std::sync::{Arc, Mutex};
use euclid::Rotation3D; use std::time::Duration;
use euclid::Size2D; use std::{mem, thread};
use euclid::Transform3D;
use euclid::Vector3D; use euclid::{Box2D, Point2D, Rect, RigidTransform3D, Rotation3D, Size2D, Transform3D, Vector3D};
use glow::PixelUnpackData; use glow::{self as gl, HasContext, PixelUnpackData};
use glow::{self as gl, HasContext};
use interaction_profiles::{get_profiles_from_path, get_supported_interaction_profiles}; use interaction_profiles::{get_profiles_from_path, get_supported_interaction_profiles};
use log::{error, warn}; use log::{error, warn};
use openxr::sys::CompositionLayerPassthroughFB; use openxr::sys::CompositionLayerPassthroughFB;
@ -22,56 +22,21 @@ use openxr::{
ReferenceSpaceType, SecondaryEndInfo, Session, Space, Swapchain, SwapchainCreateFlags, ReferenceSpaceType, SecondaryEndInfo, Session, Space, Swapchain, SwapchainCreateFlags,
SwapchainCreateInfo, SwapchainUsageFlags, SystemId, Vector3f, Version, ViewConfigurationType, SwapchainCreateInfo, SwapchainUsageFlags, SystemId, Vector3f, Version, ViewConfigurationType,
}; };
use std::collections::HashMap; use surfman::{
use std::mem; Context as SurfmanContext, Device as SurfmanDevice, Error as SurfmanError, SurfaceTexture,
use std::num::NonZeroU32; };
use std::ops::Deref;
use std::sync::{Arc, Mutex};
use std::thread;
use std::time::Duration;
use surfman::Context as SurfmanContext;
use surfman::Device as SurfmanDevice;
use surfman::Error as SurfmanError;
use surfman::SurfaceTexture;
use webxr_api; use webxr_api;
use webxr_api::util::{self, ClipPlanes}; use webxr_api::util::{self, ClipPlanes};
use webxr_api::BaseSpace; use webxr_api::{
use webxr_api::Capture; BaseSpace, Capture, ContextId, DeviceAPI, DiscoveryAPI, Display, Error, Event, EventBuffer,
use webxr_api::ContextId; Floor, Frame, GLContexts, InputId, InputSource, LayerGrandManager, LayerId, LayerInit,
use webxr_api::DeviceAPI; LayerManager, LayerManagerAPI, LeftEye, Native, Quitter, RightEye, SelectKind, Sender,
use webxr_api::DiscoveryAPI; Session as WebXrSession, SessionBuilder, SessionInit, SessionMode, SubImage, SubImages, View,
use webxr_api::Display; ViewerPose, Viewport, Viewports, Views, Visibility,
use webxr_api::Error; };
use webxr_api::Event;
use webxr_api::EventBuffer; use crate::gl_utils::GlClearer;
use webxr_api::Floor; use crate::SurfmanGL;
use webxr_api::Frame;
use webxr_api::GLContexts;
use webxr_api::InputId;
use webxr_api::InputSource;
use webxr_api::LayerGrandManager;
use webxr_api::LayerId;
use webxr_api::LayerInit;
use webxr_api::LayerManager;
use webxr_api::LayerManagerAPI;
use webxr_api::LeftEye;
use webxr_api::Native;
use webxr_api::Quitter;
use webxr_api::RightEye;
use webxr_api::SelectKind;
use webxr_api::Sender;
use webxr_api::Session as WebXrSession;
use webxr_api::SessionBuilder;
use webxr_api::SessionInit;
use webxr_api::SessionMode;
use webxr_api::SubImage;
use webxr_api::SubImages;
use webxr_api::View;
use webxr_api::ViewerPose;
use webxr_api::Viewport;
use webxr_api::Viewports;
use webxr_api::Views;
use webxr_api::Visibility;
mod input; mod input;
use input::OpenXRInput; use input::OpenXRInput;
@ -173,10 +138,10 @@ struct ViewInfo<Eye> {
impl<Eye> ViewInfo<Eye> { impl<Eye> ViewInfo<Eye> {
fn set_view(&mut self, view: openxr::View, clip_planes: ClipPlanes) { fn set_view(&mut self, view: openxr::View, clip_planes: ClipPlanes) {
self.view.pose = view.pose; self.view.pose = view.pose;
if self.view.fov.angle_left != view.fov.angle_left if self.view.fov.angle_left != view.fov.angle_left ||
|| self.view.fov.angle_right != view.fov.angle_right self.view.fov.angle_right != view.fov.angle_right ||
|| self.view.fov.angle_up != view.fov.angle_up self.view.fov.angle_up != view.fov.angle_up ||
|| self.view.fov.angle_down != view.fov.angle_down self.view.fov.angle_down != view.fov.angle_down
{ {
// It's fine if this happens occasionally, but if this happening very // It's fine if this happens occasionally, but if this happening very
// often we should stop caching // often we should stop caching
@ -239,9 +204,9 @@ pub fn create_instance(
warn!("Available extensions:\n{:?}", supported); warn!("Available extensions:\n{:?}", supported);
let mut supports_hands = needs_hands && supported.ext_hand_tracking; let mut supports_hands = needs_hands && supported.ext_hand_tracking;
let supports_passthrough = needs_passthrough && supported.fb_passthrough; let supports_passthrough = needs_passthrough && supported.fb_passthrough;
let supports_secondary = needs_secondary let supports_secondary = needs_secondary &&
&& supported.msft_secondary_view_configuration supported.msft_secondary_view_configuration &&
&& supported.msft_first_person_observer; supported.msft_first_person_observer;
let supports_updating_framerate = supported.fb_display_refresh_rate; let supports_updating_framerate = supported.fb_display_refresh_rate;
let app_info = ApplicationInfo { let app_info = ApplicationInfo {
@ -364,9 +329,9 @@ impl DiscoveryAPI<SurfmanGL> for OpenXrDiscovery {
ViewConfigurationType::PRIMARY_STEREO, ViewConfigurationType::PRIMARY_STEREO,
) { ) {
if mode == SessionMode::ImmersiveAR { if mode == SessionMode::ImmersiveAR {
supports = blend_modes.contains(&EnvironmentBlendMode::ADDITIVE) supports = blend_modes.contains(&EnvironmentBlendMode::ADDITIVE) ||
|| blend_modes.contains(&EnvironmentBlendMode::ALPHA_BLEND) blend_modes.contains(&EnvironmentBlendMode::ALPHA_BLEND) ||
|| instance.supports_passthrough; instance.supports_passthrough;
} else if mode == SessionMode::ImmersiveVR { } else if mode == SessionMode::ImmersiveVR {
// Immersive VR sessions are not precluded by non-opaque blending // Immersive VR sessions are not precluded by non-opaque blending
supports = blend_modes.len() > 0; supports = blend_modes.len() > 0;
@ -568,7 +533,7 @@ impl LayerManagerAPI<SurfmanGL> for OpenXrLayerManager {
None None
}; };
let layer_id = LayerId::new(); let layer_id = LayerId::default();
let openxr_layer = OpenXrLayer::new(swapchain, depth_stencil_texture, texture_size)?; let openxr_layer = OpenXrLayer::new(swapchain, depth_stencil_texture, texture_size)?;
self.layers.push((context_id, layer_id)); self.layers.push((context_id, layer_id));
self.openxr_layers.insert(layer_id, openxr_layer); self.openxr_layers.insert(layer_id, openxr_layer);
@ -1101,14 +1066,14 @@ impl OpenXrDevice {
Err(e) => { Err(e) => {
error!("Error polling events: {:?}", e); error!("Error polling events: {:?}", e);
return false; return false;
} },
}; };
match event { match event {
Some(SessionStateChanged(session_change)) => match session_change.state() { Some(SessionStateChanged(session_change)) => match session_change.state() {
openxr::SessionState::EXITING | openxr::SessionState::LOSS_PENDING => { openxr::SessionState::EXITING | openxr::SessionState::LOSS_PENDING => {
self.events.callback(Event::SessionEnd); self.events.callback(Event::SessionEnd);
return false; return false;
} },
openxr::SessionState::STOPPING => { openxr::SessionState::STOPPING => {
self.events self.events
.callback(Event::VisibilityChange(Visibility::Hidden)); .callback(Event::VisibilityChange(Visibility::Hidden));
@ -1116,7 +1081,7 @@ impl OpenXrDevice {
error!("Session failed to end on STOPPING: {:?}", e); error!("Session failed to end on STOPPING: {:?}", e);
} }
stopped = true; stopped = true;
} },
openxr::SessionState::READY if stopped => { openxr::SessionState::READY if stopped => {
self.events self.events
.callback(Event::VisibilityChange(Visibility::Visible)); .callback(Event::VisibilityChange(Visibility::Visible));
@ -1124,23 +1089,23 @@ impl OpenXrDevice {
error!("Session failed to begin on READY: {:?}", e); error!("Session failed to begin on READY: {:?}", e);
} }
stopped = false; stopped = false;
} },
openxr::SessionState::FOCUSED => { openxr::SessionState::FOCUSED => {
self.events self.events
.callback(Event::VisibilityChange(Visibility::Visible)); .callback(Event::VisibilityChange(Visibility::Visible));
} },
openxr::SessionState::VISIBLE => { openxr::SessionState::VISIBLE => {
self.events self.events
.callback(Event::VisibilityChange(Visibility::VisibleBlurred)); .callback(Event::VisibilityChange(Visibility::VisibleBlurred));
} },
_ => { _ => {
// FIXME: Handle other states // FIXME: Handle other states
} },
}, },
Some(InstanceLossPending(_)) => { Some(InstanceLossPending(_)) => {
self.events.callback(Event::SessionEnd); self.events.callback(Event::SessionEnd);
return false; return false;
} },
Some(InteractionProfileChanged(_)) => { Some(InteractionProfileChanged(_)) => {
let path = self.instance.string_to_path("/user/hand/right").unwrap(); let path = self.instance.string_to_path("/user/hand/right").unwrap();
let profile_path = self.session.current_interaction_profile(path).unwrap(); let profile_path = self.session.current_interaction_profile(path).unwrap();
@ -1162,12 +1127,12 @@ impl OpenXrDevice {
new_right.profiles.clone_from(&profiles); new_right.profiles.clone_from(&profiles);
self.events self.events
.callback(Event::UpdateInput(new_right.id, new_right)); .callback(Event::UpdateInput(new_right.id, new_right));
} },
Err(e) => { Err(e) => {
error!("Failed to get interaction profile: {:?}", e); error!("Failed to get interaction profile: {:?}", e);
},
} }
} },
}
Some(ReferenceSpaceChangePending(e)) => { Some(ReferenceSpaceChangePending(e)) => {
let base_space = match e.reference_space_type() { let base_space = match e.reference_space_type() {
ReferenceSpaceType::VIEW => BaseSpace::Viewer, ReferenceSpaceType::VIEW => BaseSpace::Viewer,
@ -1181,18 +1146,18 @@ impl OpenXrDevice {
let transform = transform(&e.pose_in_previous_space()); let transform = transform(&e.pose_in_previous_space());
self.events self.events
.callback(Event::ReferenceSpaceChanged(base_space, transform)); .callback(Event::ReferenceSpaceChanged(base_space, transform));
} },
Some(_) => { Some(_) => {
// FIXME: Handle other events // FIXME: Handle other events
} },
None if stopped => { None if stopped => {
// XXXManishearth be able to handle exits during this time // XXXManishearth be able to handle exits during this time
thread::sleep(Duration::from_millis(200)); thread::sleep(Duration::from_millis(200));
} },
None => { None => {
// No more events to process // No more events to process
break; break;
} },
} }
} }
true true
@ -1225,8 +1190,8 @@ impl SharedData {
if let Some(ref secondary) = self.secondary { if let Some(ref secondary) = self.secondary {
let secondary_vp = Rect::new( let secondary_vp = Rect::new(
Point2D::new(self.left.extent.width + self.right.extent.width, 0), Point2D::new(self.left.extent.width + self.right.extent.width, 0),
Size2D::new(secondary.extent.width, secondary.extent.height) Size2D::new(secondary.extent.width, secondary.extent.height) /
/ SECONDARY_VIEW_DOWNSCALE, SECONDARY_VIEW_DOWNSCALE,
); );
viewports.push(secondary_vp) viewports.push(secondary_vp)
} }
@ -1268,7 +1233,7 @@ impl DeviceAPI for OpenXrDevice {
ContextMenuResult::ExitSession => { ContextMenuResult::ExitSession => {
self.quit(); self.quit();
return None; return None;
} },
ContextMenuResult::Dismissed => self.context_menu_future = None, ContextMenuResult::Dismissed => self.context_menu_future = None,
ContextMenuResult::Pending => (), ContextMenuResult::Pending => (),
} }
@ -1280,7 +1245,7 @@ impl DeviceAPI for OpenXrDevice {
Err(e) => { Err(e) => {
error!("Error waiting on frame: {:?}", e); error!("Error waiting on frame: {:?}", e);
return None; return None;
} },
}; };
assert_eq!( assert_eq!(
@ -1294,7 +1259,7 @@ impl DeviceAPI for OpenXrDevice {
Err(e) => { Err(e) => {
error!("Error waiting on frame: {:?}", e); error!("Error waiting on frame: {:?}", e);
return None; return None;
} },
} }
}; };
@ -1315,7 +1280,7 @@ impl DeviceAPI for OpenXrDevice {
Err(e) => { Err(e) => {
error!("Error locating views: {:?}", e); error!("Error locating views: {:?}", e);
return None; return None;
} },
}; };
if !self.supports_mutable_fov { if !self.supports_mutable_fov {
views.iter_mut().for_each(|v| { views.iter_mut().for_each(|v| {
@ -1332,7 +1297,7 @@ impl DeviceAPI for OpenXrDevice {
Err(e) => { Err(e) => {
error!("Error locating viewer space: {:?}", e); error!("Error locating viewer space: {:?}", e);
return None; return None;
} },
}; };
let transform = transform(&pose.pose); let transform = transform(&pose.pose);
@ -1349,7 +1314,7 @@ impl DeviceAPI for OpenXrDevice {
Err(e) => { Err(e) => {
error!("Error locating views: {:?}", e); error!("Error locating views: {:?}", e);
return None; return None;
} },
}; };
secondary.set_view(view, self.clip_planes); secondary.set_view(view, self.clip_planes);
} }
@ -1472,22 +1437,22 @@ impl DeviceAPI for OpenXrDevice {
Err(e) => { Err(e) => {
error!("Error polling for event while quitting: {:?}", e); error!("Error polling for event while quitting: {:?}", e);
break; break;
} },
}; };
match event { match event {
Some(openxr::Event::SessionStateChanged(session_change)) => { Some(openxr::Event::SessionStateChanged(session_change)) => {
match session_change.state() { match session_change.state() {
openxr::SessionState::EXITING => { openxr::SessionState::EXITING => {
break; break;
} },
openxr::SessionState::STOPPING => { openxr::SessionState::STOPPING => {
if let Err(e) = self.session.end() { if let Err(e) = self.session.end() {
error!("Session failed to end while STOPPING: {:?}", e); error!("Session failed to end while STOPPING: {:?}", e);
} }
} },
_ => (), _ => (),
} }
} },
_ => (), _ => (),
} }
thread::sleep(Duration::from_millis(30)); thread::sleep(Duration::from_millis(30));
@ -1565,7 +1530,7 @@ impl DeviceAPI for OpenXrDevice {
} else { } else {
None None
} }
} },
Err(_) => None, Err(_) => None,
} }
} }

View file

@ -4,11 +4,11 @@
//! An implementation of layer management using surfman //! An implementation of layer management using surfman
use crate::gl_utils::GlClearer;
use euclid::{Point2D, Rect, Size2D};
use glow::{self as gl, Context as Gl, HasContext, PixelUnpackData};
use std::collections::HashMap; use std::collections::HashMap;
use std::num::NonZeroU32; use std::num::NonZeroU32;
use euclid::{Point2D, Rect, Size2D};
use glow::{self as gl, Context as Gl, HasContext, PixelUnpackData};
use surfman::chains::{PreserveBuffer, SwapChains, SwapChainsAPI}; use surfman::chains::{PreserveBuffer, SwapChains, SwapChainsAPI};
use surfman::{Context as SurfmanContext, Device as SurfmanDevice, SurfaceAccess, SurfaceTexture}; use surfman::{Context as SurfmanContext, Device as SurfmanDevice, SurfaceAccess, SurfaceTexture};
use webxr_api::{ use webxr_api::{
@ -16,7 +16,9 @@ use webxr_api::{
SubImages, Viewports, SubImages, Viewports,
}; };
#[derive(Copy, Clone, Debug)] use crate::gl_utils::GlClearer;
#[derive(Clone, Copy, Debug)]
pub enum SurfmanGL {} pub enum SurfmanGL {}
impl GLTypes for SurfmanGL { impl GLTypes for SurfmanGL {
@ -63,7 +65,7 @@ impl LayerManagerAPI<SurfmanGL> for SurfmanLayerManager {
init: LayerInit, init: LayerInit,
) -> Result<LayerId, Error> { ) -> Result<LayerId, Error> {
let texture_size = init.texture_size(&self.viewports); let texture_size = init.texture_size(&self.viewports);
let layer_id = LayerId::new(); let layer_id = LayerId::default();
let access = SurfaceAccess::GPUOnly; let access = SurfaceAccess::GPUOnly;
let size = texture_size.to_untyped(); let size = texture_size.to_untyped();
// TODO: Treat depth and stencil separately? // TODO: Treat depth and stencil separately?

View file

@ -53,7 +53,7 @@ tracing-hitrace = ["tracing", "dep:hitrace"]
tracing-perfetto = ["tracing", "dep:tracing-perfetto"] tracing-perfetto = ["tracing", "dep:tracing-perfetto"]
webdriver = ["libservo/webdriver"] webdriver = ["libservo/webdriver"]
webgl_backtrace = ["libservo/webgl_backtrace"] webgl_backtrace = ["libservo/webgl_backtrace"]
webxr = ["dep:webxr", "libservo/webxr"] webxr = ["libservo/webxr"]
webgpu = ["libservo/webgpu"] webgpu = ["libservo/webgpu"]
[dependencies] [dependencies]
@ -101,7 +101,6 @@ xcomponent-sys = { version = "0.3.1", features = ["api-12", "keyboard-types"] }
nix = { workspace = true, features = ["fs"] } nix = { workspace = true, features = ["fs"] }
surfman = { workspace = true, features = ["sm-angle-default"] } surfman = { workspace = true, features = ["sm-angle-default"] }
serde_json = { workspace = true } serde_json = { workspace = true }
webxr = { workspace = true, optional = true }
[target.'cfg(not(any(target_os = "android", target_env = "ohos")))'.dependencies] [target.'cfg(not(any(target_os = "android", target_env = "ohos")))'.dependencies]
# For optional feature servo_allocator/use-system-allocator # For optional feature servo_allocator/use-system-allocator
@ -123,7 +122,6 @@ serde_json = { workspace = true }
shellwords = "1.0.0" shellwords = "1.0.0"
surfman = { workspace = true, features = ["sm-x11", "sm-raw-window-handle-06"] } surfman = { workspace = true, features = ["sm-x11", "sm-raw-window-handle-06"] }
tinyfiledialogs = "3.0" tinyfiledialogs = "3.0"
webxr = { workspace = true, features = ["ipc", "glwindow", "headless"] }
winit = "0.30.8" winit = "0.30.8"
[target.'cfg(any(all(target_os = "linux", not(target_env = "ohos")), target_os = "windows"))'.dependencies] [target.'cfg(any(all(target_os = "linux", not(target_env = "ohos")), target_os = "windows"))'.dependencies]
@ -133,6 +131,5 @@ image = { workspace = true }
sig = "1.0" sig = "1.0"
[target.'cfg(target_os = "windows")'.dependencies] [target.'cfg(target_os = "windows")'.dependencies]
webxr = { workspace = true, features = ["ipc", "glwindow", "headless", "openxr-api"] }
windows-sys = { workspace = true, features = ["Win32_Graphics_Gdi"] } windows-sys = { workspace = true, features = ["Win32_Graphics_Gdi"] }
libservo = { path = "../../components/servo", features = ["no-wgl"] } libservo = { path = "../../components/servo", features = ["no-wgl"] }

View file

@ -20,12 +20,12 @@ use servo::config::prefs::Preferences;
use servo::servo_config::pref; use servo::servo_config::pref;
use servo::servo_url::ServoUrl; use servo::servo_url::ServoUrl;
use servo::webrender_traits::SurfmanRenderingContext; use servo::webrender_traits::SurfmanRenderingContext;
use servo::webxr::glwindow::GlWindowDiscovery;
#[cfg(target_os = "windows")]
use servo::webxr::openxr::{AppInfo, OpenXrDiscovery};
use servo::{EventLoopWaker, Servo}; use servo::{EventLoopWaker, Servo};
use surfman::Connection; use surfman::Connection;
use url::Url; use url::Url;
use webxr::glwindow::GlWindowDiscovery;
#[cfg(target_os = "windows")]
use webxr::openxr::{AppInfo, OpenXrDiscovery};
use winit::application::ApplicationHandler; use winit::application::ApplicationHandler;
use winit::event::WindowEvent; use winit::event::WindowEvent;
use winit::event_loop::{ActiveEventLoop, ControlFlow}; use winit::event_loop::{ActiveEventLoop, ControlFlow};

View file

@ -7,10 +7,10 @@
use net::protocols::ProtocolRegistry; use net::protocols::ProtocolRegistry;
use servo::compositing::windowing::EmbedderMethods; use servo::compositing::windowing::EmbedderMethods;
use servo::servo_config::pref; use servo::servo_config::pref;
use servo::{EmbedderProxy, EventLoopWaker}; use servo::webxr::glwindow::GlWindowDiscovery;
use webxr::glwindow::GlWindowDiscovery;
#[cfg(target_os = "windows")] #[cfg(target_os = "windows")]
use webxr::openxr::OpenXrDiscovery; use servo::webxr::openxr::OpenXrDiscovery;
use servo::{EmbedderProxy, EventLoopWaker};
use crate::desktop::protocols::{resource, servo as servo_handler, urlinfo}; use crate::desktop::protocols::{resource, servo as servo_handler, urlinfo};
@ -45,11 +45,13 @@ impl EmbedderMethods for EmbedderCallbacks {
#[cfg(feature = "webxr")] #[cfg(feature = "webxr")]
fn register_webxr( fn register_webxr(
&mut self, &mut self,
xr: &mut webxr::MainThreadRegistry, xr: &mut servo::webxr::MainThreadRegistry,
_embedder_proxy: EmbedderProxy, _embedder_proxy: EmbedderProxy,
) { ) {
use servo::webxr::headless::HeadlessMockDiscovery;
if pref!(dom_webxr_test) { if pref!(dom_webxr_test) {
xr.register_mock(webxr::headless::HeadlessMockDiscovery::new()); xr.register_mock(HeadlessMockDiscovery::default());
} else if let Some(xr_discovery) = self.xr_discovery.take() { } else if let Some(xr_discovery) = self.xr_discovery.take() {
match xr_discovery { match xr_discovery {
XrDiscovery::GlWindow(discovery) => xr.register(discovery), XrDiscovery::GlWindow(discovery) => xr.register(discovery),

View file

@ -636,7 +636,7 @@ impl WindowPortsMethods for Window {
fn new_glwindow( fn new_glwindow(
&self, &self,
event_loop: &winit::event_loop::ActiveEventLoop, event_loop: &winit::event_loop::ActiveEventLoop,
) -> Rc<dyn webxr::glwindow::GlWindow> { ) -> Rc<dyn servo::webxr::glwindow::GlWindow> {
let size = self.winit_window.outer_size(); let size = self.winit_window.outer_size();
let window_attr = winit::window::Window::default_attributes() let window_attr = winit::window::Window::default_attributes()
@ -734,12 +734,12 @@ struct XRWindowPose {
xr_translation: Cell<Vector3D<f32, UnknownUnit>>, xr_translation: Cell<Vector3D<f32, UnknownUnit>>,
} }
impl webxr::glwindow::GlWindow for XRWindow { impl servo::webxr::glwindow::GlWindow for XRWindow {
fn get_render_target( fn get_render_target(
&self, &self,
device: &mut Device, device: &mut Device,
_context: &mut Context, _context: &mut Context,
) -> webxr::glwindow::GlWindowRenderTarget { ) -> servo::webxr::glwindow::GlWindowRenderTarget {
self.winit_window.set_visible(true); self.winit_window.set_visible(true);
let window_handle = self let window_handle = self
.winit_window .winit_window
@ -751,7 +751,7 @@ impl webxr::glwindow::GlWindow for XRWindow {
.connection() .connection()
.create_native_widget_from_window_handle(window_handle, size) .create_native_widget_from_window_handle(window_handle, size)
.expect("Failed to create native widget"); .expect("Failed to create native widget");
webxr::glwindow::GlWindowRenderTarget::NativeWidget(native_widget) servo::webxr::glwindow::GlWindowRenderTarget::NativeWidget(native_widget)
} }
fn get_rotation(&self) -> Rotation3D<f32, UnknownUnit, UnknownUnit> { fn get_rotation(&self) -> Rotation3D<f32, UnknownUnit, UnknownUnit> {
@ -762,17 +762,17 @@ impl webxr::glwindow::GlWindow for XRWindow {
self.pose.xr_translation.get() self.pose.xr_translation.get()
} }
fn get_mode(&self) -> webxr::glwindow::GlWindowMode { fn get_mode(&self) -> servo::webxr::glwindow::GlWindowMode {
if pref!(dom_webxr_glwindow_red_cyan) { if pref!(dom_webxr_glwindow_red_cyan) {
webxr::glwindow::GlWindowMode::StereoRedCyan servo::webxr::glwindow::GlWindowMode::StereoRedCyan
} else if pref!(dom_webxr_glwindow_left_right) { } else if pref!(dom_webxr_glwindow_left_right) {
webxr::glwindow::GlWindowMode::StereoLeftRight servo::webxr::glwindow::GlWindowMode::StereoLeftRight
} else if pref!(dom_webxr_glwindow_spherical) { } else if pref!(dom_webxr_glwindow_spherical) {
webxr::glwindow::GlWindowMode::Spherical servo::webxr::glwindow::GlWindowMode::Spherical
} else if pref!(dom_webxr_glwindow_cubemap) { } else if pref!(dom_webxr_glwindow_cubemap) {
webxr::glwindow::GlWindowMode::Cubemap servo::webxr::glwindow::GlWindowMode::Cubemap
} else { } else {
webxr::glwindow::GlWindowMode::Blit servo::webxr::glwindow::GlWindowMode::Blit
} }
} }

View file

@ -123,7 +123,7 @@ impl WindowPortsMethods for Window {
fn new_glwindow( fn new_glwindow(
&self, &self,
_events_loop: &winit::event_loop::ActiveEventLoop, _events_loop: &winit::event_loop::ActiveEventLoop,
) -> Rc<dyn webxr::glwindow::GlWindow> { ) -> Rc<dyn servo::webxr::glwindow::GlWindow> {
unimplemented!() unimplemented!()
} }

View file

@ -49,7 +49,7 @@ pub trait WindowPortsMethods: WindowMethods {
fn new_glwindow( fn new_glwindow(
&self, &self,
event_loop: &winit::event_loop::ActiveEventLoop, event_loop: &winit::event_loop::ActiveEventLoop,
) -> Rc<dyn webxr::glwindow::GlWindow>; ) -> Rc<dyn servo::webxr::glwindow::GlWindow>;
fn winit_window(&self) -> Option<&winit::window::Window>; fn winit_window(&self) -> Option<&winit::window::Window>;
fn toolbar_height(&self) -> Length<f32, DeviceIndependentPixel>; fn toolbar_height(&self) -> Length<f32, DeviceIndependentPixel>;
fn set_toolbar_height(&self, height: Length<f32, DeviceIndependentPixel>); fn set_toolbar_height(&self, height: Length<f32, DeviceIndependentPixel>);

View file

@ -35,7 +35,7 @@ pub struct InitOptions {
pub coordinates: Coordinates, pub coordinates: Coordinates,
pub density: f32, pub density: f32,
#[cfg(feature = "webxr")] #[cfg(feature = "webxr")]
pub xr_discovery: Option<webxr::Discovery>, pub xr_discovery: Option<servo::webxr::Discovery>,
pub surfman_integration: SurfmanIntegration, pub surfman_integration: SurfmanIntegration,
} }

View file

@ -681,13 +681,13 @@ impl ServoGlue {
pub(super) struct ServoEmbedderCallbacks { pub(super) struct ServoEmbedderCallbacks {
waker: Box<dyn EventLoopWaker>, waker: Box<dyn EventLoopWaker>,
#[cfg(feature = "webxr")] #[cfg(feature = "webxr")]
xr_discovery: Option<webxr::Discovery>, xr_discovery: Option<servo::webxr::Discovery>,
} }
impl ServoEmbedderCallbacks { impl ServoEmbedderCallbacks {
pub(super) fn new( pub(super) fn new(
waker: Box<dyn EventLoopWaker>, waker: Box<dyn EventLoopWaker>,
#[cfg(feature = "webxr")] xr_discovery: Option<webxr::Discovery>, #[cfg(feature = "webxr")] xr_discovery: Option<servo::webxr::Discovery>,
) -> Self { ) -> Self {
Self { Self {
waker, waker,
@ -706,7 +706,7 @@ impl EmbedderMethods for ServoEmbedderCallbacks {
#[cfg(feature = "webxr")] #[cfg(feature = "webxr")]
fn register_webxr( fn register_webxr(
&mut self, &mut self,
registry: &mut webxr::MainThreadRegistry, registry: &mut servo::webxr::MainThreadRegistry,
_embedder_proxy: EmbedderProxy, _embedder_proxy: EmbedderProxy,
) { ) {
debug!("EmbedderMethods::register_xr"); debug!("EmbedderMethods::register_xr");

View file

@ -29,9 +29,6 @@ files = [
] ]
# Directories that are ignored for the non-WPT tidy check. # Directories that are ignored for the non-WPT tidy check.
directories = [ directories = [
# Ignored until these files are fully integrated into the workspace build.
"./components/webxr",
"./components/shared/webxr",
# Test have expectations in them, causing tidy to fail. # Test have expectations in them, causing tidy to fail.
"./support/crown/tests", "./support/crown/tests",
# Upstream # Upstream