Skip to content
Permalink
Browse files

Auto merge of #23731 - Manishearth:webxr-script, r=asajeffrey

Use new WebXR API in script

Todo:
 - [x] Hook new `Frame` information into `XRFrame`
 - [x] Make spaces use new transform info
 - [x] Hook up session view metadata correctly
 - [x] Get mocking working again
 - [x] Get inputs working

Optional todos:
 - [x] Add support for active and animationFrame bool on XRFrame
 - [x] Correctly handle viewer and offset spaces instead of casting
 - [x] Error on zero-length quaternions

<s>Not really ready for review yet, but you can go ahead and review what I have so far. It doesn't do anything yet, aside from crash horribly. I'm opening this PR early so i have a place to track progress.</s>

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/23731)
<!-- Reviewable:end -->
  • Loading branch information...
bors-servo committed Jul 11, 2019
2 parents 677f26d + c5a0fc5 commit 5fdc7c0d2c787ef562809072e3dd7c3258dc8a83
Showing with 702 additions and 485 deletions.
  1. +3 −2 Cargo.lock
  2. +20 −4 components/canvas/webgl_thread.rs
  3. +5 −3 components/canvas_traits/webgl.rs
  4. +2 −0 components/config/prefs.rs
  5. +1 −0 components/script/Cargo.toml
  6. +15 −3 components/script/dom/bindings/trace.rs
  7. +43 −38 components/script/dom/fakexrdevice.rs
  8. +16 −198 components/script/dom/vrdisplay.rs
  9. +0 −4 components/script/dom/vreyeparameters.rs
  10. +2 −4 components/script/dom/webidls/FakeXRDevice.webidl
  11. +1 −1 components/script/dom/webidls/XRSession.webidl
  12. +1 −1 components/script/dom/webidls/XRTest.webidl
  13. +2 −1 components/script/dom/webidls/XRView.webidl
  14. +9 −0 components/script/dom/window.rs
  15. +120 −32 components/script/dom/xr.rs
  16. +28 −14 components/script/dom/xrframe.rs
  17. +12 −24 components/script/dom/xrinputsource.rs
  18. +2 −2 components/script/dom/xrpose.rs
  19. +13 −13 components/script/dom/xrreferencespace.rs
  20. +20 −2 components/script/dom/xrrenderstate.rs
  21. +29 −19 components/script/dom/xrrigidtransform.rs
  22. +203 −32 components/script/dom/xrsession.rs
  23. +15 −19 components/script/dom/xrspace.rs
  24. +86 −13 components/script/dom/xrtest.rs
  25. +14 −23 components/script/dom/xrview.rs
  26. +15 −10 components/script/dom/xrviewerpose.rs
  27. +1 −0 components/script/script_thread.rs
  28. +1 −1 ports/glutin/Cargo.toml
  29. +13 −12 ports/glutin/embedder.rs
  30. +1 −0 resources/prefs.json
  31. +2 −2 tests/wpt/mozilla/meta/MANIFEST.json
  32. +2 −2 tests/wpt/mozilla/tests/webxr/obtain_frame.html
  33. +5 −6 tests/wpt/mozilla/tests/webxr/resources/webxr-util.js

Some generated files are not rendered by default. Learn more.

@@ -9,6 +9,7 @@ use euclid::Size2D;
use fnv::FnvHashMap;
use gleam::gl;
use half::f16;
use ipc_channel::ipc::IpcSender;
use offscreen_gl_context::{DrawBuffer, GLContext, NativeGLContextMethods};
use pixels::{self, PixelFormat};
use std::borrow::Cow;
@@ -181,6 +182,9 @@ impl<VR: WebVRRenderHandler + 'static> WebGLThread<VR> {
WebGLMsg::Lock(ctx_id, sender) => {
self.handle_lock(ctx_id, sender);
},
WebGLMsg::LockIPC(ctx_id, sender) => {
self.handle_lock_ipc(ctx_id, sender);
},
WebGLMsg::Unlock(ctx_id) => {
self.handle_unlock(ctx_id);
},
@@ -231,13 +235,27 @@ impl<VR: WebVRRenderHandler + 'static> WebGLThread<VR> {
);
}
}

/// Handles a lock external callback received from webrender::ExternalImageHandler
fn handle_lock(
&mut self,
context_id: WebGLContextId,
sender: WebGLSender<(u32, Size2D<i32>, usize)>,
) {
sender.send(self.handle_lock_inner(context_id)).unwrap();
}

/// handle_lock, but unconditionally IPC (used by webxr)
fn handle_lock_ipc(
&mut self,
context_id: WebGLContextId,
sender: IpcSender<(u32, Size2D<i32>, usize)>,
) {
sender.send(self.handle_lock_inner(context_id)).unwrap();
}

/// Shared code between handle_lock and handle_lock_ipc, does the actual syncing/flushing
/// but the caller must send the response back
fn handle_lock_inner(&mut self, context_id: WebGLContextId) -> (u32, Size2D<i32>, usize) {
let data =
Self::make_current_if_needed(context_id, &self.contexts, &mut self.bound_context_id)
.expect("WebGLContext not found in a WebGLMsg::Lock message");
@@ -251,9 +269,7 @@ impl<VR: WebVRRenderHandler + 'static> WebGLThread<VR> {
// Without proper flushing, the sync object may never be signaled.
data.ctx.gl().flush();

sender
.send((info.texture_id, info.size, gl_sync as usize))
.unwrap();
(info.texture_id, info.size, gl_sync as usize)
}

/// Handles an unlock external callback received from webrender::ExternalImageHandler
@@ -7,7 +7,7 @@ use gleam::gl;
use gleam::gl::GLsync;
use gleam::gl::GLuint;
use gleam::gl::Gl;
use ipc_channel::ipc::{IpcBytesReceiver, IpcBytesSender, IpcSender, IpcSharedMemory};
use ipc_channel::ipc::{self, IpcBytesReceiver, IpcBytesSender, IpcSender, IpcSharedMemory};
use pixels::PixelFormat;
use std::borrow::Cow;
use std::fmt;
@@ -61,6 +61,8 @@ pub enum WebGLMsg {
/// The WR client should not change the shared texture content until the Unlock call.
/// Currently OpenGL Sync Objects are used to implement the synchronization mechanism.
Lock(WebGLContextId, WebGLSender<(u32, Size2D<i32>, usize)>),
/// Lock(), but unconditionally IPC (used by webxr)
LockIPC(WebGLContextId, IpcSender<(u32, Size2D<i32>, usize)>),
/// Unlocks a specific WebGLContext. Unlock messages are used for a correct synchronization
/// with WebRender external image API.
/// The WR unlocks a context when it finished reading the shared texture contents.
@@ -195,9 +197,9 @@ struct SerializableWebGLMsgSender {
#[typetag::serde]
impl webxr_api::WebGLExternalImageApi for SerializableWebGLMsgSender {
fn lock(&self) -> Result<(GLuint, Size2D<i32>, GLsync), webxr_api::Error> {
let (sender, receiver) = webgl_channel().or(Err(webxr_api::Error::CommunicationError))?;
let (sender, receiver) = ipc::channel().or(Err(webxr_api::Error::CommunicationError))?;
self.sender
.send(WebGLMsg::Lock(self.ctx_id, sender))
.send(WebGLMsg::LockIPC(self.ctx_id, sender))
.or(Err(webxr_api::Error::CommunicationError))?;
let (texture, size, sync) = receiver
.recv()
@@ -296,6 +296,8 @@ mod gen {
enabled: bool,
#[serde(default)]
test: bool,
#[serde(default)]
glwindow: bool,
},
worklet: {
blockingsleep: {
@@ -105,6 +105,7 @@ style_traits = {path = "../style_traits"}
swapper = "0.1"
tendril = {version = "0.4.1", features = ["encoding_rs"]}
time = "0.1.12"
typetag = "0.1"
unicode-segmentation = "1.1.0"
url = "1.6"
utf-8 = "0.7"
@@ -57,8 +57,8 @@ use devtools_traits::{CSSError, TimelineMarkerType, WorkerId};
use encoding_rs::{Decoder, Encoding};
use euclid::Length as EuclidLength;
use euclid::{
Point2D, Rect, RigidTransform3D, Rotation3D, Transform2D, Transform3D, TypedScale, TypedSize2D,
Vector2D,
Point2D, Rect, RigidTransform3D, Rotation3D, Transform2D, Transform3D, TypedRigidTransform3D,
TypedScale, TypedSize2D, Vector2D,
};
use html5ever::buffer_queue::BufferQueue;
use html5ever::{LocalName, Namespace, Prefix, QualName};
@@ -486,7 +486,12 @@ unsafe_no_jsmanaged_fields!(WebGLVersion);
unsafe_no_jsmanaged_fields!(WebGLSLVersion);
unsafe_no_jsmanaged_fields!(MediaList);
unsafe_no_jsmanaged_fields!(WebVRGamepadData, WebVRGamepadState, WebVRGamepadHand);
unsafe_no_jsmanaged_fields!(webxr_api::Registry);
unsafe_no_jsmanaged_fields!(
webxr_api::Registry,
webxr_api::Session,
webxr_api::Frame,
webxr_api::InputSource
);
unsafe_no_jsmanaged_fields!(ScriptToConstellationChan);
unsafe_no_jsmanaged_fields!(InteractiveMetrics);
unsafe_no_jsmanaged_fields!(InteractiveWindow);
@@ -607,6 +612,13 @@ unsafe impl<T, U> JSTraceable for TypedScale<f32, T, U> {
}
}

unsafe impl<T, U> JSTraceable for TypedRigidTransform3D<f32, T, U> {
#[inline]
unsafe fn trace(&self, _trc: *mut JSTracer) {
// Do nothing
}
}

unsafe impl<T> JSTraceable for EuclidLength<u64, T> {
#[inline]
unsafe fn trace(&self, _trc: *mut JSTracer) {
@@ -7,43 +7,39 @@ use crate::dom::bindings::codegen::Bindings::FakeXRDeviceBinding::{
};
use crate::dom::bindings::codegen::Bindings::XRViewBinding::XREye;
use crate::dom::bindings::error::{Error, Fallible};
use crate::dom::bindings::reflector::{reflect_dom_object, DomObject, Reflector};
use crate::dom::bindings::reflector::{reflect_dom_object, Reflector};
use crate::dom::bindings::root::DomRoot;
use crate::dom::globalscope::GlobalScope;
use dom_struct::dom_struct;
use webvr_traits::{MockVRControlMsg, MockVRView, WebVRMsg};
use euclid::{TypedRigidTransform3D, TypedRotation3D, TypedTransform3D, TypedVector3D};
use ipc_channel::ipc::IpcSender;
use webxr_api::{MockDeviceMsg, View, Views};

#[dom_struct]
pub struct FakeXRDevice {
reflector: Reflector,
#[ignore_malloc_size_of = "defined in ipc-channel"]
sender: IpcSender<MockDeviceMsg>,
}

impl FakeXRDevice {
pub fn new_inherited() -> FakeXRDevice {
pub fn new_inherited(sender: IpcSender<MockDeviceMsg>) -> FakeXRDevice {
FakeXRDevice {
reflector: Reflector::new(),
sender,
}
}

pub fn new(global: &GlobalScope) -> DomRoot<FakeXRDevice> {
pub fn new(global: &GlobalScope, sender: IpcSender<MockDeviceMsg>) -> DomRoot<FakeXRDevice> {
reflect_dom_object(
Box::new(FakeXRDevice::new_inherited()),
Box::new(FakeXRDevice::new_inherited(sender)),
global,
FakeXRDeviceBinding::Wrap,
)
}

fn send_msg(&self, msg: MockVRControlMsg) {
self.global()
.as_window()
.webvr_thread()
.unwrap()
.send(WebVRMsg::MessageMockDisplay(msg))
.unwrap();
}
}

pub fn get_views(views: &[FakeXRViewInit]) -> Fallible<(MockVRView, MockVRView)> {
pub fn get_views(views: &[FakeXRViewInit]) -> Fallible<Views> {
if views.len() != 2 {
return Err(Error::NotSupported);
}
@@ -66,45 +62,53 @@ pub fn get_views(views: &[FakeXRViewInit]) -> Fallible<(MockVRView, MockVRView)>
let mut proj_r = [0.; 16];
let v: Vec<_> = left.projectionMatrix.iter().map(|x| **x).collect();
proj_l.copy_from_slice(&v);
let proj_l = TypedTransform3D::from_array(proj_l);
let v: Vec<_> = right.projectionMatrix.iter().map(|x| **x).collect();
proj_r.copy_from_slice(&v);
let proj_r = TypedTransform3D::from_array(proj_r);

// spec defines offsets as origins, but mock API expects the inverse transform
let offset_l = get_origin(&left.viewOffset)?.inverse();
let offset_r = get_origin(&right.viewOffset)?.inverse();

let mut offset_l = [0.; 3];
let mut offset_r = [0.; 3];
let v: Vec<_> = left.viewOffset.position.iter().map(|x| **x).collect();
offset_l.copy_from_slice(&v);
let v: Vec<_> = right.viewOffset.position.iter().map(|x| **x).collect();
offset_r.copy_from_slice(&v);
let left = MockVRView {
let left = View {
projection: proj_l,
offset: offset_l,
transform: offset_l,
};
let right = MockVRView {
let right = View {
projection: proj_r,
offset: offset_r,
transform: offset_r,
};
Ok((left, right))
Ok(Views::Stereo(left, right))
}

pub fn get_origin(origin: &FakeXRRigidTransformInit) -> Fallible<([f32; 3], [f32; 4])> {
pub fn get_origin<T, U>(
origin: &FakeXRRigidTransformInit,
) -> Fallible<TypedRigidTransform3D<f32, T, U>> {
if origin.position.len() != 3 || origin.orientation.len() != 4 {
return Err(Error::Type("Incorrectly sized array".into()));
}
let mut p = [0.; 3];
let mut o = [0.; 4];
let v: Vec<_> = origin.position.iter().map(|x| **x).collect();
p.copy_from_slice(&v[0..3]);
let v: Vec<_> = origin.orientation.iter().map(|x| **x).collect();
o.copy_from_slice(&v);
let p = TypedVector3D::new(
*origin.position[0],
*origin.position[1],
*origin.position[2],
);
let o = TypedRotation3D::unit_quaternion(
*origin.orientation[0],
*origin.orientation[1],
*origin.orientation[2],
*origin.orientation[3],
);

Ok((p, o))
Ok(TypedRigidTransform3D::new(o, p))
}

impl FakeXRDeviceMethods for FakeXRDevice {
/// https://github.com/immersive-web/webxr-test-api/blob/master/explainer.md
fn SetViews(&self, views: Vec<FakeXRViewInit>) -> Fallible<()> {
let (left, right) = get_views(&views)?;
self.send_msg(MockVRControlMsg::SetViews(left, right));
let _ = self
.sender
.send(MockDeviceMsg::SetViews(get_views(&views)?));
Ok(())
}

@@ -114,8 +118,9 @@ impl FakeXRDeviceMethods for FakeXRDevice {
origin: &FakeXRRigidTransformInit,
_emulated_position: bool,
) -> Fallible<()> {
let (position, orientation) = get_origin(origin)?;
self.send_msg(MockVRControlMsg::SetViewerPose(position, orientation));
let _ = self
.sender
.send(MockDeviceMsg::SetViewerOrigin(get_origin(origin)?));
Ok(())
}
}

0 comments on commit 5fdc7c0

Please sign in to comment.
You can’t perform that action at this time.