Skip to content

Commit

Permalink
webxr: Update XRSession to latest spec (servo#33059)
Browse files Browse the repository at this point in the history
* Add missing XRSession members, initial implementations

Signed-off-by: Daniel Adams <[email protected]>

* Implement supportedFramerates getter

Signed-off-by: Daniel Adams <[email protected]>

* Implement framerate changes, add spec links

Signed-off-by: Daniel Adams <[email protected]>

* Update WPT expectations

Signed-off-by: Daniel Adams <[email protected]>

* ./mach fmt

Signed-off-by: Daniel Adams <[email protected]>

* Add missing spec link

Signed-off-by: Daniel Adams <[email protected]>

---------

Signed-off-by: Daniel Adams <[email protected]>
  • Loading branch information
msub2 authored Aug 17, 2024
1 parent f0045a7 commit 20273b0
Show file tree
Hide file tree
Showing 7 changed files with 132 additions and 62 deletions.
2 changes: 1 addition & 1 deletion components/script/dom/bindings/codegen/Bindings.conf
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ DOMInterfaces = {
},

'XRSession': {
'inRealms': ['UpdateRenderState', 'RequestReferenceSpace'],
'inRealms': ['UpdateRenderState', 'RequestReferenceSpace', 'UpdateTargetFrameRate'],
},

'Bluetooth': {
Expand Down
6 changes: 6 additions & 0 deletions components/script/dom/webidls/XRSession.webidl
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,16 @@ callback XRFrameRequestCallback = undefined (DOMHighResTimeStamp time, XRFrame f
interface XRSession : EventTarget {
// Attributes
readonly attribute XRVisibilityState visibilityState;
readonly attribute float? frameRate;
readonly attribute Float32Array? supportedFrameRates;
[SameObject] readonly attribute XRRenderState renderState;
[SameObject] readonly attribute XRInputSourceArray inputSources;
readonly attribute /*FrozenArray<DOMString>*/ any enabledFeatures;
readonly attribute boolean isSystemKeyboardSupported;

// Methods
[Throws] undefined updateRenderState(optional XRRenderStateInit state = {});
Promise<undefined> updateTargetFrameRate(float rate);
Promise<XRReferenceSpace> requestReferenceSpace(XRReferenceSpaceType type);

long requestAnimationFrame(XRFrameRequestCallback callback);
Expand All @@ -49,6 +54,7 @@ interface XRSession : EventTarget {
attribute EventHandler onsqueezestart;
attribute EventHandler onsqueezeend;
attribute EventHandler onvisibilitychange;
attribute EventHandler onframeratechange;

// AR Module
// Attributes
Expand Down
126 changes: 125 additions & 1 deletion components/script/dom/xrsession.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,27 @@
use std::cell::Cell;
use std::collections::HashMap;
use std::f64::consts::{FRAC_PI_2, PI};
use std::mem;
use std::rc::Rc;
use std::{mem, ptr};

use dom_struct::dom_struct;
use euclid::{RigidTransform3D, Transform3D, Vector3D};
use ipc_channel::ipc::IpcReceiver;
use ipc_channel::router::ROUTER;
use js::jsapi::JSObject;
use js::jsval::JSVal;
use js::typedarray::Float32Array;
use metrics::ToMs;
use profile_traits::ipc;
use servo_atoms::Atom;
use webxr_api::{
self, util, ApiSpace, ContextId as WebXRContextId, Display, EntityTypes, EnvironmentBlendMode,
Event as XREvent, Frame, FrameUpdateEvent, HitTestId, HitTestSource, InputFrame, InputId, Ray,
SelectEvent, SelectKind, Session, SessionId, View, Viewer, Visibility,
};

use super::bindings::trace::HashMapTracedValues;
use crate::dom::bindings::buffer_source::create_buffer_source;
use crate::dom::bindings::callback::ExceptionHandling;
use crate::dom::bindings::cell::DomRefCell;
use crate::dom::bindings::codegen::Bindings::NavigatorBinding::Navigator_Binding::NavigatorMethods;
Expand All @@ -39,9 +44,11 @@ use crate::dom::bindings::codegen::Bindings::XRSessionBinding::{
use crate::dom::bindings::codegen::Bindings::XRSystemBinding::XRSessionMode;
use crate::dom::bindings::error::{Error, ErrorResult};
use crate::dom::bindings::inheritance::Castable;
use crate::dom::bindings::num::Finite;
use crate::dom::bindings::refcounted::Trusted;
use crate::dom::bindings::reflector::{reflect_dom_object, DomObject};
use crate::dom::bindings::root::{Dom, DomRoot, MutDom, MutNullableDom};
use crate::dom::bindings::utils::to_frozen_array;
use crate::dom::event::Event;
use crate::dom::eventtarget::EventTarget;
use crate::dom::globalscope::GlobalScope;
Expand All @@ -56,6 +63,7 @@ use crate::dom::xrrenderstate::XRRenderState;
use crate::dom::xrsessionevent::XRSessionEvent;
use crate::dom::xrspace::XRSpace;
use crate::realms::InRealm;
use crate::script_runtime::JSContext;
use crate::task_source::TaskSource;

#[dom_struct]
Expand Down Expand Up @@ -97,6 +105,9 @@ pub struct XRSession {
#[ignore_malloc_size_of = "defined in webxr"]
#[no_trace]
input_frames: DomRefCell<HashMap<InputId, InputFrame>>,
framerate: Cell<f32>,
#[ignore_malloc_size_of = "promises are hard"]
update_framerate_promise: DomRefCell<Option<Rc<Promise>>>,
}

impl XRSession {
Expand Down Expand Up @@ -128,6 +139,8 @@ impl XRSession {
pending_hit_test_promises: DomRefCell::new(HashMapTracedValues::new()),
outside_raf: Cell::new(true),
input_frames: DomRefCell::new(HashMap::new()),
framerate: Cell::new(0.0),
update_framerate_promise: DomRefCell::new(None),
}
}

Expand Down Expand Up @@ -543,6 +556,24 @@ impl XRSession {
_ => self.session.borrow_mut().apply_event(event),
}
}

/// <https://www.w3.org/TR/webxr/#apply-the-nominal-frame-rate>
fn apply_nominal_framerate(&self, rate: f32) {
if self.framerate.get() == rate || self.ended.get() {
return;
}

self.framerate.set(rate);

let event = XRSessionEvent::new(
&self.global(),
Atom::from("frameratechange"),
false,
false,
self,
);
event.upcast::<Event>().fire(self.upcast());
}
}

impl XRSessionMethods for XRSession {
Expand Down Expand Up @@ -581,6 +612,9 @@ impl XRSessionMethods for XRSession {
SetOninputsourceschange
);

// https://www.w3.org/TR/webxr/#dom-xrsession-onframeratechange
event_handler!(frameratechange, GetOnframeratechange, SetOnframeratechange);

// https://immersive-web.github.io/webxr/#dom-xrsession-renderstate
fn RenderState(&self) -> DomRoot<XRRenderState> {
self.active_render_state.get()
Expand Down Expand Up @@ -881,6 +915,96 @@ impl XRSessionMethods for XRSession {
// this should always be world space
XRInteractionMode::World_space
}

/// <https://www.w3.org/TR/webxr/#dom-xrsession-framerate>
fn GetFrameRate(&self) -> Option<Finite<f32>> {
let session = self.session.borrow();
if self.mode == XRSessionMode::Inline || session.supported_frame_rates().is_empty() {
None
} else {
Finite::new(self.framerate.get())
}
}

/// <https://www.w3.org/TR/webxr/#dom-xrsession-supportedframerates>
fn GetSupportedFrameRates(&self, cx: JSContext) -> Option<Float32Array> {
let session = self.session.borrow();
if self.mode == XRSessionMode::Inline || session.supported_frame_rates().is_empty() {
None
} else {
let framerates = session.supported_frame_rates();
rooted!(in (*cx) let mut array = ptr::null_mut::<JSObject>());
Some(
create_buffer_source(cx, framerates, array.handle_mut())
.expect("Failed to construct supported frame rates array"),
)
}
}

/// <https://www.w3.org/TR/webxr/#dom-xrsession-enabledfeatures>
fn EnabledFeatures(&self, cx: JSContext) -> JSVal {
let session = self.session.borrow();
let features = session.granted_features();
to_frozen_array(features, cx)
}

/// <https://www.w3.org/TR/webxr/#dom-xrsession-issystemkeyboardsupported>
fn IsSystemKeyboardSupported(&self) -> bool {
// Support for this only exists on Meta headsets (no desktop support)
// so this will always be false until that changes
false
}

/// <https://www.w3.org/TR/webxr/#dom-xrsession-updatetargetframerate>
fn UpdateTargetFrameRate(&self, rate: Finite<f32>, comp: InRealm) -> Rc<Promise> {
let mut session = self.session.borrow_mut();
let supported_frame_rates = session.supported_frame_rates();
let promise = Promise::new_in_current_realm(comp);

if self.mode == XRSessionMode::Inline ||
supported_frame_rates.is_empty() ||
self.ended.get()
{
promise.reject_error(Error::InvalidState);
return promise;
}

if !supported_frame_rates.contains(&*rate) {
promise.reject_error(Error::Type("Provided framerate not supported".into()));
return promise;
}

*self.update_framerate_promise.borrow_mut() = Some(promise.clone());

let this = Trusted::new(self);
let global = self.global();
let window = global.as_window();
let (task_source, canceller) = window
.task_manager()
.dom_manipulation_task_source_with_canceller();
let (sender, receiver) = ipc::channel(global.time_profiler_chan().clone()).unwrap();

ROUTER.add_route(
receiver.to_opaque(),
Box::new(move |message| {
let this = this.clone();
let _ = task_source.queue_with_canceller(
task!(update_session_framerate: move || {
let session = this.root();
session.apply_nominal_framerate(message.to().unwrap());
if let Some(promise) = session.update_framerate_promise.borrow_mut().take() {
promise.resolve_native(&());
};
}),
&canceller,
);
}),
);

session.update_frame_rate(*rate, sender);

promise
}
}

// The pose of an object in native-space. Should never be exposed.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,4 @@
[depth_sensing_preferences.https.html]
[depthSensing - Required - Fully populated grants session]
expected: FAIL

[depthSensing - Required - Empty usage grants session]
expected: FAIL

[depthSensing - Required - Empty format grants session]
expected: FAIL

[depthSensing - Required - Empty usage and format grants session]
expected: FAIL

[depthSensing - Required - Missing usage rejects session]
expected: FAIL

Expand Down
18 changes: 0 additions & 18 deletions tests/wpt/meta-legacy-layout/webxr/idlharness.https.window.js.ini
Original file line number Diff line number Diff line change
Expand Up @@ -335,18 +335,6 @@
[XRWebGLLayer interface: xrWebGLLayer must inherit property "fixedFoveation" with the proper type]
expected: FAIL

[XRSession interface: attribute frameRate]
expected: FAIL

[XRSession interface: attribute supportedFrameRates]
expected: FAIL

[XRSession interface: operation updateTargetFrameRate(float)]
expected: FAIL

[XRSession interface: attribute onframeratechange]
expected: FAIL

[XRSession interface: xrSession must inherit property "frameRate" with the proper type]
expected: FAIL

Expand All @@ -365,15 +353,9 @@
[XRFrame interface: attribute predictedDisplayTime]
expected: FAIL

[XRSession interface: attribute enabledFeatures]
expected: FAIL

[XRSession interface: xrSession must inherit property "enabledFeatures" with the proper type]
expected: FAIL

[XRSession interface: attribute isSystemKeyboardSupported]
expected: FAIL

[XRSession interface: xrSession must inherit property "isSystemKeyboardSupported" with the proper type]
expected: FAIL

Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,4 @@
[depth_sensing_preferences.https.html]
[depthSensing - Required - Fully populated grants session]
expected: FAIL

[depthSensing - Required - Empty usage grants session]
expected: FAIL

[depthSensing - Required - Empty format grants session]
expected: FAIL

[depthSensing - Required - Empty usage and format grants session]
expected: FAIL

[depthSensing - Required - Missing usage rejects session]
expected: FAIL

Expand Down
18 changes: 0 additions & 18 deletions tests/wpt/meta/webxr/idlharness.https.window.js.ini
Original file line number Diff line number Diff line change
Expand Up @@ -278,18 +278,6 @@
[XRWebGLLayer interface: xrWebGLLayer must inherit property "fixedFoveation" with the proper type]
expected: FAIL

[XRSession interface: attribute frameRate]
expected: FAIL

[XRSession interface: attribute supportedFrameRates]
expected: FAIL

[XRSession interface: operation updateTargetFrameRate(float)]
expected: FAIL

[XRSession interface: attribute onframeratechange]
expected: FAIL

[XRSession interface: xrSession must inherit property "frameRate" with the proper type]
expected: FAIL

Expand All @@ -308,15 +296,9 @@
[XRFrame interface: attribute predictedDisplayTime]
expected: FAIL

[XRSession interface: attribute enabledFeatures]
expected: FAIL

[XRSession interface: xrSession must inherit property "enabledFeatures" with the proper type]
expected: FAIL

[XRSession interface: attribute isSystemKeyboardSupported]
expected: FAIL

[XRSession interface: xrSession must inherit property "isSystemKeyboardSupported" with the proper type]
expected: FAIL

Expand Down

0 comments on commit 20273b0

Please sign in to comment.