Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use new WebXR API in script #23731

Merged
merged 19 commits into from Jul 12, 2019
Merged
Changes from all commits
Commits
File filter...
Filter file types
Jump to…
Jump to file
Failed to load files.

Always

Just for now

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]
This conversation was marked as resolved by asajeffrey

This comment has been minimized.

Copy link
@asajeffrey

asajeffrey Jul 9, 2019

Member

Oh that's annoying, unsafe_no_jsmanaged_fields! doesn't like generics?

This comment has been minimized.

Copy link
@jdm

jdm Jul 9, 2019

Member

It definitely does:

unsafe_no_jsmanaged_fields!(RefCell<Decoder>);

This comment has been minimized.

Copy link
@jdm

jdm Jul 9, 2019

Member

My mistake. It's intentional, because we've been bitten by too-broad generic implementations before.

This comment has been minimized.

Copy link
@asajeffrey

asajeffrey Jul 9, 2019

Member

OK, makes sense I guess.

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);

This comment has been minimized.

Copy link
@asajeffrey

asajeffrey Jul 10, 2019

Member

Might want to support mono at some point.

This comment has been minimized.

Copy link
@Manishearth

Manishearth Jul 11, 2019

Author Member

Yeah, inline support needs a bit more work

}
@@ -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();

This conversation was marked as resolved by Manishearth

This comment has been minimized.

Copy link
@asajeffrey

asajeffrey Jul 10, 2019

Member

s/left/right/?

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],
);
This conversation was marked as resolved by asajeffrey

This comment has been minimized.

Copy link
@asajeffrey

asajeffrey Jul 10, 2019

Member

Can we store a TypedRotation3D in FakeXRTransformInit?

This comment has been minimized.

Copy link
@Manishearth

Manishearth Jul 10, 2019

Author Member

No, it's a dictionary, we don't control it.

This comment has been minimized.

Copy link
@asajeffrey

asajeffrey Jul 10, 2019

Member

Oh well.


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(())
}
}
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.