diff options
author | Martin Robinson <mrobinson@igalia.com> | 2025-01-31 17:41:57 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2025-01-31 16:41:57 +0000 |
commit | 5466c27f6f9a151ae7f5357cb663cc2580fbca15 (patch) | |
tree | a306c16a4fc0af3fa8ab3976de0b5c79f8503de1 | |
parent | a4c6c205d2d26dd16ac1cd03e73a0262eb4c12f4 (diff) | |
download | servo-5466c27f6f9a151ae7f5357cb663cc2580fbca15.tar.gz servo-5466c27f6f9a151ae7f5357cb663cc2580fbca15.zip |
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>
41 files changed, 441 insertions, 642 deletions
diff --git a/Cargo.lock b/Cargo.lock index 53a8d03fd5c..018649f8b09 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6884,7 +6884,6 @@ dependencies = [ "tracing-subscriber", "url", "vergen-git2", - "webxr", "windows-sys 0.59.0", "winit", "winres", @@ -8605,6 +8604,7 @@ dependencies = [ "ipc-channel", "log", "serde", + "time 0.3.37", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index fe153823e0d..eeef427169d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -97,6 +97,7 @@ net_traits = { path = "components/shared/net" } nix = "0.29" num-traits = "0.2" num_cpus = "1.1.0" +openxr = "0.19" parking_lot = "0.12" percent-encoding = "2.3" proc-macro2 = "1" @@ -105,6 +106,7 @@ quote = "1" rand = "0.8" rand_core = "0.6" rand_isaac = "0.3" +raw-window-handle = "0.6" rayon = "1" regex = "1.11" 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_api = { git = "https://github.com/servo/webrender", branch = "0.65" } webrender_traits = { path = "components/shared/webrender" } -webxr = { git = "https://github.com/servo/webxr" } -webxr-api = { git = "https://github.com/servo/webxr" } +webxr-api = { path = "components/shared/webxr" } +winapi = "0.3" +wio = "0.2" wgpu-core = { git = "https://github.com/gfx-rs/wgpu", rev = "d8e7ab1ad13f2bf2f9702401d1bc625e26b1c2e6" } wgpu-types = { git = "https://github.com/gfx-rs/wgpu", rev = "d8e7ab1ad13f2bf2f9702401d1bc625e26b1c2e6" } windows-sys = "0.59" @@ -230,7 +233,3 @@ codegen-units = 1 # # [patch."https://github.com/servo/<repository>"] # <crate> = { path = "/path/to/local/checkout" } - -[patch."https://github.com/servo/webxr"] -webxr = { path = "components/webxr" } -webxr-api = { path = "components/shared/webxr" } diff --git a/components/canvas/Cargo.toml b/components/canvas/Cargo.toml index bba2189cd5d..e1ad3fb885e 100644 --- a/components/canvas/Cargo.toml +++ b/components/canvas/Cargo.toml @@ -43,5 +43,5 @@ unicode-script = { workspace = true } webrender = { workspace = true } webrender_api = { 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 } diff --git a/components/compositing/Cargo.toml b/components/compositing/Cargo.toml index ca18767baf2..833fd8f4f99 100644 --- a/components/compositing/Cargo.toml +++ b/components/compositing/Cargo.toml @@ -42,7 +42,7 @@ tracing = { workspace = true, optional = true } webrender = { workspace = true } webrender_api = { workspace = true } webrender_traits = { workspace = true } -webxr = { workspace = true, optional = true } +webxr = { path = "../webxr", optional = true } [dev-dependencies] surfman = { workspace = true } diff --git a/components/servo/Cargo.toml b/components/servo/Cargo.toml index eed717bded1..1f165ee0bb2 100644 --- a/components/servo/Cargo.toml +++ b/components/servo/Cargo.toml @@ -95,18 +95,22 @@ webgpu = { path = "../webgpu" } webrender = { workspace = true } webrender_api = { workspace = true } webrender_traits = { workspace = true } -webxr = { workspace = true, optional = true } webxr-api = { workspace = true, optional = true } [target.'cfg(any(target_os = "android", target_env = "ohos"))'.dependencies] surfman = { workspace = true, features = ["sm-angle-default"] } +webxr = { path = "../webxr", optional = true } [target.'cfg(not(any(target_os = "android", target_env = "ohos")))'.dependencies] 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] gaol = "0.2.1" +[target.'cfg(target_os = "windows")'.dependencies] +webxr = { path = "../webxr", features = ["ipc", "glwindow", "headless", "openxr-api"] } + [dev-dependencies] libservo = { path = ".", features = ["tracing"] } rustls = { version = "0.23", default-features = false, features = ["aws-lc-rs"] } diff --git a/components/servo/lib.rs b/components/servo/lib.rs index aa64ed40f3f..24584d563cc 100644 --- a/components/servo/lib.rs +++ b/components/servo/lib.rs @@ -106,6 +106,8 @@ use webrender_traits::{ CrossProcessCompositorApi, WebrenderExternalImageHandlers, WebrenderExternalImageRegistry, WebrenderImageHandlerType, }; +#[cfg(feature = "webxr")] +pub use webxr; pub use { background_hang_monitor, base, bluetooth, bluetooth_traits, canvas, canvas_traits, compositing, devtools, devtools_traits, euclid, fonts, ipc_channel, layout_thread_2020, media, net, diff --git a/components/shared/webxr/Cargo.toml b/components/shared/webxr/Cargo.toml index 47caee00131..a424c880855 100644 --- a/components/shared/webxr/Cargo.toml +++ b/components/shared/webxr/Cargo.toml @@ -1,14 +1,12 @@ [package] name = "webxr-api" -version = "0.0.1" -authors = ["The Servo Project Developers"] -edition = "2018" - -homepage = "https://github.com/servo/webxr" -repository = "https://github.com/servo/webxr" +version.workspace = true +authors.workspace = true +license.workspace = true +edition.workspace = true +publish.workspace = true +rust-version.workspace = true keywords = ["ar", "headset", "openxr", "vr", "webxr"] -license = "MPL-2.0" - description = '''A safe Rust API that provides a way to interact with 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/) @@ -21,8 +19,8 @@ path = "lib.rs" ipc = ["serde", "ipc-channel", "euclid/serde"] [dependencies] -euclid = "0.22" -ipc-channel = { version = "0.19", optional = true } -log = "0.4" -serde = { version = "1.0", optional = true } -time = { version = "0.1", optional = true } +euclid = { workspace = true } +ipc-channel = { workspace = true, optional = true } +log = { workspace = true } +serde = { workspace = true, optional = true } +time_03 = { workspace = true, optional = true } diff --git a/components/shared/webxr/device.rs b/components/shared/webxr/device.rs index 65f34d8560b..0c6a7161686 100644 --- a/components/shared/webxr/device.rs +++ b/components/shared/webxr/device.rs @@ -4,28 +4,14 @@ //! 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 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 pub trait DiscoveryAPI<GL>: 'static { fn request_session( @@ -105,10 +91,10 @@ impl<GL: 'static> DiscoveryAPI<GL> for Box<dyn DiscoveryAPI<GL>> { init: &SessionInit, xr: SessionBuilder<GL>, ) -> Result<Session, Error> { - (&mut **self).request_session(mode, init, xr) + (**self).request_session(mode, init, xr) } fn supports_session(&self, mode: SessionMode) -> bool { - (&**self).supports_session(mode) + (**self).supports_session(mode) } } diff --git a/components/shared/webxr/events.rs b/components/shared/webxr/events.rs index 338913464ba..c56332a0b7a 100644 --- a/components/shared/webxr/events.rs +++ b/components/shared/webxr/events.rs @@ -4,18 +4,13 @@ use euclid::RigidTransform3D; -use crate::ApiSpace; -use crate::BaseSpace; -use crate::Frame; -use crate::InputFrame; -use crate::InputId; -use crate::InputSource; -use crate::SelectEvent; -use crate::SelectKind; -use crate::Sender; +use crate::{ + ApiSpace, BaseSpace, Frame, InputFrame, InputId, InputSource, SelectEvent, SelectKind, Sender, +}; #[derive(Clone, Debug)] #[cfg_attr(feature = "ipc", derive(serde::Serialize, serde::Deserialize))] +#[allow(clippy::large_enum_variant)] pub enum Event { /// Input source connected AddInput(InputSource), @@ -35,7 +30,7 @@ pub enum Event { ReferenceSpaceChanged(BaseSpace, RigidTransform3D<f32, ApiSpace, ApiSpace>), } -#[derive(Copy, Clone, Debug)] +#[derive(Clone, Copy, Debug)] #[cfg_attr(feature = "ipc", derive(serde::Serialize, serde::Deserialize))] pub enum Visibility { /// Session fully displayed to user @@ -65,7 +60,7 @@ impl EventBuffer { EventBuffer::Buffered(ref mut events) => events.push(event), EventBuffer::Sink(ref dest) => { let _ = dest.send(event); - } + }, } } diff --git a/components/shared/webxr/frame.rs b/components/shared/webxr/frame.rs index 2589953ecba..d97a212dbcd 100644 --- a/components/shared/webxr/frame.rs +++ b/components/shared/webxr/frame.rs @@ -2,20 +2,14 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ -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 crate::{ + Floor, HitTestId, HitTestResult, InputFrame, Native, SubImages, Viewer, Viewports, Views, +}; + /// 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? #[derive(Clone, Debug)] #[cfg_attr(feature = "ipc", derive(serde::Serialize, serde::Deserialize))] diff --git a/components/shared/webxr/hand.rs b/components/shared/webxr/hand.rs index fa6e8fafe80..09c6b4c6df1 100644 --- a/components/shared/webxr/hand.rs +++ b/components/shared/webxr/hand.rs @@ -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; -#[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))] pub struct HandSpace; @@ -29,7 +34,7 @@ pub struct Finger<J> { pub phalanx_tip: Option<J>, } -#[derive(Copy, Clone, Debug)] +#[derive(Clone, Copy, Debug)] #[cfg_attr(feature = "ipc", derive(serde::Serialize, serde::Deserialize))] pub struct JointFrame { 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))] pub enum FingerJoint { Metacarpal, @@ -107,7 +112,7 @@ pub enum FingerJoint { PhalanxTip, } -#[derive(Copy, Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Copy, Debug, Eq, PartialEq)] #[cfg_attr(feature = "ipc", derive(serde::Serialize, serde::Deserialize))] pub enum Joint { Wrist, diff --git a/components/shared/webxr/hittest.rs b/components/shared/webxr/hittest.rs index 3e56ff8c357..9bf1cbe6dd1 100644 --- a/components/shared/webxr/hittest.rs +++ b/components/shared/webxr/hittest.rs @@ -1,16 +1,16 @@ -use crate::ApiSpace; -use crate::Native; -use crate::Space; -use euclid::Point3D; -use euclid::RigidTransform3D; -use euclid::Rotation3D; -use euclid::Vector3D; -use std::f32::EPSILON; +/* 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::iter::FromIterator; +use euclid::{Point3D, RigidTransform3D, Rotation3D, Vector3D}; + +use crate::{ApiSpace, Native, Space}; + #[derive(Clone, Copy, Debug)] #[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> { /// The origin of the ray pub origin: Vector3D<f32, Space>, @@ -20,16 +20,16 @@ pub struct Ray<Space> { #[derive(Clone, Copy, Debug)] #[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 { Point, Plane, Mesh, } -#[derive(Copy, Clone, Debug)] +#[derive(Clone, Copy, Debug)] #[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 id: HitTestId, pub space: Space, @@ -37,11 +37,11 @@ pub struct HitTestSource { 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))] pub struct HitTestId(pub u32); -#[derive(Copy, Clone, Debug, Default)] +#[derive(Clone, Copy, Debug, Default)] #[cfg_attr(feature = "ipc", derive(serde::Serialize, serde::Deserialize))] /// Vec<EntityType>, but better pub struct EntityTypes { @@ -50,7 +50,7 @@ pub struct EntityTypes { pub mesh: bool, } -#[derive(Copy, Clone, Debug)] +#[derive(Clone, Copy, Debug)] #[cfg_attr(feature = "ipc", derive(serde::Serialize, serde::Deserialize))] pub struct HitTestResult { pub id: HitTestId, @@ -62,7 +62,7 @@ pub struct HitTestResult { /// The coordinate space of a hit test result pub struct HitTestSpace; -#[derive(Copy, Clone, Debug)] +#[derive(Clone, Copy, Debug)] #[cfg_attr(feature = "ipc", derive(serde::Serialize, serde::Deserialize))] pub struct Triangle { pub first: Point3D<f32, Native>, @@ -101,7 +101,7 @@ impl FromIterator<EntityType> for EntityTypes { } 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( self, ray: Ray<Native>, @@ -117,7 +117,7 @@ impl Triangle { let h = ray.direction.cross(edge2); let a = edge1.dot(h); - if a > -EPSILON && a < EPSILON { + if a > -f32::EPSILON && a < f32::EPSILON { // ray is parallel to triangle return None; } @@ -129,7 +129,7 @@ impl Triangle { // barycentric coordinate of intersection point u let u = f * s.dot(h); // barycentric coordinates have range (0, 1) - if u < 0. || u > 1. { + if !(0. ..=1.).contains(&u) { // the intersection is outside the triangle return None; } @@ -147,7 +147,7 @@ impl Triangle { let t = f * edge2.dot(q); - if t > EPSILON { + if t > f32::EPSILON { let origin = ray.origin + ray.direction * t; // 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 y = Vector3D::new(0., 1., 0.); 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 // XXXManishearth it's possible for the vectors to be // antiparallel, unclear if normals need to be flipped diff --git a/components/shared/webxr/input.rs b/components/shared/webxr/input.rs index 9fcd2a18554..ba200b76ec6 100644 --- a/components/shared/webxr/input.rs +++ b/components/shared/webxr/input.rs @@ -2,18 +2,15 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ -use crate::Hand; -use crate::Input; -use crate::JointFrame; -use crate::Native; - 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))] pub struct InputId(pub u32); -#[derive(Copy, Clone, Debug)] +#[derive(Clone, Copy, Debug)] #[cfg_attr(feature = "ipc", derive(serde::Serialize, serde::Deserialize))] pub enum Handedness { None, @@ -21,7 +18,7 @@ pub enum Handedness { Right, } -#[derive(Copy, Clone, Debug)] +#[derive(Clone, Copy, Debug)] #[cfg_attr(feature = "ipc", derive(serde::Serialize, serde::Deserialize))] pub enum TargetRayMode { Gaze, @@ -55,7 +52,7 @@ pub struct InputFrame { 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))] pub enum SelectEvent { /// Selection started @@ -66,7 +63,7 @@ pub enum SelectEvent { Select, } -#[derive(Copy, Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Copy, Debug, Eq, PartialEq)] #[cfg_attr(feature = "ipc", derive(serde::Serialize, serde::Deserialize))] pub enum SelectKind { Select, diff --git a/components/shared/webxr/layer.rs b/components/shared/webxr/layer.rs index b0a607f290f..d98a8b83893 100644 --- a/components/shared/webxr/layer.rs +++ b/components/shared/webxr/layer.rs @@ -2,16 +2,12 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ -use crate::Error; -use crate::Viewport; -use crate::Viewports; +use std::fmt::Debug; +use std::sync::atomic::{AtomicUsize, Ordering}; -use euclid::Rect; -use euclid::Size2D; +use euclid::{Rect, Size2D}; -use std::fmt::Debug; -use std::sync::atomic::AtomicUsize; -use std::sync::atomic::Ordering; +use crate::{Error, Viewport, Viewports}; #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] #[cfg_attr(feature = "ipc", derive(Deserialize, Serialize))] @@ -165,12 +161,14 @@ impl LayerManager { impl Drop for LayerManager { fn drop(&mut self) { 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); } } } +#[allow(clippy::type_complexity)] pub struct LayerManagerFactory<GL: GLTypes>( Box< dyn Send @@ -213,16 +211,16 @@ pub struct LayerId(usize); static NEXT_LAYER_ID: AtomicUsize = AtomicUsize::new(0); -impl LayerId { - pub fn new() -> LayerId { +impl Default for LayerId { + fn default() -> Self { LayerId(NEXT_LAYER_ID.fetch_add(1, Ordering::SeqCst)) } } -#[derive(Copy, Clone, Debug)] +#[derive(Clone, Copy, Debug)] #[cfg_attr(feature = "ipc", derive(Deserialize, Serialize))] pub enum LayerInit { - // https://www.w3.org/TR/webxr/#dictdef-xrwebgllayerinit + /// <https://www.w3.org/TR/webxr/#dictdef-xrwebgllayerinit> WebGLLayer { antialias: bool, depth: bool, @@ -231,7 +229,7 @@ pub enum LayerInit { ignore_depth_values: bool, framebuffer_scale_factor: f32, }, - // https://immersive-web.github.io/layers/#xrprojectionlayerinittype + /// <https://immersive-web.github.io/layers/#xrprojectionlayerinittype> ProjectionLayer { depth: bool, stencil: bool, @@ -247,8 +245,8 @@ impl LayerInit { LayerInit::WebGLLayer { framebuffer_scale_factor: scale, .. - } - | LayerInit::ProjectionLayer { + } | + LayerInit::ProjectionLayer { scale_factor: scale, .. } => { @@ -258,13 +256,13 @@ impl LayerInit { .fold(Rect::zero(), |acc, view| acc.union(view)) .size; (native_size.to_f32() * *scale).to_i32() - } + }, } } } -/// https://immersive-web.github.io/layers/#enumdef-xrlayerlayout -#[derive(Copy, Clone, Debug)] +/// <https://immersive-web.github.io/layers/#enumdef-xrlayerlayout> +#[derive(Clone, Copy, Debug)] #[cfg_attr(feature = "ipc", derive(Deserialize, Serialize))] pub enum LayerLayout { // TODO: Default @@ -284,7 +282,7 @@ pub struct SubImages { pub view_sub_images: Vec<SubImage>, } -/// https://immersive-web.github.io/layers/#xrsubimagetype +/// <https://immersive-web.github.io/layers/#xrsubimagetype> #[derive(Clone, Debug)] #[cfg_attr(feature = "ipc", derive(Deserialize, Serialize))] pub struct SubImage { diff --git a/components/shared/webxr/lib.rs b/components/shared/webxr/lib.rs index 9acad34e0e5..2348947d3b9 100644 --- a/components/shared/webxr/lib.rs +++ b/components/shared/webxr/lib.rs @@ -19,130 +19,48 @@ mod space; pub mod util; 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(not(feature = "ipc"))] +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::IpcSender as Sender; - +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::channel; - -#[cfg(not(feature = "ipc"))] -pub use std::sync::mpsc::{Receiver, RecvTimeoutError, Sender}; +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"))] pub fn channel<T>() -> Result<(Sender<T>, Receiver<T>), ()> { @@ -169,7 +87,7 @@ where return Ok(msg); } thread::sleep(delay); - delay = delay * 2; + delay *= 2; } receiver.try_recv() } diff --git a/components/shared/webxr/mock.rs b/components/shared/webxr/mock.rs index 91c15bae44b..5c8d855e5ab 100644 --- a/components/shared/webxr/mock.rs +++ b/components/shared/webxr/mock.rs @@ -2,33 +2,16 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ -use crate::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}; - #[cfg(feature = "ipc")] 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 pub trait MockDiscoveryAPI<GL>: 'static { fn simulate_device_connection( @@ -103,7 +86,7 @@ pub enum MockInputMsg { SetGripOrigin(Option<RigidTransform3D<f32, Input, Native>>), /// Note: SelectEvent::Select here refers to a complete Select event, /// 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), Disconnect, Reconnect, diff --git a/components/shared/webxr/registry.rs b/components/shared/webxr/registry.rs index 337bb80a8a2..5835424e375 100644 --- a/components/shared/webxr/registry.rs +++ b/components/shared/webxr/registry.rs @@ -2,28 +2,16 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ -use crate::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; - #[cfg(feature = "ipc")] use serde::{Deserialize, Serialize}; +use crate::{ + DiscoveryAPI, Error, Frame, GLTypes, LayerGrandManager, MainThreadSession, MockDeviceInit, + MockDeviceMsg, MockDiscoveryAPI, Receiver, Sender, Session, SessionBuilder, SessionId, + SessionInit, SessionMode, +}; + #[derive(Clone)] #[cfg_attr(feature = "ipc", derive(Serialize, Deserialize))] pub struct Registry { @@ -188,13 +176,13 @@ impl<GL: 'static + GLTypes> MainThreadRegistry<GL> { match msg { RegistryMsg::SupportsSession(mode, dest) => { let _ = dest.send(self.supports_session(mode)); - } + }, RegistryMsg::RequestSession(mode, init, dest, raf_sender) => { let _ = dest.send(self.request_session(mode, init, raf_sender)); - } + }, RegistryMsg::SimulateDeviceConnection(init, dest) => { 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))] +#[allow(clippy::large_enum_variant)] enum RegistryMsg { RequestSession( SessionMode, diff --git a/components/shared/webxr/session.rs b/components/shared/webxr/session.rs index be731b8c243..17219d03868 100644 --- a/components/shared/webxr/session.rs +++ b/components/shared/webxr/session.rs @@ -2,43 +2,24 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ -use crate::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::time::Duration; +use euclid::{Point2D, Rect, RigidTransform3D, Size2D}; +use log::warn; #[cfg(feature = "ipc")] 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. 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)] #[cfg_attr(feature = "ipc", derive(Serialize, Deserialize))] pub enum SessionMode { @@ -47,7 +28,7 @@ pub enum SessionMode { ImmersiveAR, } -/// https://immersive-web.github.io/webxr/#dictdef-xrsessioninit +/// <https://immersive-web.github.io/webxr/#dictdef-xrsessioninit> #[derive(Clone, Debug, Eq, PartialEq)] #[cfg_attr(feature = "ipc", derive(Serialize, Deserialize))] pub struct SessionInit { @@ -76,9 +57,9 @@ impl SessionInit { } let mut granted = self.required_features.clone(); for f in &self.optional_features { - if f == "viewer" - || (f == "local" && mode != SessionMode::Inline) - || supported.contains(f) + if f == "viewer" || + (f == "local" && mode != SessionMode::Inline) || + supported.contains(f) { granted.push(f.clone()); } @@ -91,12 +72,11 @@ impl SessionInit { self.required_features .iter() .chain(self.optional_features.iter()) - .find(|x| *x == f) - .is_some() + .any(|x| *x == f) } } -/// 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)] #[cfg_attr(feature = "ipc", derive(Serialize, Deserialize))] pub enum EnvironmentBlendMode { @@ -137,7 +117,7 @@ impl Quitter { /// An object that represents an XR session. /// 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))] pub struct Session { floor_transform: Option<RigidTransform3D<f32, Native, Floor>>, @@ -160,7 +140,7 @@ impl Session { } 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>>> { @@ -182,7 +162,7 @@ impl Session { } /// 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 pub fn recommended_framebuffer_resolution(&self) -> Option<Size2D<i32, Viewport>> { @@ -335,13 +315,9 @@ where } pub fn run(&mut self) { - loop { - if let Ok(msg) = self.receiver.recv() { - if !self.handle_msg(msg) { - self.running = false; - break; - } - } else { + while let Ok(msg) = self.receiver.recv() { + if !self.handle_msg(msg) { + self.running = false; break; } } @@ -352,24 +328,24 @@ where match msg { SessionMsg::SetEventDest(dest) => { self.device.set_event_dest(dest); - } + }, SessionMsg::RequestHitTest(source) => { self.device.request_hit_test(source); - } + }, SessionMsg::CancelHitTest(id) => { self.device.cancel_hit_test(id); - } + }, SessionMsg::CreateLayer(context_id, layer_init, sender) => { let result = self.device.create_layer(context_id, layer_init); let _ = sender.send(result); - } + }, SessionMsg::DestroyLayer(context_id, layer_id) => { self.layers.retain(|&(_, other_id)| layer_id != other_id); self.device.destroy_layer(context_id, layer_id); - } + }, SessionMsg::SetLayers(layers) => { self.pending_layers = Some(layers); - } + }, SessionMsg::StartRenderLoop => { if let Some(layers) = self.pending_layers.take() { self.layers = layers; @@ -379,11 +355,11 @@ where None => { warn!("Device stopped providing frames, exiting"); return false; - } + }, }; self.render_state = RenderState::InRenderLoop; let _ = self.frame_sender.send(frame); - } + }, SessionMsg::UpdateClipPlanes(near, far) => self.device.update_clip_planes(near, far), SessionMsg::RenderAnimationFrame => { self.frame_count += 1; @@ -404,15 +380,15 @@ where None => { warn!("Device stopped providing frames, exiting"); return false; - } + }, }; let _ = self.frame_sender.send(frame); - } + }, SessionMsg::UpdateFrameRate(rate, sender) => { let new_framerate = self.device.update_frame_rate(rate); let _ = sender.send(new_framerate); - } + }, SessionMsg::Quit => { if self.render_state == RenderState::NotInRenderLoop { self.quit(); @@ -420,11 +396,11 @@ where } else { self.render_state = RenderState::PendingQuit; } - } + }, SessionMsg::GetBoundsGeometry(sender) => { let bounds = self.device.reference_space_bounds(); let _ = sender.send(bounds); - } + }, } true } @@ -506,10 +482,10 @@ impl<'a, GL: 'static> SessionBuilder<'a, GL> { let session = thread.new_session(); let _ = acks.send(Ok(session)); thread.run(); - } + }, Err(err) => { let _ = acks.send(Err(err)); - } + }, } }); ackr.recv().unwrap_or(Err(Error::CommunicationError)) diff --git a/components/shared/webxr/space.rs b/components/shared/webxr/space.rs index 4ab116c5b90..e48c614d027 100644 --- a/components/shared/webxr/space.rs +++ b/components/shared/webxr/space.rs @@ -1,7 +1,11 @@ -use crate::InputId; -use crate::Joint; +/* 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 crate::{InputId, Joint}; + #[derive(Clone, Copy, Debug)] #[cfg_attr(feature = "ipc", derive(serde::Serialize, serde::Deserialize))] /// A stand-in type for "the space isn't statically known since diff --git a/components/shared/webxr/util.rs b/components/shared/webxr/util.rs index e6342d42faf..312a1dfe68e 100644 --- a/components/shared/webxr/util.rs +++ b/components/shared/webxr/util.rs @@ -1,8 +1,11 @@ -use crate::FrameUpdateEvent; -use crate::HitTestId; -use crate::HitTestSource; +/* 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::Transform3D; +use crate::{FrameUpdateEvent, HitTestId, HitTestSource}; + #[derive(Clone, Copy, Debug)] #[cfg_attr(feature = "ipc", derive(serde::Serialize, serde::Deserialize))] pub struct ClipPlanes { diff --git a/components/shared/webxr/view.rs b/components/shared/webxr/view.rs index 566748f8a7a..9490f051729 100644 --- a/components/shared/webxr/view.rs +++ b/components/shared/webxr/view.rs @@ -4,35 +4,32 @@ //! This crate uses `euclid`'s typed units, and exposes different coordinate spaces. -use euclid::Rect; -use euclid::RigidTransform3D; -use euclid::Transform3D; +use std::marker::PhantomData; +use euclid::{Rect, RigidTransform3D, Transform3D}; #[cfg(feature = "ipc")] use serde::{Deserialize, Serialize}; -use std::marker::PhantomData; - /// 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)] #[cfg_attr(feature = "ipc", derive(Serialize, Deserialize))] pub enum Viewer {} /// 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)] #[cfg_attr(feature = "ipc", derive(Serialize, Deserialize))] pub enum Floor {} /// 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)] #[cfg_attr(feature = "ipc", derive(Serialize, Deserialize))] pub enum LeftEye {} /// 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)] #[cfg_attr(feature = "ipc", derive(Serialize, Deserialize))] pub enum RightEye {} @@ -115,7 +112,7 @@ pub enum Capture {} /// its projection onto its display. /// For stereo displays, we have a `View<LeftEye>` and a `View<RightEye>`. /// 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)] #[cfg_attr(feature = "ipc", derive(Serialize, Deserialize))] pub struct View<Eye> { @@ -144,6 +141,7 @@ impl<Eye> View<Eye> { /// Whether a device is mono or stereo, and the views it supports. #[derive(Clone, Debug)] #[cfg_attr(feature = "ipc", derive(Serialize, Deserialize))] +#[allow(clippy::large_enum_variant)] pub enum Views { /// Mono view for inline VR, viewport and projection matrices are calculated by client Inline, diff --git a/components/webxr/Cargo.toml b/components/webxr/Cargo.toml index 23c7c4b85c7..84faa7d6ac4 100644 --- a/components/webxr/Cargo.toml +++ b/components/webxr/Cargo.toml @@ -1,14 +1,12 @@ [package] name = "webxr" -version = "0.0.1" -authors = ["The Servo Project Developers"] -edition = "2018" - -homepage = "https://github.com/servo/webxr" -repository = "https://github.com/servo/webxr" +version.workspace = true +authors.workspace = true +license.workspace = true +edition.workspace = true +publish.workspace = true +rust-version.workspace = true keywords = ["ar", "headset", "openxr", "vr", "webxr"] -license = "MPL-2.0" - description = '''A safe Rust API that provides a way to interact with 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/) @@ -27,23 +25,16 @@ ipc = ["webxr-api/ipc", "serde"] openxr-api = ["angle", "openxr", "winapi", "wio", "surfman/sm-angle-default"] [dependencies] -webxr-api = { path = "../shared/webxr" } -crossbeam-channel = "0.5" -euclid = "0.22" -log = "0.4.6" -openxr = { version = "0.19", optional = true } -serde = { version = "1.0", optional = true } -glow = "0.16" -raw-window-handle = "0.6" -surfman = { git = "https://github.com/servo/surfman", rev = "300789ddbda45c89e9165c31118bf1c4c07f89f6", features = [ - "chains", - "sm-raw-window-handle-06", -] } +webxr-api = { workspace = true } +crossbeam-channel = { workspace = true } +euclid = { workspace = true } +log = { workspace = true } +openxr = { workspace = true, optional = true } +serde = { workspace = true, optional = true } +glow = { workspace = true } +raw-window-handle = { workspace = true } +surfman = { workspace = true, features = ["chains", "sm-raw-window-handle-06"] } [target.'cfg(target_os = "windows")'.dependencies] -winapi = { version = "0.3", features = [ - "dxgi", - "d3d11", - "winerror", -], optional = true } -wio = { version = "0.2", optional = true } +winapi = { workspace = true, features = ["dxgi", "d3d11", "winerror"], optional = true } +wio = { workspace = true, optional = true } diff --git a/components/webxr/gl_utils.rs b/components/webxr/gl_utils.rs index fff74017c8d..752a68a45e3 100644 --- a/components/webxr/gl_utils.rs +++ b/components/webxr/gl_utils.rs @@ -2,16 +2,15 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ -use crate::SurfmanGL; -use glow as gl; -use glow::Context as Gl; -use glow::HasContext; use std::collections::HashMap; use std::num::NonZero; + +use glow as gl; +use glow::{Context as Gl, HasContext}; use surfman::Device as SurfmanDevice; -use webxr_api::ContextId; -use webxr_api::GLContexts; -use webxr_api::LayerId; +use webxr_api::{ContextId, GLContexts, LayerId}; + +use crate::SurfmanGL; pub(crate) fn framebuffer(framebuffer: u32) -> Option<gl::NativeFramebuffer> { NonZero::new(framebuffer).map(gl::NativeFramebuffer) @@ -93,6 +92,7 @@ impl GlClearer { }) } + #[allow(clippy::too_many_arguments)] pub(crate) fn clear( &mut self, device: &mut SurfmanDevice, @@ -114,8 +114,6 @@ impl GlClearer { let mut clear_color = [0., 0., 0., 0.]; let mut clear_depth = [0.]; let mut clear_stencil = [0]; - let color_mask; - let depth_mask; let mut stencil_mask = [0]; let scissor_enabled = gl.is_enabled(gl::SCISSOR_TEST); 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::DEPTH_CLEAR_VALUE, &mut clear_depth[..]); 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[..]); - 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 gl.bind_framebuffer(gl::FRAMEBUFFER, fbo); diff --git a/components/webxr/glwindow/mod.rs b/components/webxr/glwindow/mod.rs index 9f24c85f14e..a1b9136cd9e 100644 --- a/components/webxr/glwindow/mod.rs +++ b/components/webxr/glwindow/mod.rs @@ -2,16 +2,15 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ -use crate::gl_utils::framebuffer; -use crate::{SurfmanGL, SurfmanLayerManager}; use core::slice; +use std::num::NonZeroU32; +use std::rc::Rc; + use euclid::{ Angle, Point2D, Rect, RigidTransform3D, Rotation3D, Size2D, Transform3D, UnknownUnit, Vector3D, }; use glow::{self as gl, Context as Gl, HasContext}; use raw_window_handle::DisplayHandle; -use std::num::NonZeroU32; -use std::rc::Rc; use surfman::chains::{PreserveBuffer, SwapChain, SwapChainAPI, SwapChains, SwapChainsAPI}; use surfman::{ Adapter, Connection, Context as SurfmanContext, ContextAttributeFlags, ContextAttributes, @@ -26,6 +25,9 @@ use webxr_api::{ VIEWER, }; +use crate::gl_utils::framebuffer; +use crate::{SurfmanGL, SurfmanLayerManager}; + // How far off the ground are the viewer's eyes? const HEIGHT: f32 = 1.0; @@ -55,7 +57,7 @@ pub trait GlWindow { fn display_handle(&self) -> DisplayHandle; } -#[derive(Copy, Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Copy, Debug, Eq, PartialEq)] pub enum GlWindowMode { Blit, StereoLeftRight, @@ -80,9 +82,9 @@ impl GlWindowDiscovery { pub fn new(window: Rc<dyn GlWindow>) -> GlWindowDiscovery { let connection = Connection::from_display_handle(window.display_handle()).unwrap(); let adapter = connection.create_adapter().unwrap(); - let flags = ContextAttributeFlags::ALPHA - | ContextAttributeFlags::DEPTH - | ContextAttributeFlags::STENCIL; + let flags = ContextAttributeFlags::ALPHA | + ContextAttributeFlags::DEPTH | + ContextAttributeFlags::STENCIL; let version = match connection.gl_api() { GLApi::GLES => GLVersion { major: 3, minor: 0 }, 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 connection = self.connection.clone(); let adapter = self.adapter.clone(); - let context_attributes = self.context_attributes.clone(); + let context_attributes = self.context_attributes; let window = self.window.clone(); xr.run_on_main_thread(move |grand_manager| { GlWindowDevice::new( @@ -155,6 +157,7 @@ impl DeviceAPI for GlWindowDevice { fn viewports(&self) -> Viewports { let size = self.viewport_size(); let viewports = match self.window.get_mode() { + #[allow(clippy::erasing_op, clippy::identity_op)] GlWindowMode::Cubemap | GlWindowMode::Spherical => vec![ Rect::new(Point2D::new(size.width * 1, 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::new(size.width, 0), size), ] - } + }, }; Viewports { viewports } } @@ -282,7 +285,7 @@ impl DeviceAPI for GlWindowDevice { target_swap_chain .swap_buffers(&mut self.device, &mut self.context, PreserveBuffer::No) .unwrap(); - } + }, None => { // Rendering to a native widget let mut surface = self @@ -296,7 +299,7 @@ impl DeviceAPI for GlWindowDevice { self.device .bind_surface_to_context(&mut self.context, surface) .unwrap(); - } + }, } debug_assert_eq!(unsafe { self.gl.get_error() }, gl::NO_ERROR); @@ -377,11 +380,11 @@ impl GlWindowDevice { .bind_surface_to_context(&mut context, surface) .unwrap(); None - } + }, GlWindowRenderTarget::SwapChain(target_swap_chain) => { debug_assert!(target_swap_chain.is_attached()); Some(target_swap_chain) - } + }, }; 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.) let wasted_pixels = (INTER_PUPILLARY_DISTANCE / PIXELS_PER_METRE) as i32; Size2D::new(window_size.width + wasted_pixels, window_size.height) - } + }, GlWindowMode::Cubemap => { // Cubemap viewports should be square let size = 1.max(window_size.width / 3).max(window_size.height / 2); Size2D::new(size, size) - } + }, GlWindowMode::Spherical => { // Cubemap viewports should be square let size = 1.max(window_size.width / 2).max(window_size.height); Size2D::new(size, size) - } + }, GlWindowMode::StereoLeftRight | GlWindowMode::Blit => { Size2D::new(window_size.width / 2, window_size.height) - } + }, } } @@ -525,7 +528,7 @@ impl GlWindowDevice { ), GlWindowMode::Blit | GlWindowMode::StereoLeftRight | GlWindowMode::StereoRedCyan => { 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::Blit | GlWindowMode::StereoLeftRight | GlWindowMode::StereoRedCyan => { Angle::degrees(FOV_UP) - } + }, }; let f = 1.0 / fov_up.radians.tan(); let nf = 1.0 / (near - far); @@ -723,13 +726,13 @@ impl GlWindowShader { let (vertex_source, fragment_source) = match mode { GlWindowMode::Blit => { return None; - } + }, GlWindowMode::StereoLeftRight | GlWindowMode::Cubemap => { (PASSTHROUGH_VERTEX_SHADER, PASSTHROUGH_FRAGMENT_SHADER) - } + }, GlWindowMode::StereoRedCyan => { (ANAGLYPH_VERTEX_SHADER, ANAGLYPH_RED_CYAN_FRAGMENT_SHADER) - } + }, GlWindowMode::Spherical => (SPHERICAL_VERTEX_SHADER, SPHERICAL_FRAGMENT_SHADER), }; @@ -839,17 +842,15 @@ impl GlWindowShader { match self.mode { GlWindowMode::StereoRedCyan => { - let wasted = 1.0 - - (texture_size.width as f32 / viewport_size.width as f32) - .max(0.0) - .min(1.0); + let wasted = 1.0 - + (texture_size.width as f32 / viewport_size.width as f32).clamp(0.0, 1.0); let wasted_location = self.gl.get_uniform_location(self.program, "wasted"); self.gl.uniform_1_f32(wasted_location.as_ref(), wasted); - } - GlWindowMode::Blit - | GlWindowMode::Cubemap - | GlWindowMode::Spherical - | GlWindowMode::StereoLeftRight => {} + }, + GlWindowMode::Blit | + GlWindowMode::Cubemap | + GlWindowMode::Spherical | + GlWindowMode::StereoLeftRight => {}, } self.gl diff --git a/components/webxr/headless/mod.rs b/components/webxr/headless/mod.rs index 7a8fea01f28..032687b25a7 100644 --- a/components/webxr/headless/mod.rs +++ b/components/webxr/headless/mod.rs @@ -2,11 +2,10 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ -use crate::SurfmanGL; -use crate::SurfmanLayerManager; -use euclid::{Point2D, RigidTransform3D}; use std::sync::{Arc, Mutex}; use std::thread; + +use euclid::{Point2D, RigidTransform3D}; use surfman::chains::SwapChains; use webxr_api::util::{self, ClipPlanes, HitTestList}; use webxr_api::{ @@ -18,6 +17,9 @@ use webxr_api::{ SessionMode, Space, SubImages, View, Viewer, ViewerPose, Viewports, Views, }; +use crate::{SurfmanGL, SurfmanLayerManager}; + +#[derive(Default)] pub struct HeadlessMockDiscovery {} struct HeadlessDiscovery { @@ -74,7 +76,7 @@ impl MockDiscoveryAPI<SurfmanGL> for HeadlessMockDiscovery { init: MockDeviceInit, receiver: Receiver<MockDeviceMsg>, ) -> 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 views = init.views.clone(); let data = HeadlessDeviceData { @@ -209,7 +211,7 @@ impl HeadlessDevice { impl DeviceAPI for HeadlessDevice { 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 { @@ -264,9 +266,9 @@ impl DeviceAPI for HeadlessDevice { } if data.needs_floor_update { - frame.events.push(FrameUpdateEvent::UpdateFloorTransform( - data.floor_transform.clone(), - )); + frame + .events + .push(FrameUpdateEvent::UpdateFloorTransform(data.floor_transform)); data.needs_floor_update = false; } Some(frame) @@ -315,12 +317,6 @@ impl DeviceAPI for HeadlessDevice { } } -impl HeadlessMockDiscovery { - pub fn new() -> HeadlessMockDiscovery { - HeadlessMockDiscovery {} - } -} - macro_rules! with_all_sessions { ($self:ident, |$s:ident| $e:expr) => { for $s in &mut $self.sessions { @@ -401,20 +397,20 @@ impl HeadlessDeviceData { MockDeviceMsg::ClearWorld => self.world = None, MockDeviceMsg::SetViewerOrigin(viewer_origin) => { self.viewer_origin = viewer_origin; - } + }, MockDeviceMsg::SetFloorOrigin(floor_origin) => { self.floor_transform = floor_origin.map(|f| f.inverse()); self.needs_floor_update = true; - } + }, MockDeviceMsg::SetViews(views) => { self.views = views; with_all_sessions!(self, |s| { s.needs_vp_update = true; }) - } + }, MockDeviceMsg::VisibilityChange(v) => { with_all_sessions!(self, |s| s.events.callback(Event::VisibilityChange(v))) - } + }, MockDeviceMsg::AddInputSource(init) => { self.inputs.push(InputInfo { source: init.source.clone(), @@ -427,7 +423,7 @@ impl HeadlessDeviceData { with_all_sessions!(self, |s| s .events .callback(Event::AddInput(init.source.clone()))) - } + }, MockDeviceMsg::MessageInputSource(id, msg) => { if let Some(ref mut input) = self.inputs.iter_mut().find(|i| i.source.id == id) { match msg { @@ -437,21 +433,21 @@ impl HeadlessDeviceData { s.events .callback(Event::UpdateInput(id, input.source.clone())) }); - } + }, MockInputMsg::SetProfiles(p) => { input.source.profiles = p; with_all_sessions!(self, |s| { s.events .callback(Event::UpdateInput(id, input.source.clone())) }); - } + }, MockInputMsg::SetTargetRayMode(t) => { input.source.target_ray_mode = t; with_all_sessions!(self, |s| { s.events .callback(Event::UpdateInput(id, input.source.clone())) }); - } + }, MockInputMsg::SetPointerOrigin(p) => input.pointer = p, MockInputMsg::SetGripOrigin(p) => input.grip = p, MockInputMsg::TriggerSelect(kind, event) => { @@ -463,20 +459,20 @@ impl HeadlessDeviceData { match event { SelectEvent::Start => { self.trigger_select(id, kind, event); - } + }, SelectEvent::End => { if clicking { self.trigger_select(id, kind, SelectEvent::Select); } else { self.trigger_select(id, kind, SelectEvent::End); } - } + }, SelectEvent::Select => { self.trigger_select(id, kind, SelectEvent::Start); self.trigger_select(id, kind, SelectEvent::Select); - } + }, } - } + }, MockInputMsg::Disconnect => { if input.active { with_all_sessions!(self, |s| s @@ -485,7 +481,7 @@ impl HeadlessDeviceData { input.active = false; input.clicking = false; } - } + }, MockInputMsg::Reconnect => { if !input.active { with_all_sessions!(self, |s| s @@ -493,14 +489,14 @@ impl HeadlessDeviceData { .callback(Event::AddInput(input.source.clone()))); input.active = true; } - } + }, MockInputMsg::SetSupportedButtons(buttons) => { input.buttons = buttons; with_all_sessions!(self, |s| s.events.callback(Event::UpdateInput( input.source.id, input.source.clone() ))); - } + }, MockInputMsg::UpdateButtonState(state) => { if let Some(button) = input .buttons @@ -509,26 +505,26 @@ impl HeadlessDeviceData { { *button = state; } - } + }, } } - } + }, MockDeviceMsg::Disconnect(s) => { self.disconnected = true; with_all_sessions!(self, |s| s.quitter.as_ref().map(|q| q.quit())); // notify the client that we're done disconnecting let _ = s.send(()); return false; - } + }, MockDeviceMsg::SetBoundsGeometry(g) => { self.bounds_geometry = g; - } + }, MockDeviceMsg::SimulateResetPose => { with_all_sessions!(self, |s| s.events.callback(Event::ReferenceSpaceChanged( BaseSpace::Local, RigidTransform3D::identity() ))); - } + }, } true } diff --git a/components/webxr/lib.rs b/components/webxr/lib.rs index ad731b92f07..862d8e9814e 100644 --- a/components/webxr/lib.rs +++ b/components/webxr/lib.rs @@ -14,8 +14,7 @@ pub mod headless; pub mod openxr; pub mod surfman_layer_manager; -pub use surfman_layer_manager::SurfmanGL; -pub use surfman_layer_manager::SurfmanLayerManager; +pub use surfman_layer_manager::{SurfmanGL, SurfmanLayerManager}; pub type MainThreadRegistry = webxr_api::MainThreadRegistry<surfman_layer_manager::SurfmanGL>; pub type Discovery = Box<dyn webxr_api::DiscoveryAPI<SurfmanGL>>; diff --git a/components/webxr/openxr/graphics.rs b/components/webxr/openxr/graphics.rs index 442c3ae952c..8bc8123ad3b 100644 --- a/components/webxr/openxr/graphics.rs +++ b/components/webxr/openxr/graphics.rs @@ -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 openxr::{ExtensionSet, FrameStream, FrameWaiter, Graphics, Instance, Session, SystemId}; -use surfman::Context as SurfmanContext; -use surfman::Device as SurfmanDevice; -use surfman::Error as SurfmanError; -use surfman::SurfaceTexture; +use surfman::{ + Context as SurfmanContext, Device as SurfmanDevice, Error as SurfmanError, SurfaceTexture, +}; use webxr_api::Error; pub enum GraphicsProvider {} diff --git a/components/webxr/openxr/graphics_d3d11.rs b/components/webxr/openxr/graphics_d3d11.rs index 24e7538b129..15a472a6c3e 100644 --- a/components/webxr/openxr/graphics_d3d11.rs +++ b/components/webxr/openxr/graphics_d3d11.rs @@ -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 euclid::{Size2D, UnknownUnit}; @@ -6,11 +10,10 @@ use openxr::d3d::{Requirements, SessionCreateInfoD3D11, D3D11}; use openxr::{ ExtensionSet, FormFactor, FrameStream, FrameWaiter, Graphics, Instance, Session, SystemId, }; -use surfman::Adapter as SurfmanAdapter; -use surfman::Context as SurfmanContext; -use surfman::Device as SurfmanDevice; -use surfman::Error as SurfmanError; -use surfman::SurfaceTexture; +use surfman::{ + Adapter as SurfmanAdapter, Context as SurfmanContext, Device as SurfmanDevice, + Error as SurfmanError, SurfaceTexture, +}; use webxr_api::Error; use winapi::shared::winerror::{DXGI_ERROR_NOT_FOUND, S_OK}; use winapi::shared::{dxgi, dxgiformat}; @@ -40,7 +43,7 @@ impl GraphicsProviderMethods<D3D11> for GraphicsProvider { //dxgiformat::DXGI_FORMAT_R8G8B8A8_UNORM => return *format, f => { warn!("Backend requested unsupported format {:?}", f); - } + }, } } @@ -116,8 +119,8 @@ fn get_matching_adapter( let result = adapter.GetDesc1(&mut adapter_desc); assert_eq!(result, S_OK); let adapter_luid = &adapter_desc.AdapterLuid; - if adapter_luid.LowPart == requirements.adapter_luid.LowPart - && adapter_luid.HighPart == requirements.adapter_luid.HighPart + if adapter_luid.LowPart == requirements.adapter_luid.LowPart && + adapter_luid.HighPart == requirements.adapter_luid.HighPart { return Ok(adapter); } diff --git a/components/webxr/openxr/input.rs b/components/webxr/openxr/input.rs index bcd060f3876..0a940aff002 100644 --- a/components/webxr/openxr/input.rs +++ b/components/webxr/openxr/input.rs @@ -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::mem::MaybeUninit; @@ -12,22 +16,13 @@ use openxr::{ HandJointLocation, HandTracker, HandTrackingAimFlagsFB, Instance, Path, Posef, Session, Space, SpaceLocationFlags, HAND_JOINT_COUNT, }; -use webxr_api::Finger; -use webxr_api::Hand; -use webxr_api::Handedness; -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 webxr_api::{ + Finger, Hand, Handedness, Input, InputFrame, InputId, InputSource, JointFrame, Native, + SelectEvent, TargetRayMode, Viewer, +}; use super::interaction_profiles::InteractionProfile; use super::IDENTITY_POSE; - use crate::ext_string; 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 { Clicking, Done, @@ -95,15 +90,15 @@ impl ClickState { *self = ClickState::Done; // Cancel the select, we're showing a menu Some(SelectEvent::End) - } + }, (true, ClickState::Done) => { *self = ClickState::Clicking; Some(SelectEvent::Start) - } + }, (false, ClickState::Clicking) => { *self = ClickState::Done; Some(SelectEvent::Select) - } + }, _ => None, } } else if *self == ClickState::Clicking { @@ -506,7 +501,7 @@ impl OpenXRInput { let (button_values, buttons_changed) = { let mut changed = false; let mut values = Vec::<f32>::new(); - let mut sync_buttons = |actions: &Vec<Action<f32>>| { + let mut sync_buttons = |actions: &[Action<f32>]| { let buttons = actions .iter() .map(|action| { @@ -678,7 +673,7 @@ fn locate_hand<G: Graphics>( openxr::sys::Result::SUCCESS if location_info.is_active.into() => { aim_state.replace(state.assume_init()); Some(locations.assume_init()) - } + }, _ => None, }, ) diff --git a/components/webxr/openxr/interaction_profiles.rs b/components/webxr/openxr/interaction_profiles.rs index 5192fc2c775..c728e958748 100644 --- a/components/webxr/openxr/interaction_profiles.rs +++ b/components/webxr/openxr/interaction_profiles.rs @@ -1,15 +1,16 @@ -use openxr::{ - sys::{ - BD_CONTROLLER_INTERACTION_EXTENSION_NAME, EXT_HAND_INTERACTION_EXTENSION_NAME, - EXT_HP_MIXED_REALITY_CONTROLLER_EXTENSION_NAME, - EXT_SAMSUNG_ODYSSEY_CONTROLLER_EXTENSION_NAME, FB_HAND_TRACKING_AIM_EXTENSION_NAME, - FB_TOUCH_CONTROLLER_PRO_EXTENSION_NAME, - HTC_VIVE_COSMOS_CONTROLLER_INTERACTION_EXTENSION_NAME, - HTC_VIVE_FOCUS3_CONTROLLER_INTERACTION_EXTENSION_NAME, - META_TOUCH_CONTROLLER_PLUS_EXTENSION_NAME, ML_ML2_CONTROLLER_INTERACTION_EXTENSION_NAME, - }, - ExtensionSet, +/* 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 openxr::sys::{ + BD_CONTROLLER_INTERACTION_EXTENSION_NAME, EXT_HAND_INTERACTION_EXTENSION_NAME, + EXT_HP_MIXED_REALITY_CONTROLLER_EXTENSION_NAME, EXT_SAMSUNG_ODYSSEY_CONTROLLER_EXTENSION_NAME, + FB_HAND_TRACKING_AIM_EXTENSION_NAME, FB_TOUCH_CONTROLLER_PRO_EXTENSION_NAME, + HTC_VIVE_COSMOS_CONTROLLER_INTERACTION_EXTENSION_NAME, + HTC_VIVE_FOCUS3_CONTROLLER_INTERACTION_EXTENSION_NAME, + META_TOUCH_CONTROLLER_PLUS_EXTENSION_NAME, ML_ML2_CONTROLLER_INTERACTION_EXTENSION_NAME, }; +use openxr::ExtensionSet; #[macro_export] macro_rules! ext_string { diff --git a/components/webxr/openxr/mod.rs b/components/webxr/openxr/mod.rs index 2981c91b83a..12cb9c3b15e 100644 --- a/components/webxr/openxr/mod.rs +++ b/components/webxr/openxr/mod.rs @@ -1,16 +1,16 @@ -use crate::gl_utils::GlClearer; -use crate::SurfmanGL; +/* 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::Box2D; -use euclid::Point2D; -use euclid::Rect; -use euclid::RigidTransform3D; -use euclid::Rotation3D; -use euclid::Size2D; -use euclid::Transform3D; -use euclid::Vector3D; -use glow::PixelUnpackData; -use glow::{self as gl, HasContext}; +use std::collections::HashMap; +use std::num::NonZeroU32; +use std::ops::Deref; +use std::sync::{Arc, Mutex}; +use std::time::Duration; +use std::{mem, thread}; + +use euclid::{Box2D, Point2D, Rect, RigidTransform3D, Rotation3D, Size2D, Transform3D, Vector3D}; +use glow::{self as gl, HasContext, PixelUnpackData}; use interaction_profiles::{get_profiles_from_path, get_supported_interaction_profiles}; use log::{error, warn}; use openxr::sys::CompositionLayerPassthroughFB; @@ -22,56 +22,21 @@ use openxr::{ ReferenceSpaceType, SecondaryEndInfo, Session, Space, Swapchain, SwapchainCreateFlags, SwapchainCreateInfo, SwapchainUsageFlags, SystemId, Vector3f, Version, ViewConfigurationType, }; -use std::collections::HashMap; -use std::mem; -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 surfman::{ + Context as SurfmanContext, Device as SurfmanDevice, Error as SurfmanError, SurfaceTexture, +}; use webxr_api; use webxr_api::util::{self, ClipPlanes}; -use webxr_api::BaseSpace; -use webxr_api::Capture; -use webxr_api::ContextId; -use webxr_api::DeviceAPI; -use webxr_api::DiscoveryAPI; -use webxr_api::Display; -use webxr_api::Error; -use webxr_api::Event; -use webxr_api::EventBuffer; -use webxr_api::Floor; -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; +use webxr_api::{ + BaseSpace, Capture, ContextId, DeviceAPI, DiscoveryAPI, Display, Error, Event, EventBuffer, + Floor, Frame, GLContexts, InputId, InputSource, LayerGrandManager, LayerId, LayerInit, + LayerManager, LayerManagerAPI, LeftEye, Native, Quitter, RightEye, SelectKind, Sender, + Session as WebXrSession, SessionBuilder, SessionInit, SessionMode, SubImage, SubImages, View, + ViewerPose, Viewport, Viewports, Views, Visibility, +}; + +use crate::gl_utils::GlClearer; +use crate::SurfmanGL; mod input; use input::OpenXRInput; @@ -173,10 +138,10 @@ struct ViewInfo<Eye> { impl<Eye> ViewInfo<Eye> { fn set_view(&mut self, view: openxr::View, clip_planes: ClipPlanes) { self.view.pose = view.pose; - if self.view.fov.angle_left != view.fov.angle_left - || self.view.fov.angle_right != view.fov.angle_right - || self.view.fov.angle_up != view.fov.angle_up - || self.view.fov.angle_down != view.fov.angle_down + if self.view.fov.angle_left != view.fov.angle_left || + self.view.fov.angle_right != view.fov.angle_right || + self.view.fov.angle_up != view.fov.angle_up || + self.view.fov.angle_down != view.fov.angle_down { // It's fine if this happens occasionally, but if this happening very // often we should stop caching @@ -239,9 +204,9 @@ pub fn create_instance( warn!("Available extensions:\n{:?}", supported); let mut supports_hands = needs_hands && supported.ext_hand_tracking; let supports_passthrough = needs_passthrough && supported.fb_passthrough; - let supports_secondary = needs_secondary - && supported.msft_secondary_view_configuration - && supported.msft_first_person_observer; + let supports_secondary = needs_secondary && + supported.msft_secondary_view_configuration && + supported.msft_first_person_observer; let supports_updating_framerate = supported.fb_display_refresh_rate; let app_info = ApplicationInfo { @@ -364,9 +329,9 @@ impl DiscoveryAPI<SurfmanGL> for OpenXrDiscovery { ViewConfigurationType::PRIMARY_STEREO, ) { if mode == SessionMode::ImmersiveAR { - supports = blend_modes.contains(&EnvironmentBlendMode::ADDITIVE) - || blend_modes.contains(&EnvironmentBlendMode::ALPHA_BLEND) - || instance.supports_passthrough; + supports = blend_modes.contains(&EnvironmentBlendMode::ADDITIVE) || + blend_modes.contains(&EnvironmentBlendMode::ALPHA_BLEND) || + instance.supports_passthrough; } else if mode == SessionMode::ImmersiveVR { // Immersive VR sessions are not precluded by non-opaque blending supports = blend_modes.len() > 0; @@ -568,7 +533,7 @@ impl LayerManagerAPI<SurfmanGL> for OpenXrLayerManager { None }; - let layer_id = LayerId::new(); + let layer_id = LayerId::default(); let openxr_layer = OpenXrLayer::new(swapchain, depth_stencil_texture, texture_size)?; self.layers.push((context_id, layer_id)); self.openxr_layers.insert(layer_id, openxr_layer); @@ -1101,14 +1066,14 @@ impl OpenXrDevice { Err(e) => { error!("Error polling events: {:?}", e); return false; - } + }, }; match event { Some(SessionStateChanged(session_change)) => match session_change.state() { openxr::SessionState::EXITING | openxr::SessionState::LOSS_PENDING => { self.events.callback(Event::SessionEnd); return false; - } + }, openxr::SessionState::STOPPING => { self.events .callback(Event::VisibilityChange(Visibility::Hidden)); @@ -1116,7 +1081,7 @@ impl OpenXrDevice { error!("Session failed to end on STOPPING: {:?}", e); } stopped = true; - } + }, openxr::SessionState::READY if stopped => { self.events .callback(Event::VisibilityChange(Visibility::Visible)); @@ -1124,23 +1089,23 @@ impl OpenXrDevice { error!("Session failed to begin on READY: {:?}", e); } stopped = false; - } + }, openxr::SessionState::FOCUSED => { self.events .callback(Event::VisibilityChange(Visibility::Visible)); - } + }, openxr::SessionState::VISIBLE => { self.events .callback(Event::VisibilityChange(Visibility::VisibleBlurred)); - } + }, _ => { // FIXME: Handle other states - } + }, }, Some(InstanceLossPending(_)) => { self.events.callback(Event::SessionEnd); return false; - } + }, Some(InteractionProfileChanged(_)) => { let path = self.instance.string_to_path("/user/hand/right").unwrap(); let profile_path = self.session.current_interaction_profile(path).unwrap(); @@ -1162,12 +1127,12 @@ impl OpenXrDevice { new_right.profiles.clone_from(&profiles); self.events .callback(Event::UpdateInput(new_right.id, new_right)); - } + }, Err(e) => { error!("Failed to get interaction profile: {:?}", e); - } + }, } - } + }, Some(ReferenceSpaceChangePending(e)) => { let base_space = match e.reference_space_type() { ReferenceSpaceType::VIEW => BaseSpace::Viewer, @@ -1181,18 +1146,18 @@ impl OpenXrDevice { let transform = transform(&e.pose_in_previous_space()); self.events .callback(Event::ReferenceSpaceChanged(base_space, transform)); - } + }, Some(_) => { // FIXME: Handle other events - } + }, None if stopped => { // XXXManishearth be able to handle exits during this time thread::sleep(Duration::from_millis(200)); - } + }, None => { // No more events to process break; - } + }, } } true @@ -1225,8 +1190,8 @@ impl SharedData { if let Some(ref secondary) = self.secondary { let secondary_vp = Rect::new( Point2D::new(self.left.extent.width + self.right.extent.width, 0), - Size2D::new(secondary.extent.width, secondary.extent.height) - / SECONDARY_VIEW_DOWNSCALE, + Size2D::new(secondary.extent.width, secondary.extent.height) / + SECONDARY_VIEW_DOWNSCALE, ); viewports.push(secondary_vp) } @@ -1268,7 +1233,7 @@ impl DeviceAPI for OpenXrDevice { ContextMenuResult::ExitSession => { self.quit(); return None; - } + }, ContextMenuResult::Dismissed => self.context_menu_future = None, ContextMenuResult::Pending => (), } @@ -1280,7 +1245,7 @@ impl DeviceAPI for OpenXrDevice { Err(e) => { error!("Error waiting on frame: {:?}", e); return None; - } + }, }; assert_eq!( @@ -1294,7 +1259,7 @@ impl DeviceAPI for OpenXrDevice { Err(e) => { error!("Error waiting on frame: {:?}", e); return None; - } + }, } }; @@ -1315,7 +1280,7 @@ impl DeviceAPI for OpenXrDevice { Err(e) => { error!("Error locating views: {:?}", e); return None; - } + }, }; if !self.supports_mutable_fov { views.iter_mut().for_each(|v| { @@ -1332,7 +1297,7 @@ impl DeviceAPI for OpenXrDevice { Err(e) => { error!("Error locating viewer space: {:?}", e); return None; - } + }, }; let transform = transform(&pose.pose); @@ -1349,7 +1314,7 @@ impl DeviceAPI for OpenXrDevice { Err(e) => { error!("Error locating views: {:?}", e); return None; - } + }, }; secondary.set_view(view, self.clip_planes); } @@ -1472,22 +1437,22 @@ impl DeviceAPI for OpenXrDevice { Err(e) => { error!("Error polling for event while quitting: {:?}", e); break; - } + }, }; match event { Some(openxr::Event::SessionStateChanged(session_change)) => { match session_change.state() { openxr::SessionState::EXITING => { break; - } + }, openxr::SessionState::STOPPING => { if let Err(e) = self.session.end() { error!("Session failed to end while STOPPING: {:?}", e); } - } + }, _ => (), } - } + }, _ => (), } thread::sleep(Duration::from_millis(30)); @@ -1565,7 +1530,7 @@ impl DeviceAPI for OpenXrDevice { } else { None } - } + }, Err(_) => None, } } diff --git a/components/webxr/surfman_layer_manager.rs b/components/webxr/surfman_layer_manager.rs index 33ef961b4a8..5b6f0fdbfaf 100644 --- a/components/webxr/surfman_layer_manager.rs +++ b/components/webxr/surfman_layer_manager.rs @@ -4,11 +4,11 @@ //! 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::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::{Context as SurfmanContext, Device as SurfmanDevice, SurfaceAccess, SurfaceTexture}; use webxr_api::{ @@ -16,7 +16,9 @@ use webxr_api::{ SubImages, Viewports, }; -#[derive(Copy, Clone, Debug)] +use crate::gl_utils::GlClearer; + +#[derive(Clone, Copy, Debug)] pub enum SurfmanGL {} impl GLTypes for SurfmanGL { @@ -63,7 +65,7 @@ impl LayerManagerAPI<SurfmanGL> for SurfmanLayerManager { init: LayerInit, ) -> Result<LayerId, Error> { let texture_size = init.texture_size(&self.viewports); - let layer_id = LayerId::new(); + let layer_id = LayerId::default(); let access = SurfaceAccess::GPUOnly; let size = texture_size.to_untyped(); // TODO: Treat depth and stencil separately? diff --git a/ports/servoshell/Cargo.toml b/ports/servoshell/Cargo.toml index 0ce645879f9..b13c251ce89 100644 --- a/ports/servoshell/Cargo.toml +++ b/ports/servoshell/Cargo.toml @@ -53,7 +53,7 @@ tracing-hitrace = ["tracing", "dep:hitrace"] tracing-perfetto = ["tracing", "dep:tracing-perfetto"] webdriver = ["libservo/webdriver"] webgl_backtrace = ["libservo/webgl_backtrace"] -webxr = ["dep:webxr", "libservo/webxr"] +webxr = ["libservo/webxr"] webgpu = ["libservo/webgpu"] [dependencies] @@ -101,7 +101,6 @@ xcomponent-sys = { version = "0.3.1", features = ["api-12", "keyboard-types"] } nix = { workspace = true, features = ["fs"] } surfman = { workspace = true, features = ["sm-angle-default"] } serde_json = { workspace = true } -webxr = { workspace = true, optional = true } [target.'cfg(not(any(target_os = "android", target_env = "ohos")))'.dependencies] # For optional feature servo_allocator/use-system-allocator @@ -123,7 +122,6 @@ serde_json = { workspace = true } shellwords = "1.0.0" surfman = { workspace = true, features = ["sm-x11", "sm-raw-window-handle-06"] } tinyfiledialogs = "3.0" -webxr = { workspace = true, features = ["ipc", "glwindow", "headless"] } winit = "0.30.8" [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" [target.'cfg(target_os = "windows")'.dependencies] -webxr = { workspace = true, features = ["ipc", "glwindow", "headless", "openxr-api"] } windows-sys = { workspace = true, features = ["Win32_Graphics_Gdi"] } libservo = { path = "../../components/servo", features = ["no-wgl"] } diff --git a/ports/servoshell/desktop/app.rs b/ports/servoshell/desktop/app.rs index c9b30ab669e..806341c2215 100644 --- a/ports/servoshell/desktop/app.rs +++ b/ports/servoshell/desktop/app.rs @@ -20,12 +20,12 @@ use servo::config::prefs::Preferences; use servo::servo_config::pref; use servo::servo_url::ServoUrl; 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 surfman::Connection; use url::Url; -use webxr::glwindow::GlWindowDiscovery; -#[cfg(target_os = "windows")] -use webxr::openxr::{AppInfo, OpenXrDiscovery}; use winit::application::ApplicationHandler; use winit::event::WindowEvent; use winit::event_loop::{ActiveEventLoop, ControlFlow}; diff --git a/ports/servoshell/desktop/embedder.rs b/ports/servoshell/desktop/embedder.rs index d4c20573ac7..ccb4e5fde84 100644 --- a/ports/servoshell/desktop/embedder.rs +++ b/ports/servoshell/desktop/embedder.rs @@ -7,10 +7,10 @@ use net::protocols::ProtocolRegistry; use servo::compositing::windowing::EmbedderMethods; use servo::servo_config::pref; -use servo::{EmbedderProxy, EventLoopWaker}; -use webxr::glwindow::GlWindowDiscovery; +use servo::webxr::glwindow::GlWindowDiscovery; #[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}; @@ -45,11 +45,13 @@ impl EmbedderMethods for EmbedderCallbacks { #[cfg(feature = "webxr")] fn register_webxr( &mut self, - xr: &mut webxr::MainThreadRegistry, + xr: &mut servo::webxr::MainThreadRegistry, _embedder_proxy: EmbedderProxy, ) { + use servo::webxr::headless::HeadlessMockDiscovery; + 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() { match xr_discovery { XrDiscovery::GlWindow(discovery) => xr.register(discovery), diff --git a/ports/servoshell/desktop/headed_window.rs b/ports/servoshell/desktop/headed_window.rs index 798519b17c3..38dea704497 100644 --- a/ports/servoshell/desktop/headed_window.rs +++ b/ports/servoshell/desktop/headed_window.rs @@ -636,7 +636,7 @@ impl WindowPortsMethods for Window { fn new_glwindow( &self, 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 window_attr = winit::window::Window::default_attributes() @@ -734,12 +734,12 @@ struct XRWindowPose { xr_translation: Cell<Vector3D<f32, UnknownUnit>>, } -impl webxr::glwindow::GlWindow for XRWindow { +impl servo::webxr::glwindow::GlWindow for XRWindow { fn get_render_target( &self, device: &mut Device, _context: &mut Context, - ) -> webxr::glwindow::GlWindowRenderTarget { + ) -> servo::webxr::glwindow::GlWindowRenderTarget { self.winit_window.set_visible(true); let window_handle = self .winit_window @@ -751,7 +751,7 @@ impl webxr::glwindow::GlWindow for XRWindow { .connection() .create_native_widget_from_window_handle(window_handle, size) .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> { @@ -762,17 +762,17 @@ impl webxr::glwindow::GlWindow for XRWindow { 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) { - webxr::glwindow::GlWindowMode::StereoRedCyan + servo::webxr::glwindow::GlWindowMode::StereoRedCyan } else if pref!(dom_webxr_glwindow_left_right) { - webxr::glwindow::GlWindowMode::StereoLeftRight + servo::webxr::glwindow::GlWindowMode::StereoLeftRight } else if pref!(dom_webxr_glwindow_spherical) { - webxr::glwindow::GlWindowMode::Spherical + servo::webxr::glwindow::GlWindowMode::Spherical } else if pref!(dom_webxr_glwindow_cubemap) { - webxr::glwindow::GlWindowMode::Cubemap + servo::webxr::glwindow::GlWindowMode::Cubemap } else { - webxr::glwindow::GlWindowMode::Blit + servo::webxr::glwindow::GlWindowMode::Blit } } diff --git a/ports/servoshell/desktop/headless_window.rs b/ports/servoshell/desktop/headless_window.rs index 9e41adfbe42..efc53e5042c 100644 --- a/ports/servoshell/desktop/headless_window.rs +++ b/ports/servoshell/desktop/headless_window.rs @@ -123,7 +123,7 @@ impl WindowPortsMethods for Window { fn new_glwindow( &self, _events_loop: &winit::event_loop::ActiveEventLoop, - ) -> Rc<dyn webxr::glwindow::GlWindow> { + ) -> Rc<dyn servo::webxr::glwindow::GlWindow> { unimplemented!() } diff --git a/ports/servoshell/desktop/window_trait.rs b/ports/servoshell/desktop/window_trait.rs index 91338ac7aed..8f481140273 100644 --- a/ports/servoshell/desktop/window_trait.rs +++ b/ports/servoshell/desktop/window_trait.rs @@ -49,7 +49,7 @@ pub trait WindowPortsMethods: WindowMethods { fn new_glwindow( &self, 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 toolbar_height(&self) -> Length<f32, DeviceIndependentPixel>; fn set_toolbar_height(&self, height: Length<f32, DeviceIndependentPixel>); diff --git a/ports/servoshell/egl/android/simpleservo.rs b/ports/servoshell/egl/android/simpleservo.rs index c9c5f6481d3..03286bd4427 100644 --- a/ports/servoshell/egl/android/simpleservo.rs +++ b/ports/servoshell/egl/android/simpleservo.rs @@ -35,7 +35,7 @@ pub struct InitOptions { pub coordinates: Coordinates, pub density: f32, #[cfg(feature = "webxr")] - pub xr_discovery: Option<webxr::Discovery>, + pub xr_discovery: Option<servo::webxr::Discovery>, pub surfman_integration: SurfmanIntegration, } diff --git a/ports/servoshell/egl/servo_glue.rs b/ports/servoshell/egl/servo_glue.rs index 8bb38e5fc3d..5311f2a197c 100644 --- a/ports/servoshell/egl/servo_glue.rs +++ b/ports/servoshell/egl/servo_glue.rs @@ -681,13 +681,13 @@ impl ServoGlue { pub(super) struct ServoEmbedderCallbacks { waker: Box<dyn EventLoopWaker>, #[cfg(feature = "webxr")] - xr_discovery: Option<webxr::Discovery>, + xr_discovery: Option<servo::webxr::Discovery>, } impl ServoEmbedderCallbacks { pub(super) fn new( waker: Box<dyn EventLoopWaker>, - #[cfg(feature = "webxr")] xr_discovery: Option<webxr::Discovery>, + #[cfg(feature = "webxr")] xr_discovery: Option<servo::webxr::Discovery>, ) -> Self { Self { waker, @@ -706,7 +706,7 @@ impl EmbedderMethods for ServoEmbedderCallbacks { #[cfg(feature = "webxr")] fn register_webxr( &mut self, - registry: &mut webxr::MainThreadRegistry, + registry: &mut servo::webxr::MainThreadRegistry, _embedder_proxy: EmbedderProxy, ) { debug!("EmbedderMethods::register_xr"); diff --git a/servo-tidy.toml b/servo-tidy.toml index 355350ba0be..76c6c016462 100644 --- a/servo-tidy.toml +++ b/servo-tidy.toml @@ -29,9 +29,6 @@ files = [ ] # Directories that are ignored for the non-WPT tidy check. 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. "./support/crown/tests", # Upstream |