mirror of
https://github.com/servo/servo.git
synced 2025-06-06 16:45:39 +00:00
Remove WebVR
This commit is contained in:
parent
d8781c1054
commit
c611e46381
74 changed files with 97 additions and 3178 deletions
80
Cargo.lock
generated
80
Cargo.lock
generated
|
@ -530,7 +530,6 @@ dependencies = [
|
|||
"sparkle",
|
||||
"time",
|
||||
"webrender_api",
|
||||
"webvr_traits",
|
||||
"webxr-api",
|
||||
]
|
||||
|
||||
|
@ -764,7 +763,6 @@ dependencies = [
|
|||
"num-traits",
|
||||
"pixels",
|
||||
"profile_traits",
|
||||
"rust-webvr",
|
||||
"script_traits",
|
||||
"servo-media",
|
||||
"servo_geometry",
|
||||
|
@ -774,7 +772,6 @@ dependencies = [
|
|||
"toml",
|
||||
"webrender",
|
||||
"webrender_api",
|
||||
"webvr_traits",
|
||||
"webxr",
|
||||
]
|
||||
|
||||
|
@ -822,7 +819,6 @@ dependencies = [
|
|||
"style_traits",
|
||||
"webgpu",
|
||||
"webrender_api",
|
||||
"webvr_traits",
|
||||
"webxr-api",
|
||||
]
|
||||
|
||||
|
@ -3154,7 +3150,6 @@ dependencies = [
|
|||
"libc",
|
||||
"libservo",
|
||||
"log",
|
||||
"rust-webvr",
|
||||
"servo-egl",
|
||||
"simpleservo",
|
||||
"smallvec 0.6.10",
|
||||
|
@ -3214,8 +3209,6 @@ dependencies = [
|
|||
"webrender",
|
||||
"webrender_api",
|
||||
"webrender_traits",
|
||||
"webvr",
|
||||
"webvr_traits",
|
||||
"webxr",
|
||||
"webxr-api",
|
||||
]
|
||||
|
@ -3997,12 +3990,6 @@ dependencies = [
|
|||
"shared_library",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ovr-mobile-sys"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a69b517feac6fc640f0679625defa0998bbcb32871a6901e63063c2abf9c4cbe"
|
||||
|
||||
[[package]]
|
||||
name = "owning_ref"
|
||||
version = "0.4.0"
|
||||
|
@ -4611,40 +4598,6 @@ dependencies = [
|
|||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rust-webvr"
|
||||
version = "0.19.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a965d7b934fef625349e5f21774046da180000911140898235576a91dfbbe633"
|
||||
dependencies = [
|
||||
"bindgen",
|
||||
"euclid",
|
||||
"gl_generator 0.13.1",
|
||||
"gleam 0.9.2",
|
||||
"glutin",
|
||||
"gvr-sys",
|
||||
"libc",
|
||||
"libloading",
|
||||
"log",
|
||||
"ovr-mobile-sys",
|
||||
"rust-webvr-api",
|
||||
"sparkle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rust-webvr-api"
|
||||
version = "0.17.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "aeb2bc6eabb244825b6667e68ffe30e4647d629ba81f68f798ad9e4cec753edf"
|
||||
dependencies = [
|
||||
"android_injected_glue",
|
||||
"ipc-channel",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"sparkle",
|
||||
"time",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc-demangle"
|
||||
version = "0.1.4"
|
||||
|
@ -4801,7 +4754,6 @@ dependencies = [
|
|||
"webdriver",
|
||||
"webgpu",
|
||||
"webrender_api",
|
||||
"webvr_traits",
|
||||
"webxr-api",
|
||||
"xml5ever",
|
||||
]
|
||||
|
@ -4894,7 +4846,6 @@ dependencies = [
|
|||
"webdriver",
|
||||
"webgpu",
|
||||
"webrender_api",
|
||||
"webvr_traits",
|
||||
"webxr-api",
|
||||
]
|
||||
|
||||
|
@ -5004,7 +4955,6 @@ dependencies = [
|
|||
"log",
|
||||
"osmesa-src",
|
||||
"osmesa-sys",
|
||||
"rust-webvr",
|
||||
"servo-media",
|
||||
"shellwords",
|
||||
"sig",
|
||||
|
@ -6649,45 +6599,19 @@ dependencies = [
|
|||
"webrender_api",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "webvr"
|
||||
version = "0.0.1"
|
||||
dependencies = [
|
||||
"canvas_traits",
|
||||
"compositing",
|
||||
"crossbeam-channel",
|
||||
"euclid",
|
||||
"ipc-channel",
|
||||
"log",
|
||||
"msg",
|
||||
"rust-webvr",
|
||||
"rust-webvr-api",
|
||||
"servo_config",
|
||||
"sparkle",
|
||||
"webvr_traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "webvr_traits"
|
||||
version = "0.0.1"
|
||||
dependencies = [
|
||||
"ipc-channel",
|
||||
"msg",
|
||||
"rust-webvr-api",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "webxr"
|
||||
version = "0.0.1"
|
||||
source = "git+https://github.com/servo/webxr#2ff799c23431d5c20f38b49b211101c86cc1728f"
|
||||
dependencies = [
|
||||
"android_injected_glue",
|
||||
"bindgen",
|
||||
"crossbeam-channel",
|
||||
"euclid",
|
||||
"gl_generator 0.13.1",
|
||||
"gleam 0.9.2",
|
||||
"glutin",
|
||||
"gvr-sys",
|
||||
"log",
|
||||
"openxr",
|
||||
"serde",
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use crate::webgl_thread::{SurfaceProviders, WebGLThread, WebGLThreadInit, WebGlExecutor};
|
||||
use canvas_traits::webgl::{webgl_channel, WebVRRenderHandler};
|
||||
use canvas_traits::webgl::webgl_channel;
|
||||
use canvas_traits::webgl::{WebGLContextId, WebGLMsg, WebGLThreads};
|
||||
use euclid::default::Size2D;
|
||||
use fnv::FnvHashMap;
|
||||
|
@ -41,7 +41,6 @@ impl WebGLComm {
|
|||
context: Context,
|
||||
webrender_gl: Rc<dyn gleam::gl::Gl>,
|
||||
webrender_api_sender: webrender_api::RenderApiSender,
|
||||
webvr_compositor: Option<Box<dyn WebVRRenderHandler>>,
|
||||
external_images: Arc<Mutex<WebrenderExternalImageRegistry>>,
|
||||
api_type: GlType,
|
||||
) -> WebGLComm {
|
||||
|
@ -55,7 +54,6 @@ impl WebGLComm {
|
|||
// This implementation creates a single `WebGLThread` for all the pipelines.
|
||||
let init = WebGLThreadInit {
|
||||
webrender_api_sender,
|
||||
webvr_compositor,
|
||||
external_images,
|
||||
sender: sender.clone(),
|
||||
receiver,
|
||||
|
|
|
@ -42,8 +42,6 @@ use canvas_traits::webgl::WebGLTextureId;
|
|||
use canvas_traits::webgl::WebGLTransparentFramebufferId;
|
||||
use canvas_traits::webgl::WebGLVersion;
|
||||
use canvas_traits::webgl::WebGLVertexArrayId;
|
||||
use canvas_traits::webgl::WebVRCommand;
|
||||
use canvas_traits::webgl::WebVRRenderHandler;
|
||||
use canvas_traits::webgl::YAxisTreatment;
|
||||
use euclid::default::Size2D;
|
||||
use fnv::FnvHashMap;
|
||||
|
@ -130,10 +128,6 @@ pub(crate) struct WebGLThread {
|
|||
cached_context_info: FnvHashMap<WebGLContextId, WebGLContextInfo>,
|
||||
/// Current bound context.
|
||||
bound_context_id: Option<WebGLContextId>,
|
||||
/// Handler user to send WebVR commands.
|
||||
// TODO: replace webvr implementation with one built on top of webxr
|
||||
#[allow(dead_code)]
|
||||
webvr_compositor: Option<Box<dyn WebVRRenderHandler>>,
|
||||
/// Texture ids and sizes used in DOM to texture outputs.
|
||||
dom_outputs: FnvHashMap<webrender_api::PipelineId, DOMToTextureData>,
|
||||
/// List of registered webrender external images.
|
||||
|
@ -164,7 +158,6 @@ pub type SurfaceProvider = Box<dyn surfman_chains::SurfaceProvider + Send>;
|
|||
pub(crate) struct WebGLThreadInit {
|
||||
pub webxr_surface_providers: SurfaceProviders,
|
||||
pub webrender_api_sender: webrender_api::RenderApiSender,
|
||||
pub webvr_compositor: Option<Box<dyn WebVRRenderHandler>>,
|
||||
pub external_images: Arc<Mutex<WebrenderExternalImageRegistry>>,
|
||||
pub sender: WebGLSender<WebGLMsg>,
|
||||
pub receiver: WebGLReceiver<WebGLMsg>,
|
||||
|
@ -184,7 +177,6 @@ impl WebGLThread {
|
|||
pub(crate) fn new(
|
||||
WebGLThreadInit {
|
||||
webrender_api_sender,
|
||||
webvr_compositor,
|
||||
external_images,
|
||||
sender,
|
||||
receiver,
|
||||
|
@ -203,7 +195,6 @@ impl WebGLThread {
|
|||
contexts: Default::default(),
|
||||
cached_context_info: Default::default(),
|
||||
bound_context_id: None,
|
||||
webvr_compositor,
|
||||
dom_outputs: Default::default(),
|
||||
external_images,
|
||||
sender,
|
||||
|
@ -320,9 +311,6 @@ impl WebGLThread {
|
|||
WebGLMsg::WebGLCommand(ctx_id, command, backtrace) => {
|
||||
self.handle_webgl_command(ctx_id, command, backtrace);
|
||||
},
|
||||
WebGLMsg::WebVRCommand(ctx_id, command) => {
|
||||
self.handle_webvr_command(ctx_id, command);
|
||||
},
|
||||
WebGLMsg::CreateWebXRSwapChain(ctx_id, size, sender, id) => {
|
||||
let _ = sender.send(self.create_webxr_swap_chain(ctx_id, size, id));
|
||||
},
|
||||
|
@ -398,11 +386,6 @@ impl WebGLThread {
|
|||
}
|
||||
}
|
||||
|
||||
/// Handles a WebVRCommand for a specific WebGLContext
|
||||
fn handle_webvr_command(&mut self, _context_id: WebGLContextId, _command: WebVRCommand) {
|
||||
// TODO(pcwalton): Reenable.
|
||||
}
|
||||
|
||||
/// Creates a new WebGLContext
|
||||
#[allow(unsafe_code)]
|
||||
fn create_webgl_context(
|
||||
|
|
|
@ -29,5 +29,4 @@ servo_config = {path = "../config"}
|
|||
sparkle = "0.1"
|
||||
time = { version = "0.1.0", optional = true }
|
||||
webrender_api = {git = "https://github.com/servo/webrender"}
|
||||
webvr_traits = {path = "../webvr_traits"}
|
||||
webxr-api = {git = "https://github.com/servo/webxr", features = ["ipc"]}
|
||||
|
|
|
@ -7,13 +7,11 @@ use ipc_channel::ipc::{IpcBytesReceiver, IpcBytesSender, IpcSharedMemory};
|
|||
use pixels::PixelFormat;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use sparkle::gl;
|
||||
use sparkle::gl::Gl;
|
||||
use std::borrow::Cow;
|
||||
use std::fmt;
|
||||
use std::num::{NonZeroU32, NonZeroU64};
|
||||
use std::ops::Deref;
|
||||
use webrender_api::{DocumentId, ImageKey, PipelineId};
|
||||
use webvr_traits::WebVRPoseInformation;
|
||||
use webxr_api::SessionId;
|
||||
use webxr_api::SwapChainId as WebXRSwapChainId;
|
||||
|
||||
|
@ -72,8 +70,6 @@ pub enum WebGLMsg {
|
|||
RemoveContext(WebGLContextId),
|
||||
/// Runs a WebGLCommand in a specific WebGLContext.
|
||||
WebGLCommand(WebGLContextId, WebGLCommand, WebGLCommandBacktrace),
|
||||
/// Runs a WebVRCommand in a specific WebGLContext.
|
||||
WebVRCommand(WebGLContextId, WebVRCommand),
|
||||
/// Commands used for the DOMToTexture feature.
|
||||
DOMToTextureCommand(DOMToTextureCommand),
|
||||
/// Creates a new opaque framebuffer for WebXR.
|
||||
|
@ -162,13 +158,6 @@ impl WebGLMsgSender {
|
|||
.send(WebGLMsg::WebGLCommand(self.ctx_id, command, backtrace))
|
||||
}
|
||||
|
||||
/// Send a WebVRCommand message
|
||||
#[inline]
|
||||
pub fn send_vr(&self, command: WebVRCommand) -> WebGLSendResult {
|
||||
self.sender
|
||||
.send(WebGLMsg::WebVRCommand(self.ctx_id, command))
|
||||
}
|
||||
|
||||
/// Send a resize message
|
||||
#[inline]
|
||||
pub fn send_resize(
|
||||
|
@ -684,36 +673,6 @@ pub enum WebGLFramebufferBindingRequest {
|
|||
|
||||
pub type WebGLResult<T> = Result<T, WebGLError>;
|
||||
|
||||
pub type WebVRDeviceId = u32;
|
||||
|
||||
// WebVR commands that must be called in the WebGL render thread.
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
pub enum WebVRCommand {
|
||||
/// Start presenting to a VR device.
|
||||
Create(WebVRDeviceId),
|
||||
/// Synchronize the pose information to be used in the frame.
|
||||
SyncPoses(
|
||||
WebVRDeviceId,
|
||||
// near
|
||||
f64,
|
||||
// far
|
||||
f64,
|
||||
// sync gamepads too
|
||||
bool,
|
||||
WebGLSender<Result<WebVRPoseInformation, ()>>,
|
||||
),
|
||||
/// Submit the frame to a VR device using the specified texture coordinates.
|
||||
SubmitFrame(WebVRDeviceId, [f32; 4], [f32; 4]),
|
||||
/// Stop presenting to a VR device
|
||||
Release(WebVRDeviceId),
|
||||
}
|
||||
|
||||
// Trait object that handles WebVR commands.
|
||||
// Receives the texture id and size associated to the WebGLContext.
|
||||
pub trait WebVRRenderHandler: Send {
|
||||
fn handle(&mut self, gl: &Gl, command: WebVRCommand, texture: Option<(u32, Size2D<i32>)>);
|
||||
}
|
||||
|
||||
/// WebGL commands required to implement DOMToTexture feature.
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
pub enum DOMToTextureCommand {
|
||||
|
|
|
@ -32,7 +32,6 @@ net_traits = {path = "../net_traits"}
|
|||
num-traits = "0.2"
|
||||
pixels = {path = "../pixels", optional = true}
|
||||
profile_traits = {path = "../profile_traits"}
|
||||
rust-webvr = {version = "0.19", features = ["mock", "openvr", "vrexternal"]}
|
||||
script_traits = {path = "../script_traits"}
|
||||
servo_geometry = {path = "../geometry"}
|
||||
servo-media = {git = "https://github.com/servo/media"}
|
||||
|
@ -41,7 +40,6 @@ style_traits = {path = "../style_traits"}
|
|||
time = "0.1.17"
|
||||
webrender = {git = "https://github.com/servo/webrender", features = ["capture"]}
|
||||
webrender_api = {git = "https://github.com/servo/webrender"}
|
||||
webvr_traits = {path = "../webvr_traits"}
|
||||
webxr = {git = "https://github.com/servo/webxr"}
|
||||
|
||||
[build-dependencies]
|
||||
|
|
|
@ -46,7 +46,6 @@ use style_traits::{CSSPixel, DevicePixel, PinchZoomFactor};
|
|||
use time::{now, precise_time_ns, precise_time_s};
|
||||
use webrender_api::units::{DeviceIntPoint, DeviceIntSize, DevicePoint, LayoutVector2D};
|
||||
use webrender_api::{self, HitTestFlags, HitTestResult, ScrollLocation};
|
||||
use webvr_traits::WebVRMainThreadHeartbeat;
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
enum UnableToComposite {
|
||||
|
@ -179,9 +178,6 @@ pub struct IOCompositor<Window: WindowMethods + ?Sized> {
|
|||
/// The webrender interface, if enabled.
|
||||
webrender_api: webrender_api::RenderApi,
|
||||
|
||||
/// Some VR displays want to be sent a heartbeat from the main thread.
|
||||
webvr_heartbeats: Vec<Box<dyn WebVRMainThreadHeartbeat>>,
|
||||
|
||||
/// Some XR devices want to run on the main thread.
|
||||
pub webxr_main_thread: webxr::MainThreadRegistry,
|
||||
|
||||
|
@ -320,7 +316,6 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
|
|||
webrender: state.webrender,
|
||||
webrender_document: state.webrender_document,
|
||||
webrender_api: state.webrender_api,
|
||||
webvr_heartbeats: state.webvr_heartbeats,
|
||||
webxr_main_thread: state.webxr_main_thread,
|
||||
pending_paint_metrics: HashMap::new(),
|
||||
cursor: Cursor::None,
|
||||
|
@ -1017,10 +1012,7 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
|
|||
pipeline_ids.push(*pipeline_id);
|
||||
}
|
||||
}
|
||||
let animation_state = if pipeline_ids.is_empty() &&
|
||||
!self.webvr_heartbeats_racing() &&
|
||||
!self.webxr_main_thread.running()
|
||||
{
|
||||
let animation_state = if pipeline_ids.is_empty() && !self.webxr_main_thread.running() {
|
||||
windowing::AnimationState::Idle
|
||||
} else {
|
||||
windowing::AnimationState::Animating
|
||||
|
@ -1031,10 +1023,6 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
|
|||
}
|
||||
}
|
||||
|
||||
fn webvr_heartbeats_racing(&self) -> bool {
|
||||
self.webvr_heartbeats.iter().any(|hb| hb.heart_racing())
|
||||
}
|
||||
|
||||
fn tick_animations_for_pipeline(&mut self, pipeline_id: PipelineId) {
|
||||
let animation_callbacks_running = self
|
||||
.pipeline_details(pipeline_id)
|
||||
|
@ -1499,11 +1487,6 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
|
|||
CompositionRequest::CompositeNow(_) => self.composite(),
|
||||
}
|
||||
|
||||
// Send every VR display that wants one a main-thread heartbeat
|
||||
for webvr_heartbeat in &mut self.webvr_heartbeats {
|
||||
webvr_heartbeat.heartbeat();
|
||||
}
|
||||
|
||||
// Run the WebXR main thread
|
||||
self.webxr_main_thread.run_one_frame();
|
||||
|
||||
|
|
|
@ -23,7 +23,6 @@ use style_traits::viewport::ViewportConstraints;
|
|||
use style_traits::CSSPixel;
|
||||
use webrender_api;
|
||||
use webrender_api::units::{DeviceIntPoint, DeviceIntSize};
|
||||
use webvr_traits::WebVRMainThreadHeartbeat;
|
||||
|
||||
/// Sends messages to the compositor.
|
||||
pub struct CompositorProxy {
|
||||
|
@ -167,7 +166,6 @@ pub struct InitialCompositorState {
|
|||
pub webrender: webrender::Renderer,
|
||||
pub webrender_document: webrender_api::DocumentId,
|
||||
pub webrender_api: webrender_api::RenderApi,
|
||||
pub webvr_heartbeats: Vec<Box<dyn WebVRMainThreadHeartbeat>>,
|
||||
pub webxr_main_thread: webxr::MainThreadRegistry,
|
||||
pub pending_wr_frame: Arc<AtomicBool>,
|
||||
}
|
||||
|
|
|
@ -28,7 +28,6 @@ use servo_url::ServoUrl;
|
|||
use std::collections::HashMap;
|
||||
use std::fmt;
|
||||
use std::time::Duration;
|
||||
use webvr_traits::WebVREvent;
|
||||
|
||||
mod compositor;
|
||||
pub mod compositor_thread;
|
||||
|
@ -88,8 +87,6 @@ pub enum ConstellationMsg {
|
|||
Reload(TopLevelBrowsingContextId),
|
||||
/// A log entry, with the top-level browsing context id and thread name
|
||||
LogEntry(Option<TopLevelBrowsingContextId>, Option<String>, LogEntry),
|
||||
/// Dispatch WebVR events to the subscribed script threads.
|
||||
WebVREvents(Vec<PipelineId>, Vec<WebVREvent>),
|
||||
/// Create a new top level browsing context.
|
||||
NewBrowser(ServoUrl, TopLevelBrowsingContextId),
|
||||
/// Close a top level browsing context.
|
||||
|
@ -132,7 +129,6 @@ impl fmt::Debug for ConstellationMsg {
|
|||
WebDriverCommand(..) => "WebDriverCommand",
|
||||
Reload(..) => "Reload",
|
||||
LogEntry(..) => "LogEntry",
|
||||
WebVREvents(..) => "WebVREvents",
|
||||
NewBrowser(..) => "NewBrowser",
|
||||
CloseBrowser(..) => "CloseBrowser",
|
||||
SendError(..) => "SendError",
|
||||
|
|
|
@ -21,11 +21,9 @@ use std::rc::Rc;
|
|||
use std::time::Duration;
|
||||
use style_traits::DevicePixel;
|
||||
|
||||
use rust_webvr::VRServiceManager;
|
||||
use webrender_api::units::DevicePoint;
|
||||
use webrender_api::units::{DeviceIntPoint, DeviceIntRect, DeviceIntSize};
|
||||
use webrender_api::ScrollLocation;
|
||||
use webvr_traits::WebVRMainThreadHeartbeat;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum MouseWindowEvent {
|
||||
|
@ -176,13 +174,6 @@ pub trait WindowMethods {
|
|||
pub trait EmbedderMethods {
|
||||
/// Returns a thread-safe object to wake up the window's event loop.
|
||||
fn create_event_loop_waker(&mut self) -> Box<dyn EventLoopWaker>;
|
||||
/// Register services with a VRServiceManager.
|
||||
fn register_vr_services(
|
||||
&mut self,
|
||||
_: &mut VRServiceManager,
|
||||
_: &mut Vec<Box<dyn WebVRMainThreadHeartbeat>>,
|
||||
) {
|
||||
}
|
||||
|
||||
/// Register services with a WebXR Registry.
|
||||
fn register_webxr(
|
||||
|
|
|
@ -289,11 +289,6 @@ mod gen {
|
|||
#[serde(default)]
|
||||
enabled: bool,
|
||||
},
|
||||
webvr: {
|
||||
enabled: bool,
|
||||
event_polling_interval: i64,
|
||||
test: bool,
|
||||
},
|
||||
webvtt: {
|
||||
enabled: bool,
|
||||
},
|
||||
|
|
|
@ -43,7 +43,6 @@ servo_rand = {path = "../rand"}
|
|||
servo_remutex = {path = "../remutex"}
|
||||
servo_url = {path = "../url"}
|
||||
webgpu = {path = "../webgpu"}
|
||||
webvr_traits = {path = "../webvr_traits"}
|
||||
webrender_api = {git = "https://github.com/servo/webrender"}
|
||||
webxr-api = {git = "https://github.com/servo/webxr", features = ["ipc"]}
|
||||
|
||||
|
|
|
@ -179,7 +179,6 @@ use std::thread;
|
|||
use style_traits::viewport::ViewportConstraints;
|
||||
use style_traits::CSSPixel;
|
||||
use webgpu::{WebGPU, WebGPURequest};
|
||||
use webvr_traits::{WebVREvent, WebVRMsg};
|
||||
|
||||
type PendingApprovalNavigations = HashMap<PipelineId, (LoadData, HistoryEntryReplacement)>;
|
||||
|
||||
|
@ -463,9 +462,6 @@ pub struct Constellation<Message, LTF, STF, SWF> {
|
|||
/// Entry point to create and get channels to a WebGLThread.
|
||||
webgl_threads: Option<WebGLThreads>,
|
||||
|
||||
/// A channel through which messages can be sent to the webvr thread.
|
||||
webvr_chan: Option<IpcSender<WebVRMsg>>,
|
||||
|
||||
/// The XR device registry
|
||||
webxr_registry: webxr_api::Registry,
|
||||
|
||||
|
@ -549,9 +545,6 @@ pub struct InitialConstellationState {
|
|||
/// Entry point to create and get channels to a WebGLThread.
|
||||
pub webgl_threads: Option<WebGLThreads>,
|
||||
|
||||
/// A channel to the webgl thread.
|
||||
pub webvr_chan: Option<IpcSender<WebVRMsg>>,
|
||||
|
||||
/// The XR device registry
|
||||
pub webxr_registry: webxr_api::Registry,
|
||||
|
||||
|
@ -1014,7 +1007,6 @@ where
|
|||
(rng, prob)
|
||||
}),
|
||||
webgl_threads: state.webgl_threads,
|
||||
webvr_chan: state.webvr_chan,
|
||||
webxr_registry: state.webxr_registry,
|
||||
canvas_chan,
|
||||
ipc_canvas_chan,
|
||||
|
@ -1271,7 +1263,6 @@ where
|
|||
.webgl_threads
|
||||
.as_ref()
|
||||
.map(|threads| threads.pipeline()),
|
||||
webvr_chan: self.webvr_chan.clone(),
|
||||
webxr_registry: self.webxr_registry.clone(),
|
||||
player_context: self.player_context.clone(),
|
||||
event_loop_waker: self.event_loop_waker.as_ref().map(|w| (*w).clone_box()),
|
||||
|
@ -1704,9 +1695,6 @@ where
|
|||
FromCompositorMsg::LogEntry(top_level_browsing_context_id, thread_name, entry) => {
|
||||
self.handle_log_entry(top_level_browsing_context_id, thread_name, entry);
|
||||
},
|
||||
FromCompositorMsg::WebVREvents(pipeline_ids, events) => {
|
||||
self.handle_webvr_events(pipeline_ids, events);
|
||||
},
|
||||
FromCompositorMsg::ForwardEvent(destination_pipeline_id, event) => {
|
||||
self.forward_event(destination_pipeline_id, event);
|
||||
},
|
||||
|
@ -2839,13 +2827,6 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
if let Some(chan) = self.webvr_chan.as_ref() {
|
||||
debug!("Exiting WebVR thread.");
|
||||
if let Err(e) = chan.send(WebVRMsg::Exit) {
|
||||
warn!("Exit WebVR thread failed ({})", e);
|
||||
}
|
||||
}
|
||||
|
||||
debug!("Exiting GLPlayer thread.");
|
||||
if let Some(glplayer_threads) = self.glplayer_threads.as_ref() {
|
||||
if let Err(e) = glplayer_threads.exit() {
|
||||
|
@ -2993,20 +2974,6 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
fn handle_webvr_events(&mut self, ids: Vec<PipelineId>, events: Vec<WebVREvent>) {
|
||||
for id in ids {
|
||||
match self.pipelines.get_mut(&id) {
|
||||
Some(ref pipeline) => {
|
||||
// Notify script thread
|
||||
let _ = pipeline
|
||||
.event_loop
|
||||
.send(ConstellationControlMsg::WebVREvents(id, events.clone()));
|
||||
},
|
||||
None => warn!("constellation got webvr event for dead pipeline"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn forward_event(&mut self, destination_pipeline_id: PipelineId, event: CompositorEvent) {
|
||||
if let MouseButtonEvent(event_type, button, ..) = &event {
|
||||
match event_type {
|
||||
|
|
|
@ -46,7 +46,6 @@ use std::collections::{HashMap, HashSet};
|
|||
use std::rc::Rc;
|
||||
use std::sync::atomic::AtomicBool;
|
||||
use std::sync::Arc;
|
||||
use webvr_traits::WebVRMsg;
|
||||
|
||||
/// A `Pipeline` is the constellation's view of a `Document`. Each pipeline has an
|
||||
/// event loop (executed by a script thread) and a layout thread. A script thread
|
||||
|
@ -191,9 +190,6 @@ pub struct InitialPipelineState {
|
|||
/// A channel to the WebGL thread.
|
||||
pub webgl_chan: Option<WebGLPipeline>,
|
||||
|
||||
/// A channel to the webvr thread.
|
||||
pub webvr_chan: Option<IpcSender<WebVRMsg>>,
|
||||
|
||||
/// The XR device registry
|
||||
pub webxr_registry: webxr_api::Registry,
|
||||
|
||||
|
@ -305,7 +301,6 @@ impl Pipeline {
|
|||
webrender_image_api_sender: state.webrender_image_api_sender,
|
||||
webrender_document: state.webrender_document,
|
||||
webgl_chan: state.webgl_chan,
|
||||
webvr_chan: state.webvr_chan,
|
||||
webxr_registry: state.webxr_registry,
|
||||
player_context: state.player_context,
|
||||
user_agent: state.user_agent,
|
||||
|
@ -522,7 +517,6 @@ pub struct UnprivilegedPipelineContent {
|
|||
webrender_image_api_sender: net_traits::WebrenderIpcSender,
|
||||
webrender_document: webrender_api::DocumentId,
|
||||
webgl_chan: Option<WebGLPipeline>,
|
||||
webvr_chan: Option<IpcSender<WebVRMsg>>,
|
||||
webxr_registry: webxr_api::Registry,
|
||||
player_context: WindowGLContext,
|
||||
user_agent: Cow<'static, str>,
|
||||
|
@ -575,7 +569,6 @@ impl UnprivilegedPipelineContent {
|
|||
pipeline_namespace_id: self.pipeline_namespace_id,
|
||||
content_process_shutdown_chan: content_process_shutdown_chan,
|
||||
webgl_chan: self.webgl_chan,
|
||||
webvr_chan: self.webvr_chan,
|
||||
webxr_registry: self.webxr_registry,
|
||||
webrender_document: self.webrender_document,
|
||||
webrender_api_sender: self.webrender_api_sender.clone(),
|
||||
|
|
|
@ -116,7 +116,6 @@ xml5ever = "0.16"
|
|||
webdriver = "0.40"
|
||||
webgpu = {path = "../webgpu"}
|
||||
webrender_api = {git = "https://github.com/servo/webrender"}
|
||||
webvr_traits = {path = "../webvr_traits"}
|
||||
webxr-api = {git = "https://github.com/servo/webxr", features = ["ipc"]}
|
||||
|
||||
[target.'cfg(not(target_os = "ios"))'.dependencies]
|
||||
|
|
|
@ -157,7 +157,6 @@ use webgpu::{
|
|||
WebGPUPipelineLayout, WebGPUQueue, WebGPUShaderModule,
|
||||
};
|
||||
use webrender_api::{DocumentId, ImageKey};
|
||||
use webvr_traits::{WebVRGamepadData, WebVRGamepadHand, WebVRGamepadState};
|
||||
use webxr_api::SwapChainId as WebXRSwapChainId;
|
||||
|
||||
unsafe_no_jsmanaged_fields!(Tm);
|
||||
|
@ -548,7 +547,6 @@ unsafe_no_jsmanaged_fields!(RefCell<Option<RawPass>>);
|
|||
unsafe_no_jsmanaged_fields!(GPUBufferState);
|
||||
unsafe_no_jsmanaged_fields!(WebXRSwapChainId);
|
||||
unsafe_no_jsmanaged_fields!(MediaList);
|
||||
unsafe_no_jsmanaged_fields!(WebVRGamepadData, WebVRGamepadState, WebVRGamepadHand);
|
||||
unsafe_no_jsmanaged_fields!(
|
||||
webxr_api::Registry,
|
||||
webxr_api::Session,
|
||||
|
|
|
@ -44,6 +44,7 @@ use js::rust::wrappers::JS_HasPropertyById;
|
|||
use js::rust::wrappers::JS_SetProperty;
|
||||
use js::rust::{get_object_class, is_dom_class, GCMethods, ToString, ToWindowProxyIfWindow};
|
||||
use js::rust::{Handle, HandleId, HandleObject, HandleValue, MutableHandleValue};
|
||||
use js::typedarray::{CreateWith, Float32Array};
|
||||
use js::JS_CALLEE;
|
||||
use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
|
||||
use std::ffi::CString;
|
||||
|
@ -134,6 +135,15 @@ pub fn to_frozen_array<T: ToJSValConvertible>(convertibles: &[T], cx: SafeJSCont
|
|||
*ports
|
||||
}
|
||||
|
||||
/// Creates a Float32 array
|
||||
pub fn create_typed_array(cx: SafeJSContext, src: &[f32], dst: &Heap<*mut JSObject>) {
|
||||
rooted!(in (*cx) let mut array = ptr::null_mut::<JSObject>());
|
||||
unsafe {
|
||||
let _ = Float32Array::create(*cx, CreateWith::Slice(src), array.handle_mut());
|
||||
}
|
||||
(*dst).set(array.get());
|
||||
}
|
||||
|
||||
/// Returns the ProtoOrIfaceArray for the given global object.
|
||||
/// Fails if `global` is not a DOM global object.
|
||||
pub fn get_proto_or_iface_array(global: *mut JSObject) -> *mut ProtoOrIfaceArray {
|
||||
|
|
|
@ -2,26 +2,23 @@
|
|||
* 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::dom::bindings::codegen::Bindings::GamepadBinding::GamepadHand;
|
||||
use crate::dom::bindings::codegen::Bindings::GamepadBinding::GamepadMethods;
|
||||
use crate::dom::bindings::inheritance::Castable;
|
||||
use crate::dom::bindings::num::Finite;
|
||||
use crate::dom::bindings::reflector::{reflect_dom_object, DomObject, Reflector};
|
||||
use crate::dom::bindings::reflector::{DomObject, Reflector};
|
||||
use crate::dom::bindings::root::{Dom, DomRoot};
|
||||
use crate::dom::bindings::str::DOMString;
|
||||
use crate::dom::event::Event;
|
||||
use crate::dom::eventtarget::EventTarget;
|
||||
use crate::dom::gamepadbuttonlist::GamepadButtonList;
|
||||
use crate::dom::gamepadevent::{GamepadEvent, GamepadEventType};
|
||||
use crate::dom::globalscope::GlobalScope;
|
||||
use crate::dom::vrpose::VRPose;
|
||||
use crate::dom::gamepadpose::GamepadPose;
|
||||
use crate::script_runtime::JSContext;
|
||||
use dom_struct::dom_struct;
|
||||
use js::jsapi::{Heap, JSObject};
|
||||
use js::typedarray::{CreateWith, Float64Array};
|
||||
use std::cell::Cell;
|
||||
use std::ptr;
|
||||
use std::ptr::NonNull;
|
||||
use webvr_traits::{WebVRGamepadData, WebVRGamepadHand, WebVRGamepadState};
|
||||
|
||||
#[dom_struct]
|
||||
pub struct Gamepad {
|
||||
|
@ -35,12 +32,13 @@ pub struct Gamepad {
|
|||
#[ignore_malloc_size_of = "mozjs"]
|
||||
axes: Heap<*mut JSObject>,
|
||||
buttons: Dom<GamepadButtonList>,
|
||||
pose: Option<Dom<VRPose>>,
|
||||
pose: Option<Dom<GamepadPose>>,
|
||||
#[ignore_malloc_size_of = "Defined in rust-webvr"]
|
||||
hand: WebVRGamepadHand,
|
||||
display_id: u32,
|
||||
hand: GamepadHand,
|
||||
}
|
||||
|
||||
// TODO: support gamepad discovery
|
||||
#[allow(dead_code)]
|
||||
impl Gamepad {
|
||||
fn new_inherited(
|
||||
gamepad_id: u32,
|
||||
|
@ -50,9 +48,8 @@ impl Gamepad {
|
|||
timestamp: f64,
|
||||
mapping_type: String,
|
||||
buttons: &GamepadButtonList,
|
||||
pose: Option<&VRPose>,
|
||||
hand: WebVRGamepadHand,
|
||||
display_id: u32,
|
||||
pose: Option<&GamepadPose>,
|
||||
hand: GamepadHand,
|
||||
) -> Gamepad {
|
||||
Self {
|
||||
reflector_: Reflector::new(),
|
||||
|
@ -66,45 +63,8 @@ impl Gamepad {
|
|||
buttons: Dom::from_ref(buttons),
|
||||
pose: pose.map(Dom::from_ref),
|
||||
hand: hand,
|
||||
display_id: display_id,
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unsafe_code)]
|
||||
pub fn new_from_vr(
|
||||
global: &GlobalScope,
|
||||
index: i32,
|
||||
data: &WebVRGamepadData,
|
||||
state: &WebVRGamepadState,
|
||||
) -> DomRoot<Gamepad> {
|
||||
let buttons = GamepadButtonList::new_from_vr(&global, &state.buttons);
|
||||
let pose = VRPose::new(&global, &state.pose);
|
||||
|
||||
let gamepad = reflect_dom_object(
|
||||
Box::new(Gamepad::new_inherited(
|
||||
state.gamepad_id,
|
||||
data.name.clone(),
|
||||
index,
|
||||
state.connected,
|
||||
state.timestamp,
|
||||
"".into(),
|
||||
&buttons,
|
||||
Some(&pose),
|
||||
data.hand.clone(),
|
||||
data.display_id,
|
||||
)),
|
||||
global,
|
||||
);
|
||||
|
||||
let cx = global.get_cx();
|
||||
rooted!(in (*cx) let mut array = ptr::null_mut::<JSObject>());
|
||||
unsafe {
|
||||
let _ = Float64Array::create(*cx, CreateWith::Slice(&state.axes), array.handle_mut());
|
||||
}
|
||||
gamepad.axes.set(array.get());
|
||||
|
||||
gamepad
|
||||
}
|
||||
}
|
||||
|
||||
impl GamepadMethods for Gamepad {
|
||||
|
@ -145,44 +105,19 @@ impl GamepadMethods for Gamepad {
|
|||
}
|
||||
|
||||
// https://w3c.github.io/gamepad/extensions.html#gamepadhand-enum
|
||||
fn Hand(&self) -> DOMString {
|
||||
let value = match self.hand {
|
||||
WebVRGamepadHand::Unknown => "",
|
||||
WebVRGamepadHand::Left => "left",
|
||||
WebVRGamepadHand::Right => "right",
|
||||
};
|
||||
value.into()
|
||||
fn Hand(&self) -> GamepadHand {
|
||||
self.hand
|
||||
}
|
||||
|
||||
// https://w3c.github.io/gamepad/extensions.html#dom-gamepad-pose
|
||||
fn GetPose(&self) -> Option<DomRoot<VRPose>> {
|
||||
fn GetPose(&self) -> Option<DomRoot<GamepadPose>> {
|
||||
self.pose.as_ref().map(|p| DomRoot::from_ref(&**p))
|
||||
}
|
||||
|
||||
// https://w3c.github.io/webvr/spec/1.1/#gamepad-getvrdisplays-attribute
|
||||
fn DisplayId(&self) -> u32 {
|
||||
self.display_id
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: support gamepad discovery
|
||||
#[allow(dead_code)]
|
||||
impl Gamepad {
|
||||
#[allow(unsafe_code)]
|
||||
pub fn update_from_vr(&self, state: &WebVRGamepadState) {
|
||||
self.timestamp.set(state.timestamp);
|
||||
unsafe {
|
||||
let cx = self.global().get_cx();
|
||||
typedarray!(in(*cx) let axes: Float64Array = self.axes.get());
|
||||
if let Ok(mut array) = axes {
|
||||
array.update(&state.axes);
|
||||
}
|
||||
}
|
||||
self.buttons.sync_from_vr(&state.buttons);
|
||||
if let Some(ref pose) = self.pose {
|
||||
pose.update(&state.pose);
|
||||
}
|
||||
self.update_connected(state.connected);
|
||||
}
|
||||
|
||||
pub fn gamepad_id(&self) -> u32 {
|
||||
self.gamepad_id
|
||||
}
|
||||
|
|
|
@ -18,6 +18,8 @@ pub struct GamepadButton {
|
|||
value: Cell<f64>,
|
||||
}
|
||||
|
||||
// TODO: support gamepad discovery
|
||||
#[allow(dead_code)]
|
||||
impl GamepadButton {
|
||||
pub fn new_inherited(pressed: bool, touched: bool) -> GamepadButton {
|
||||
Self {
|
||||
|
@ -53,6 +55,8 @@ impl GamepadButtonMethods for GamepadButton {
|
|||
}
|
||||
}
|
||||
|
||||
// TODO: support gamepad discovery
|
||||
#[allow(dead_code)]
|
||||
impl GamepadButton {
|
||||
pub fn update(&self, pressed: bool, touched: bool) {
|
||||
self.pressed.set(pressed);
|
||||
|
|
|
@ -3,12 +3,10 @@
|
|||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use crate::dom::bindings::codegen::Bindings::GamepadButtonListBinding::GamepadButtonListMethods;
|
||||
use crate::dom::bindings::reflector::{reflect_dom_object, Reflector};
|
||||
use crate::dom::bindings::root::{Dom, DomRoot, DomSlice};
|
||||
use crate::dom::bindings::reflector::Reflector;
|
||||
use crate::dom::bindings::root::{Dom, DomRoot};
|
||||
use crate::dom::gamepadbutton::GamepadButton;
|
||||
use crate::dom::globalscope::GlobalScope;
|
||||
use dom_struct::dom_struct;
|
||||
use webvr_traits::WebVRGamepadButton;
|
||||
|
||||
// https://w3c.github.io/gamepad/#gamepadbutton-interface
|
||||
#[dom_struct]
|
||||
|
@ -17,6 +15,8 @@ pub struct GamepadButtonList {
|
|||
list: Vec<Dom<GamepadButton>>,
|
||||
}
|
||||
|
||||
// TODO: support gamepad discovery
|
||||
#[allow(dead_code)]
|
||||
impl GamepadButtonList {
|
||||
#[allow(unrooted_must_root)]
|
||||
fn new_inherited(list: &[&GamepadButton]) -> GamepadButtonList {
|
||||
|
@ -25,22 +25,6 @@ impl GamepadButtonList {
|
|||
list: list.iter().map(|button| Dom::from_ref(*button)).collect(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_from_vr(
|
||||
global: &GlobalScope,
|
||||
buttons: &[WebVRGamepadButton],
|
||||
) -> DomRoot<GamepadButtonList> {
|
||||
rooted_vec!(let list <- buttons.iter()
|
||||
.map(|btn| GamepadButton::new(&global, btn.pressed, btn.touched)));
|
||||
|
||||
reflect_dom_object(Box::new(GamepadButtonList::new_inherited(list.r())), global)
|
||||
}
|
||||
|
||||
pub fn sync_from_vr(&self, vr_buttons: &[WebVRGamepadButton]) {
|
||||
for (gp_btn, btn) in self.list.iter().zip(vr_buttons.iter()) {
|
||||
gp_btn.update(btn.pressed, btn.touched);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl GamepadButtonListMethods for GamepadButtonList {
|
||||
|
|
|
@ -17,6 +17,8 @@ pub struct GamepadList {
|
|||
list: DomRefCell<Vec<Dom<Gamepad>>>,
|
||||
}
|
||||
|
||||
// TODO: support gamepad discovery
|
||||
#[allow(dead_code)]
|
||||
impl GamepadList {
|
||||
fn new_inherited(list: &[&Gamepad]) -> GamepadList {
|
||||
GamepadList {
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
* 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::dom::bindings::codegen::Bindings::VRPoseBinding::VRPoseMethods;
|
||||
use crate::dom::bindings::reflector::{reflect_dom_object, DomObject, Reflector};
|
||||
use crate::dom::bindings::codegen::Bindings::GamepadPoseBinding::GamepadPoseMethods;
|
||||
use crate::dom::bindings::reflector::{reflect_dom_object, Reflector};
|
||||
use crate::dom::bindings::root::DomRoot;
|
||||
use crate::dom::globalscope::GlobalScope;
|
||||
use crate::script_runtime::JSContext;
|
||||
|
@ -12,10 +12,9 @@ use js::jsapi::{Heap, JSObject};
|
|||
use js::typedarray::{CreateWith, Float32Array};
|
||||
use std::ptr;
|
||||
use std::ptr::NonNull;
|
||||
use webvr_traits::webvr;
|
||||
|
||||
#[dom_struct]
|
||||
pub struct VRPose {
|
||||
pub struct GamepadPose {
|
||||
reflector_: Reflector,
|
||||
#[ignore_malloc_size_of = "mozjs"]
|
||||
position: Heap<*mut JSObject>,
|
||||
|
@ -31,6 +30,8 @@ pub struct VRPose {
|
|||
angular_acc: Heap<*mut JSObject>,
|
||||
}
|
||||
|
||||
// TODO: support gamepad discovery
|
||||
#[allow(dead_code)]
|
||||
#[allow(unsafe_code)]
|
||||
fn update_or_create_typed_array(cx: JSContext, src: Option<&[f32]>, dst: &Heap<*mut JSObject>) {
|
||||
match src {
|
||||
|
@ -67,9 +68,11 @@ fn heap_to_option(heap: &Heap<*mut JSObject>) -> Option<NonNull<JSObject>> {
|
|||
}
|
||||
}
|
||||
|
||||
impl VRPose {
|
||||
fn new_inherited() -> VRPose {
|
||||
VRPose {
|
||||
// TODO: support gamepad discovery
|
||||
#[allow(dead_code)]
|
||||
impl GamepadPose {
|
||||
fn new_inherited() -> GamepadPose {
|
||||
GamepadPose {
|
||||
reflector_: Reflector::new(),
|
||||
position: Heap::default(),
|
||||
orientation: Heap::default(),
|
||||
|
@ -80,71 +83,48 @@ impl VRPose {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn new(global: &GlobalScope, pose: &webvr::VRPose) -> DomRoot<VRPose> {
|
||||
let root = reflect_dom_object(Box::new(VRPose::new_inherited()), global);
|
||||
root.update(&pose);
|
||||
root
|
||||
}
|
||||
|
||||
#[allow(unsafe_code)]
|
||||
pub fn update(&self, pose: &webvr::VRPose) {
|
||||
let cx = self.global().get_cx();
|
||||
update_or_create_typed_array(cx, pose.position.as_ref().map(|v| &v[..]), &self.position);
|
||||
update_or_create_typed_array(
|
||||
cx,
|
||||
pose.orientation.as_ref().map(|v| &v[..]),
|
||||
&self.orientation,
|
||||
);
|
||||
update_or_create_typed_array(
|
||||
cx,
|
||||
pose.linear_velocity.as_ref().map(|v| &v[..]),
|
||||
&self.linear_vel,
|
||||
);
|
||||
update_or_create_typed_array(
|
||||
cx,
|
||||
pose.angular_velocity.as_ref().map(|v| &v[..]),
|
||||
&self.angular_vel,
|
||||
);
|
||||
update_or_create_typed_array(
|
||||
cx,
|
||||
pose.linear_acceleration.as_ref().map(|v| &v[..]),
|
||||
&self.linear_acc,
|
||||
);
|
||||
update_or_create_typed_array(
|
||||
cx,
|
||||
pose.angular_acceleration.as_ref().map(|v| &v[..]),
|
||||
&self.angular_acc,
|
||||
);
|
||||
pub fn new(global: &GlobalScope) -> DomRoot<GamepadPose> {
|
||||
reflect_dom_object(Box::new(GamepadPose::new_inherited()), global)
|
||||
}
|
||||
}
|
||||
|
||||
impl VRPoseMethods for VRPose {
|
||||
// https://w3c.github.io/webvr/#dom-vrpose-position
|
||||
impl GamepadPoseMethods for GamepadPose {
|
||||
// https://w3c.github.io/gamepad/extensions.html#dom-gamepadpose-position
|
||||
fn GetPosition(&self, _cx: JSContext) -> Option<NonNull<JSObject>> {
|
||||
heap_to_option(&self.position)
|
||||
}
|
||||
|
||||
// https://w3c.github.io/webvr/#dom-vrpose-linearvelocity
|
||||
// https://w3c.github.io/gamepad/extensions.html#dom-gamepadpose-hasposition
|
||||
fn HasPosition(&self) -> bool {
|
||||
!self.position.get().is_null()
|
||||
}
|
||||
|
||||
// https://w3c.github.io/gamepad/extensions.html#dom-gamepadpose-linearvelocity
|
||||
fn GetLinearVelocity(&self, _cx: JSContext) -> Option<NonNull<JSObject>> {
|
||||
heap_to_option(&self.linear_vel)
|
||||
}
|
||||
|
||||
// https://w3c.github.io/webvr/#dom-vrpose-linearacceleration
|
||||
// https://w3c.github.io/gamepad/extensions.html#dom-gamepadpose-linearacceleration
|
||||
fn GetLinearAcceleration(&self, _cx: JSContext) -> Option<NonNull<JSObject>> {
|
||||
heap_to_option(&self.linear_acc)
|
||||
}
|
||||
|
||||
// https://w3c.github.io/webvr/#dom-vrpose-orientation
|
||||
// https://w3c.github.io/gamepad/extensions.html#dom-gamepadpose-orientation
|
||||
fn GetOrientation(&self, _cx: JSContext) -> Option<NonNull<JSObject>> {
|
||||
heap_to_option(&self.orientation)
|
||||
}
|
||||
|
||||
// https://w3c.github.io/webvr/#dom-vrpose-angularvelocity
|
||||
// https://w3c.github.io/gamepad/extensions.html#dom-gamepadpose-orientation
|
||||
fn HasOrientation(&self) -> bool {
|
||||
!self.orientation.get().is_null()
|
||||
}
|
||||
|
||||
// https://w3c.github.io/gamepad/extensions.html#dom-gamepadpose-angularvelocity
|
||||
fn GetAngularVelocity(&self, _cx: JSContext) -> Option<NonNull<JSObject>> {
|
||||
heap_to_option(&self.angular_vel)
|
||||
}
|
||||
|
||||
// https://w3c.github.io/webvr/#dom-vrpose-angularacceleration
|
||||
// https://w3c.github.io/gamepad/extensions.html#dom-gamepadpose-angularacceleration
|
||||
fn GetAngularAcceleration(&self, _cx: JSContext) -> Option<NonNull<JSObject>> {
|
||||
heap_to_option(&self.angular_acc)
|
||||
}
|
|
@ -527,13 +527,6 @@ macro_rules! window_event_handlers(
|
|||
event_handler!(unhandledrejection, GetOnunhandledrejection,
|
||||
SetOnunhandledrejection);
|
||||
event_handler!(unload, GetOnunload, SetOnunload);
|
||||
event_handler!(vrdisplayconnect, GetOnvrdisplayconnect, SetOnvrdisplayconnect);
|
||||
event_handler!(vrdisplaydisconnect, GetOnvrdisplaydisconnect, SetOnvrdisplaydisconnect);
|
||||
event_handler!(vrdisplayactivate, GetOnvrdisplayactivate, SetOnvrdisplayactivate);
|
||||
event_handler!(vrdisplaydeactivate, GetOnvrdisplaydeactivate, SetOnvrdisplaydeactivate);
|
||||
event_handler!(vrdisplayblur, GetOnvrdisplayblur, SetOnvrdisplayblur);
|
||||
event_handler!(vrdisplayfocus, GetOnvrdisplayfocus, SetOnvrdisplayfocus);
|
||||
event_handler!(vrdisplaypresentchange, GetOnvrdisplaypresentchange, SetOnvrdisplaypresentchange);
|
||||
);
|
||||
(ForwardToWindow) => (
|
||||
window_owned_event_handler!(afterprint, GetOnafterprint,
|
||||
|
@ -560,14 +553,6 @@ macro_rules! window_event_handlers(
|
|||
window_owned_event_handler!(unhandledrejection, GetOnunhandledrejection,
|
||||
SetOnunhandledrejection);
|
||||
window_owned_event_handler!(unload, GetOnunload, SetOnunload);
|
||||
|
||||
window_owned_event_handler!(vrdisplayconnect, GetOnvrdisplayconnect, SetOnvrdisplayconnect);
|
||||
window_owned_event_handler!(vrdisplaydisconnect, GetOnvrdisplaydisconnect, SetOnvrdisplaydisconnect);
|
||||
window_owned_event_handler!(vrdisplayactivate, GetOnvrdisplayactivate, SetOnvrdisplayactivate);
|
||||
window_owned_event_handler!(vrdisplaydeactivate, GetOnvrdisplaydeactivate, SetOnvrdisplaydeactivate);
|
||||
window_owned_event_handler!(vrdisplayblur, GetOnvrdisplayblur, SetOnvrdisplayblur);
|
||||
window_owned_event_handler!(vrdisplayfocus, GetOnvrdisplayfocus, SetOnvrdisplayfocus);
|
||||
window_owned_event_handler!(vrdisplaypresentchange, GetOnvrdisplaypresentchange, SetOnvrdisplaypresentchange);
|
||||
);
|
||||
);
|
||||
|
||||
|
|
|
@ -316,6 +316,7 @@ pub mod gamepadbutton;
|
|||
pub mod gamepadbuttonlist;
|
||||
pub mod gamepadevent;
|
||||
pub mod gamepadlist;
|
||||
pub mod gamepadpose;
|
||||
pub mod globalscope;
|
||||
pub mod gpu;
|
||||
pub mod gpuadapter;
|
||||
|
@ -532,14 +533,6 @@ pub mod vertexarrayobject;
|
|||
pub mod videotrack;
|
||||
pub mod videotracklist;
|
||||
pub mod virtualmethods;
|
||||
pub mod vrdisplay;
|
||||
pub mod vrdisplaycapabilities;
|
||||
pub mod vrdisplayevent;
|
||||
pub mod vreyeparameters;
|
||||
pub mod vrfieldofview;
|
||||
pub mod vrframedata;
|
||||
pub mod vrpose;
|
||||
pub mod vrstageparameters;
|
||||
pub mod vttcue;
|
||||
pub mod vttregion;
|
||||
pub mod webgl_extensions;
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use crate::dom::bindings::codegen::Bindings::NavigatorBinding::NavigatorMethods;
|
||||
use crate::dom::bindings::error::Error;
|
||||
use crate::dom::bindings::reflector::{reflect_dom_object, DomObject, Reflector};
|
||||
use crate::dom::bindings::root::{DomRoot, MutNullableDom};
|
||||
use crate::dom::bindings::str::DOMString;
|
||||
|
@ -16,13 +15,10 @@ use crate::dom::mimetypearray::MimeTypeArray;
|
|||
use crate::dom::navigatorinfo;
|
||||
use crate::dom::permissions::Permissions;
|
||||
use crate::dom::pluginarray::PluginArray;
|
||||
use crate::dom::promise::Promise;
|
||||
use crate::dom::serviceworkercontainer::ServiceWorkerContainer;
|
||||
use crate::dom::window::Window;
|
||||
use crate::dom::xrsystem::XRSystem;
|
||||
use crate::realms::InRealm;
|
||||
use dom_struct::dom_struct;
|
||||
use std::rc::Rc;
|
||||
|
||||
#[dom_struct]
|
||||
pub struct Navigator {
|
||||
|
@ -159,9 +155,7 @@ impl NavigatorMethods for Navigator {
|
|||
.gamepads
|
||||
.or_init(|| GamepadList::new(&self.global(), &[]));
|
||||
|
||||
let vr_gamepads = self.Xr().get_gamepads();
|
||||
root.add_if_not_exists(&vr_gamepads);
|
||||
// TODO: Add not VR related gamepads
|
||||
// TODO: Add gamepads
|
||||
root
|
||||
}
|
||||
// https://w3c.github.io/permissions/#navigator-and-workernavigator-extension
|
||||
|
@ -170,17 +164,6 @@ impl NavigatorMethods for Navigator {
|
|||
.or_init(|| Permissions::new(&self.global()))
|
||||
}
|
||||
|
||||
// https://w3c.github.io/webvr/spec/1.1/#navigator-getvrdisplays-attribute
|
||||
fn GetVRDisplays(&self, comp: InRealm) -> Rc<Promise> {
|
||||
let promise = Promise::new_in_current_realm(&self.global(), comp);
|
||||
let displays = self.Xr().get_displays();
|
||||
match displays {
|
||||
Ok(displays) => promise.resolve_native(&displays),
|
||||
Err(_) => promise.reject_error(Error::Security),
|
||||
}
|
||||
promise
|
||||
}
|
||||
|
||||
/// https://immersive-web.github.io/webxr/#dom-navigator-xr
|
||||
fn Xr(&self) -> DomRoot<XRSystem> {
|
||||
self.xr
|
||||
|
|
|
@ -1,840 +0,0 @@
|
|||
/* 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 crate::dom::bindings::callback::ExceptionHandling;
|
||||
use crate::dom::bindings::cell::DomRefCell;
|
||||
use crate::dom::bindings::codegen::Bindings::NavigatorBinding::NavigatorMethods;
|
||||
use crate::dom::bindings::codegen::Bindings::PerformanceBinding::PerformanceMethods;
|
||||
use crate::dom::bindings::codegen::Bindings::VRDisplayBinding::VRDisplayMethods;
|
||||
use crate::dom::bindings::codegen::Bindings::VRDisplayBinding::VREye;
|
||||
use crate::dom::bindings::codegen::Bindings::VRLayerBinding::VRLayer;
|
||||
use crate::dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::WebGLRenderingContextMethods;
|
||||
use crate::dom::bindings::codegen::Bindings::WindowBinding::FrameRequestCallback;
|
||||
use crate::dom::bindings::codegen::Bindings::WindowBinding::WindowMethods;
|
||||
use crate::dom::bindings::codegen::Bindings::XRRenderStateBinding::XRRenderStateInit;
|
||||
use crate::dom::bindings::error::Error;
|
||||
use crate::dom::bindings::inheritance::Castable;
|
||||
use crate::dom::bindings::num::Finite;
|
||||
use crate::dom::bindings::refcounted::{Trusted, TrustedPromise};
|
||||
use crate::dom::bindings::reflector::{reflect_dom_object, DomObject};
|
||||
use crate::dom::bindings::root::{DomRoot, MutDom, MutNullableDom};
|
||||
use crate::dom::bindings::str::DOMString;
|
||||
use crate::dom::event::Event;
|
||||
use crate::dom::eventtarget::EventTarget;
|
||||
use crate::dom::promise::Promise;
|
||||
use crate::dom::vrdisplaycapabilities::VRDisplayCapabilities;
|
||||
use crate::dom::vrdisplayevent::VRDisplayEvent;
|
||||
use crate::dom::vreyeparameters::VREyeParameters;
|
||||
use crate::dom::vrframedata::VRFrameData;
|
||||
use crate::dom::vrpose::VRPose;
|
||||
use crate::dom::vrstageparameters::VRStageParameters;
|
||||
use crate::dom::webglrenderingcontext::{WebGLMessageSender, WebGLRenderingContext};
|
||||
use crate::dom::window::Window;
|
||||
use crate::realms::InRealm;
|
||||
use crate::script_runtime::CommonScriptMsg;
|
||||
use crate::script_runtime::ScriptThreadEventCategory::WebVREvent;
|
||||
use crate::task_source::{TaskSource, TaskSourceName};
|
||||
use canvas_traits::webgl::{webgl_channel, WebGLReceiver, WebVRCommand};
|
||||
use crossbeam_channel::{unbounded, Sender};
|
||||
use dom_struct::dom_struct;
|
||||
use ipc_channel::ipc::IpcSender;
|
||||
use msg::constellation_msg::PipelineId;
|
||||
use profile_traits::ipc;
|
||||
use std::cell::Cell;
|
||||
use std::mem;
|
||||
use std::rc::Rc;
|
||||
use std::thread;
|
||||
use webvr_traits::{WebVRDisplayData, WebVRDisplayEvent, WebVRFrameData, WebVRPoseInformation};
|
||||
use webvr_traits::{WebVRLayer, WebVRMsg};
|
||||
|
||||
#[dom_struct]
|
||||
pub struct VRDisplay {
|
||||
eventtarget: EventTarget,
|
||||
#[ignore_malloc_size_of = "Defined in rust-webvr"]
|
||||
display: DomRefCell<WebVRDisplayData>,
|
||||
depth_near: Cell<f64>,
|
||||
depth_far: Cell<f64>,
|
||||
presenting: Cell<bool>,
|
||||
has_raf_thread: Cell<bool>,
|
||||
left_eye_params: MutDom<VREyeParameters>,
|
||||
right_eye_params: MutDom<VREyeParameters>,
|
||||
capabilities: MutDom<VRDisplayCapabilities>,
|
||||
stage_params: MutNullableDom<VRStageParameters>,
|
||||
#[ignore_malloc_size_of = "Defined in rust-webvr"]
|
||||
frame_data: DomRefCell<WebVRFrameData>,
|
||||
#[ignore_malloc_size_of = "Defined in rust-webvr"]
|
||||
layer: DomRefCell<WebVRLayer>,
|
||||
layer_ctx: MutNullableDom<WebGLRenderingContext>,
|
||||
#[ignore_malloc_size_of = "Defined in rust-webvr"]
|
||||
next_raf_id: Cell<u32>,
|
||||
/// List of request animation frame callbacks
|
||||
#[ignore_malloc_size_of = "closures are hard"]
|
||||
raf_callback_list: DomRefCell<Vec<(u32, Option<Rc<FrameRequestCallback>>)>>,
|
||||
/// When there isn't any layer_ctx the RAF thread needs to be "woken up"
|
||||
raf_wakeup_sender: DomRefCell<Option<Sender<()>>>,
|
||||
#[ignore_malloc_size_of = "Rc is hard"]
|
||||
pending_renderstate_updates: DomRefCell<Vec<(XRRenderStateInit, Rc<Promise>)>>,
|
||||
// Compositor VRFrameData synchonization
|
||||
frame_data_status: Cell<VRFrameDataStatus>,
|
||||
#[ignore_malloc_size_of = "closures are hard"]
|
||||
frame_data_receiver: DomRefCell<Option<WebGLReceiver<Result<WebVRPoseInformation, ()>>>>,
|
||||
running_display_raf: Cell<bool>,
|
||||
paused: Cell<bool>,
|
||||
stopped_on_pause: Cell<bool>,
|
||||
#[ignore_malloc_size_of = "channels are hard"]
|
||||
webvr_thread: IpcSender<WebVRMsg>,
|
||||
pipeline: PipelineId,
|
||||
}
|
||||
|
||||
unsafe_no_jsmanaged_fields!(WebVRDisplayData);
|
||||
unsafe_no_jsmanaged_fields!(WebVRFrameData);
|
||||
unsafe_no_jsmanaged_fields!(WebVRLayer);
|
||||
unsafe_no_jsmanaged_fields!(VRFrameDataStatus);
|
||||
|
||||
#[derive(Clone, Copy, Eq, MallocSizeOf, PartialEq)]
|
||||
enum VRFrameDataStatus {
|
||||
Waiting,
|
||||
Synced,
|
||||
Exit,
|
||||
}
|
||||
|
||||
#[derive(Clone, MallocSizeOf)]
|
||||
struct VRRAFUpdate {
|
||||
depth_near: f64,
|
||||
depth_far: f64,
|
||||
/// WebGL API sender
|
||||
api_sender: Option<WebGLMessageSender>,
|
||||
/// Number uniquely identifying the WebGL context
|
||||
/// so that we may setup/tear down VR compositors as things change
|
||||
context_id: usize,
|
||||
}
|
||||
|
||||
type VRRAFUpdateSender = Sender<Result<VRRAFUpdate, ()>>;
|
||||
|
||||
impl VRDisplay {
|
||||
fn new_inherited(global: &Window, display: WebVRDisplayData) -> VRDisplay {
|
||||
let stage = match display.stage_parameters {
|
||||
Some(ref params) => Some(VRStageParameters::new(params.clone(), &global)),
|
||||
None => None,
|
||||
};
|
||||
|
||||
VRDisplay {
|
||||
eventtarget: EventTarget::new_inherited(),
|
||||
display: DomRefCell::new(display.clone()),
|
||||
depth_near: Cell::new(0.01),
|
||||
depth_far: Cell::new(10000.0),
|
||||
presenting: Cell::new(false),
|
||||
has_raf_thread: Cell::new(false),
|
||||
left_eye_params: MutDom::new(&*VREyeParameters::new(
|
||||
display.left_eye_parameters.clone(),
|
||||
&global,
|
||||
)),
|
||||
right_eye_params: MutDom::new(&*VREyeParameters::new(
|
||||
display.right_eye_parameters.clone(),
|
||||
&global,
|
||||
)),
|
||||
capabilities: MutDom::new(&*VRDisplayCapabilities::new(
|
||||
display.capabilities.clone(),
|
||||
&global,
|
||||
)),
|
||||
stage_params: MutNullableDom::new(stage.as_deref()),
|
||||
frame_data: DomRefCell::new(Default::default()),
|
||||
layer: DomRefCell::new(Default::default()),
|
||||
layer_ctx: MutNullableDom::default(),
|
||||
next_raf_id: Cell::new(1),
|
||||
raf_callback_list: DomRefCell::new(vec![]),
|
||||
raf_wakeup_sender: DomRefCell::new(None),
|
||||
pending_renderstate_updates: DomRefCell::new(vec![]),
|
||||
frame_data_status: Cell::new(VRFrameDataStatus::Waiting),
|
||||
frame_data_receiver: DomRefCell::new(None),
|
||||
running_display_raf: Cell::new(false),
|
||||
// Some VR implementations (e.g. Daydream) can be paused in some life cycle situations
|
||||
// such as showing and hiding the controller pairing screen.
|
||||
paused: Cell::new(false),
|
||||
// This flag is set when the Display was presenting when it received a VR Pause event.
|
||||
// When the VR Resume event is received and the flag is set, VR presentation automatically restarts.
|
||||
stopped_on_pause: Cell::new(false),
|
||||
webvr_thread: global.webvr_thread().expect("webvr is disabled"),
|
||||
pipeline: global.pipeline_id(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new(global: &Window, display: WebVRDisplayData) -> DomRoot<VRDisplay> {
|
||||
reflect_dom_object(Box::new(VRDisplay::new_inherited(&global, display)), global)
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for VRDisplay {
|
||||
fn drop(&mut self) {
|
||||
if self.presenting.get() {
|
||||
self.force_stop_present();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl VRDisplayMethods for VRDisplay {
|
||||
// https://w3c.github.io/webvr/#dom-vrdisplay-isconnected
|
||||
fn IsConnected(&self) -> bool {
|
||||
self.display.borrow().connected
|
||||
}
|
||||
|
||||
// https://w3c.github.io/webvr/#dom-vrdisplay-ispresenting
|
||||
fn IsPresenting(&self) -> bool {
|
||||
self.presenting.get()
|
||||
}
|
||||
|
||||
// https://w3c.github.io/webvr/#dom-vrdisplay-capabilities
|
||||
fn Capabilities(&self) -> DomRoot<VRDisplayCapabilities> {
|
||||
DomRoot::from_ref(&*self.capabilities.get())
|
||||
}
|
||||
|
||||
// https://w3c.github.io/webvr/#dom-vrdisplay-stageparameters
|
||||
fn GetStageParameters(&self) -> Option<DomRoot<VRStageParameters>> {
|
||||
self.stage_params.get().map(|s| DomRoot::from_ref(&*s))
|
||||
}
|
||||
|
||||
// https://w3c.github.io/webvr/#dom-vrdisplay-geteyeparameters
|
||||
fn GetEyeParameters(&self, eye: VREye) -> DomRoot<VREyeParameters> {
|
||||
match eye {
|
||||
VREye::Left => DomRoot::from_ref(&*self.left_eye_params.get()),
|
||||
VREye::Right => DomRoot::from_ref(&*self.right_eye_params.get()),
|
||||
}
|
||||
}
|
||||
|
||||
// https://w3c.github.io/webvr/#dom-vrdisplay-displayid
|
||||
fn DisplayId(&self) -> u32 {
|
||||
self.display.borrow().display_id
|
||||
}
|
||||
|
||||
// https://w3c.github.io/webvr/#dom-vrdisplay-displayname
|
||||
fn DisplayName(&self) -> DOMString {
|
||||
DOMString::from(self.display.borrow().display_name.clone())
|
||||
}
|
||||
|
||||
// https://w3c.github.io/webvr/#dom-vrdisplay-getframedata-framedata-framedata
|
||||
fn GetFrameData(&self, frame_data: &VRFrameData) -> bool {
|
||||
// If presenting we use a synced data with compositor for the whole frame.
|
||||
// Frame data is only synced with compositor when GetFrameData is called from
|
||||
// inside the VRDisplay.requestAnimationFrame. This is checked using the running_display_raf property.
|
||||
// This check avoids data race conditions when calling GetFrameData from outside of the
|
||||
// VRDisplay.requestAnimationFrame callbacks and fixes a possible deadlock during the interval
|
||||
// when the requestAnimationFrame is moved from window to VRDisplay.
|
||||
if self.presenting.get() && self.running_display_raf.get() {
|
||||
if self.frame_data_status.get() == VRFrameDataStatus::Waiting {
|
||||
self.sync_frame_data();
|
||||
}
|
||||
frame_data.update(&self.frame_data.borrow());
|
||||
return true;
|
||||
}
|
||||
|
||||
// If not presenting we fetch inmediante VRFrameData
|
||||
let (sender, receiver) = ipc::channel(self.global().time_profiler_chan().clone()).unwrap();
|
||||
self.webvr_thread
|
||||
.send(WebVRMsg::GetFrameData(
|
||||
self.global().pipeline_id(),
|
||||
self.DisplayId(),
|
||||
self.depth_near.get(),
|
||||
self.depth_far.get(),
|
||||
sender,
|
||||
))
|
||||
.unwrap();
|
||||
return match receiver.recv().unwrap() {
|
||||
Ok(data) => {
|
||||
frame_data.update(&data);
|
||||
true
|
||||
},
|
||||
Err(e) => {
|
||||
error!("WebVR::GetFrameData: {:?}", e);
|
||||
false
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
// https://w3c.github.io/webvr/#dom-vrdisplay-getpose
|
||||
fn GetPose(&self) -> DomRoot<VRPose> {
|
||||
VRPose::new(&self.global(), &self.frame_data.borrow().pose)
|
||||
}
|
||||
|
||||
// https://w3c.github.io/webvr/#dom-vrdisplay-resetpose
|
||||
fn ResetPose(&self) {
|
||||
let (sender, receiver) = ipc::channel(self.global().time_profiler_chan().clone()).unwrap();
|
||||
self.webvr_thread
|
||||
.send(WebVRMsg::ResetPose(
|
||||
self.global().pipeline_id(),
|
||||
self.DisplayId(),
|
||||
sender,
|
||||
))
|
||||
.unwrap();
|
||||
if let Ok(data) = receiver.recv().unwrap() {
|
||||
// Some VRDisplay data might change after calling ResetPose()
|
||||
*self.display.borrow_mut() = data;
|
||||
}
|
||||
}
|
||||
|
||||
// https://w3c.github.io/webvr/#dom-vrdisplay-depthnear
|
||||
fn DepthNear(&self) -> Finite<f64> {
|
||||
Finite::wrap(self.depth_near.get())
|
||||
}
|
||||
|
||||
// https://w3c.github.io/webvr/#dom-vrdisplay-depthnear
|
||||
fn SetDepthNear(&self, value: Finite<f64>) {
|
||||
self.depth_near.set(*value);
|
||||
}
|
||||
|
||||
// https://w3c.github.io/webvr/#dom-vrdisplay-depthfar
|
||||
fn DepthFar(&self) -> Finite<f64> {
|
||||
Finite::wrap(self.depth_far.get())
|
||||
}
|
||||
|
||||
// https://w3c.github.io/webvr/#dom-vrdisplay-depthfar
|
||||
fn SetDepthFar(&self, value: Finite<f64>) {
|
||||
self.depth_far.set(*value);
|
||||
}
|
||||
|
||||
// https://w3c.github.io/webvr/#dom-vrdisplay-requestanimationframe
|
||||
fn RequestAnimationFrame(&self, callback: Rc<FrameRequestCallback>) -> u32 {
|
||||
if self.presenting.get() {
|
||||
let raf_id = self.next_raf_id.get();
|
||||
self.next_raf_id.set(raf_id + 1);
|
||||
self.raf_callback_list
|
||||
.borrow_mut()
|
||||
.push((raf_id, Some(callback)));
|
||||
raf_id
|
||||
} else {
|
||||
// WebVR spec: When a VRDisplay is not presenting it should
|
||||
// fallback to window.requestAnimationFrame.
|
||||
self.global().as_window().RequestAnimationFrame(callback)
|
||||
}
|
||||
}
|
||||
|
||||
// https://w3c.github.io/webvr/#dom-vrdisplay-cancelanimationframe
|
||||
fn CancelAnimationFrame(&self, handle: u32) {
|
||||
if self.presenting.get() {
|
||||
let mut list = self.raf_callback_list.borrow_mut();
|
||||
if let Some(pair) = list.iter_mut().find(|pair| pair.0 == handle) {
|
||||
pair.1 = None;
|
||||
}
|
||||
} else {
|
||||
// WebVR spec: When a VRDisplay is not presenting it should
|
||||
// fallback to window.cancelAnimationFrame.
|
||||
self.global().as_window().CancelAnimationFrame(handle);
|
||||
}
|
||||
}
|
||||
|
||||
// https://w3c.github.io/webvr/#dom-vrdisplay-requestpresent
|
||||
fn RequestPresent(&self, layers: Vec<VRLayer>, comp: InRealm) -> Rc<Promise> {
|
||||
let promise = Promise::new_in_current_realm(&self.global(), comp);
|
||||
// TODO: WebVR spec: this method must be called in response to a user gesture
|
||||
|
||||
// WebVR spec: If canPresent is false the promise MUST be rejected
|
||||
if !self.display.borrow().capabilities.can_present {
|
||||
let msg = "VRDisplay canPresent is false".to_string();
|
||||
promise.reject_native(&msg);
|
||||
return promise;
|
||||
}
|
||||
|
||||
// Current WebVRSpec only allows 1 VRLayer if the VRDevice can present.
|
||||
// Future revisions of this spec may allow multiple layers to enable more complex rendering effects
|
||||
// such as compositing WebGL and DOM elements together.
|
||||
// That functionality is not allowed by this revision of the spec.
|
||||
if layers.len() != 1 {
|
||||
let msg = "The number of layers must be 1".to_string();
|
||||
promise.reject_native(&msg);
|
||||
return promise;
|
||||
}
|
||||
|
||||
// Parse and validate received VRLayer
|
||||
let layer = validate_layer(&layers[0]);
|
||||
|
||||
let layer_bounds;
|
||||
let layer_ctx;
|
||||
|
||||
match layer {
|
||||
Ok((bounds, ctx)) => {
|
||||
layer_bounds = bounds;
|
||||
layer_ctx = ctx;
|
||||
},
|
||||
Err(msg) => {
|
||||
let msg = msg.to_string();
|
||||
promise.reject_native(&msg);
|
||||
return promise;
|
||||
},
|
||||
};
|
||||
|
||||
// WebVR spec: Repeat calls while already presenting will update the VRLayers being displayed.
|
||||
if self.presenting.get() {
|
||||
*self.layer.borrow_mut() = layer_bounds;
|
||||
self.layer_ctx.set(Some(&layer_ctx));
|
||||
promise.resolve_native(&());
|
||||
return promise;
|
||||
}
|
||||
|
||||
let xr = self.global().as_window().Navigator().Xr();
|
||||
|
||||
if xr.pending_or_active_session() {
|
||||
// WebVR spec doesn't mandate anything here, however
|
||||
// the WebXR spec expects there to be only one immersive XR session at a time,
|
||||
// and WebVR is deprecated
|
||||
promise.reject_error(Error::InvalidState);
|
||||
return promise;
|
||||
}
|
||||
|
||||
self.request_present(layer_bounds, Some(&layer_ctx), Some(promise.clone()), |p| {
|
||||
p.resolve_native(&())
|
||||
});
|
||||
promise
|
||||
}
|
||||
|
||||
// https://w3c.github.io/webvr/#dom-vrdisplay-exitpresent
|
||||
fn ExitPresent(&self, comp: InRealm) -> Rc<Promise> {
|
||||
let promise = Promise::new_in_current_realm(&self.global(), comp);
|
||||
|
||||
// WebVR spec: If the VRDisplay is not presenting the promise MUST be rejected.
|
||||
if !self.presenting.get() {
|
||||
let msg = "VRDisplay is not presenting".to_string();
|
||||
promise.reject_native(&msg);
|
||||
return promise;
|
||||
}
|
||||
|
||||
// Exit present
|
||||
let (sender, receiver) = ipc::channel(self.global().time_profiler_chan().clone()).unwrap();
|
||||
self.webvr_thread
|
||||
.send(WebVRMsg::ExitPresent(
|
||||
self.global().pipeline_id(),
|
||||
self.display.borrow().display_id,
|
||||
Some(sender),
|
||||
))
|
||||
.unwrap();
|
||||
match receiver.recv().unwrap() {
|
||||
Ok(()) => {
|
||||
self.stop_present();
|
||||
promise.resolve_native(&());
|
||||
},
|
||||
Err(e) => {
|
||||
promise.reject_native(&e);
|
||||
},
|
||||
}
|
||||
|
||||
promise
|
||||
}
|
||||
|
||||
// https://w3c.github.io/webvr/#dom-vrdisplay-submitframe
|
||||
fn SubmitFrame(&self) {
|
||||
if !self.presenting.get() {
|
||||
warn!("VRDisplay not presenting");
|
||||
return;
|
||||
}
|
||||
|
||||
let display_id = self.display.borrow().display_id;
|
||||
let layer = self.layer.borrow();
|
||||
let msg = WebVRCommand::SubmitFrame(display_id, layer.left_bounds, layer.right_bounds);
|
||||
self.layer_ctx
|
||||
.get()
|
||||
.expect("SubmitFrame can only be called when there is a webgl layer")
|
||||
.send_vr_command(msg);
|
||||
}
|
||||
|
||||
// https://w3c.github.io/webvr/spec/1.1/#dom-vrdisplay-getlayers
|
||||
fn GetLayers(&self) -> Vec<VRLayer> {
|
||||
// WebVR spec: MUST return an empty array if the VRDisplay is not currently presenting
|
||||
if !self.presenting.get() {
|
||||
return Vec::new();
|
||||
}
|
||||
|
||||
let layer = self.layer.borrow();
|
||||
|
||||
vec![VRLayer {
|
||||
leftBounds: Some(bounds_to_vec(&layer.left_bounds)),
|
||||
rightBounds: Some(bounds_to_vec(&layer.right_bounds)),
|
||||
source: self.layer_ctx.get().map(|ctx| ctx.Canvas()),
|
||||
}]
|
||||
}
|
||||
}
|
||||
|
||||
impl VRDisplay {
|
||||
pub fn update_display(&self, display: &WebVRDisplayData) {
|
||||
*self.display.borrow_mut() = display.clone();
|
||||
if let Some(ref stage) = display.stage_parameters {
|
||||
if self.stage_params.get().is_none() {
|
||||
let params = Some(VRStageParameters::new(
|
||||
stage.clone(),
|
||||
&self.global().as_window(),
|
||||
));
|
||||
self.stage_params.set(params.as_deref());
|
||||
} else {
|
||||
self.stage_params.get().unwrap().update(&stage);
|
||||
}
|
||||
} else {
|
||||
self.stage_params.set(None);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn request_present<F>(
|
||||
&self,
|
||||
layer_bounds: WebVRLayer,
|
||||
ctx: Option<&WebGLRenderingContext>,
|
||||
promise: Option<Rc<Promise>>,
|
||||
resolve: F,
|
||||
) where
|
||||
F: FnOnce(Rc<Promise>) + Send + 'static,
|
||||
{
|
||||
// Request Present
|
||||
let (sender, receiver) = ipc::channel(self.global().time_profiler_chan().clone()).unwrap();
|
||||
self.webvr_thread
|
||||
.send(WebVRMsg::RequestPresent(
|
||||
self.global().pipeline_id(),
|
||||
self.display.borrow().display_id,
|
||||
sender,
|
||||
))
|
||||
.unwrap();
|
||||
let promise = promise.map(TrustedPromise::new);
|
||||
let this = Trusted::new(self);
|
||||
let ctx = ctx.map(|c| Trusted::new(c));
|
||||
let global = self.global();
|
||||
let window = global.as_window();
|
||||
let (task_source, canceller) = window
|
||||
.task_manager()
|
||||
.dom_manipulation_task_source_with_canceller();
|
||||
thread::spawn(move || {
|
||||
let recv = receiver.recv().unwrap();
|
||||
let _ = task_source.queue_with_canceller(
|
||||
task!(vr_presenting: move || {
|
||||
let this = this.root();
|
||||
let promise = promise.map(|p| p.root());
|
||||
let ctx = ctx.map(|c| c.root());
|
||||
match recv {
|
||||
Ok(()) => {
|
||||
*this.layer.borrow_mut() = layer_bounds;
|
||||
this.layer_ctx.set(ctx.as_deref());
|
||||
this.init_present();
|
||||
promise.map(resolve);
|
||||
},
|
||||
Err(e) => {
|
||||
promise.map(|p| p.reject_native(&e));
|
||||
},
|
||||
}
|
||||
}),
|
||||
&canceller,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
pub fn handle_webvr_event(&self, event: &WebVRDisplayEvent) {
|
||||
match *event {
|
||||
WebVRDisplayEvent::Connect(ref display) => {
|
||||
self.update_display(&display);
|
||||
},
|
||||
WebVRDisplayEvent::Disconnect(_id) => {
|
||||
self.display.borrow_mut().connected = false;
|
||||
},
|
||||
WebVRDisplayEvent::Activate(ref display, _) |
|
||||
WebVRDisplayEvent::Deactivate(ref display, _) |
|
||||
WebVRDisplayEvent::Blur(ref display) |
|
||||
WebVRDisplayEvent::Focus(ref display) => {
|
||||
self.update_display(&display);
|
||||
self.notify_event(&event);
|
||||
},
|
||||
WebVRDisplayEvent::PresentChange(ref display, presenting) => {
|
||||
self.update_display(&display);
|
||||
self.presenting.set(presenting);
|
||||
self.notify_event(&event);
|
||||
},
|
||||
WebVRDisplayEvent::Change(ref display) => {
|
||||
// Change event doesn't exist in WebVR spec.
|
||||
// So we update display data but don't notify JS.
|
||||
self.update_display(&display);
|
||||
},
|
||||
WebVRDisplayEvent::Pause(_) => {
|
||||
if self.paused.get() {
|
||||
return;
|
||||
}
|
||||
self.paused.set(true);
|
||||
if self.presenting.get() {
|
||||
self.stop_present();
|
||||
self.stopped_on_pause.set(true);
|
||||
}
|
||||
},
|
||||
WebVRDisplayEvent::Resume(_) => {
|
||||
self.paused.set(false);
|
||||
if self.stopped_on_pause.get() {
|
||||
self.stopped_on_pause.set(false);
|
||||
self.init_present();
|
||||
}
|
||||
},
|
||||
WebVRDisplayEvent::Exit(_) => {
|
||||
self.stopped_on_pause.set(false);
|
||||
if self.presenting.get() {
|
||||
self.stop_present();
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
fn notify_event(&self, event: &WebVRDisplayEvent) {
|
||||
let root = DomRoot::from_ref(&*self);
|
||||
let event = VRDisplayEvent::new_from_webvr(&self.global(), &root, &event);
|
||||
event
|
||||
.upcast::<Event>()
|
||||
.fire(self.global().upcast::<EventTarget>());
|
||||
}
|
||||
|
||||
fn api_sender(&self) -> Option<WebGLMessageSender> {
|
||||
self.layer_ctx.get().map(|c| c.webgl_sender())
|
||||
}
|
||||
|
||||
fn context_id(&self) -> usize {
|
||||
self.layer_ctx
|
||||
.get()
|
||||
.map(|c| &*c as *const WebGLRenderingContext as usize)
|
||||
.unwrap_or(0)
|
||||
}
|
||||
|
||||
fn vr_raf_update(&self) -> VRRAFUpdate {
|
||||
VRRAFUpdate {
|
||||
depth_near: self.depth_near.get(),
|
||||
depth_far: self.depth_far.get(),
|
||||
api_sender: self.api_sender(),
|
||||
context_id: self.context_id(),
|
||||
}
|
||||
}
|
||||
|
||||
fn init_present(&self) {
|
||||
self.presenting.set(true);
|
||||
if self.has_raf_thread.get() {
|
||||
return;
|
||||
}
|
||||
self.has_raf_thread.set(true);
|
||||
let (sync_sender, sync_receiver) = webgl_channel().unwrap();
|
||||
*self.frame_data_receiver.borrow_mut() = Some(sync_receiver);
|
||||
|
||||
let display_id = self.display.borrow().display_id;
|
||||
let mut api_sender = self.api_sender();
|
||||
let mut context_id = self.context_id();
|
||||
let js_sender = self.global().script_chan();
|
||||
let address = Trusted::new(&*self);
|
||||
let mut near = self.depth_near.get();
|
||||
let mut far = self.depth_far.get();
|
||||
let pipeline_id = self.global().pipeline_id();
|
||||
|
||||
let (raf_sender, raf_receiver) = unbounded();
|
||||
let (wakeup_sender, wakeup_receiver) = unbounded();
|
||||
*self.raf_wakeup_sender.borrow_mut() = Some(wakeup_sender);
|
||||
|
||||
// The render loop at native headset frame rate is implemented using a dedicated thread.
|
||||
// Every loop iteration syncs pose data with the HMD, submits the pixels to the display and waits for Vsync.
|
||||
// Both the requestAnimationFrame call of a VRDisplay in the JavaScript thread and the VRSyncPoses call
|
||||
// in the Webrender thread are executed in parallel. This allows to get some JavaScript code executed ahead.
|
||||
// while the render thread is syncing the VRFrameData to be used for the current frame.
|
||||
// This thread runs until the user calls ExitPresent, the tab is closed or some unexpected error happened.
|
||||
thread::Builder::new()
|
||||
.name("WebVR_RAF".into())
|
||||
.spawn(move || {
|
||||
// Initialize compositor
|
||||
if let Some(ref api_sender) = api_sender {
|
||||
api_sender
|
||||
.send_vr(WebVRCommand::Create(display_id))
|
||||
.unwrap();
|
||||
}
|
||||
loop {
|
||||
if let Some(ref api_sender) = api_sender {
|
||||
// Run RAF callbacks on JavaScript thread
|
||||
let this = address.clone();
|
||||
let sender = raf_sender.clone();
|
||||
let task = Box::new(task!(handle_vrdisplay_raf: move || {
|
||||
this.root().handle_raf(&sender);
|
||||
}));
|
||||
// NOTE: WebVR spec doesn't specify what task source we should use. Is
|
||||
// dom-manipulation a good choice long term?
|
||||
js_sender
|
||||
.send(CommonScriptMsg::Task(
|
||||
WebVREvent,
|
||||
task,
|
||||
Some(pipeline_id),
|
||||
TaskSourceName::DOMManipulation,
|
||||
))
|
||||
.unwrap();
|
||||
|
||||
// Run Sync Poses in parallell on Render thread
|
||||
let msg = WebVRCommand::SyncPoses(
|
||||
display_id,
|
||||
near,
|
||||
far,
|
||||
false,
|
||||
sync_sender.clone(),
|
||||
);
|
||||
api_sender.send_vr(msg).unwrap();
|
||||
} else {
|
||||
let _ = wakeup_receiver.recv();
|
||||
let sender = raf_sender.clone();
|
||||
let this = address.clone();
|
||||
let task = Box::new(task!(flush_renderstate_queue: move || {
|
||||
let this = this.root();
|
||||
sender.send(Ok(this.vr_raf_update())).unwrap();
|
||||
}));
|
||||
js_sender
|
||||
.send(CommonScriptMsg::Task(
|
||||
WebVREvent,
|
||||
task,
|
||||
Some(pipeline_id),
|
||||
TaskSourceName::DOMManipulation,
|
||||
))
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
// Wait until both SyncPoses & RAF ends
|
||||
if let Ok(update) = raf_receiver.recv().unwrap() {
|
||||
near = update.depth_near;
|
||||
far = update.depth_far;
|
||||
if update.context_id != context_id {
|
||||
if let Some(ref api_sender) = update.api_sender {
|
||||
api_sender
|
||||
.send_vr(WebVRCommand::Create(display_id))
|
||||
.unwrap();
|
||||
}
|
||||
if let Some(ref api_sender) = api_sender {
|
||||
// shut down old vr compositor
|
||||
api_sender
|
||||
.send_vr(WebVRCommand::Release(display_id))
|
||||
.unwrap();
|
||||
}
|
||||
context_id = update.context_id;
|
||||
}
|
||||
|
||||
api_sender = update.api_sender;
|
||||
} else {
|
||||
// Stop thread
|
||||
// ExitPresent called or some error happened
|
||||
return;
|
||||
}
|
||||
}
|
||||
})
|
||||
.expect("Thread spawning failed");
|
||||
}
|
||||
|
||||
fn stop_present(&self) {
|
||||
self.presenting.set(false);
|
||||
*self.frame_data_receiver.borrow_mut() = None;
|
||||
self.has_raf_thread.set(false);
|
||||
if let Some(api_sender) = self.api_sender() {
|
||||
let display_id = self.display.borrow().display_id;
|
||||
api_sender
|
||||
.send_vr(WebVRCommand::Release(display_id))
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
// Only called when the JSContext is destroyed while presenting.
|
||||
// In this case we don't want to wait for WebVR Thread response.
|
||||
fn force_stop_present(&self) {
|
||||
self.webvr_thread
|
||||
.send(WebVRMsg::ExitPresent(
|
||||
self.global().pipeline_id(),
|
||||
self.display.borrow().display_id,
|
||||
None,
|
||||
))
|
||||
.unwrap();
|
||||
self.stop_present();
|
||||
}
|
||||
|
||||
fn sync_frame_data(&self) {
|
||||
let status = if let Some(receiver) = self.frame_data_receiver.borrow().as_ref() {
|
||||
match receiver.recv().unwrap() {
|
||||
Ok(pose) => {
|
||||
*self.frame_data.borrow_mut() = pose.frame.block();
|
||||
VRFrameDataStatus::Synced
|
||||
},
|
||||
Err(()) => VRFrameDataStatus::Exit,
|
||||
}
|
||||
} else {
|
||||
VRFrameDataStatus::Exit
|
||||
};
|
||||
|
||||
self.frame_data_status.set(status);
|
||||
}
|
||||
|
||||
fn handle_raf(&self, end_sender: &VRRAFUpdateSender) {
|
||||
self.frame_data_status.set(VRFrameDataStatus::Waiting);
|
||||
|
||||
let now = self.global().as_window().Performance().Now();
|
||||
|
||||
self.running_display_raf.set(true);
|
||||
let mut callbacks = mem::replace(&mut *self.raf_callback_list.borrow_mut(), vec![]);
|
||||
// Call registered VRDisplay.requestAnimationFrame callbacks.
|
||||
for (_, callback) in callbacks.drain(..) {
|
||||
if let Some(callback) = callback {
|
||||
let _ = callback.Call__(Finite::wrap(*now), ExceptionHandling::Report);
|
||||
}
|
||||
}
|
||||
|
||||
self.running_display_raf.set(false);
|
||||
if self.frame_data_status.get() == VRFrameDataStatus::Waiting {
|
||||
// User didn't call getFrameData while presenting.
|
||||
// We automatically reads the pending VRFrameData to avoid overflowing the IPC-Channel buffers.
|
||||
// Show a warning as the WebVR Spec recommends.
|
||||
warn!("WebVR: You should call GetFrameData while presenting");
|
||||
self.sync_frame_data();
|
||||
}
|
||||
|
||||
match self.frame_data_status.get() {
|
||||
VRFrameDataStatus::Synced => {
|
||||
// Sync succeeded. Notify RAF thread.
|
||||
end_sender.send(Ok(self.vr_raf_update())).unwrap();
|
||||
},
|
||||
VRFrameDataStatus::Exit | VRFrameDataStatus::Waiting => {
|
||||
// ExitPresent called or some error ocurred.
|
||||
// Notify VRDisplay RAF thread to stop.
|
||||
end_sender.send(Err(())).unwrap();
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// WebVR Spec: If the number of values in the leftBounds/rightBounds arrays
|
||||
// is not 0 or 4 for any of the passed layers the promise is rejected
|
||||
fn parse_bounds(src: &Option<Vec<Finite<f32>>>, dst: &mut [f32; 4]) -> Result<(), &'static str> {
|
||||
match *src {
|
||||
Some(ref values) => {
|
||||
if values.len() == 0 {
|
||||
return Ok(());
|
||||
}
|
||||
if values.len() != 4 {
|
||||
return Err(
|
||||
"The number of values in the leftBounds/rightBounds arrays must be 0 or 4",
|
||||
);
|
||||
}
|
||||
for i in 0..4 {
|
||||
dst[i] = *values[i];
|
||||
}
|
||||
Ok(())
|
||||
},
|
||||
None => Ok(()),
|
||||
}
|
||||
}
|
||||
|
||||
fn validate_layer(
|
||||
layer: &VRLayer,
|
||||
) -> Result<(WebVRLayer, DomRoot<WebGLRenderingContext>), &'static str> {
|
||||
let ctx = layer
|
||||
.source
|
||||
.as_ref()
|
||||
.map(|ref s| s.get_base_webgl_context())
|
||||
.unwrap_or(None);
|
||||
if let Some(ctx) = ctx {
|
||||
let mut data = WebVRLayer::default();
|
||||
parse_bounds(&layer.leftBounds, &mut data.left_bounds)?;
|
||||
parse_bounds(&layer.rightBounds, &mut data.right_bounds)?;
|
||||
Ok((data, ctx))
|
||||
} else {
|
||||
Err("VRLayer source must be a WebGL Context")
|
||||
}
|
||||
}
|
||||
|
||||
fn bounds_to_vec(src: &[f32; 4]) -> Vec<Finite<f32>> {
|
||||
vec![
|
||||
Finite::wrap(src[0]),
|
||||
Finite::wrap(src[1]),
|
||||
Finite::wrap(src[2]),
|
||||
Finite::wrap(src[3]),
|
||||
]
|
||||
}
|
|
@ -1,70 +0,0 @@
|
|||
/* 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 crate::dom::bindings::cell::DomRefCell;
|
||||
use crate::dom::bindings::codegen::Bindings::VRDisplayCapabilitiesBinding::VRDisplayCapabilitiesMethods;
|
||||
use crate::dom::bindings::reflector::{reflect_dom_object, Reflector};
|
||||
use crate::dom::bindings::root::DomRoot;
|
||||
use crate::dom::window::Window;
|
||||
use dom_struct::dom_struct;
|
||||
use webvr_traits::WebVRDisplayCapabilities;
|
||||
|
||||
#[dom_struct]
|
||||
pub struct VRDisplayCapabilities {
|
||||
reflector_: Reflector,
|
||||
#[ignore_malloc_size_of = "Defined in rust-webvr"]
|
||||
capabilities: DomRefCell<WebVRDisplayCapabilities>,
|
||||
}
|
||||
|
||||
unsafe_no_jsmanaged_fields!(WebVRDisplayCapabilities);
|
||||
|
||||
impl VRDisplayCapabilities {
|
||||
fn new_inherited(capabilities: WebVRDisplayCapabilities) -> VRDisplayCapabilities {
|
||||
VRDisplayCapabilities {
|
||||
reflector_: Reflector::new(),
|
||||
capabilities: DomRefCell::new(capabilities),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new(
|
||||
capabilities: WebVRDisplayCapabilities,
|
||||
global: &Window,
|
||||
) -> DomRoot<VRDisplayCapabilities> {
|
||||
reflect_dom_object(
|
||||
Box::new(VRDisplayCapabilities::new_inherited(capabilities)),
|
||||
global,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl VRDisplayCapabilitiesMethods for VRDisplayCapabilities {
|
||||
// https://w3c.github.io/webvr/#dom-vrdisplaycapabilities-hasposition
|
||||
fn HasPosition(&self) -> bool {
|
||||
self.capabilities.borrow().has_position
|
||||
}
|
||||
|
||||
// https://w3c.github.io/webvr/#dom-vrdisplaycapabilities-hasorientation
|
||||
fn HasOrientation(&self) -> bool {
|
||||
self.capabilities.borrow().has_orientation
|
||||
}
|
||||
|
||||
// https://w3c.github.io/webvr/#dom-vrdisplaycapabilities-hasexternaldisplay
|
||||
fn HasExternalDisplay(&self) -> bool {
|
||||
self.capabilities.borrow().has_external_display
|
||||
}
|
||||
|
||||
// https://w3c.github.io/webvr/#dom-vrdisplaycapabilities-canpresent
|
||||
fn CanPresent(&self) -> bool {
|
||||
self.capabilities.borrow().can_present
|
||||
}
|
||||
|
||||
// https://w3c.github.io/webvr/#dom-vrdisplaycapabilities-maxlayers
|
||||
fn MaxLayers(&self) -> u32 {
|
||||
if self.CanPresent() {
|
||||
1
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,125 +0,0 @@
|
|||
/* 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 crate::dom::bindings::codegen::Bindings::EventBinding::EventBinding::EventMethods;
|
||||
use crate::dom::bindings::codegen::Bindings::VRDisplayEventBinding;
|
||||
use crate::dom::bindings::codegen::Bindings::VRDisplayEventBinding::VRDisplayEventMethods;
|
||||
use crate::dom::bindings::codegen::Bindings::VRDisplayEventBinding::VRDisplayEventReason;
|
||||
use crate::dom::bindings::error::Fallible;
|
||||
use crate::dom::bindings::inheritance::Castable;
|
||||
use crate::dom::bindings::reflector::{reflect_dom_object, DomObject};
|
||||
use crate::dom::bindings::root::{Dom, DomRoot};
|
||||
use crate::dom::bindings::str::DOMString;
|
||||
use crate::dom::event::Event;
|
||||
use crate::dom::globalscope::GlobalScope;
|
||||
use crate::dom::vrdisplay::VRDisplay;
|
||||
use crate::dom::window::Window;
|
||||
use dom_struct::dom_struct;
|
||||
use servo_atoms::Atom;
|
||||
use webvr_traits::{WebVRDisplayEvent, WebVRDisplayEventReason};
|
||||
|
||||
#[dom_struct]
|
||||
pub struct VRDisplayEvent {
|
||||
event: Event,
|
||||
display: Dom<VRDisplay>,
|
||||
reason: Option<VRDisplayEventReason>,
|
||||
}
|
||||
|
||||
impl VRDisplayEvent {
|
||||
fn new_inherited(display: &VRDisplay, reason: Option<VRDisplayEventReason>) -> VRDisplayEvent {
|
||||
VRDisplayEvent {
|
||||
event: Event::new_inherited(),
|
||||
display: Dom::from_ref(display),
|
||||
reason: reason.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new(
|
||||
global: &GlobalScope,
|
||||
type_: Atom,
|
||||
bubbles: bool,
|
||||
cancelable: bool,
|
||||
display: &VRDisplay,
|
||||
reason: Option<VRDisplayEventReason>,
|
||||
) -> DomRoot<VRDisplayEvent> {
|
||||
let ev = reflect_dom_object(
|
||||
Box::new(VRDisplayEvent::new_inherited(&display, reason)),
|
||||
global,
|
||||
);
|
||||
{
|
||||
let event = ev.upcast::<Event>();
|
||||
event.init_event(type_, bubbles, cancelable);
|
||||
}
|
||||
ev
|
||||
}
|
||||
|
||||
pub fn new_from_webvr(
|
||||
global: &GlobalScope,
|
||||
display: &VRDisplay,
|
||||
event: &WebVRDisplayEvent,
|
||||
) -> DomRoot<VRDisplayEvent> {
|
||||
let (name, reason) = match *event {
|
||||
WebVRDisplayEvent::Connect(_) => ("vrdisplayconnect", None),
|
||||
WebVRDisplayEvent::Disconnect(_) => ("vrdisplaydisconnect", None),
|
||||
WebVRDisplayEvent::Activate(_, reason) => ("vrdisplayactivate", Some(reason)),
|
||||
WebVRDisplayEvent::Deactivate(_, reason) => ("vrdisplaydeactivate", Some(reason)),
|
||||
WebVRDisplayEvent::Blur(_) => ("vrdisplayblur", None),
|
||||
WebVRDisplayEvent::Focus(_) => ("vrdisplayfocus", None),
|
||||
WebVRDisplayEvent::PresentChange(_, _) => ("vrdisplaypresentchange", None),
|
||||
WebVRDisplayEvent::Change(_) |
|
||||
WebVRDisplayEvent::Pause(_) |
|
||||
WebVRDisplayEvent::Resume(_) |
|
||||
WebVRDisplayEvent::Exit(_) => panic!("{:?} event not available in WebVR", event),
|
||||
};
|
||||
|
||||
// map to JS enum values
|
||||
let reason = reason.map(|r| match r {
|
||||
WebVRDisplayEventReason::Navigation => VRDisplayEventReason::Navigation,
|
||||
WebVRDisplayEventReason::Mounted => VRDisplayEventReason::Mounted,
|
||||
WebVRDisplayEventReason::Unmounted => VRDisplayEventReason::Unmounted,
|
||||
});
|
||||
|
||||
VRDisplayEvent::new(
|
||||
&global,
|
||||
Atom::from(DOMString::from(name)),
|
||||
false,
|
||||
false,
|
||||
&display,
|
||||
reason,
|
||||
)
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
pub fn Constructor(
|
||||
window: &Window,
|
||||
type_: DOMString,
|
||||
init: &VRDisplayEventBinding::VRDisplayEventInit,
|
||||
) -> Fallible<DomRoot<VRDisplayEvent>> {
|
||||
Ok(VRDisplayEvent::new(
|
||||
&window.global(),
|
||||
Atom::from(type_),
|
||||
init.parent.bubbles,
|
||||
init.parent.cancelable,
|
||||
&init.display,
|
||||
init.reason,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
impl VRDisplayEventMethods for VRDisplayEvent {
|
||||
// https://w3c.github.io/webvr/#dom-vrdisplayevent-display
|
||||
fn Display(&self) -> DomRoot<VRDisplay> {
|
||||
DomRoot::from_ref(&*self.display)
|
||||
}
|
||||
|
||||
// https://w3c.github.io/webvr/#enumdef-vrdisplayeventreason
|
||||
fn GetReason(&self) -> Option<VRDisplayEventReason> {
|
||||
self.reason
|
||||
}
|
||||
|
||||
// https://dom.spec.whatwg.org/#dom-event-istrusted
|
||||
fn IsTrusted(&self) -> bool {
|
||||
self.event.IsTrusted()
|
||||
}
|
||||
}
|
|
@ -1,87 +0,0 @@
|
|||
/* 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 crate::dom::bindings::cell::DomRefCell;
|
||||
use crate::dom::bindings::codegen::Bindings::VREyeParametersBinding::VREyeParametersMethods;
|
||||
use crate::dom::bindings::reflector::{reflect_dom_object, Reflector};
|
||||
use crate::dom::bindings::root::{Dom, DomRoot};
|
||||
use crate::dom::vrfieldofview::VRFieldOfView;
|
||||
use crate::dom::window::Window;
|
||||
use crate::script_runtime::JSContext;
|
||||
use dom_struct::dom_struct;
|
||||
use js::jsapi::{Heap, JSObject};
|
||||
use js::typedarray::{CreateWith, Float32Array};
|
||||
use std::default::Default;
|
||||
use std::ptr;
|
||||
use std::ptr::NonNull;
|
||||
use webvr_traits::WebVREyeParameters;
|
||||
|
||||
#[dom_struct]
|
||||
pub struct VREyeParameters {
|
||||
reflector_: Reflector,
|
||||
#[ignore_malloc_size_of = "Defined in rust-webvr"]
|
||||
parameters: DomRefCell<WebVREyeParameters>,
|
||||
#[ignore_malloc_size_of = "mozjs"]
|
||||
offset: Heap<*mut JSObject>,
|
||||
fov: Dom<VRFieldOfView>,
|
||||
}
|
||||
|
||||
unsafe_no_jsmanaged_fields!(WebVREyeParameters);
|
||||
|
||||
impl VREyeParameters {
|
||||
fn new_inherited(parameters: WebVREyeParameters, fov: &VRFieldOfView) -> VREyeParameters {
|
||||
VREyeParameters {
|
||||
reflector_: Reflector::new(),
|
||||
parameters: DomRefCell::new(parameters),
|
||||
offset: Heap::default(),
|
||||
fov: Dom::from_ref(&*fov),
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unsafe_code)]
|
||||
pub fn new(parameters: WebVREyeParameters, global: &Window) -> DomRoot<VREyeParameters> {
|
||||
let fov = VRFieldOfView::new(&global, parameters.field_of_view.clone());
|
||||
|
||||
let cx = global.get_cx();
|
||||
rooted!(in (*cx) let mut array = ptr::null_mut::<JSObject>());
|
||||
unsafe {
|
||||
let _ = Float32Array::create(
|
||||
*cx,
|
||||
CreateWith::Slice(¶meters.offset),
|
||||
array.handle_mut(),
|
||||
);
|
||||
}
|
||||
|
||||
let eye_parameters = reflect_dom_object(
|
||||
Box::new(VREyeParameters::new_inherited(parameters, &fov)),
|
||||
global,
|
||||
);
|
||||
eye_parameters.offset.set(array.get());
|
||||
|
||||
eye_parameters
|
||||
}
|
||||
}
|
||||
|
||||
impl VREyeParametersMethods for VREyeParameters {
|
||||
#[allow(unsafe_code)]
|
||||
// https://w3c.github.io/webvr/#dom-vreyeparameters-offset
|
||||
fn Offset(&self, _cx: JSContext) -> NonNull<JSObject> {
|
||||
unsafe { NonNull::new_unchecked(self.offset.get()) }
|
||||
}
|
||||
|
||||
// https://w3c.github.io/webvr/#dom-vreyeparameters-fieldofview
|
||||
fn FieldOfView(&self) -> DomRoot<VRFieldOfView> {
|
||||
DomRoot::from_ref(&*self.fov)
|
||||
}
|
||||
|
||||
// https://w3c.github.io/webvr/#dom-vreyeparameters-renderwidth
|
||||
fn RenderWidth(&self) -> u32 {
|
||||
self.parameters.borrow().render_width
|
||||
}
|
||||
|
||||
// https://w3c.github.io/webvr/#dom-vreyeparameters-renderheight
|
||||
fn RenderHeight(&self) -> u32 {
|
||||
self.parameters.borrow().render_height
|
||||
}
|
||||
}
|
|
@ -1,56 +0,0 @@
|
|||
/* 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 crate::dom::bindings::cell::DomRefCell;
|
||||
use crate::dom::bindings::codegen::Bindings::VRFieldOfViewBinding::VRFieldOfViewMethods;
|
||||
use crate::dom::bindings::num::Finite;
|
||||
use crate::dom::bindings::reflector::{reflect_dom_object, Reflector};
|
||||
use crate::dom::bindings::root::DomRoot;
|
||||
use crate::dom::window::Window;
|
||||
use dom_struct::dom_struct;
|
||||
use webvr_traits::WebVRFieldOfView;
|
||||
|
||||
#[dom_struct]
|
||||
pub struct VRFieldOfView {
|
||||
reflector_: Reflector,
|
||||
#[ignore_malloc_size_of = "Defined in rust-webvr"]
|
||||
fov: DomRefCell<WebVRFieldOfView>,
|
||||
}
|
||||
|
||||
unsafe_no_jsmanaged_fields!(WebVRFieldOfView);
|
||||
|
||||
impl VRFieldOfView {
|
||||
fn new_inherited(fov: WebVRFieldOfView) -> VRFieldOfView {
|
||||
VRFieldOfView {
|
||||
reflector_: Reflector::new(),
|
||||
fov: DomRefCell::new(fov),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new(global: &Window, fov: WebVRFieldOfView) -> DomRoot<VRFieldOfView> {
|
||||
reflect_dom_object(Box::new(VRFieldOfView::new_inherited(fov)), global)
|
||||
}
|
||||
}
|
||||
|
||||
impl VRFieldOfViewMethods for VRFieldOfView {
|
||||
// https://w3c.github.io/webvr/#interface-interface-vrfieldofview
|
||||
fn UpDegrees(&self) -> Finite<f64> {
|
||||
Finite::wrap(self.fov.borrow().up_degrees)
|
||||
}
|
||||
|
||||
// https://w3c.github.io/webvr/#interface-interface-vrfieldofview
|
||||
fn RightDegrees(&self) -> Finite<f64> {
|
||||
Finite::wrap(self.fov.borrow().right_degrees)
|
||||
}
|
||||
|
||||
// https://w3c.github.io/webvr/#interface-interface-vrfieldofview
|
||||
fn DownDegrees(&self) -> Finite<f64> {
|
||||
Finite::wrap(self.fov.borrow().down_degrees)
|
||||
}
|
||||
|
||||
// https://w3c.github.io/webvr/#interface-interface-vrfieldofview
|
||||
fn LeftDegrees(&self) -> Finite<f64> {
|
||||
Finite::wrap(self.fov.borrow().left_degrees)
|
||||
}
|
||||
}
|
|
@ -1,150 +0,0 @@
|
|||
/* 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 crate::dom::bindings::codegen::Bindings::PerformanceBinding::DOMHighResTimeStamp;
|
||||
use crate::dom::bindings::codegen::Bindings::VRFrameDataBinding::VRFrameDataMethods;
|
||||
use crate::dom::bindings::error::Fallible;
|
||||
use crate::dom::bindings::reflector::{reflect_dom_object, DomObject, Reflector};
|
||||
use crate::dom::bindings::root::{Dom, DomRoot};
|
||||
use crate::dom::globalscope::GlobalScope;
|
||||
use crate::dom::performance::reduce_timing_resolution;
|
||||
use crate::dom::vrpose::VRPose;
|
||||
use crate::dom::window::Window;
|
||||
use crate::script_runtime::JSContext;
|
||||
use dom_struct::dom_struct;
|
||||
use js::jsapi::{Heap, JSObject};
|
||||
use js::typedarray::{CreateWith, Float32Array};
|
||||
use std::cell::Cell;
|
||||
use std::ptr;
|
||||
use std::ptr::NonNull;
|
||||
use webvr_traits::WebVRFrameData;
|
||||
|
||||
#[dom_struct]
|
||||
pub struct VRFrameData {
|
||||
reflector_: Reflector,
|
||||
#[ignore_malloc_size_of = "mozjs"]
|
||||
left_proj: Heap<*mut JSObject>,
|
||||
#[ignore_malloc_size_of = "mozjs"]
|
||||
left_view: Heap<*mut JSObject>,
|
||||
#[ignore_malloc_size_of = "mozjs"]
|
||||
right_proj: Heap<*mut JSObject>,
|
||||
#[ignore_malloc_size_of = "mozjs"]
|
||||
right_view: Heap<*mut JSObject>,
|
||||
pose: Dom<VRPose>,
|
||||
timestamp: Cell<f64>,
|
||||
first_timestamp: Cell<f64>,
|
||||
}
|
||||
|
||||
impl VRFrameData {
|
||||
fn new_inherited(pose: &VRPose) -> VRFrameData {
|
||||
VRFrameData {
|
||||
reflector_: Reflector::new(),
|
||||
left_proj: Heap::default(),
|
||||
left_view: Heap::default(),
|
||||
right_proj: Heap::default(),
|
||||
right_view: Heap::default(),
|
||||
pose: Dom::from_ref(&*pose),
|
||||
timestamp: Cell::new(0.0),
|
||||
first_timestamp: Cell::new(0.0),
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unsafe_code)]
|
||||
fn new(global: &GlobalScope) -> DomRoot<VRFrameData> {
|
||||
let matrix = [
|
||||
1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0f32,
|
||||
];
|
||||
let pose = VRPose::new(&global, &Default::default());
|
||||
|
||||
let root = reflect_dom_object(Box::new(VRFrameData::new_inherited(&pose)), global);
|
||||
let cx = global.get_cx();
|
||||
create_typed_array(cx, &matrix, &root.left_proj);
|
||||
create_typed_array(cx, &matrix, &root.left_view);
|
||||
create_typed_array(cx, &matrix, &root.right_proj);
|
||||
create_typed_array(cx, &matrix, &root.right_view);
|
||||
|
||||
root
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
pub fn Constructor(window: &Window) -> Fallible<DomRoot<VRFrameData>> {
|
||||
Ok(VRFrameData::new(&window.global()))
|
||||
}
|
||||
}
|
||||
|
||||
/// FIXME(#22526) this should be in a better place
|
||||
#[allow(unsafe_code)]
|
||||
pub fn create_typed_array(cx: JSContext, src: &[f32], dst: &Heap<*mut JSObject>) {
|
||||
rooted!(in (*cx) let mut array = ptr::null_mut::<JSObject>());
|
||||
unsafe {
|
||||
let _ = Float32Array::create(*cx, CreateWith::Slice(src), array.handle_mut());
|
||||
}
|
||||
(*dst).set(array.get());
|
||||
}
|
||||
|
||||
impl VRFrameData {
|
||||
#[allow(unsafe_code)]
|
||||
pub fn update(&self, data: &WebVRFrameData) {
|
||||
unsafe {
|
||||
let cx = self.global().get_cx();
|
||||
typedarray!(in(*cx) let left_proj_array: Float32Array = self.left_proj.get());
|
||||
if let Ok(mut array) = left_proj_array {
|
||||
array.update(&data.left_projection_matrix);
|
||||
}
|
||||
typedarray!(in(*cx) let left_view_array: Float32Array = self.left_view.get());
|
||||
if let Ok(mut array) = left_view_array {
|
||||
array.update(&data.left_view_matrix);
|
||||
}
|
||||
typedarray!(in(*cx) let right_proj_array: Float32Array = self.right_proj.get());
|
||||
if let Ok(mut array) = right_proj_array {
|
||||
array.update(&data.right_projection_matrix);
|
||||
}
|
||||
typedarray!(in(*cx) let right_view_array: Float32Array = self.right_view.get());
|
||||
if let Ok(mut array) = right_view_array {
|
||||
array.update(&data.right_view_matrix);
|
||||
}
|
||||
self.pose.update(&data.pose);
|
||||
self.timestamp.set(data.timestamp);
|
||||
if self.first_timestamp.get() == 0.0 {
|
||||
self.first_timestamp.set(data.timestamp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl VRFrameDataMethods for VRFrameData {
|
||||
// https://w3c.github.io/webvr/#dom-vrframedata-timestamp
|
||||
fn Timestamp(&self) -> DOMHighResTimeStamp {
|
||||
reduce_timing_resolution(self.timestamp.get() - self.first_timestamp.get())
|
||||
}
|
||||
|
||||
#[allow(unsafe_code)]
|
||||
// https://w3c.github.io/webvr/#dom-vrframedata-leftprojectionmatrix
|
||||
fn LeftProjectionMatrix(&self, _cx: JSContext) -> NonNull<JSObject> {
|
||||
unsafe { NonNull::new_unchecked(self.left_proj.get()) }
|
||||
}
|
||||
|
||||
#[allow(unsafe_code)]
|
||||
// https://w3c.github.io/webvr/#dom-vrframedata-leftviewmatrix
|
||||
fn LeftViewMatrix(&self, _cx: JSContext) -> NonNull<JSObject> {
|
||||
unsafe { NonNull::new_unchecked(self.left_view.get()) }
|
||||
}
|
||||
|
||||
#[allow(unsafe_code)]
|
||||
// https://w3c.github.io/webvr/#dom-vrframedata-rightprojectionmatrix
|
||||
fn RightProjectionMatrix(&self, _cx: JSContext) -> NonNull<JSObject> {
|
||||
unsafe { NonNull::new_unchecked(self.right_proj.get()) }
|
||||
}
|
||||
|
||||
#[allow(unsafe_code)]
|
||||
// https://w3c.github.io/webvr/#dom-vrframedata-rightviewmatrix
|
||||
fn RightViewMatrix(&self, _cx: JSContext) -> NonNull<JSObject> {
|
||||
unsafe { NonNull::new_unchecked(self.right_view.get()) }
|
||||
}
|
||||
|
||||
// https://w3c.github.io/webvr/#dom-vrframedata-pose
|
||||
fn Pose(&self) -> DomRoot<VRPose> {
|
||||
DomRoot::from_ref(&*self.pose)
|
||||
}
|
||||
}
|
|
@ -1,90 +0,0 @@
|
|||
/* 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 crate::dom::bindings::cell::DomRefCell;
|
||||
use crate::dom::bindings::codegen::Bindings::VRStageParametersBinding::VRStageParametersMethods;
|
||||
use crate::dom::bindings::num::Finite;
|
||||
use crate::dom::bindings::reflector::{reflect_dom_object, DomObject, Reflector};
|
||||
use crate::dom::bindings::root::DomRoot;
|
||||
use crate::dom::window::Window;
|
||||
use crate::script_runtime::JSContext;
|
||||
use dom_struct::dom_struct;
|
||||
use js::jsapi::{Heap, JSObject};
|
||||
use js::typedarray::{CreateWith, Float32Array};
|
||||
use std::ptr;
|
||||
use std::ptr::NonNull;
|
||||
use webvr_traits::WebVRStageParameters;
|
||||
|
||||
#[dom_struct]
|
||||
pub struct VRStageParameters {
|
||||
reflector_: Reflector,
|
||||
#[ignore_malloc_size_of = "Defined in rust-webvr"]
|
||||
parameters: DomRefCell<WebVRStageParameters>,
|
||||
#[ignore_malloc_size_of = "mozjs"]
|
||||
transform: Heap<*mut JSObject>,
|
||||
}
|
||||
|
||||
unsafe_no_jsmanaged_fields!(WebVRStageParameters);
|
||||
|
||||
impl VRStageParameters {
|
||||
fn new_inherited(parameters: WebVRStageParameters) -> VRStageParameters {
|
||||
VRStageParameters {
|
||||
reflector_: Reflector::new(),
|
||||
parameters: DomRefCell::new(parameters),
|
||||
transform: Heap::default(),
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unsafe_code)]
|
||||
pub fn new(parameters: WebVRStageParameters, global: &Window) -> DomRoot<VRStageParameters> {
|
||||
let cx = global.get_cx();
|
||||
rooted!(in (*cx) let mut array = ptr::null_mut::<JSObject>());
|
||||
unsafe {
|
||||
let _ = Float32Array::create(
|
||||
*cx,
|
||||
CreateWith::Slice(¶meters.sitting_to_standing_transform),
|
||||
array.handle_mut(),
|
||||
);
|
||||
}
|
||||
|
||||
let stage_parameters = reflect_dom_object(
|
||||
Box::new(VRStageParameters::new_inherited(parameters)),
|
||||
global,
|
||||
);
|
||||
|
||||
stage_parameters.transform.set(array.get());
|
||||
|
||||
stage_parameters
|
||||
}
|
||||
|
||||
#[allow(unsafe_code)]
|
||||
pub fn update(&self, parameters: &WebVRStageParameters) {
|
||||
unsafe {
|
||||
let cx = self.global().get_cx();
|
||||
typedarray!(in(*cx) let array: Float32Array = self.transform.get());
|
||||
if let Ok(mut array) = array {
|
||||
array.update(¶meters.sitting_to_standing_transform);
|
||||
}
|
||||
}
|
||||
*self.parameters.borrow_mut() = parameters.clone();
|
||||
}
|
||||
}
|
||||
|
||||
impl VRStageParametersMethods for VRStageParameters {
|
||||
#[allow(unsafe_code)]
|
||||
// https://w3c.github.io/webvr/#dom-vrstageparameters-sittingtostandingtransform
|
||||
fn SittingToStandingTransform(&self, _cx: JSContext) -> NonNull<JSObject> {
|
||||
unsafe { NonNull::new_unchecked(self.transform.get()) }
|
||||
}
|
||||
|
||||
// https://w3c.github.io/webvr/#dom-vrstageparameters-sizex
|
||||
fn SizeX(&self) -> Finite<f32> {
|
||||
Finite::wrap(self.parameters.borrow().size_x)
|
||||
}
|
||||
|
||||
// https://w3c.github.io/webvr/#dom-vrstageparameters-sizez
|
||||
fn SizeZ(&self) -> Finite<f32> {
|
||||
Finite::wrap(self.parameters.borrow().size_z)
|
||||
}
|
||||
}
|
|
@ -60,7 +60,7 @@ use canvas_traits::webgl::{
|
|||
Parameter, TexDataType, TexFormat, TexParameter, WebGLChan, WebGLCommand,
|
||||
WebGLCommandBacktrace, WebGLContextId, WebGLError, WebGLFramebufferBindingRequest, WebGLMsg,
|
||||
WebGLMsgSender, WebGLOpaqueFramebufferId, WebGLProgramId, WebGLResult, WebGLSLVersion,
|
||||
WebGLSendResult, WebGLSender, WebGLVersion, WebVRCommand, YAxisTreatment,
|
||||
WebGLSendResult, WebGLSender, WebGLVersion, YAxisTreatment,
|
||||
};
|
||||
use dom_struct::dom_struct;
|
||||
use embedder_traits::EventLoopWaker;
|
||||
|
@ -383,11 +383,6 @@ impl WebGLRenderingContext {
|
|||
let _ = self.webgl_sender.send_swap_buffers(id);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn send_vr_command(&self, command: WebVRCommand) {
|
||||
self.webgl_sender.send_vr(command).unwrap();
|
||||
}
|
||||
|
||||
pub fn webgl_error(&self, err: WebGLError) {
|
||||
// TODO(emilio): Add useful debug messages to this
|
||||
warn!(
|
||||
|
@ -4716,10 +4711,6 @@ impl WebGLMessageSender {
|
|||
self.wake_after_send(|| self.sender.send(msg, backtrace))
|
||||
}
|
||||
|
||||
pub fn send_vr(&self, command: WebVRCommand) -> WebGLSendResult {
|
||||
self.wake_after_send(|| self.sender.send_vr(command))
|
||||
}
|
||||
|
||||
pub fn send_swap_buffers(&self, id: Option<WebGLOpaqueFramebufferId>) -> WebGLSendResult {
|
||||
self.wake_after_send(|| self.sender.send_swap_buffers(id))
|
||||
}
|
||||
|
|
|
@ -122,17 +122,6 @@ interface mixin WindowEventHandlers {
|
|||
attribute EventHandler onunload;
|
||||
};
|
||||
|
||||
// https://w3c.github.io/webvr/spec/1.1/#interface-window
|
||||
partial interface mixin WindowEventHandlers {
|
||||
attribute EventHandler onvrdisplayconnect;
|
||||
attribute EventHandler onvrdisplaydisconnect;
|
||||
attribute EventHandler onvrdisplayactivate;
|
||||
attribute EventHandler onvrdisplaydeactivate;
|
||||
attribute EventHandler onvrdisplayblur;
|
||||
attribute EventHandler onvrdisplayfocus;
|
||||
attribute EventHandler onvrdisplaypresentchange;
|
||||
};
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/#documentandelementeventhandlers
|
||||
[Exposed=Window]
|
||||
interface mixin DocumentAndElementEventHandlers {
|
||||
|
|
|
@ -14,13 +14,16 @@ interface Gamepad {
|
|||
[SameObject] readonly attribute GamepadButtonList buttons;
|
||||
};
|
||||
|
||||
// https://w3c.github.io/gamepad/extensions.html#dom-gamepad
|
||||
// https://w3c.github.io/gamepad/extensions.html#partial-gamepad-interface
|
||||
partial interface Gamepad {
|
||||
readonly attribute DOMString hand;
|
||||
readonly attribute VRPose? pose;
|
||||
readonly attribute GamepadHand hand;
|
||||
// readonly attribute FrozenArray<GamepadHapticActuator> hapticActuators;
|
||||
readonly attribute GamepadPose? pose;
|
||||
};
|
||||
|
||||
// https://w3c.github.io/webvr/spec/1.1/#interface-gamepad
|
||||
partial interface Gamepad {
|
||||
readonly attribute unsigned long displayId;
|
||||
// https://w3c.github.io/gamepad/extensions.html#gamepadhand-enum
|
||||
enum GamepadHand {
|
||||
"", /* unknown, both hands, or not applicable */
|
||||
"left",
|
||||
"right"
|
||||
};
|
||||
|
|
|
@ -2,9 +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/. */
|
||||
|
||||
// https://w3c.github.io/webvr/#interface-vrpose
|
||||
[Exposed=Window, Pref="dom.webvr.enabled"]
|
||||
interface VRPose {
|
||||
// https://w3c.github.io/gamepad/extensions.html#gamepadpose-interface
|
||||
[Exposed=Window, Pref="dom.gamepad.enabled"]
|
||||
interface GamepadPose {
|
||||
readonly attribute boolean hasOrientation;
|
||||
readonly attribute boolean hasPosition;
|
||||
|
||||
readonly attribute Float32Array? position;
|
||||
readonly attribute Float32Array? linearVelocity;
|
||||
readonly attribute Float32Array? linearAcceleration;
|
|
@ -60,11 +60,6 @@ interface mixin NavigatorCookies {
|
|||
readonly attribute boolean cookieEnabled;
|
||||
};
|
||||
|
||||
// https://w3c.github.io/webvr/spec/1.1/#interface-navigator
|
||||
partial interface Navigator {
|
||||
[Pref="dom.webvr.enabled"] Promise<sequence<VRDisplay>> getVRDisplays();
|
||||
};
|
||||
|
||||
// https://w3c.github.io/permissions/#navigator-and-workernavigator-extension
|
||||
[Exposed=(Window)]
|
||||
partial interface Navigator {
|
||||
|
|
|
@ -1,131 +0,0 @@
|
|||
/* 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/. */
|
||||
|
||||
enum VREye {
|
||||
"left",
|
||||
"right"
|
||||
};
|
||||
|
||||
|
||||
// https://w3c.github.io/webvr/#interface-vrdisplay
|
||||
[Exposed=Window, Pref="dom.webvr.enabled"]
|
||||
interface VRDisplay : EventTarget {
|
||||
readonly attribute boolean isConnected;
|
||||
readonly attribute boolean isPresenting;
|
||||
|
||||
/**
|
||||
* Dictionary of capabilities describing the VRDisplay.
|
||||
*/
|
||||
[SameObject] readonly attribute VRDisplayCapabilities capabilities;
|
||||
|
||||
/**
|
||||
* If this VRDisplay supports room-scale experiences, the optional
|
||||
* stage attribute contains details on the room-scale parameters.
|
||||
* The stageParameters attribute can not change between null
|
||||
* and non-null once the VRDisplay is enumerated; however,
|
||||
* the values within VRStageParameters may change after
|
||||
* any call to VRDisplay.submitFrame as the user may re-configure
|
||||
* their environment at any time.
|
||||
*/
|
||||
readonly attribute VRStageParameters? stageParameters;
|
||||
|
||||
/**
|
||||
* Return the current VREyeParameters for the given eye.
|
||||
*/
|
||||
VREyeParameters getEyeParameters(VREye whichEye);
|
||||
|
||||
/**
|
||||
* An identifier for this distinct VRDisplay. Used as an
|
||||
* association point in the Gamepad API.
|
||||
*/
|
||||
readonly attribute unsigned long displayId;
|
||||
|
||||
/**
|
||||
* A display name, a user-readable name identifying it.
|
||||
*/
|
||||
readonly attribute DOMString displayName;
|
||||
|
||||
/**
|
||||
* Populates the passed VRFrameData with the information required to render
|
||||
* the current frame.
|
||||
*/
|
||||
boolean getFrameData(VRFrameData frameData);
|
||||
|
||||
/**
|
||||
* Return a VRPose containing the future predicted pose of the VRDisplay
|
||||
* when the current frame will be presented. The value returned will not
|
||||
* change until JavaScript has returned control to the browser.
|
||||
*
|
||||
* The VRPose will contain the position, orientation, velocity,
|
||||
* and acceleration of each of these properties.
|
||||
*/
|
||||
[NewObject] VRPose getPose();
|
||||
|
||||
/**
|
||||
* Reset the pose for this display, treating its current position and
|
||||
* orientation as the "origin/zero" values. VRPose.position,
|
||||
* VRPose.orientation, and VRStageParameters.sittingToStandingTransform may be
|
||||
* updated when calling resetPose(). This should be called in only
|
||||
* sitting-space experiences.
|
||||
*/
|
||||
void resetPose();
|
||||
|
||||
/**
|
||||
* z-depth defining the near plane of the eye view frustum
|
||||
* enables mapping of values in the render target depth
|
||||
* attachment to scene coordinates. Initially set to 0.01.
|
||||
*/
|
||||
attribute double depthNear;
|
||||
|
||||
/**
|
||||
* z-depth defining the far plane of the eye view frustum
|
||||
* enables mapping of values in the render target depth
|
||||
* attachment to scene coordinates. Initially set to 10000.0.
|
||||
*/
|
||||
attribute double depthFar;
|
||||
|
||||
/**
|
||||
* The callback passed to `requestAnimationFrame` will be called
|
||||
* any time a new frame should be rendered. When the VRDisplay is
|
||||
* presenting the callback will be called at the native refresh
|
||||
* rate of the HMD. When not presenting this function acts
|
||||
* identically to how window.requestAnimationFrame acts. Content should
|
||||
* make no assumptions of frame rate or vsync behavior as the HMD runs
|
||||
* asynchronously from other displays and at differing refresh rates.
|
||||
*/
|
||||
unsigned long requestAnimationFrame(FrameRequestCallback callback);
|
||||
|
||||
/**
|
||||
* Passing the value returned by `requestAnimationFrame` to
|
||||
* `cancelAnimationFrame` will unregister the callback.
|
||||
*/
|
||||
void cancelAnimationFrame(unsigned long handle);
|
||||
|
||||
/**
|
||||
* Begin presenting to the VRDisplay. Must be called in response to a user gesture.
|
||||
* Repeat calls while already presenting will update the VRLayers being displayed.
|
||||
* If the number of values in the leftBounds/rightBounds arrays is not 0 or 4 for
|
||||
* any of the passed layers the promise is rejected.
|
||||
* If the source of any of the layers is not present (null), the promise is rejected.
|
||||
*/
|
||||
Promise<void> requestPresent(sequence<VRLayer> layers);
|
||||
|
||||
/**
|
||||
* Stops presenting to the VRDisplay.
|
||||
*/
|
||||
Promise<void> exitPresent();
|
||||
|
||||
/**
|
||||
* Get the layers currently being presented.
|
||||
*/
|
||||
sequence<VRLayer> getLayers();
|
||||
|
||||
/**
|
||||
* The VRLayer provided to the VRDisplay will be captured and presented
|
||||
* in the HMD. Calling this function has the same effect on the source
|
||||
* canvas as any other operation that uses its source image, and canvases
|
||||
* created without preserveDrawingBuffer set to true will be cleared.
|
||||
*/
|
||||
void submitFrame();
|
||||
};
|
|
@ -1,13 +0,0 @@
|
|||
/* 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/. */
|
||||
|
||||
// https://w3c.github.io/webvr/#interface-vrdisplaycapabilities
|
||||
[Exposed=Window, Pref="dom.webvr.enabled"]
|
||||
interface VRDisplayCapabilities {
|
||||
readonly attribute boolean hasPosition;
|
||||
readonly attribute boolean hasOrientation;
|
||||
readonly attribute boolean hasExternalDisplay;
|
||||
readonly attribute boolean canPresent;
|
||||
readonly attribute unsigned long maxLayers;
|
||||
};
|
|
@ -1,24 +0,0 @@
|
|||
/* 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/. */
|
||||
|
||||
// https://w3c.github.io/webvr/#interface-vrdisplayevent
|
||||
|
||||
enum VRDisplayEventReason {
|
||||
"navigation",
|
||||
"mounted",
|
||||
"unmounted",
|
||||
"requested"
|
||||
};
|
||||
|
||||
[Exposed=Window, Pref="dom.webvr.enabled"]
|
||||
interface VRDisplayEvent : Event {
|
||||
[Throws] constructor(DOMString type, VRDisplayEventInit eventInitDict);
|
||||
readonly attribute VRDisplay display;
|
||||
readonly attribute VRDisplayEventReason? reason;
|
||||
};
|
||||
|
||||
dictionary VRDisplayEventInit : EventInit {
|
||||
required VRDisplay display;
|
||||
VRDisplayEventReason reason;
|
||||
};
|
|
@ -1,13 +0,0 @@
|
|||
/* 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/. */
|
||||
|
||||
// https://w3c.github.io/webvr/#interface-vreyeparameters
|
||||
|
||||
[Exposed=Window, Pref="dom.webvr.enabled"]
|
||||
interface VREyeParameters {
|
||||
readonly attribute Float32Array offset;
|
||||
[SameObject] readonly attribute VRFieldOfView fieldOfView;
|
||||
readonly attribute unsigned long renderWidth;
|
||||
readonly attribute unsigned long renderHeight;
|
||||
};
|
|
@ -1,13 +0,0 @@
|
|||
/* 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/. */
|
||||
|
||||
// https://w3c.github.io/webvr/#interface-vrfieldofview
|
||||
|
||||
[Exposed=Window, Pref="dom.webvr.enabled"]
|
||||
interface VRFieldOfView {
|
||||
readonly attribute double upDegrees;
|
||||
readonly attribute double rightDegrees;
|
||||
readonly attribute double downDegrees;
|
||||
readonly attribute double leftDegrees;
|
||||
};
|
|
@ -1,16 +0,0 @@
|
|||
/* 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/. */
|
||||
|
||||
// https://w3c.github.io/webvr/#interface-vrframedata
|
||||
|
||||
[Exposed=Window, Pref="dom.webvr.enabled"]
|
||||
interface VRFrameData {
|
||||
[Throws] constructor();
|
||||
readonly attribute DOMHighResTimeStamp timestamp;
|
||||
readonly attribute Float32Array leftProjectionMatrix;
|
||||
readonly attribute Float32Array leftViewMatrix;
|
||||
readonly attribute Float32Array rightProjectionMatrix;
|
||||
readonly attribute Float32Array rightViewMatrix;
|
||||
readonly attribute VRPose pose;
|
||||
};
|
|
@ -1,13 +0,0 @@
|
|||
/* 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/. */
|
||||
|
||||
// https://w3c.github.io/webvr/#interface-vrlayer
|
||||
|
||||
//typedef (HTMLCanvasElement or OffscreenCanvas) VRSource;
|
||||
|
||||
dictionary VRLayer {
|
||||
HTMLCanvasElement source;
|
||||
sequence<float> leftBounds;
|
||||
sequence<float> rightBounds;
|
||||
};
|
|
@ -1,11 +0,0 @@
|
|||
/* 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/. */
|
||||
|
||||
// https://w3c.github.io/webvr/#interface-vrstageparameters
|
||||
[Exposed=Window, Pref="dom.webvr.enabled"]
|
||||
interface VRStageParameters {
|
||||
readonly attribute Float32Array sittingToStandingTransform;
|
||||
readonly attribute float sizeX;
|
||||
readonly attribute float sizeZ;
|
||||
};
|
|
@ -139,7 +139,6 @@ use style_traits::{CSSPixel, DevicePixel, ParsingMode};
|
|||
use url::Position;
|
||||
use webrender_api::units::{DeviceIntPoint, DeviceIntSize, LayoutPixel};
|
||||
use webrender_api::{DocumentId, ExternalScrollId};
|
||||
use webvr_traits::WebVRMsg;
|
||||
|
||||
/// Current state of the window object
|
||||
#[derive(Clone, Copy, Debug, JSTraceable, MallocSizeOf, PartialEq)]
|
||||
|
@ -268,10 +267,6 @@ pub struct Window {
|
|||
#[ignore_malloc_size_of = "channels are hard"]
|
||||
webgl_chan: Option<WebGLChan>,
|
||||
|
||||
/// A handle for communicating messages to the webvr thread, if available.
|
||||
#[ignore_malloc_size_of = "channels are hard"]
|
||||
webvr_chan: Option<IpcSender<WebVRMsg>>,
|
||||
|
||||
#[ignore_malloc_size_of = "defined in webxr"]
|
||||
webxr_registry: webxr_api::Registry,
|
||||
|
||||
|
@ -468,10 +463,6 @@ impl Window {
|
|||
.map(|chan| WebGLCommandSender::new(chan.clone(), self.get_event_loop_waker()))
|
||||
}
|
||||
|
||||
pub fn webvr_thread(&self) -> Option<IpcSender<WebVRMsg>> {
|
||||
self.webvr_chan.clone()
|
||||
}
|
||||
|
||||
pub fn webxr_registry(&self) -> webxr_api::Registry {
|
||||
self.webxr_registry.clone()
|
||||
}
|
||||
|
@ -2272,7 +2263,6 @@ impl Window {
|
|||
navigation_start: u64,
|
||||
navigation_start_precise: u64,
|
||||
webgl_chan: Option<WebGLChan>,
|
||||
webvr_chan: Option<IpcSender<WebVRMsg>>,
|
||||
webxr_registry: webxr_api::Registry,
|
||||
microtask_queue: Rc<MicrotaskQueue>,
|
||||
webrender_document: DocumentId,
|
||||
|
@ -2350,7 +2340,6 @@ impl Window {
|
|||
media_query_lists: DOMTracker::new(),
|
||||
test_runner: Default::default(),
|
||||
webgl_chan,
|
||||
webvr_chan,
|
||||
webxr_registry,
|
||||
pending_layout_images: Default::default(),
|
||||
unminified_js_dir: Default::default(),
|
||||
|
|
|
@ -21,7 +21,7 @@ use webxr_api::Frame;
|
|||
pub struct XRFrame {
|
||||
reflector_: Reflector,
|
||||
session: Dom<XRSession>,
|
||||
#[ignore_malloc_size_of = "defined in rust-webvr"]
|
||||
#[ignore_malloc_size_of = "defined in webxr_api"]
|
||||
data: Frame,
|
||||
active: Cell<bool>,
|
||||
animation_frame: Cell<bool>,
|
||||
|
|
|
@ -9,9 +9,9 @@ use crate::dom::bindings::error::Fallible;
|
|||
use crate::dom::bindings::reflector::DomObject;
|
||||
use crate::dom::bindings::reflector::{reflect_dom_object, Reflector};
|
||||
use crate::dom::bindings::root::{DomRoot, MutNullableDom};
|
||||
use crate::dom::bindings::utils::create_typed_array;
|
||||
use crate::dom::dompointreadonly::DOMPointReadOnly;
|
||||
use crate::dom::globalscope::GlobalScope;
|
||||
use crate::dom::vrframedata::create_typed_array;
|
||||
use crate::dom::window::Window;
|
||||
use crate::dom::xrsession::ApiRigidTransform;
|
||||
use crate::script_runtime::JSContext;
|
||||
|
|
|
@ -3,23 +3,17 @@
|
|||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use crate::dom::bindings::cell::DomRefCell;
|
||||
use crate::dom::bindings::codegen::Bindings::VRDisplayBinding::VRDisplayMethods;
|
||||
use crate::dom::bindings::codegen::Bindings::XRSystemBinding::XRSessionInit;
|
||||
use crate::dom::bindings::codegen::Bindings::XRSystemBinding::{XRSessionMode, XRSystemMethods};
|
||||
use crate::dom::bindings::conversions::{ConversionResult, FromJSValConvertible};
|
||||
use crate::dom::bindings::error::Error;
|
||||
use crate::dom::bindings::inheritance::Castable;
|
||||
use crate::dom::bindings::refcounted::{Trusted, TrustedPromise};
|
||||
use crate::dom::bindings::reflector::{reflect_dom_object, DomObject};
|
||||
use crate::dom::bindings::root::{Dom, DomRoot, MutNullableDom};
|
||||
use crate::dom::bindings::trace::RootedTraceableBox;
|
||||
use crate::dom::event::Event;
|
||||
use crate::dom::eventtarget::EventTarget;
|
||||
use crate::dom::gamepad::Gamepad;
|
||||
use crate::dom::gamepadevent::GamepadEventType;
|
||||
use crate::dom::promise::Promise;
|
||||
use crate::dom::vrdisplay::VRDisplay;
|
||||
use crate::dom::vrdisplayevent::VRDisplayEvent;
|
||||
use crate::dom::window::Window;
|
||||
use crate::dom::xrsession::XRSession;
|
||||
use crate::dom::xrtest::XRTest;
|
||||
|
@ -27,55 +21,43 @@ use crate::realms::InRealm;
|
|||
use crate::script_thread::ScriptThread;
|
||||
use crate::task_source::TaskSource;
|
||||
use dom_struct::dom_struct;
|
||||
use ipc_channel::ipc::{self as ipc_crate, IpcReceiver, IpcSender};
|
||||
use ipc_channel::ipc::{self as ipc_crate, IpcReceiver};
|
||||
use ipc_channel::router::ROUTER;
|
||||
use msg::constellation_msg::PipelineId;
|
||||
use profile_traits::ipc;
|
||||
use std::cell::Cell;
|
||||
use std::rc::Rc;
|
||||
use webvr_traits::{WebVRDisplayData, WebVRDisplayEvent, WebVREvent, WebVRMsg};
|
||||
use webvr_traits::{WebVRGamepadData, WebVRGamepadEvent, WebVRGamepadState};
|
||||
use webxr_api::{Error as XRError, Frame, Session, SessionInit, SessionMode};
|
||||
|
||||
#[dom_struct]
|
||||
pub struct XRSystem {
|
||||
eventtarget: EventTarget,
|
||||
displays: DomRefCell<Vec<Dom<VRDisplay>>>,
|
||||
gamepads: DomRefCell<Vec<Dom<Gamepad>>>,
|
||||
pending_immersive_session: Cell<bool>,
|
||||
active_immersive_session: MutNullableDom<XRSession>,
|
||||
active_inline_sessions: DomRefCell<Vec<Dom<XRSession>>>,
|
||||
test: MutNullableDom<XRTest>,
|
||||
pipeline: PipelineId,
|
||||
#[ignore_malloc_size_of = "channels are hard"]
|
||||
webvr_thread: Option<IpcSender<WebVRMsg>>,
|
||||
}
|
||||
|
||||
impl XRSystem {
|
||||
fn new_inherited(pipeline: PipelineId, webvr_thread: Option<IpcSender<WebVRMsg>>) -> XRSystem {
|
||||
fn new_inherited(pipeline: PipelineId) -> XRSystem {
|
||||
XRSystem {
|
||||
eventtarget: EventTarget::new_inherited(),
|
||||
displays: DomRefCell::new(Vec::new()),
|
||||
gamepads: DomRefCell::new(Vec::new()),
|
||||
pending_immersive_session: Cell::new(false),
|
||||
active_immersive_session: Default::default(),
|
||||
active_inline_sessions: DomRefCell::new(Vec::new()),
|
||||
test: Default::default(),
|
||||
pipeline,
|
||||
webvr_thread,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new(window: &Window) -> DomRoot<XRSystem> {
|
||||
let root = reflect_dom_object(
|
||||
Box::new(XRSystem::new_inherited(
|
||||
window.pipeline_id(),
|
||||
window.webvr_thread(),
|
||||
)),
|
||||
reflect_dom_object(
|
||||
Box::new(XRSystem::new_inherited(window.pipeline_id())),
|
||||
window,
|
||||
);
|
||||
root.register();
|
||||
root
|
||||
)
|
||||
}
|
||||
|
||||
pub fn pending_or_active_session(&self) -> bool {
|
||||
|
@ -107,12 +89,6 @@ impl XRSystem {
|
|||
}
|
||||
}
|
||||
|
||||
impl Drop for XRSystem {
|
||||
fn drop(&mut self) {
|
||||
self.unregister();
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<SessionMode> for XRSessionMode {
|
||||
fn into(self) -> SessionMode {
|
||||
match self {
|
||||
|
@ -309,202 +285,4 @@ impl XRSystem {
|
|||
// This must be called _after_ the promise is resolved
|
||||
session.setup_initial_inputs();
|
||||
}
|
||||
|
||||
pub fn get_displays(&self) -> Result<Vec<DomRoot<VRDisplay>>, ()> {
|
||||
if let Some(ref webvr_thread) = self.webvr_thread {
|
||||
let (sender, receiver) =
|
||||
ipc::channel(self.global().time_profiler_chan().clone()).unwrap();
|
||||
webvr_thread.send(WebVRMsg::GetDisplays(sender)).unwrap();
|
||||
|
||||
// FIXME(#22505) we should not block here and instead produce a promise
|
||||
match receiver.recv().unwrap() {
|
||||
Ok(displays) => {
|
||||
// Sync displays
|
||||
for display in displays {
|
||||
self.sync_display(&display);
|
||||
}
|
||||
},
|
||||
Err(_) => return Err(()),
|
||||
}
|
||||
} else {
|
||||
// WebVR spec: The Promise MUST be rejected if WebVR is not enabled/supported.
|
||||
return Err(());
|
||||
}
|
||||
|
||||
// convert from Dom to DomRoot
|
||||
Ok(self
|
||||
.displays
|
||||
.borrow()
|
||||
.iter()
|
||||
.map(|d| DomRoot::from_ref(&**d))
|
||||
.collect())
|
||||
}
|
||||
|
||||
fn find_display(&self, display_id: u32) -> Option<DomRoot<VRDisplay>> {
|
||||
self.displays
|
||||
.borrow()
|
||||
.iter()
|
||||
.find(|d| d.DisplayId() == display_id)
|
||||
.map(|d| DomRoot::from_ref(&**d))
|
||||
}
|
||||
|
||||
fn register(&self) {
|
||||
if let Some(ref webvr_thread) = self.webvr_thread {
|
||||
let msg = WebVRMsg::RegisterContext(self.global().pipeline_id());
|
||||
webvr_thread.send(msg).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
fn unregister(&self) {
|
||||
if let Some(ref webvr_thread) = self.webvr_thread {
|
||||
let msg = WebVRMsg::UnregisterContext(self.pipeline);
|
||||
webvr_thread.send(msg).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
fn sync_display(&self, display: &WebVRDisplayData) -> DomRoot<VRDisplay> {
|
||||
if let Some(existing) = self.find_display(display.display_id) {
|
||||
existing.update_display(&display);
|
||||
existing
|
||||
} else {
|
||||
let root = VRDisplay::new(&self.global().as_window(), display.clone());
|
||||
self.displays.borrow_mut().push(Dom::from_ref(&*root));
|
||||
root
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_display_event(&self, event: WebVRDisplayEvent) {
|
||||
match event {
|
||||
WebVRDisplayEvent::Connect(ref display) => {
|
||||
let display = self.sync_display(&display);
|
||||
display.handle_webvr_event(&event);
|
||||
self.notify_display_event(&display, &event);
|
||||
},
|
||||
WebVRDisplayEvent::Disconnect(id) => {
|
||||
if let Some(display) = self.find_display(id) {
|
||||
display.handle_webvr_event(&event);
|
||||
self.notify_display_event(&display, &event);
|
||||
}
|
||||
},
|
||||
WebVRDisplayEvent::Activate(ref display, _) |
|
||||
WebVRDisplayEvent::Deactivate(ref display, _) |
|
||||
WebVRDisplayEvent::Blur(ref display) |
|
||||
WebVRDisplayEvent::Focus(ref display) |
|
||||
WebVRDisplayEvent::PresentChange(ref display, _) |
|
||||
WebVRDisplayEvent::Change(ref display) => {
|
||||
let display = self.sync_display(&display);
|
||||
display.handle_webvr_event(&event);
|
||||
},
|
||||
WebVRDisplayEvent::Pause(id) |
|
||||
WebVRDisplayEvent::Resume(id) |
|
||||
WebVRDisplayEvent::Exit(id) => {
|
||||
if let Some(display) = self.find_display(id) {
|
||||
display.handle_webvr_event(&event);
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
fn handle_gamepad_event(&self, event: WebVRGamepadEvent) {
|
||||
match event {
|
||||
WebVRGamepadEvent::Connect(data, state) => {
|
||||
if let Some(gamepad) = self.find_gamepad(state.gamepad_id) {
|
||||
gamepad.update_from_vr(&state);
|
||||
} else {
|
||||
// new gamepad
|
||||
self.sync_gamepad(Some(data), &state);
|
||||
}
|
||||
},
|
||||
WebVRGamepadEvent::Disconnect(id) => {
|
||||
if let Some(gamepad) = self.find_gamepad(id) {
|
||||
gamepad.update_connected(false);
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
pub fn handle_webvr_event(&self, event: WebVREvent) {
|
||||
match event {
|
||||
WebVREvent::Display(event) => {
|
||||
self.handle_display_event(event);
|
||||
},
|
||||
WebVREvent::Gamepad(event) => {
|
||||
self.handle_gamepad_event(event);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
pub fn handle_webvr_events(&self, events: Vec<WebVREvent>) {
|
||||
for event in events {
|
||||
self.handle_webvr_event(event);
|
||||
}
|
||||
}
|
||||
|
||||
fn notify_display_event(&self, display: &VRDisplay, event: &WebVRDisplayEvent) {
|
||||
let event = VRDisplayEvent::new_from_webvr(&self.global(), &display, &event);
|
||||
event
|
||||
.upcast::<Event>()
|
||||
.fire(self.global().upcast::<EventTarget>());
|
||||
}
|
||||
}
|
||||
|
||||
// Gamepad
|
||||
impl XRSystem {
|
||||
fn find_gamepad(&self, gamepad_id: u32) -> Option<DomRoot<Gamepad>> {
|
||||
self.gamepads
|
||||
.borrow()
|
||||
.iter()
|
||||
.find(|g| g.gamepad_id() == gamepad_id)
|
||||
.map(|g| DomRoot::from_ref(&**g))
|
||||
}
|
||||
|
||||
fn sync_gamepad(&self, data: Option<WebVRGamepadData>, state: &WebVRGamepadState) {
|
||||
if let Some(existing) = self.find_gamepad(state.gamepad_id) {
|
||||
existing.update_from_vr(&state);
|
||||
} else {
|
||||
let index = self.gamepads.borrow().len();
|
||||
let data = data.unwrap_or_default();
|
||||
let root = Gamepad::new_from_vr(&self.global(), index as i32, &data, &state);
|
||||
self.gamepads.borrow_mut().push(Dom::from_ref(&*root));
|
||||
if state.connected {
|
||||
root.notify_event(GamepadEventType::Connected);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Gamepads are synced immediately in response to the API call.
|
||||
// The current approach allows the to sample gamepad state multiple times per frame. This
|
||||
// guarantees that the gamepads always have a valid state and can be very useful for
|
||||
// motion capture or drawing applications.
|
||||
pub fn get_gamepads(&self) -> Vec<DomRoot<Gamepad>> {
|
||||
if let Some(ref wevbr_sender) = self.webvr_thread {
|
||||
let (sender, receiver) =
|
||||
ipc::channel(self.global().time_profiler_chan().clone()).unwrap();
|
||||
let synced_ids = self
|
||||
.gamepads
|
||||
.borrow()
|
||||
.iter()
|
||||
.map(|g| g.gamepad_id())
|
||||
.collect();
|
||||
wevbr_sender
|
||||
.send(WebVRMsg::GetGamepads(synced_ids, sender))
|
||||
.unwrap();
|
||||
match receiver.recv().unwrap() {
|
||||
Ok(gamepads) => {
|
||||
// Sync displays
|
||||
for gamepad in gamepads {
|
||||
self.sync_gamepad(gamepad.0, &gamepad.1);
|
||||
}
|
||||
},
|
||||
Err(_) => {},
|
||||
}
|
||||
}
|
||||
|
||||
// We can add other not VR related gamepad providers here
|
||||
self.gamepads
|
||||
.borrow()
|
||||
.iter()
|
||||
.map(|g| DomRoot::from_ref(&**g))
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,8 +5,8 @@
|
|||
use crate::dom::bindings::codegen::Bindings::XRViewBinding::{XREye, XRViewMethods};
|
||||
use crate::dom::bindings::reflector::{reflect_dom_object, Reflector};
|
||||
use crate::dom::bindings::root::{Dom, DomRoot};
|
||||
use crate::dom::bindings::utils::create_typed_array;
|
||||
use crate::dom::globalscope::GlobalScope;
|
||||
use crate::dom::vrframedata::create_typed_array;
|
||||
use crate::dom::xrrigidtransform::XRRigidTransform;
|
||||
use crate::dom::xrsession::{cast_transform, ApiViewerPose, XRSession};
|
||||
use crate::script_runtime::JSContext;
|
||||
|
|
|
@ -156,7 +156,6 @@ pub enum ScriptThreadEventCategory {
|
|||
ServiceWorkerEvent,
|
||||
EnterFullscreen,
|
||||
ExitFullscreen,
|
||||
WebVREvent,
|
||||
PerformanceTimelineTask,
|
||||
}
|
||||
|
||||
|
|
|
@ -167,7 +167,6 @@ use time::{at_utc, get_time, precise_time_ns, Timespec};
|
|||
use url::Position;
|
||||
use webrender_api::units::LayoutPixel;
|
||||
use webrender_api::DocumentId;
|
||||
use webvr_traits::{WebVREvent, WebVRMsg};
|
||||
|
||||
pub type ImageCacheMsg = (PipelineId, PendingImageResponse);
|
||||
|
||||
|
@ -630,9 +629,6 @@ pub struct ScriptThread {
|
|||
/// A handle to the WebGL thread
|
||||
webgl_chan: Option<WebGLPipeline>,
|
||||
|
||||
/// A handle to the webvr thread, if available
|
||||
webvr_chan: Option<IpcSender<WebVRMsg>>,
|
||||
|
||||
/// The WebXR device registry
|
||||
webxr_registry: webxr_api::Registry,
|
||||
|
||||
|
@ -1338,7 +1334,6 @@ impl ScriptThread {
|
|||
layout_to_constellation_chan: state.layout_to_constellation_chan,
|
||||
|
||||
webgl_chan: state.webgl_chan,
|
||||
webvr_chan: state.webvr_chan,
|
||||
webxr_registry: state.webxr_registry,
|
||||
|
||||
worklet_thread_pool: Default::default(),
|
||||
|
@ -1660,7 +1655,6 @@ impl ScriptThread {
|
|||
},
|
||||
ScriptThreadEventCategory::EnterFullscreen => ScriptHangAnnotation::EnterFullscreen,
|
||||
ScriptThreadEventCategory::ExitFullscreen => ScriptHangAnnotation::ExitFullscreen,
|
||||
ScriptThreadEventCategory::WebVREvent => ScriptHangAnnotation::WebVREvent,
|
||||
ScriptThreadEventCategory::PerformanceTimelineTask => {
|
||||
ScriptHangAnnotation::PerformanceTimelineTask
|
||||
},
|
||||
|
@ -1710,7 +1704,6 @@ impl ScriptThread {
|
|||
DispatchStorageEvent(id, ..) => Some(id),
|
||||
ReportCSSError(id, ..) => Some(id),
|
||||
Reload(id, ..) => Some(id),
|
||||
WebVREvents(id, ..) => Some(id),
|
||||
PaintMetric(..) => None,
|
||||
ExitFullScreen(id, ..) => Some(id),
|
||||
MediaSessionAction(..) => None,
|
||||
|
@ -1771,7 +1764,6 @@ impl ScriptThread {
|
|||
ScriptThreadEventCategory::SetViewport => ProfilerCategory::ScriptSetViewport,
|
||||
ScriptThreadEventCategory::TimerEvent => ProfilerCategory::ScriptTimerEvent,
|
||||
ScriptThreadEventCategory::WebSocketEvent => ProfilerCategory::ScriptWebSocketEvent,
|
||||
ScriptThreadEventCategory::WebVREvent => ProfilerCategory::ScriptWebVREvent,
|
||||
ScriptThreadEventCategory::WorkerEvent => ProfilerCategory::ScriptWorkerEvent,
|
||||
ScriptThreadEventCategory::WorkletEvent => ProfilerCategory::ScriptWorkletEvent,
|
||||
ScriptThreadEventCategory::ServiceWorkerEvent => {
|
||||
|
@ -1930,9 +1922,6 @@ impl ScriptThread {
|
|||
ConstellationControlMsg::ExitPipeline(pipeline_id, discard_browsing_context) => {
|
||||
self.handle_exit_pipeline_msg(pipeline_id, discard_browsing_context)
|
||||
},
|
||||
ConstellationControlMsg::WebVREvents(pipeline_id, events) => {
|
||||
self.handle_webvr_events(pipeline_id, events)
|
||||
},
|
||||
ConstellationControlMsg::PaintMetric(pipeline_id, metric_type, metric_value) => {
|
||||
self.handle_paint_metric(pipeline_id, metric_type, metric_value)
|
||||
},
|
||||
|
@ -3210,7 +3199,6 @@ impl ScriptThread {
|
|||
incomplete.navigation_start,
|
||||
incomplete.navigation_start_precise,
|
||||
self.webgl_chan.as_ref().map(|chan| chan.channel()),
|
||||
self.webvr_chan.clone(),
|
||||
self.webxr_registry.clone(),
|
||||
self.microtask_queue.clone(),
|
||||
self.webrender_document,
|
||||
|
@ -3876,14 +3864,6 @@ impl ScriptThread {
|
|||
}
|
||||
}
|
||||
|
||||
fn handle_webvr_events(&self, pipeline_id: PipelineId, events: Vec<WebVREvent>) {
|
||||
let window = self.documents.borrow().find_window(pipeline_id);
|
||||
if let Some(window) = window {
|
||||
let xr = window.Navigator().Xr();
|
||||
xr.handle_webvr_events(events);
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_paint_metric(
|
||||
&self,
|
||||
pipeline_id: PipelineId,
|
||||
|
|
|
@ -44,5 +44,4 @@ uuid = {version = "0.8", features = ["v4"]}
|
|||
webdriver = "0.40"
|
||||
webgpu = {path = "../webgpu"}
|
||||
webrender_api = {git = "https://github.com/servo/webrender"}
|
||||
webvr_traits = {path = "../webvr_traits"}
|
||||
webxr-api = {git = "https://github.com/servo/webxr", features = ["ipc"]}
|
||||
|
|
|
@ -69,7 +69,6 @@ use webrender_api::units::{
|
|||
};
|
||||
use webrender_api::{BuiltDisplayList, DocumentId, ExternalScrollId, ImageKey, ScrollClamping};
|
||||
use webrender_api::{BuiltDisplayListDescriptor, HitTestFlags, HitTestResult, ResourceUpdate};
|
||||
use webvr_traits::{WebVREvent, WebVRMsg};
|
||||
|
||||
pub use crate::script_msg::{
|
||||
DOMMessage, HistoryEntryReplacement, SWManagerMsg, SWManagerSenders, ScopeThings,
|
||||
|
@ -397,8 +396,6 @@ pub enum ConstellationControlMsg {
|
|||
ReportCSSError(PipelineId, String, u32, u32, String),
|
||||
/// Reload the given page.
|
||||
Reload(PipelineId),
|
||||
/// Notifies the script thread of WebVR events.
|
||||
WebVREvents(PipelineId, Vec<WebVREvent>),
|
||||
/// Notifies the script thread about a new recorded paint metric.
|
||||
PaintMetric(PipelineId, ProgressiveWebMetricType, u64),
|
||||
/// Notifies the media session about a user requested media session action.
|
||||
|
@ -438,7 +435,6 @@ impl fmt::Debug for ConstellationControlMsg {
|
|||
DispatchStorageEvent(..) => "DispatchStorageEvent",
|
||||
ReportCSSError(..) => "ReportCSSError",
|
||||
Reload(..) => "Reload",
|
||||
WebVREvents(..) => "WebVREvents",
|
||||
PaintMetric(..) => "PaintMetric",
|
||||
ExitFullScreen(..) => "ExitFullScreen",
|
||||
MediaSessionAction(..) => "MediaSessionAction",
|
||||
|
@ -669,8 +665,6 @@ pub struct InitialScriptState {
|
|||
pub content_process_shutdown_chan: Sender<()>,
|
||||
/// A channel to the WebGL thread used in this pipeline.
|
||||
pub webgl_chan: Option<WebGLPipeline>,
|
||||
/// A channel to the webvr thread, if available.
|
||||
pub webvr_chan: Option<IpcSender<WebVRMsg>>,
|
||||
/// The XR device registry
|
||||
pub webxr_registry: webxr_api::Registry,
|
||||
/// The Webrender document ID associated with this thread.
|
||||
|
|
|
@ -16,7 +16,7 @@ debugmozjs = ["script/debugmozjs"]
|
|||
egl = ["mozangle/egl"]
|
||||
energy-profiling = ["profile_traits/energy-profiling"]
|
||||
profilemozjs = ["script/profilemozjs"]
|
||||
googlevr = ["webvr/googlevr"]
|
||||
googlevr = ["webxr/googlevr"]
|
||||
jitspew = ["script/jitspew"]
|
||||
js_backtrace = ["script/js_backtrace"]
|
||||
layout-2013 = ["layout_thread_2013"]
|
||||
|
@ -27,7 +27,6 @@ no-wgl = ["canvas/no-wgl"]
|
|||
uwp = ["servo_config/uwp", "script/uwp"]
|
||||
webrender_debugger = ["webrender/debugger"]
|
||||
no_static_freetype = ["webrender/no_static_freetype"]
|
||||
oculusvr = ["webvr/oculusvr"]
|
||||
refcell_backtrace = ["script/refcell_backtrace"]
|
||||
webdriver = ["webdriver_server"]
|
||||
webgl_backtrace = [
|
||||
|
@ -84,8 +83,6 @@ webrender = {git = "https://github.com/servo/webrender"}
|
|||
webrender_api = {git = "https://github.com/servo/webrender"}
|
||||
webrender_traits = {path = "../webrender_traits"}
|
||||
webdriver_server = {path = "../webdriver_server", optional = true}
|
||||
webvr = {path = "../webvr"}
|
||||
webvr_traits = {path = "../webvr_traits"}
|
||||
webxr-api = {git = "https://github.com/servo/webxr"}
|
||||
webxr = {git = "https://github.com/servo/webxr"}
|
||||
surfman = { version = "0.1", features = ["sm-osmesa"] }
|
||||
|
|
|
@ -52,8 +52,6 @@ pub use style_traits;
|
|||
pub use webgpu;
|
||||
pub use webrender_api;
|
||||
pub use webrender_traits;
|
||||
pub use webvr;
|
||||
pub use webvr_traits;
|
||||
|
||||
#[cfg(feature = "webdriver")]
|
||||
fn webdriver(port: u16, constellation: Sender<ConstellationMsg>) {
|
||||
|
@ -128,8 +126,6 @@ use surfman::platform::generic::universal::device::Device;
|
|||
use webrender::{RendererKind, ShaderPrecacheFlags};
|
||||
use webrender_traits::WebrenderImageHandlerType;
|
||||
use webrender_traits::{WebrenderExternalImageHandlers, WebrenderExternalImageRegistry};
|
||||
use webvr::{VRServiceManager, WebVRCompositorHandler, WebVRThread};
|
||||
use webvr_traits::WebVRMsg;
|
||||
|
||||
pub use gleam::gl;
|
||||
pub use keyboard_types;
|
||||
|
@ -448,40 +444,9 @@ where
|
|||
None
|
||||
};
|
||||
|
||||
if pref!(dom.webxr.enabled) && pref!(dom.webvr.enabled) {
|
||||
panic!("We don't currently support running both WebVR and WebXR");
|
||||
}
|
||||
|
||||
let mut webvr_heartbeats = Vec::new();
|
||||
let webvr_services = if pref!(dom.webvr.enabled) {
|
||||
let mut services = VRServiceManager::new();
|
||||
services.register_defaults();
|
||||
embedder.register_vr_services(&mut services, &mut webvr_heartbeats);
|
||||
Some(services)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let (webvr_chan, webvr_constellation_sender, webvr_compositor) =
|
||||
if let Some(services) = webvr_services {
|
||||
// WebVR initialization
|
||||
let (mut handler, sender) = WebVRCompositorHandler::new();
|
||||
let (webvr_thread, constellation_sender) = WebVRThread::spawn(sender, services);
|
||||
handler.set_webvr_thread_sender(webvr_thread.clone());
|
||||
(
|
||||
Some(webvr_thread),
|
||||
Some(constellation_sender),
|
||||
Some(handler),
|
||||
)
|
||||
} else {
|
||||
(None, None, None)
|
||||
};
|
||||
|
||||
let (external_image_handlers, external_images) = WebrenderExternalImageHandlers::new();
|
||||
let mut external_image_handlers = Box::new(external_image_handlers);
|
||||
|
||||
// For the moment, we enable use both the webxr crate and the rust-webvr crate,
|
||||
// but we are migrating over to just using webxr.
|
||||
let mut webxr_main_thread = webxr::MainThreadRegistry::new(event_loop_waker)
|
||||
.expect("Failed to create WebXR device registry");
|
||||
|
||||
|
@ -489,7 +454,6 @@ where
|
|||
&*window,
|
||||
&mut webrender,
|
||||
webrender_api_sender.clone(),
|
||||
webvr_compositor,
|
||||
&mut webxr_main_thread,
|
||||
&mut external_image_handlers,
|
||||
external_images.clone(),
|
||||
|
@ -553,8 +517,6 @@ where
|
|||
webxr_main_thread.registry(),
|
||||
player_context,
|
||||
webgl_threads,
|
||||
webvr_chan,
|
||||
webvr_constellation_sender,
|
||||
glplayer_threads,
|
||||
event_loop_waker,
|
||||
window_size,
|
||||
|
@ -580,7 +542,6 @@ where
|
|||
webrender,
|
||||
webrender_document,
|
||||
webrender_api,
|
||||
webvr_heartbeats,
|
||||
webxr_main_thread,
|
||||
pending_wr_frame,
|
||||
},
|
||||
|
@ -890,8 +851,6 @@ fn create_constellation(
|
|||
webxr_registry: webxr_api::Registry,
|
||||
player_context: WindowGLContext,
|
||||
webgl_threads: Option<WebGLThreads>,
|
||||
webvr_chan: Option<IpcSender<WebVRMsg>>,
|
||||
webvr_constellation_sender: Option<Sender<Sender<ConstellationMsg>>>,
|
||||
glplayer_threads: Option<GLPlayerThreads>,
|
||||
event_loop_waker: Option<Box<dyn EventLoopWaker>>,
|
||||
initial_window_size: WindowSizeData,
|
||||
|
@ -930,9 +889,8 @@ fn create_constellation(
|
|||
mem_profiler_chan,
|
||||
webrender_document,
|
||||
webrender_api_sender,
|
||||
webgl_threads,
|
||||
webvr_chan,
|
||||
webxr_registry,
|
||||
webgl_threads,
|
||||
glplayer_threads,
|
||||
player_context,
|
||||
event_loop_waker,
|
||||
|
@ -959,13 +917,6 @@ fn create_constellation(
|
|||
ipc_canvas_chan,
|
||||
);
|
||||
|
||||
if let Some(webvr_constellation_sender) = webvr_constellation_sender {
|
||||
// Set constellation channel used by WebVR thread to broadcast events
|
||||
webvr_constellation_sender
|
||||
.send(constellation_chan.clone())
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
constellation_chan
|
||||
}
|
||||
|
||||
|
@ -1083,7 +1034,6 @@ fn create_webgl_threads<W>(
|
|||
window: &W,
|
||||
webrender: &mut webrender::Renderer,
|
||||
webrender_api_sender: webrender_api::RenderApiSender,
|
||||
webvr_compositor: Option<Box<WebVRCompositorHandler>>,
|
||||
webxr_main_thread: &mut webxr::MainThreadRegistry,
|
||||
external_image_handlers: &mut WebrenderExternalImageHandlers,
|
||||
external_images: Arc<Mutex<WebrenderExternalImageRegistry>>,
|
||||
|
@ -1145,7 +1095,6 @@ where
|
|||
context,
|
||||
window.gl(),
|
||||
webrender_api_sender,
|
||||
webvr_compositor.map(|compositor| compositor as Box<_>),
|
||||
external_images,
|
||||
gl_type,
|
||||
);
|
||||
|
|
|
@ -1,29 +0,0 @@
|
|||
[package]
|
||||
name = "webvr"
|
||||
version = "0.0.1"
|
||||
authors = ["The Servo Project Developers"]
|
||||
license = "MPL-2.0"
|
||||
edition = "2018"
|
||||
publish = false
|
||||
|
||||
[lib]
|
||||
name = "webvr"
|
||||
path = "lib.rs"
|
||||
|
||||
[features]
|
||||
googlevr = ['rust-webvr/googlevr']
|
||||
oculusvr = ['rust-webvr/oculusvr']
|
||||
|
||||
[dependencies]
|
||||
canvas_traits = {path = "../canvas_traits"}
|
||||
compositing = {path = "../compositing"}
|
||||
crossbeam-channel = "0.4"
|
||||
euclid = "0.20"
|
||||
ipc-channel = "0.14"
|
||||
log = "0.4"
|
||||
msg = {path = "../msg"}
|
||||
rust-webvr = {version = "0.19", features = ["mock", "openvr", "vrexternal"]}
|
||||
rust-webvr-api = "0.17"
|
||||
servo_config = {path = "../config"}
|
||||
sparkle = "0.1"
|
||||
webvr_traits = {path = "../webvr_traits" }
|
|
@ -1,15 +0,0 @@
|
|||
/* 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/. */
|
||||
|
||||
#![deny(unsafe_code)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate log;
|
||||
|
||||
mod webvr_thread;
|
||||
pub use crate::webvr_thread::{WebVRCompositorHandler, WebVRThread};
|
||||
pub use rust_webvr::api::VRExternalShmemPtr;
|
||||
pub use rust_webvr::VRMainThreadHeartbeat;
|
||||
pub use rust_webvr::VRServiceManager;
|
||||
pub use rust_webvr_api::VRService;
|
|
@ -1,513 +0,0 @@
|
|||
/* 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 canvas_traits::webgl;
|
||||
use compositing::ConstellationMsg;
|
||||
use crossbeam_channel::{unbounded, Receiver, Sender};
|
||||
use euclid::default::Size2D;
|
||||
use ipc_channel::ipc;
|
||||
use ipc_channel::ipc::{IpcReceiver, IpcSender};
|
||||
use msg::constellation_msg::PipelineId;
|
||||
use rust_webvr::VRServiceManager;
|
||||
use servo_config::pref;
|
||||
use sparkle::gl::Gl;
|
||||
use std::collections::hash_map::Entry;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::sync::mpsc;
|
||||
use std::{thread, time};
|
||||
use webvr_traits::webvr::*;
|
||||
use webvr_traits::{WebVRMsg, WebVRPoseInformation, WebVRResult};
|
||||
|
||||
/// WebVRThread owns native VRDisplays, handles their life cycle inside Servo and
|
||||
/// acts a doorman for untrusted VR requests from DOM Objects. These are the key components
|
||||
/// * WebVRThread::spawn() creates a long living thread that waits for VR Commands from DOM objects
|
||||
/// and handles them in its trusted thread. The back and forth comunication with DOM is implemented
|
||||
/// using IPC-channels. This thread creates the VRServiceManager instance, which handles the life cycle
|
||||
/// of all VR Vendor SDKs and owns all the native VRDisplays. These displays are guaranteed to live while
|
||||
/// the spawned thread is alive. The WebVRThread is unique and it's closed using the Exit message when the
|
||||
/// whole browser is going to be closed.
|
||||
/// * A Event Polling thread is created in order to implement WebVR Events (connected, disconnected,..).
|
||||
/// This thread wakes up the WebVRThread from time to time by sending a PollEvents message. This thread
|
||||
/// is only created when there is at least one live JavaScript context using the WebVR APIs and shuts down it when
|
||||
/// the tab is closed. A single instance of the thread is used to handle multiple JavaScript contexts.
|
||||
/// Constellation channel is used to notify events to the Script Thread.
|
||||
/// * When the WeVR APIs are used in a tab, it's pipeline_id is registered using the RegisterContext message. When
|
||||
/// the tab is closed, UnregisterContext message is sent. This way the WebVR thread has a list of the pipeline
|
||||
/// ids using the WebVR APIs. These ids are used to implement privacy guidelines defined in the WebVR Spec.
|
||||
/// * When a JavaScript thread gains access to present to a headset, WebVRThread is not used as a intermediary in
|
||||
/// the VRDisplay.requestAnimationFrame loop in order to minimize latency. A direct communication with WebRender
|
||||
/// is used instead. See WebVRCompositorHandler and the WebVRCommands for more details.
|
||||
pub struct WebVRThread {
|
||||
receiver: IpcReceiver<WebVRMsg>,
|
||||
sender: IpcSender<WebVRMsg>,
|
||||
service: VRServiceManager,
|
||||
contexts: HashSet<PipelineId>,
|
||||
constellation_chan: Sender<ConstellationMsg>,
|
||||
vr_compositor_chan: WebVRCompositorSender,
|
||||
polling_events: bool,
|
||||
presenting: HashMap<u32, PipelineId>,
|
||||
mock: Option<mpsc::Sender<MockVRControlMsg>>,
|
||||
}
|
||||
|
||||
impl WebVRThread {
|
||||
fn new(
|
||||
receiver: IpcReceiver<WebVRMsg>,
|
||||
sender: IpcSender<WebVRMsg>,
|
||||
constellation_chan: Sender<ConstellationMsg>,
|
||||
vr_compositor_chan: WebVRCompositorSender,
|
||||
service: VRServiceManager,
|
||||
) -> WebVRThread {
|
||||
WebVRThread {
|
||||
receiver: receiver,
|
||||
sender: sender,
|
||||
service: service,
|
||||
contexts: HashSet::new(),
|
||||
constellation_chan: constellation_chan,
|
||||
vr_compositor_chan: vr_compositor_chan,
|
||||
polling_events: false,
|
||||
presenting: HashMap::new(),
|
||||
mock: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn spawn(
|
||||
vr_compositor_chan: WebVRCompositorSender,
|
||||
service: VRServiceManager,
|
||||
) -> (IpcSender<WebVRMsg>, Sender<Sender<ConstellationMsg>>) {
|
||||
let (sender, receiver) = ipc::channel().unwrap();
|
||||
let (constellation_sender, constellation_receiver) = unbounded();
|
||||
let sender_clone = sender.clone();
|
||||
thread::Builder::new()
|
||||
.name("WebVRThread".into())
|
||||
.spawn(move || {
|
||||
let constellation_chan = constellation_receiver.recv().unwrap();
|
||||
WebVRThread::new(
|
||||
receiver,
|
||||
sender_clone,
|
||||
constellation_chan,
|
||||
vr_compositor_chan,
|
||||
service,
|
||||
)
|
||||
.start();
|
||||
})
|
||||
.expect("Thread spawning failed");
|
||||
|
||||
(sender, constellation_sender)
|
||||
}
|
||||
|
||||
fn start(&mut self) {
|
||||
while let Ok(msg) = self.receiver.recv() {
|
||||
match msg {
|
||||
WebVRMsg::RegisterContext(context) => {
|
||||
self.handle_register_context(context);
|
||||
self.schedule_poll_events();
|
||||
},
|
||||
WebVRMsg::UnregisterContext(context) => {
|
||||
self.handle_unregister_context(context);
|
||||
},
|
||||
WebVRMsg::PollEvents(sender) => {
|
||||
self.poll_events(sender);
|
||||
},
|
||||
WebVRMsg::GetDisplays(sender) => {
|
||||
self.handle_get_displays(sender);
|
||||
self.schedule_poll_events();
|
||||
},
|
||||
WebVRMsg::GetFrameData(pipeline_id, display_id, near, far, sender) => {
|
||||
self.handle_framedata(pipeline_id, display_id, near, far, sender);
|
||||
},
|
||||
WebVRMsg::ResetPose(pipeline_id, display_id, sender) => {
|
||||
self.handle_reset_pose(pipeline_id, display_id, sender);
|
||||
},
|
||||
WebVRMsg::RequestPresent(pipeline_id, display_id, sender) => {
|
||||
self.handle_request_present(pipeline_id, display_id, sender);
|
||||
},
|
||||
WebVRMsg::ExitPresent(pipeline_id, display_id, sender) => {
|
||||
self.handle_exit_present(pipeline_id, display_id, sender);
|
||||
},
|
||||
WebVRMsg::CreateCompositor(display_id) => {
|
||||
self.handle_create_compositor(display_id);
|
||||
},
|
||||
WebVRMsg::GetGamepads(synced_ids, sender) => {
|
||||
self.handle_get_gamepads(synced_ids, sender);
|
||||
},
|
||||
WebVRMsg::GetGamepadsForDisplay(display_id, sender) => {
|
||||
self.handle_get_gamepads_for_display(display_id, sender);
|
||||
},
|
||||
|
||||
WebVRMsg::CreateMockDisplay(init) => {
|
||||
self.handle_create_mock(init);
|
||||
},
|
||||
WebVRMsg::MessageMockDisplay(msg) => {
|
||||
self.handle_message_mock_display(msg);
|
||||
},
|
||||
WebVRMsg::Exit => break,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_register_context(&mut self, ctx: PipelineId) {
|
||||
self.contexts.insert(ctx);
|
||||
}
|
||||
|
||||
fn handle_unregister_context(&mut self, ctx: PipelineId) {
|
||||
self.contexts.remove(&ctx);
|
||||
}
|
||||
|
||||
fn handle_get_displays(&mut self, sender: IpcSender<WebVRResult<Vec<VRDisplayData>>>) {
|
||||
let displays = self.service.get_displays();
|
||||
let mut result = Vec::new();
|
||||
for display in displays {
|
||||
result.push(display.borrow().data());
|
||||
}
|
||||
sender.send(Ok(result)).unwrap();
|
||||
}
|
||||
|
||||
fn handle_framedata(
|
||||
&mut self,
|
||||
pipeline: PipelineId,
|
||||
display_id: u32,
|
||||
near: f64,
|
||||
far: f64,
|
||||
sender: IpcSender<WebVRResult<VRFrameData>>,
|
||||
) {
|
||||
match self.access_check(pipeline, display_id) {
|
||||
Ok(display) => sender
|
||||
.send(Ok(display.borrow().immediate_frame_data(near, far)))
|
||||
.unwrap(),
|
||||
Err(msg) => sender.send(Err(msg.into())).unwrap(),
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_reset_pose(
|
||||
&mut self,
|
||||
pipeline: PipelineId,
|
||||
display_id: u32,
|
||||
sender: IpcSender<WebVRResult<VRDisplayData>>,
|
||||
) {
|
||||
match self.access_check(pipeline, display_id) {
|
||||
Ok(display) => {
|
||||
display.borrow_mut().reset_pose();
|
||||
sender.send(Ok(display.borrow().data())).unwrap();
|
||||
},
|
||||
Err(msg) => sender.send(Err(msg.into())).unwrap(),
|
||||
}
|
||||
}
|
||||
|
||||
// This method implements the privacy and security guidelines defined in the WebVR spec.
|
||||
// For example a secondary tab is not allowed to read VRDisplay data or stop a VR presentation
|
||||
// while the user is having a VR experience in the current tab.
|
||||
// These security rules also avoid multithreading race conditions between WebVRThread and
|
||||
// Webrender thread. See WebVRCompositorHandler implementation notes for more details about this.
|
||||
fn access_check(
|
||||
&self,
|
||||
pipeline: PipelineId,
|
||||
display_id: u32,
|
||||
) -> Result<&VRDisplayPtr, &'static str> {
|
||||
if *self.presenting.get(&display_id).unwrap_or(&pipeline) != pipeline {
|
||||
return Err(
|
||||
"No access granted to this Display because it's presenting on other JavaScript Tab",
|
||||
);
|
||||
}
|
||||
self.service
|
||||
.get_display(display_id)
|
||||
.ok_or("Device not found")
|
||||
}
|
||||
|
||||
fn handle_request_present(
|
||||
&mut self,
|
||||
pipeline: PipelineId,
|
||||
display_id: u32,
|
||||
sender: IpcSender<WebVRResult<()>>,
|
||||
) {
|
||||
match self.access_check(pipeline, display_id).map(|d| d.clone()) {
|
||||
Ok(display) => {
|
||||
self.presenting.insert(display_id, pipeline);
|
||||
let data = display.borrow().data();
|
||||
sender.send(Ok(())).unwrap();
|
||||
self.notify_event(VRDisplayEvent::PresentChange(data, true).into());
|
||||
},
|
||||
Err(msg) => {
|
||||
sender.send(Err(msg.into())).unwrap();
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_exit_present(
|
||||
&mut self,
|
||||
pipeline: PipelineId,
|
||||
display_id: u32,
|
||||
sender: Option<IpcSender<WebVRResult<()>>>,
|
||||
) {
|
||||
match self.access_check(pipeline, display_id).map(|d| d.clone()) {
|
||||
Ok(display) => {
|
||||
self.presenting.remove(&display_id);
|
||||
if let Some(sender) = sender {
|
||||
sender.send(Ok(())).unwrap();
|
||||
}
|
||||
let data = display.borrow().data();
|
||||
self.notify_event(VRDisplayEvent::PresentChange(data, false).into());
|
||||
},
|
||||
Err(msg) => {
|
||||
if let Some(sender) = sender {
|
||||
sender.send(Err(msg.into())).unwrap();
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_create_compositor(&mut self, display_id: u32) {
|
||||
let compositor = self
|
||||
.service
|
||||
.get_display(display_id)
|
||||
.map(|d| WebVRCompositor(d.as_ptr()));
|
||||
self.vr_compositor_chan.send(compositor).unwrap();
|
||||
}
|
||||
|
||||
fn handle_get_gamepads_for_display(
|
||||
&mut self,
|
||||
display_id: u32,
|
||||
sender: IpcSender<WebVRResult<Vec<(VRGamepadData, VRGamepadState)>>>,
|
||||
) {
|
||||
match self.service.get_display(display_id) {
|
||||
Some(display) => {
|
||||
let gamepads = display.borrow_mut().fetch_gamepads();
|
||||
match gamepads {
|
||||
Ok(gamepads) => {
|
||||
let data = gamepads
|
||||
.iter()
|
||||
.map(|g| {
|
||||
let g = g.borrow();
|
||||
(g.data(), g.state())
|
||||
})
|
||||
.collect();
|
||||
sender.send(Ok(data)).unwrap();
|
||||
},
|
||||
Err(e) => sender.send(Err(e)).unwrap(),
|
||||
}
|
||||
},
|
||||
None => sender.send(Err("Device not found".into())).unwrap(),
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_get_gamepads(
|
||||
&mut self,
|
||||
synced_ids: Vec<u32>,
|
||||
sender: IpcSender<WebVRResult<Vec<(Option<VRGamepadData>, VRGamepadState)>>>,
|
||||
) {
|
||||
let gamepads = self.service.get_gamepads();
|
||||
let data = gamepads
|
||||
.iter()
|
||||
.map(|g| {
|
||||
let g = g.borrow();
|
||||
// Optimization, don't fetch and send gamepad static data when the gamepad is already synced.
|
||||
let data = if synced_ids.iter().any(|v| *v == g.id()) {
|
||||
None
|
||||
} else {
|
||||
Some(g.data())
|
||||
};
|
||||
(data, g.state())
|
||||
})
|
||||
.collect();
|
||||
sender.send(Ok(data)).unwrap();
|
||||
}
|
||||
|
||||
fn handle_create_mock(&mut self, init: MockVRInit) {
|
||||
if self.mock.is_some() {
|
||||
warn!("Mock display already created");
|
||||
return;
|
||||
}
|
||||
self.mock = Some(self.service.register_mock_with_remote(init));
|
||||
}
|
||||
|
||||
fn handle_message_mock_display(&mut self, msg: MockVRControlMsg) {
|
||||
self.mock
|
||||
.as_ref()
|
||||
.expect("Mock Display not yet set up")
|
||||
.send(msg)
|
||||
.expect("Could not send message to mock display");
|
||||
}
|
||||
|
||||
fn poll_events(&mut self, sender: IpcSender<bool>) {
|
||||
loop {
|
||||
let events = self.service.poll_events();
|
||||
if events.is_empty() {
|
||||
break;
|
||||
}
|
||||
self.notify_events(events)
|
||||
}
|
||||
|
||||
// Stop polling events if the callers are not using VR
|
||||
self.polling_events = self.contexts.len() > 0;
|
||||
sender.send(self.polling_events).unwrap();
|
||||
}
|
||||
|
||||
fn notify_events(&self, events: Vec<VREvent>) {
|
||||
let pipeline_ids: Vec<PipelineId> = self.contexts.iter().map(|c| *c).collect();
|
||||
self.constellation_chan
|
||||
.send(ConstellationMsg::WebVREvents(pipeline_ids, events))
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn notify_event(&self, event: VREvent) {
|
||||
self.notify_events(vec![event]);
|
||||
}
|
||||
|
||||
fn schedule_poll_events(&mut self) {
|
||||
if !self.service.is_initialized() || self.polling_events {
|
||||
return;
|
||||
}
|
||||
self.polling_events = true;
|
||||
let webvr_thread = self.sender.clone();
|
||||
let (sender, receiver) = ipc::channel().unwrap();
|
||||
|
||||
// Defines the polling interval time in ms for VR Events such as VRDisplay connected, disconnected, etc.
|
||||
let polling_interval = pref!(dom.webvr.event_polling_interval) as u64;
|
||||
|
||||
thread::Builder::new()
|
||||
.name("WebVRPollEvents".into())
|
||||
.spawn(move || {
|
||||
loop {
|
||||
if webvr_thread
|
||||
.send(WebVRMsg::PollEvents(sender.clone()))
|
||||
.is_err()
|
||||
{
|
||||
// WebVR Thread closed
|
||||
break;
|
||||
}
|
||||
if !receiver.recv().unwrap_or(false) {
|
||||
// WebVR Thread asked to unschedule this thread
|
||||
break;
|
||||
}
|
||||
thread::sleep(time::Duration::from_millis(polling_interval));
|
||||
}
|
||||
})
|
||||
.expect("Thread spawning failed");
|
||||
}
|
||||
}
|
||||
|
||||
/// Notes about WebVRCompositorHandler implementation:
|
||||
/// Raw pointers are used instead of Arc<Mutex> as a heavy optimization for latency reasons.
|
||||
/// This also avoids "JS DDoS" attacks: like a secondary JavaScript tab degrading performance
|
||||
/// 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.
|
||||
/// * VRDisplay implementations are designed to allow calling compositor functions
|
||||
/// in another thread by using the Send + Sync traits.
|
||||
/// VRDisplays pointers are guaranteed to be valid memory:
|
||||
/// * VRDisplays are owned by the VRServiceManager which lives in the WebVRThread.
|
||||
/// * WebVRCompositorHandler is stopped automatically when a JS tab is closed or the whole browser is closed.
|
||||
/// * WebVRThread and its VRDisplays are destroyed after all tabs are dropped and the browser is about to exit.
|
||||
/// WebVRThread is closed using the Exit message.
|
||||
|
||||
pub struct WebVRCompositor(*mut dyn VRDisplay);
|
||||
pub struct WebVRCompositorHandler {
|
||||
compositors: HashMap<webgl::WebVRDeviceId, WebVRCompositor>,
|
||||
webvr_thread_receiver: Receiver<Option<WebVRCompositor>>,
|
||||
webvr_thread_sender: Option<IpcSender<WebVRMsg>>,
|
||||
}
|
||||
|
||||
#[allow(unsafe_code)]
|
||||
unsafe impl Send for WebVRCompositor {}
|
||||
|
||||
pub type WebVRCompositorSender = Sender<Option<WebVRCompositor>>;
|
||||
|
||||
impl WebVRCompositorHandler {
|
||||
pub fn new() -> (Box<WebVRCompositorHandler>, WebVRCompositorSender) {
|
||||
let (sender, receiver) = unbounded();
|
||||
let instance = Box::new(WebVRCompositorHandler {
|
||||
compositors: HashMap::new(),
|
||||
webvr_thread_receiver: receiver,
|
||||
webvr_thread_sender: None,
|
||||
});
|
||||
|
||||
(instance, sender)
|
||||
}
|
||||
}
|
||||
|
||||
impl webgl::WebVRRenderHandler for WebVRCompositorHandler {
|
||||
#[allow(unsafe_code)]
|
||||
fn handle(&mut self, gl: &Gl, cmd: webgl::WebVRCommand, texture: Option<(u32, Size2D<i32>)>) {
|
||||
match cmd {
|
||||
webgl::WebVRCommand::Create(compositor_id) => {
|
||||
if let Some(compositor) = self.create_compositor(compositor_id) {
|
||||
unsafe { (*compositor.0).start_present(None) };
|
||||
}
|
||||
},
|
||||
webgl::WebVRCommand::SyncPoses(compositor_id, near, far, get_gamepads, sender) => {
|
||||
if let Some(compositor) = self.compositors.get(&compositor_id) {
|
||||
let pose = unsafe { (*compositor.0).future_frame_data(near, far) };
|
||||
let mut pose_information = WebVRPoseInformation {
|
||||
frame: pose,
|
||||
gamepads: vec![],
|
||||
};
|
||||
if get_gamepads {
|
||||
let gamepads = unsafe { (*compositor.0).fetch_gamepads() };
|
||||
if let Ok(gamepads) = gamepads {
|
||||
for gamepad in gamepads {
|
||||
let g = gamepad.borrow();
|
||||
pose_information.gamepads.push((g.id(), g.state()));
|
||||
}
|
||||
}
|
||||
}
|
||||
let _ = sender.send(Ok(pose_information));
|
||||
} else {
|
||||
let _ = sender.send(Err(()));
|
||||
}
|
||||
},
|
||||
webgl::WebVRCommand::SubmitFrame(compositor_id, left_bounds, right_bounds) => {
|
||||
if let Some(compositor) = self.compositors.get(&compositor_id) {
|
||||
if let Some((texture_id, size)) = texture {
|
||||
let layer = VRLayer {
|
||||
texture_id: texture_id,
|
||||
left_bounds: left_bounds,
|
||||
right_bounds: right_bounds,
|
||||
texture_size: Some((size.width as u32, size.height as u32)),
|
||||
};
|
||||
unsafe { (*compositor.0).submit_layer(gl, &layer) };
|
||||
}
|
||||
}
|
||||
},
|
||||
webgl::WebVRCommand::Release(compositor_id) => {
|
||||
if let Some(compositor) = self.compositors.remove(&compositor_id) {
|
||||
unsafe { (*compositor.0).stop_present() };
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl WebVRCompositorHandler {
|
||||
#[allow(unsafe_code)]
|
||||
fn create_compositor(
|
||||
&mut self,
|
||||
display_id: webgl::WebVRDeviceId,
|
||||
) -> Option<&mut WebVRCompositor> {
|
||||
let sender = match self.webvr_thread_sender {
|
||||
Some(ref s) => s,
|
||||
None => return None,
|
||||
};
|
||||
|
||||
sender
|
||||
.send(WebVRMsg::CreateCompositor(display_id as u32))
|
||||
.unwrap();
|
||||
let display = self.webvr_thread_receiver.recv().unwrap();
|
||||
|
||||
match display {
|
||||
Some(display) => match self.compositors.entry(display_id) {
|
||||
Entry::Vacant(entry) => return Some(entry.insert(display)),
|
||||
Entry::Occupied(_) => error!("VRDisplay already presenting"),
|
||||
},
|
||||
None => error!("VRDisplay not found when creating a new VRCompositor"),
|
||||
};
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
// This is done on only a per-platform basis on initialization.
|
||||
pub fn set_webvr_thread_sender(&mut self, sender: IpcSender<WebVRMsg>) {
|
||||
self.webvr_thread_sender = Some(sender);
|
||||
}
|
||||
}
|
|
@ -1,17 +0,0 @@
|
|||
[package]
|
||||
name = "webvr_traits"
|
||||
version = "0.0.1"
|
||||
authors = ["The Servo Project Developers"]
|
||||
license = "MPL-2.0"
|
||||
edition = "2018"
|
||||
publish = false
|
||||
|
||||
[lib]
|
||||
name = "webvr_traits"
|
||||
path = "lib.rs"
|
||||
|
||||
[dependencies]
|
||||
ipc-channel = "0.14"
|
||||
msg = {path = "../msg"}
|
||||
rust-webvr-api = {version = "0.17", features = ["ipc"]}
|
||||
serde = "1.0"
|
|
@ -1,39 +0,0 @@
|
|||
/* 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/. */
|
||||
|
||||
#![deny(unsafe_code)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate serde;
|
||||
|
||||
mod webvr_traits;
|
||||
|
||||
pub use crate::webvr_traits::{WebVRMsg, WebVRResult};
|
||||
pub use rust_webvr_api as webvr;
|
||||
pub use rust_webvr_api::VRDisplayCapabilities as WebVRDisplayCapabilities;
|
||||
pub use rust_webvr_api::VRDisplayData as WebVRDisplayData;
|
||||
pub use rust_webvr_api::VRDisplayEvent as WebVRDisplayEvent;
|
||||
pub use rust_webvr_api::VRDisplayEventReason as WebVRDisplayEventReason;
|
||||
pub use rust_webvr_api::VREvent as WebVREvent;
|
||||
pub use rust_webvr_api::VREye as WebVREye;
|
||||
pub use rust_webvr_api::VREyeParameters as WebVREyeParameters;
|
||||
pub use rust_webvr_api::VRFieldOfView as WebVRFieldOfView;
|
||||
pub use rust_webvr_api::VRFrameData as WebVRFrameData;
|
||||
pub use rust_webvr_api::VRFutureFrameData as WebVRFutureFrameData;
|
||||
pub use rust_webvr_api::VRGamepadButton as WebVRGamepadButton;
|
||||
pub use rust_webvr_api::VRGamepadData as WebVRGamepadData;
|
||||
pub use rust_webvr_api::VRGamepadEvent as WebVRGamepadEvent;
|
||||
pub use rust_webvr_api::VRGamepadHand as WebVRGamepadHand;
|
||||
pub use rust_webvr_api::VRGamepadState as WebVRGamepadState;
|
||||
pub use rust_webvr_api::VRLayer as WebVRLayer;
|
||||
pub use rust_webvr_api::VRMainThreadHeartbeat as WebVRMainThreadHeartbeat;
|
||||
pub use rust_webvr_api::VRPose as WebVRPose;
|
||||
pub use rust_webvr_api::VRStageParameters as WebVRStageParameters;
|
||||
pub use rust_webvr_api::{MockVRControlMsg, MockVRInit, MockVRView};
|
||||
|
||||
#[derive(Deserialize, Serialize)]
|
||||
pub struct WebVRPoseInformation {
|
||||
pub frame: WebVRFutureFrameData,
|
||||
pub gamepads: Vec<(u32, WebVRGamepadState)>,
|
||||
}
|
|
@ -1,40 +0,0 @@
|
|||
/* 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 ipc_channel::ipc::IpcSender;
|
||||
use msg::constellation_msg::PipelineId;
|
||||
use rust_webvr_api::*;
|
||||
|
||||
pub type WebVRResult<T> = Result<T, String>;
|
||||
|
||||
// Messages from Script thread to WebVR thread.
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
pub enum WebVRMsg {
|
||||
RegisterContext(PipelineId),
|
||||
UnregisterContext(PipelineId),
|
||||
PollEvents(IpcSender<bool>),
|
||||
GetDisplays(IpcSender<WebVRResult<Vec<VRDisplayData>>>),
|
||||
GetFrameData(
|
||||
PipelineId,
|
||||
u32,
|
||||
f64,
|
||||
f64,
|
||||
IpcSender<WebVRResult<VRFrameData>>,
|
||||
),
|
||||
ResetPose(PipelineId, u32, IpcSender<WebVRResult<VRDisplayData>>),
|
||||
RequestPresent(PipelineId, u32, IpcSender<WebVRResult<()>>),
|
||||
ExitPresent(PipelineId, u32, Option<IpcSender<WebVRResult<()>>>),
|
||||
CreateCompositor(u32),
|
||||
CreateMockDisplay(MockVRInit),
|
||||
MessageMockDisplay(MockVRControlMsg),
|
||||
GetGamepads(
|
||||
Vec<u32>,
|
||||
IpcSender<WebVRResult<Vec<(Option<VRGamepadData>, VRGamepadState)>>>,
|
||||
),
|
||||
GetGamepadsForDisplay(
|
||||
u32,
|
||||
IpcSender<WebVRResult<Vec<(VRGamepadData, VRGamepadState)>>>,
|
||||
),
|
||||
Exit,
|
||||
}
|
|
@ -59,7 +59,6 @@ lazy_static = "1"
|
|||
libservo = {path = "../../components/servo"}
|
||||
libc = "0.2"
|
||||
log = "0.4"
|
||||
rust-webvr = { version = "0.19", features = ["glwindow"] }
|
||||
servo-media = {git = "https://github.com/servo/media"}
|
||||
shellwords = "1.0.0"
|
||||
tinyfiledialogs = "3.0"
|
||||
|
|
|
@ -65,7 +65,6 @@ impl App {
|
|||
window.clone(),
|
||||
events_loop.clone(),
|
||||
window.gl(),
|
||||
angle,
|
||||
));
|
||||
|
||||
// Handle browser state.
|
||||
|
|
|
@ -4,20 +4,13 @@
|
|||
|
||||
//! Implements the global methods required by Servo (not window/gl/compositor related).
|
||||
|
||||
use crate::app;
|
||||
use crate::events_loop::EventsLoop;
|
||||
use crate::window_trait::WindowPortsMethods;
|
||||
use gleam::gl;
|
||||
use glutin;
|
||||
use glutin::dpi::LogicalSize;
|
||||
use glutin::EventsLoopClosed;
|
||||
use rust_webvr::GlWindowVRService;
|
||||
use servo::canvas::{SurfaceProviders, WebGlExecutor};
|
||||
use servo::compositing::windowing::EmbedderMethods;
|
||||
use servo::embedder_traits::{EmbedderProxy, EventLoopWaker};
|
||||
use servo::servo_config::{opts, pref};
|
||||
use servo::webvr::VRServiceManager;
|
||||
use servo::webvr_traits::WebVRMainThreadHeartbeat;
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
|
||||
|
@ -25,7 +18,6 @@ pub struct EmbedderCallbacks {
|
|||
window: Rc<dyn WindowPortsMethods>,
|
||||
events_loop: Rc<RefCell<EventsLoop>>,
|
||||
gl: Rc<dyn gl::Gl>,
|
||||
angle: bool,
|
||||
}
|
||||
|
||||
impl EmbedderCallbacks {
|
||||
|
@ -33,13 +25,11 @@ impl EmbedderCallbacks {
|
|||
window: Rc<dyn WindowPortsMethods>,
|
||||
events_loop: Rc<RefCell<EventsLoop>>,
|
||||
gl: Rc<dyn gl::Gl>,
|
||||
angle: bool,
|
||||
) -> EmbedderCallbacks {
|
||||
EmbedderCallbacks {
|
||||
window,
|
||||
events_loop,
|
||||
gl,
|
||||
angle,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -49,47 +39,6 @@ impl EmbedderMethods for EmbedderCallbacks {
|
|||
self.events_loop.borrow().create_event_loop_waker()
|
||||
}
|
||||
|
||||
fn register_vr_services(
|
||||
&mut self,
|
||||
services: &mut VRServiceManager,
|
||||
heartbeats: &mut Vec<Box<dyn WebVRMainThreadHeartbeat>>,
|
||||
) {
|
||||
if !opts::get().headless {
|
||||
if pref!(dom.webvr.test) {
|
||||
warn!("Creating test VR display");
|
||||
// This is safe, because register_vr_services is called from the main thread.
|
||||
let name = String::from("Test VR Display");
|
||||
let size = opts::get().initial_window_size.to_f64();
|
||||
let size = LogicalSize::new(size.width, size.height);
|
||||
let events_loop_clone = self.events_loop.clone();
|
||||
let events_loop_factory = Box::new(move || {
|
||||
events_loop_clone
|
||||
.borrow_mut()
|
||||
.take()
|
||||
.ok_or(EventsLoopClosed)
|
||||
});
|
||||
let window_builder = glutin::WindowBuilder::new()
|
||||
.with_title(name.clone())
|
||||
.with_dimensions(size)
|
||||
.with_visibility(false)
|
||||
.with_multitouch();
|
||||
let context = glutin::ContextBuilder::new()
|
||||
.with_gl(app::gl_version(self.angle))
|
||||
.with_vsync(false) // Assume the browser vsync is the same as the test VR window vsync
|
||||
.build_windowed(window_builder, &*self.events_loop.borrow().as_winit())
|
||||
.expect("Failed to create window.");
|
||||
let gl = self.gl.clone();
|
||||
let (service, heartbeat) =
|
||||
GlWindowVRService::new(name, context, events_loop_factory, gl);
|
||||
|
||||
services.register(Box::new(service));
|
||||
heartbeats.push(Box::new(heartbeat));
|
||||
}
|
||||
} else {
|
||||
// FIXME: support headless mode
|
||||
}
|
||||
}
|
||||
|
||||
fn register_webxr(
|
||||
&mut self,
|
||||
xr: &mut webxr::MainThreadRegistry,
|
||||
|
|
|
@ -62,12 +62,6 @@ impl EventsLoop {
|
|||
panic!("Can't access winit event loop while using the fake headless event loop"),
|
||||
}
|
||||
}
|
||||
pub fn take(&mut self) -> Option<glutin::EventsLoop> {
|
||||
match self.0 {
|
||||
EventLoop::Glutin(ref mut event_loop) => event_loop.take(),
|
||||
EventLoop::Headless(..) => None,
|
||||
}
|
||||
}
|
||||
pub fn poll_events<F>(&mut self, callback: F) where F: FnMut(glutin::Event) {
|
||||
match self.0 {
|
||||
EventLoop::Glutin(Some(ref mut events_loop)) => events_loop.poll_events(callback),
|
||||
|
|
|
@ -20,7 +20,6 @@ layout-2020 = ["simpleservo/layout-2020"]
|
|||
[dependencies]
|
||||
libservo = { path = "../../components/servo", features = ["no_static_freetype"] }
|
||||
simpleservo = { path = "../libsimpleservo/api", features = ["no_static_freetype"] }
|
||||
rust-webvr = { version = "0.19", features = ["magicleap"] }
|
||||
webxr-api = { git = "https://github.com/servo/webxr", features = ["ipc"] }
|
||||
webxr = { git = "https://github.com/servo/webxr", features = ["ipc", "magicleap"] }
|
||||
libc = "0.2"
|
||||
|
|
|
@ -47,7 +47,6 @@ max_log_level = ["log/release_max_level_info"]
|
|||
native-bluetooth = ["libservo/native-bluetooth"]
|
||||
no_static_freetype = ["libservo/no_static_freetype"]
|
||||
no-wgl = ["libservo/no-wgl"]
|
||||
oculusvr = ["libservo/oculusvr"]
|
||||
profilemozjs = ["libservo/profilemozjs"]
|
||||
refcell_backtrace = ["libservo/refcell_backtrace"]
|
||||
webdriver = ["libservo/webdriver"]
|
||||
|
|
|
@ -32,7 +32,6 @@ use servo::servo_config::{pref, set_pref};
|
|||
use servo::servo_url::ServoUrl;
|
||||
use servo::webrender_api::units::DevicePixel;
|
||||
use servo::webrender_api::ScrollLocation;
|
||||
use servo::webvr::{VRExternalShmemPtr, VRMainThreadHeartbeat, VRService, VRServiceManager};
|
||||
use servo::{self, gl, BrowserId, Servo};
|
||||
use servo_media::player::context as MediaPlayerContext;
|
||||
use std::cell::RefCell;
|
||||
|
@ -55,19 +54,12 @@ pub struct InitOptions {
|
|||
pub url: Option<String>,
|
||||
pub coordinates: Coordinates,
|
||||
pub density: f32,
|
||||
pub vr_init: VRInitOptions,
|
||||
pub xr_discovery: Option<webxr::Discovery>,
|
||||
pub enable_subpixel_text_antialiasing: bool,
|
||||
pub gl_context_pointer: Option<*const c_void>,
|
||||
pub native_display_pointer: Option<*const c_void>,
|
||||
}
|
||||
|
||||
pub enum VRInitOptions {
|
||||
None,
|
||||
VRExternal(*mut c_void),
|
||||
VRService(Box<dyn VRService>, Box<dyn VRMainThreadHeartbeat>),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Coordinates {
|
||||
pub viewport: Rect<i32, DevicePixel>,
|
||||
|
@ -229,7 +221,6 @@ pub fn init(
|
|||
});
|
||||
|
||||
let embedder_callbacks = Box::new(ServoEmbedderCallbacks {
|
||||
vr_init: init_opts.vr_init,
|
||||
xr_discovery: init_opts.xr_discovery,
|
||||
waker,
|
||||
gl: gl.clone(),
|
||||
|
@ -727,7 +718,6 @@ impl ServoGlue {
|
|||
struct ServoEmbedderCallbacks {
|
||||
waker: Box<dyn EventLoopWaker>,
|
||||
xr_discovery: Option<webxr::Discovery>,
|
||||
vr_init: VRInitOptions,
|
||||
#[allow(unused)]
|
||||
gl: Rc<dyn gl::Gl>,
|
||||
}
|
||||
|
@ -742,24 +732,6 @@ struct ServoWindowCallbacks {
|
|||
}
|
||||
|
||||
impl EmbedderMethods for ServoEmbedderCallbacks {
|
||||
fn register_vr_services(
|
||||
&mut self,
|
||||
services: &mut VRServiceManager,
|
||||
heartbeats: &mut Vec<Box<dyn VRMainThreadHeartbeat>>,
|
||||
) {
|
||||
debug!("EmbedderMethods::register_vrexternal");
|
||||
match mem::replace(&mut self.vr_init, VRInitOptions::None) {
|
||||
VRInitOptions::None => {},
|
||||
VRInitOptions::VRExternal(ptr) => {
|
||||
services.register_vrexternal(VRExternalShmemPtr::new(ptr));
|
||||
},
|
||||
VRInitOptions::VRService(service, heartbeat) => {
|
||||
services.register(service);
|
||||
heartbeats.push(heartbeat);
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "uwp")]
|
||||
fn register_webxr(
|
||||
&mut self,
|
||||
|
|
|
@ -41,7 +41,6 @@ layout-2020 = ["simpleservo/layout-2020"]
|
|||
max_log_level = ["simpleservo/max_log_level"]
|
||||
native-bluetooth = ["simpleservo/native-bluetooth"]
|
||||
no-wgl = ["simpleservo/no-wgl"]
|
||||
oculusvr = ["simpleservo/oculusvr"]
|
||||
profilemozjs = ["simpleservo/profilemozjs"]
|
||||
refcell_backtrace = ["simpleservo/refcell_backtrace"]
|
||||
uwp = ["simpleservo/uwp"]
|
||||
|
|
|
@ -18,7 +18,7 @@ use log::LevelFilter;
|
|||
use simpleservo::{self, gl_glue, ServoGlue, SERVO};
|
||||
use simpleservo::{
|
||||
ContextMenuResult, Coordinates, EventLoopWaker, HostTrait, InitOptions, MediaSessionActionType,
|
||||
MediaSessionPlaybackState, MouseButton, PromptResult, VRInitOptions,
|
||||
MediaSessionPlaybackState, MouseButton, PromptResult,
|
||||
};
|
||||
use std::ffi::{CStr, CString};
|
||||
#[cfg(target_os = "windows")]
|
||||
|
@ -242,7 +242,6 @@ pub struct CInitOptions {
|
|||
pub width: i32,
|
||||
pub height: i32,
|
||||
pub density: f32,
|
||||
pub vr_pointer: *mut c_void,
|
||||
pub enable_subpixel_text_antialiasing: bool,
|
||||
pub vslogger_mod_list: *const *const c_char,
|
||||
pub vslogger_mod_size: u32,
|
||||
|
@ -439,11 +438,6 @@ unsafe fn init(
|
|||
url,
|
||||
coordinates,
|
||||
density: opts.density,
|
||||
vr_init: if opts.vr_pointer.is_null() {
|
||||
VRInitOptions::None
|
||||
} else {
|
||||
VRInitOptions::VRExternal(opts.vr_pointer)
|
||||
},
|
||||
xr_discovery: None,
|
||||
enable_subpixel_text_antialiasing: opts.enable_subpixel_text_antialiasing,
|
||||
gl_context_pointer: gl_context,
|
||||
|
|
|
@ -39,6 +39,5 @@ layout-2013 = ["simpleservo/layout-2013"]
|
|||
layout-2020 = ["simpleservo/layout-2020"]
|
||||
max_log_level = ["simpleservo/max_log_level"]
|
||||
native-bluetooth = ["simpleservo/native-bluetooth"]
|
||||
oculusvr = ["simpleservo/oculusvr"]
|
||||
webdriver = ["simpleservo/webdriver"]
|
||||
webgl_backtrace = ["simpleservo/webgl_backtrace"]
|
||||
|
|
|
@ -118,7 +118,6 @@ Servo::Servo(hstring url, hstring args, GLsizei width, GLsizei height,
|
|||
o.height = mWindowHeight;
|
||||
o.density = dpi;
|
||||
o.enable_subpixel_text_antialiasing = false;
|
||||
o.vr_pointer = NULL;
|
||||
|
||||
// Note about logs:
|
||||
// By default: all modules are enabled. Only warn level-logs are displayed.
|
||||
|
|
|
@ -1 +1 @@
|
|||
prefs: ["dom.gamepad.enabled:true", "dom.webvr.enabled:true", "dom.webxr.enabled:false"]
|
||||
disabled: No longer supporting WebVR
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue