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

WebVR API Implementation #14618

Merged
merged 1 commit into from Jan 9, 2017
Merged

WebVR API Implementation #14618

merged 1 commit into from Jan 9, 2017

Conversation

@MortimerGoro
Copy link
Contributor

MortimerGoro commented Dec 16, 2016

WebVR API Implementation with HTC Vive support on Windows. The current implementations only enables the WebVR support on Windows. In other platforms the API is available on JavaScript but navigator.vr.getDisplays() returns an empty array. This will change when we add support for more VR providers and platforms ;)

Info about the architecture:
https://blog.mozvr.com/webvr-servo-architecture-and-latency-optimizations/

  • ./mach build -d does not report any errors
  • ./mach test-tidy does not report any errors
  • These changes fix #__ (github issue number if applicable).
  • There are tests for these changes OR
  • These changes do not require tests because _____

Proprietary openvr.dll must be copied next to servo.exe in order to test on HTC Vive (https://github.com/ValveSoftware/openvr/tree/master/bin/win64) I have added some of the official WebVR samples for testing. Switch on your headset and run:

mach run tests/html/webvr/room-scale.html


This change is Reviewable

@highfive
Copy link

highfive commented Dec 16, 2016

Heads up! This PR modifies the following files:

  • @asajeffrey: components/constellation/lib.rs, components/constellation/pipeline.rs, components/constellation/Cargo.toml, components/constellation/constellation.rs
  • @KiChjang: components/script/dom/webidls/VRDisplayCapabilities.webidl, components/script/dom/navigator.rs, components/script/dom/vrdisplay.rs, components/script/dom/webidls/VRFrameData.webidl, components/script/dom/mod.rs, components/script/dom/vr.rs, components/script/dom/vrdisplaycapabilities.rs, components/script/dom/vrstageparameters.rs, components/script/dom/vrdisplayevent.rs, components/script/dom/window.rs, components/script/dom/webidls/VREyeParameters.webidl, components/script_traits/lib.rs, components/script_traits/lib.rs, components/script/lib.rs, components/script/dom/webidls/Window.webidl, components/script/dom/vreyeparameters.rs, components/script/dom/webidls/VRStageParameters.webidl, components/script/dom/vrframedata.rs, components/script/dom/macros.rs, components/script/dom/vrpose.rs, components/script/dom/webidls/Navigator.webidl, components/script/dom/webidls/VR.webidl, components/script/dom/webidls/VRPose.webidl, components/script/Cargo.toml, components/script/dom/webidls/VRDisplay.webidl, components/script/dom/webidls/VRDisplayEvent.webidl, components/script/script_thread.rs, components/script/script_runtime.rs, components/script/dom/vrfieldofview.rs, components/script/dom/webidls/VRFieldOfView.webidl, components/script/dom/bindings/conversions.rs, components/script/dom/webidls/VRLayer.webidl, components/script_traits/Cargo.toml, components/script_traits/Cargo.toml
  • @fitzgen: components/script/dom/webidls/VRDisplayCapabilities.webidl, components/script/dom/navigator.rs, components/script/dom/vrdisplay.rs, components/script/dom/webidls/VRFrameData.webidl, components/script/dom/mod.rs, components/script/dom/vr.rs, components/script/dom/vrdisplaycapabilities.rs, components/script/dom/vrstageparameters.rs, components/script/dom/vrdisplayevent.rs, components/script/dom/window.rs, components/script/dom/webidls/VREyeParameters.webidl, components/script_traits/lib.rs, components/script_traits/lib.rs, components/script/lib.rs, components/script/dom/webidls/Window.webidl, components/script/dom/vreyeparameters.rs, components/script/dom/webidls/VRStageParameters.webidl, components/script/dom/vrframedata.rs, components/script/dom/macros.rs, components/script/dom/vrpose.rs, components/script/dom/webidls/Navigator.webidl, components/script/dom/webidls/VR.webidl, components/script/dom/webidls/VRPose.webidl, components/profile/time.rs, components/script/Cargo.toml, components/script/dom/webidls/VRDisplay.webidl, components/profile_traits/time.rs, components/profile_traits/time.rs, components/script/dom/webidls/VRDisplayEvent.webidl, components/script/script_thread.rs, components/script/script_runtime.rs, components/script/dom/vrfieldofview.rs, components/script/dom/webidls/VRFieldOfView.webidl, components/script/dom/bindings/conversions.rs, components/script/dom/webidls/VRLayer.webidl, components/script_traits/Cargo.toml, components/script_traits/Cargo.toml
  • @emilio: components/canvas/webgl_paint_thread.rs
@highfive
Copy link

highfive commented Dec 16, 2016

warning Warning warning

  • These commits modify unsafe code. Please review it carefully!
  • These commits modify script code, but no tests are modified. Please consider adding a test!
Copy link
Member

emilio left a comment

Just some mostly-superficial comments, since @larsbergstrom has kindly offered to take over the review.

I guess adding automatic tests for this is not truly feasible? Is there a plan to test this stuff?

@@ -2197,6 +2207,13 @@ impl ScriptThread {
}
}

fn handle_webvr_event(&self, pipeline_id: PipelineId, event: WebVREventMsg) {
if let Some(window) = self.documents.borrow().find_window(pipeline_id) {

This comment has been minimized.

Copy link
@emilio

emilio Dec 16, 2016

Member

Use a different variable for this, see #14589.

sender
}

#[allow(unsafe_code)]

This comment has been minimized.

Copy link
@emilio

emilio Dec 16, 2016

Member

there doesn't seem to be unsafe code here?


fn poll_events(&mut self, sender: IpcSender<bool>) {
let events = self.service.poll_events();
if events.len() > 0 {

This comment has been minimized.

Copy link
@emilio

emilio Dec 16, 2016

Member

if !events.is_empty()

}

fn schedule_poll_events(&mut self) {
if self.service.is_initialized() && !self.polling_events {

This comment has been minimized.

Copy link
@emilio

emilio Dec 16, 2016

Member

nit: Probably nicer to read as:

if !self.service.is_initialized() || self.polling_events {
    return;
}

// ...
// WebVR Thread asked to unschedule this thread
break;
}
thread::sleep(time::Duration::from_millis(500));

This comment has been minimized.

Copy link
@emilio

emilio Dec 16, 2016

Member

This seems quite arbitrary. I understand why it's this way, but probably worth moving the 500 to a constant.

// This also avoids "JS DDoS" attacks: A Second JSContext doing a lot of calls.
// while the main one is presenting and demands both high framerate and low latency.

pub struct WebVRCompositor(*mut VRDevice);

This comment has been minimized.

Copy link
@emilio

emilio Dec 16, 2016

Member

huh, this is going to need a better comment explaining how it's used and why it's safe and not racy.

This comment has been minimized.

Copy link
@emilio

emilio Dec 16, 2016

Member

Also, would be helpful to know when this VRDevice can be null or not, and how does is this VRDevice freed, since I don't see any Drop impl.

(*compositor.0).sync_poses();
(*compositor.0).synced_frame_data(near, far).to_bytes()
};
let _result = sender.send(Ok(pose));

This comment has been minimized.

Copy link
@emilio

emilio Dec 16, 2016

Member

The patterns let _ = sender.send(..) or drop(sender.send()) seem more used across the codebase.

impl WebVRCompositorHandler {
#[allow(unsafe_code)]
fn create_compositor(&mut self, device_id: webrender_traits::VRCompositorId) {
if let Some(ref sender) = self.webvr_thread_sender {

This comment has been minimized.

Copy link
@emilio

emilio Dec 16, 2016

Member

Probably worth:

let sender = match self.webvr_thread_sender {
    Some(ref s) => s,
    None => return,
};
}
}

pub fn set_webvr_thread_sender(&mut self, sender: IpcSender<WebVRMsg>) {

This comment has been minimized.

Copy link
@emilio

emilio Dec 16, 2016

Member

Worth pointing here with a comment that this is done only a per-platform basis on initialization.

@@ -119,6 +120,8 @@ pub struct InitialPipelineState {
pub webrender_api_sender: webrender_traits::RenderApiSender,
/// Whether this pipeline is considered private.
pub is_private: bool,
/// A channel to the webvr thread.
pub webvr_thread: Option<IpcSender<WebVRMsg>>,

This comment has been minimized.

Copy link
@asajeffrey

asajeffrey Dec 16, 2016

Member

When is this used?

This comment has been minimized.

Copy link
@MortimerGoro

MortimerGoro Dec 16, 2016

Author Contributor

It's used to create the ScriptThreadFactory. When a script thread is created it gets a cloned handle to the webvr_thread sender. This sender is used by DOMObjects to comunicate with the WebVRThread and send messages like: getDisplays, requestPresent, etc.

@MortimerGoro MortimerGoro force-pushed the MortimerGoro:webvr_api branch from 35a11fb to 5e9a162 Dec 16, 2016
@MortimerGoro
Copy link
Contributor Author

MortimerGoro commented Dec 16, 2016

@emilio WRT automated testing it could be done with mocked devices, but it requires more work: like setting up predefined pose animations and comparing images submitted to the display. I have an initial implementation of a MockVRDevice and @dmarcos was working on a mock openvr_api.dll. @dmarcos is there any plan for official WebVR conformance tests? Maybe you have talked about that in the latest W3C workshop/meetings.

@dmarcos
Copy link
Contributor

dmarcos commented Dec 16, 2016

@MortimerGoro @emilio No official plan for conformance tests. There's a face to face meeting scheduled in January that will touch the subject (among other things). I think in the short we can use your MockVRDevice. In the mid term and for cross browser testing will be better to implement a mock OpenVR driver (instead of the full OpenVR API implementation I had started). In the long term we will probably move to the driver standard that is supposed to come from the khronos vr effort.

@Ms2ger
Copy link
Contributor

Ms2ger commented Dec 17, 2016

Seems like this should all be behind a pref.

@MortimerGoro
Copy link
Contributor Author

MortimerGoro commented Dec 17, 2016

@Ms2ger Sounds good, I'll add a new pref to https://github.com/servo/servo/blob/master/components/config/opts.rs that decides if the WebVR API is enabled.

@jdm
Copy link
Member

jdm commented Dec 17, 2016

@MortimerGoro It belongs in resources/prefs.json and annotated in the WebIDL files using [Pref=] instead of a command-line option.

@MortimerGoro
Copy link
Contributor Author

MortimerGoro commented Dec 17, 2016

@jdm Thanks for the info, never had played with that json before ;)

Copy link
Member

nox left a comment

Started looking at it a bit.

@@ -463,6 +466,9 @@ pub unsafe trait ArrayBufferViewContents: Clone {
/// Check if the JS ArrayBufferView type is compatible with the implementor of the
/// trait
fn is_type_compatible(ty: Type) -> bool;

/// Creates a typed array
fn new(cx: *mut JSContext, num: u32) -> *mut JSObject;

This comment has been minimized.

Copy link
@nox

nox Dec 18, 2016

Member

This should be unsafe.

@@ -595,3 +633,25 @@ pub unsafe fn is_array_like(cx: *mut JSContext, value: HandleValue) -> bool {
assert!(JS_IsArrayObject(cx, value, &mut result));
result
}

/// Creates a typed JS array from a Rust slice
pub fn slice_to_array_buffer_view<T>(cx: *mut JSContext, data: &[T]) -> *mut JSObject

This comment has been minimized.

Copy link
@nox

nox Dec 18, 2016

Member

This should be unsafe.


impl Navigator {
pub fn handle_webvr_event(&self, event: WebVREventMsg) {
if let Some(vr) = self.vr.get() {

This comment has been minimized.

Copy link
@nox

nox Dec 18, 2016

Member

How can this be called with self.vr being None?

return promise;
}

if let Some(wevbr_sender) = self.webvr_thread() {

This comment has been minimized.

Copy link
@nox

nox Dec 18, 2016

Member

Spelling of webvr_sender is wrong, and it is weird to call the variable sender when the method says thread.

capabilities: DOMRefCell<WebVRDisplayCapabilities>
}

// Wrappers required to include WebVR structs in a DOM struct

This comment has been minimized.

Copy link
@nox

nox Dec 18, 2016

Member

Why?


impl VRDisplayEvent {
fn new_inherited(display: &VRDisplay,
reason: &Option<VRDisplayEventReason>)

This comment has been minimized.

Copy link
@nox

nox Dec 18, 2016

Member

Why a ref? Pass Option<VRDisplayEventReason>.

display: &VRDisplay,
event: &webvr::VRDisplayEvent)
-> Root<VRDisplayEvent> {
let (name, reason) = match event {

This comment has been minimized.

Copy link
@nox

nox Dec 18, 2016

Member

Nit: match *event.

fov: JS<VRFieldOfView>,
}

// Wrappers required to include WebVR structs in a DOM struct

This comment has been minimized.

Copy link
@nox

nox Dec 18, 2016

Member

Why?

This comment has been minimized.

Copy link
@MortimerGoro

MortimerGoro Dec 19, 2016

Author Contributor

I added the wrappers because Rust didn't allow to implement no_jsmanaged_fields macro or JSTraceable for structs defined in a different crate. I have done a test with the latest rustc compiler used in Servo and it seems to work now. I'll get rid of them now ;)

let (name, reason) = match event {
&webvr::VRDisplayEvent::Connect(_) => ("displayconnect", None),
&webvr::VRDisplayEvent::Disconnect(_) => ("displaydisconnect", None),
&webvr::VRDisplayEvent::Activate(_, ref reason) => ("activate", Some(reason)),

This comment has been minimized.

Copy link
@nox

nox Dec 18, 2016

Member

Why ref? Seems to me like VRDisplayEventReason should be Clone and Copy.


impl VREyeParameters {
#[allow(unrooted_must_root)]
fn new_inherited(parameters: &webvr::VREyeParameters, global: &GlobalScope) -> VREyeParameters {

This comment has been minimized.

Copy link
@nox

nox Dec 18, 2016

Member

Why a reference?

Copy link

cvan left a comment

just feedback from having worked on the spec and helped Kip with Gecko implementation + bugs in the past. I'm not familiar with Rust, so take my webdev ergonomics POV with a grain of salt.

I'd like to iron out the event issues, but all means if the reviewers here okay this PR, feel free to proceed.

truly great work - this is really inspiring to see.

self.webvr_thread = Some(webvr_thread)
}
FromCompositorMsg::WebVREvent(pipeline_ids, event) => {
debug!("constellation got webvr event message");

This comment has been minimized.

Copy link
@cvan

cvan Dec 19, 2016

is the message part necessary?

This comment has been minimized.

Copy link
@emilio

emilio Dec 19, 2016

Member

Also, if we go this spell-checking mode, you may want to capitalize WebVR :P

@@ -1181,6 +1195,13 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
}
}

if let Some(chan) = self.webvr_thread.as_ref() {
debug!("Exiting WebVR thread.");

This comment has been minimized.

Copy link
@cvan

cvan Dec 19, 2016

should this be logged outside the if check (à la above)?

This comment has been minimized.

Copy link
@MortimerGoro

MortimerGoro Dec 19, 2016

Author Contributor

I included it inside the if because WebVR can be disabled and it didn't make sense to show that message in that case. I checked and the same pattern is used in ""Exiting devtools" too ;)

@@ -151,6 +151,7 @@ impl Formattable for ProfilerCategory {
ProfilerCategory::ScriptServiceWorkerEvent => "Script Service Worker Event",
ProfilerCategory::ScriptEnterFullscreen => "Script Enter Fullscreen",
ProfilerCategory::ScriptExitFullscreen => "Script Exit Fullscreen",
ProfilerCategory::ScriptWebVREvent => "Script Web VR Event",

This comment has been minimized.

Copy link
@cvan

cvan Dec 19, 2016

one word: WebVR

@@ -495,6 +495,13 @@ macro_rules! window_event_handlers(
event_handler!(unhandledrejection, GetOnunhandledrejection,
SetOnunhandledrejection);
event_handler!(unload, GetOnunload, SetOnunload);
event_handler!(vrdisplayconnect, GetOnvrdisplayconnect, SetOnvrdisplayconnect);

This comment has been minimized.

Copy link
@cvan

cvan Dec 19, 2016

I couldn't find one, but is there an issue no track to move these events from window to the VRDisplay interface?

(See immersive-web/webxr#152.)

This comment has been minimized.

Copy link
@cvan

cvan Dec 19, 2016

but then I see you're implementing navigator.vr.getDisplays instead of navigator.getVRDisplays(). these events should be emitted from the VRDisplay instances not off of window.

This comment has been minimized.

Copy link
@MortimerGoro

MortimerGoro Dec 19, 2016

Author Contributor

Yes, I'll remove these ones. I started implementing 1.1 API but moved to 1.2. These events are already moved to VRDisplay instances (in the implementation and samples)

self.displays.borrow()
.iter()
.find(|d| d.get_display_id() == display_id)
.map(|d| Root::from_ref(&**d))

This comment has been minimized.

Copy link
@cvan

cvan Dec 19, 2016

intentionally no semicolons here?

This comment has been minimized.

Copy link
@MortimerGoro

MortimerGoro Dec 19, 2016

Author Contributor

Yes, because it's a implicit return

serde_derive = "0.8"
rust-webvr = {version = "0.1", features = ["serde-serialization"] }


This comment has been minimized.

Copy link
@cvan

cvan Dec 19, 2016

feel free to remove these two superfluous newlines, but keep a single one at EOF

msg = {path = "../msg"}
serde = "0.8"
serde_derive = "0.8"
rust-webvr = {version = "0.1", features = ["serde-serialization"] }

This comment has been minimized.

Copy link
@cvan

cvan Dec 19, 2016

can remove the space before the closing curly brace at the end: }


pub type WebVRResult<T> = Result<T, String>;

// Messages from Script Thread to WebVR thread.

This comment has been minimized.

Copy link
@cvan

cvan Dec 19, 2016

Script Thread -> Script thread


if let Some(wevbr_sender) = self.webvr_thread() {
let (sender, receiver) = ipc::channel().unwrap();
wevbr_sender.send(WebVRMsg::GetVRDisplays(sender)).unwrap();

This comment has been minimized.

Copy link
@cvan

cvan Dec 19, 2016

also: GetDisplays

RegisterContext(PipelineId),
UnregisterContext(PipelineId),
PollEvents(IpcSender<bool>),
GetVRDisplays(IpcSender<WebVRResult<Vec<VRDisplayData>>>),

This comment has been minimized.

Copy link
@cvan

cvan Dec 19, 2016

same here: GetDisplays

Copy link
Member

emilio left a comment

I took a closer look, here are a few comments :)

@@ -209,6 +209,7 @@ impl<'a> CanvasPaintThread<'a> {
}
}
CanvasMsg::WebGL(_) => panic!("Wrong message sent to Canvas2D thread"),
CanvasMsg::WebVR(_) => panic!("Wrong message sent to Canvas2D thread"),

This comment has been minimized.

Copy link
@emilio

emilio Dec 19, 2016

Member

It'd be nice to differentiate these error messages now.

WebGLPaintTaskData::WebRender(ref api, id) => {
api.send_vr_compositor_command(id, message);
}
WebGLPaintTaskData::Readback(_, _, _) => {

This comment has been minimized.

Copy link
@emilio

emilio Dec 19, 2016

Member

nit: You can use WebGLPaintTaskData::Readback(..) if you want.

@@ -872,6 +879,13 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
FromCompositorMsg::LogEntry(top_level_frame_id, thread_name, entry) => {
self.handle_log_entry(top_level_frame_id, thread_name, entry);
}
FromCompositorMsg::SetWebVRThread(webvr_thread) => {
self.webvr_thread = Some(webvr_thread)

This comment has been minimized.

Copy link
@emilio

emilio Dec 19, 2016

Member

Probably is worth sanity-checking with something like: assert!(self.webvr_thread.is_none())

self.webvr_thread = Some(webvr_thread)
}
FromCompositorMsg::WebVREvent(pipeline_ids, event) => {
debug!("constellation got webvr event message");

This comment has been minimized.

Copy link
@emilio

emilio Dec 19, 2016

Member

Also, if we go this spell-checking mode, you may want to capitalize WebVR :P

fn Vr(&self) -> Root<VR> {
self.vr.or_init(|| VR::new(&self.global()))
}

This comment has been minimized.

Copy link
@emilio

emilio Dec 19, 2016

Member

nit: Extra newline.


pub fn new(global: &GlobalScope, pose: &webvr::VRPose) -> Root<VRPose> {
let root = reflect_dom_object(box VRPose::new_inherited(),
global,

This comment has been minimized.

Copy link
@emilio

emilio Dec 19, 2016

Member

nit: Indentation


// https://w3c.github.io/webvr/#interface-vrlayer

//typedef (HTMLCanvasElement or OffscreenCanvas) VRSource;

This comment has been minimized.

Copy link
@emilio

emilio Dec 19, 2016

Member

Thanks for filling that :)

It's probably fine to add typedef HTMLCanvasElement VRSource for now, but I don't think it's worth it.

default_features = false
features = ["serde_derive"]


This comment has been minimized.

Copy link
@emilio

emilio Dec 19, 2016

Member

Yeah, please delete these trailing newlines.

use vr_traits::webvr::*;
use webrender_traits;

// Defines the polling interval time in ms for VR Events such as VRDevice connected, disconnected, etc.

This comment has been minimized.

Copy link
@emilio

emilio Dec 19, 2016

Member

Also, I think you can use doc comments for these.

// * WebVRCompositorHandler is stopped automatically when a JS tab is closed or the whole browser is closed.
// * WebVRThread and it's VRDevices are destroyed after all tabs are dropped and the browser is about to exit.
// WebVRThread is closed using the Exit message.

This comment has been minimized.

Copy link
@emilio

emilio Dec 19, 2016

Member

Doc comment above, then remove this newline :)

@MortimerGoro MortimerGoro force-pushed the MortimerGoro:webvr_api branch from 5e9a162 to 8e1208b Dec 20, 2016
@MortimerGoro
Copy link
Contributor Author

MortimerGoro commented Dec 20, 2016

@nox @jdm @emilio @larsbergstrom @cvan @Ms2ger Thanks for the feedback. I have updated the PR:

  • Everything is behind the dom.webvr.enabled preference now
  • Used expect instead of if let Some() in places where the webvr_thread is guaranteed to be enabled
  • Renamed VRDevice to VRDisplay
  • Fixed nits
  • There are two trivial TODOs (getLayers and activeDisplays functions) because of a issue with the python WebIDL code autogeneration tool: it crashes when using readonly attribute sequence<T> pattern. I'll fill a issue about this.
@MortimerGoro MortimerGoro force-pushed the MortimerGoro:webvr_api branch 3 times, most recently from 566ecdc to ac3df0f Dec 20, 2016
@@ -208,7 +208,8 @@ impl<'a> CanvasPaintThread<'a> {
}
}
}
CanvasMsg::WebGL(_) => panic!("Wrong message sent to Canvas2D thread"),
CanvasMsg::WebGL(_) => panic!("Wrong WebGLmessage sent to Canvas2D thread"),

This comment has been minimized.

Copy link
@larsbergstrom

larsbergstrom Dec 21, 2016

Contributor

nit: space between WebGL and message

#[allow(unsafe_code)]
// https://w3c.github.io/webvr/#dom-vrpose-linearacceleration
unsafe fn GetLinearAcceleration(&self, _cx: *mut JSContext) -> Option<NonZero<*mut JSObject>> {
heap_to_option(&self.linear_vel)

This comment has been minimized.

Copy link
@larsbergstrom

larsbergstrom Dec 21, 2016

Contributor

Should this be &self.linear_acc?

@@ -473,6 +475,8 @@ pub struct ScriptThread {
content_process_shutdown_chan: IpcSender<()>,

promise_job_queue: PromiseJobQueue,
/// A handle to the webvr thread, if available

This comment has been minimized.

Copy link
@larsbergstrom

larsbergstrom Dec 21, 2016

Contributor

nit: blank line before this comment (they are roughly separated by "area")

@@ -284,7 +289,8 @@ impl fmt::Debug for ConstellationControlMsg {
DispatchStorageEvent(..) => "DispatchStorageEvent",
FramedContentChanged(..) => "FramedContentChanged",
ReportCSSError(..) => "ReportCSSError",
Reload(..) => "Reload"
Reload(..) => "Reload",
WebVREvent(..) => "WebVREvent"

This comment has been minimized.

Copy link
@larsbergstrom

larsbergstrom Dec 21, 2016

Contributor

nit: we usually keep the trailing , in the final line of a match. It helps both with consistency and if you add more entries to the end, as the diff is one line shorter :-)

@@ -7,6 +7,7 @@
"dom.serviceworker.timeout_seconds": 60,
"dom.testable_crash.enabled": false,
"dom.testbinding.enabled": false,
"dom.webvr.enabled": true,

This comment has been minimized.

Copy link
@larsbergstrom

larsbergstrom Dec 21, 2016

Contributor

This should be false by default

if !events.is_empty() {
let pipeline_ids: Vec<PipelineId> = self.contexts.iter().map(|c| *c).collect();
for event in events {
let event = WebVREventMsg::DisplayEvent(event);

This comment has been minimized.

Copy link
@larsbergstrom

larsbergstrom Dec 21, 2016

Contributor

There's a bit of duplicated code here with notify_events except for the lifting of the pipeline_ids. Can this be shared?


fn poll_events(&mut self, sender: IpcSender<bool>) {
let events = self.service.poll_events();
if !events.is_empty() {

This comment has been minimized.

Copy link
@larsbergstrom

larsbergstrom Dec 21, 2016

Contributor

Can more events come in while you are handling the current set? Elsewhere in Servo event polling threads, we use a pattern that is more like while (events = poll_events() && !events.is_empty()) { ... } to avoid falling into the polling delay interval during periods of rapid interactions / event floods.

/// by flooding the WebVRThread with messages while the main JavaScript tab is presenting to the headset.
/// Multithreading won't be a problem because:
/// * Thanks to the security rules implemented in the WebVRThread, when a VRDisplay is in a presenting loop
/// no other JSContext is granted access to the VRDisplay. So really there aren’t multithreading race conditions.

This comment has been minimized.

Copy link
@larsbergstrom

larsbergstrom Dec 21, 2016

Contributor

I assume that this is the access_check method above? If so, please make a comment about its importance near that method so people don't accidentally remove / "optimize" it away :-)

This comment has been minimized.

Copy link
@MortimerGoro

MortimerGoro Dec 22, 2016

Author Contributor

Yes, I added more comments ;)


/// WebVRThread owns native VRDisplays, handles their life cycle inside Servo and
/// acts a doorman for untrusted VR requests from DOM Objects.
/// It waits for VR Commands from DOM objects and handles them in its trusted thread.

This comment has been minimized.

Copy link
@larsbergstrom

larsbergstrom Dec 21, 2016

Contributor

Could you add some more info on the design here? There are some long-running and short-lived threads plus communication back with the constellation and the lifetimes and expectations for some of the parts was not totally clear without a pretty deep reading. e.g., which threads have a lifetime tied to a pipeline vs. a single GetDisplays request vs. etc.

use webvr_traits::webvr::*;

/// Defines the polling interval time in ms for VR Events such as VRDisplay connected, disconnected, etc.
const EVENT_POLLING_INTERVAL: u64 = 500;

This comment has been minimized.

Copy link
@larsbergstrom

larsbergstrom Dec 21, 2016

Contributor

How was this chosen? I'm not against a hardcoded polling interval, but is there a reason to believe that 500 is the right number?

This comment has been minimized.

Copy link
@MortimerGoro

MortimerGoro Dec 22, 2016

Author Contributor

Good question. There isn't a formula to decide the perfect value, but 500 seemed like a good balance between resource usage and desired precision. I saw similar values in native games and other implementations. In general these events (ie discovering new displays) don't need very high precision. We can reduce the value if needed because the pooling thread is only active when there is an active tab using WebVR APIs.

This comment has been minimized.

Copy link
@cvan

cvan Dec 23, 2016

can this constant be a pref?

}

fn register(&self) {
if let Some(wevbr_sender) = self.webvr_thread() {

This comment has been minimized.

Copy link
@emilio

emilio Dec 21, 2016

Member

Spelling is wrong.

}

fn unregister(&self) {
if let Some(wevbr_sender) = self.webvr_thread() {

This comment has been minimized.

Copy link
@emilio

emilio Dec 21, 2016

Member

and here.

@larsbergstrom
Copy link
Contributor

larsbergstrom commented Dec 21, 2016

@MortimerGoro Nice work - things are getting close! I think that @emilio and I have a few more issues to address but that it's almost there. There will certainly be some follow-up issues for the bigger items especially that @cvan mentioned, but they shouldn't block getting this landed pretty soon.

@MortimerGoro MortimerGoro force-pushed the MortimerGoro:webvr_api branch 2 times, most recently from 00b1897 to 85ce70c Dec 22, 2016
@MortimerGoro
Copy link
Contributor Author

MortimerGoro commented Dec 22, 2016

@larsbergstrom @emilio PR updated!

@bors-servo
Copy link
Contributor

bors-servo commented Dec 23, 2016

The latest upstream changes (presumably #14684) made this pull request unmergeable. Please resolve the merge conflicts.

@bors-servo
Copy link
Contributor

bors-servo commented Jan 7, 2017

The latest upstream changes (presumably #14874) made this pull request unmergeable. Please resolve the merge conflicts.

@jdm
Copy link
Member

jdm commented Jan 7, 2017

Sorry, that was #14323. We can keep working on merging it after a rebase.

@MortimerGoro MortimerGoro force-pushed the MortimerGoro:webvr_api branch from 47ccd82 to c5705bf Jan 9, 2017
@MortimerGoro
Copy link
Contributor Author

MortimerGoro commented Jan 9, 2017

@jdm Ok, no problem. Rebase done and fixed proc_macro attribute no longer needed warnings with the latest rust compiler.

@emilio
Copy link
Member

emilio commented Jan 9, 2017

@bors-servo r=larsbergstrom,emilio,jdm,nox,asajeffrey,cvan

@bors-servo
Copy link
Contributor

bors-servo commented Jan 9, 2017

📌 Commit c5705bf has been approved by larsbergstrom,emilio,jdm,nox,asajeffrey,cvan

@bors-servo
Copy link
Contributor

bors-servo commented Jan 9, 2017

Testing commit c5705bf with merge 47b776f...

bors-servo added a commit that referenced this pull request Jan 9, 2017
…,jdm,nox,asajeffrey,cvan

WebVR API Implementation

<!-- Please describe your changes on the following line: -->

WebVR API Implementation with HTC Vive support on Windows. The current implementations only enables the WebVR support on Windows. In other platforms the API is available on JavaScript but navigator.vr.getDisplays() returns an empty array. This will change when we add support for more VR providers and platforms ;)

Info about the architecture:
https://blog.mozvr.com/webvr-servo-architecture-and-latency-optimizations/
---
<!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `__` with appropriate data: -->
- [X] `./mach build -d` does not report any errors
- [X] `./mach test-tidy` does not report any errors
- [ ] These changes fix #__ (github issue number if applicable).

<!-- Either: -->
- [X] There are tests for these changes OR
- [ ] These changes do not require tests because _____

Proprietary openvr.dll must be copied next to servo.exe in order to test on HTC Vive (https://github.com/ValveSoftware/openvr/tree/master/bin/win64) I have added some of the official WebVR samples for testing. Switch on your headset and run:

mach run tests/html/webvr/room-scale.html

<!-- 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/14618)
<!-- Reviewable:end -->
@bors-servo
Copy link
Contributor

bors-servo commented Jan 9, 2017

💔 Test failed - linux-dev

@jdm
Copy link
Member

jdm commented Jan 9, 2017

@bors-servo: retry

  • linker failed; might be disk space.
@bors-servo
Copy link
Contributor

bors-servo commented Jan 9, 2017

Testing commit c5705bf with merge 518ef39...

bors-servo added a commit that referenced this pull request Jan 9, 2017
…,jdm,nox,asajeffrey,cvan

WebVR API Implementation

<!-- Please describe your changes on the following line: -->

WebVR API Implementation with HTC Vive support on Windows. The current implementations only enables the WebVR support on Windows. In other platforms the API is available on JavaScript but navigator.vr.getDisplays() returns an empty array. This will change when we add support for more VR providers and platforms ;)

Info about the architecture:
https://blog.mozvr.com/webvr-servo-architecture-and-latency-optimizations/
---
<!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `__` with appropriate data: -->
- [X] `./mach build -d` does not report any errors
- [X] `./mach test-tidy` does not report any errors
- [ ] These changes fix #__ (github issue number if applicable).

<!-- Either: -->
- [X] There are tests for these changes OR
- [ ] These changes do not require tests because _____

Proprietary openvr.dll must be copied next to servo.exe in order to test on HTC Vive (https://github.com/ValveSoftware/openvr/tree/master/bin/win64) I have added some of the official WebVR samples for testing. Switch on your headset and run:

mach run tests/html/webvr/room-scale.html

<!-- 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/14618)
<!-- Reviewable:end -->
@bors-servo bors-servo merged commit c5705bf into servo:master Jan 9, 2017
2 of 3 checks passed
2 of 3 checks passed
continuous-integration/travis-ci/pr The Travis CI build failed
Details
continuous-integration/appveyor/pr AppVeyor build succeeded
Details
homu Test successful
Details
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked issues

Successfully merging this pull request may close these issues.

None yet

You can’t perform that action at this time.