From 349619ed2d741312e34924aabc3e6abcc3c468ed Mon Sep 17 00:00:00 2001 From: Alan Jeffrey Date: Wed, 15 Apr 2020 18:04:32 -0500 Subject: [PATCH] Support for webxr layer management --- Cargo.lock | 29 +- Cargo.toml | 2 - components/canvas/Cargo.toml | 7 +- components/canvas/lib.rs | 3 - components/canvas/webgl_mode/inprocess.rs | 23 +- components/canvas/webgl_thread.rs | 627 ++++++++++++------ components/canvas_traits/webgl.rs | 123 ++-- components/compositing/windowing.rs | 10 +- components/script/dom/bindings/trace.rs | 6 +- components/script/dom/document.rs | 4 +- components/script/dom/webglframebuffer.rs | 110 +-- .../script/dom/webglrenderingcontext.rs | 23 +- components/script/dom/webidls/XRLayer.webidl | 3 - .../script/dom/webidls/XRWebGLLayer.webidl | 3 +- .../script/dom/webidls/XRWebGLSubImage.webidl | 6 +- components/script/dom/xrframe.rs | 10 + components/script/dom/xrlayer.rs | 40 +- components/script/dom/xrrenderstate.rs | 58 +- components/script/dom/xrsession.rs | 142 ++-- components/script/dom/xrwebglbinding.rs | 14 + components/script/dom/xrwebgllayer.rs | 156 +++-- components/script/dom/xrwebglsubimage.rs | 13 + components/servo/Cargo.toml | 2 +- components/servo/lib.rs | 104 +-- components/webrender_surfman/#Cargo.toml# | 17 + components/webrender_surfman/.#Cargo.toml | 1 + components/webrender_surfman/Cargo.toml | 4 +- components/webrender_surfman/lib.rs | 6 +- ports/gstplugin/Cargo.toml | 4 +- ports/libsimpleservo/api/Cargo.toml | 2 +- ports/libsimpleservo/api/src/lib.rs | 32 +- ports/libsimpleservo/capi/Cargo.toml | 2 +- ports/winit/Cargo.toml | 2 +- ports/winit/embedder.rs | 3 - 34 files changed, 949 insertions(+), 642 deletions(-) create mode 100644 components/webrender_surfman/#Cargo.toml# create mode 120000 components/webrender_surfman/.#Cargo.toml diff --git a/Cargo.lock b/Cargo.lock index bba68728820f..fef028c035c7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -529,6 +529,7 @@ dependencies = [ "webrender_api", "webrender_surfman", "webrender_traits", + "webxr", "webxr-api", ] @@ -1952,15 +1953,6 @@ dependencies = [ "gl_generator 0.13.1", ] -[[package]] -name = "gleam" -version = "0.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "332d1f4e6c6181ed07178f84a552b2387d43ecf6821a86c22cfb3883ea3fb1b9" -dependencies = [ - "gl_generator 0.14.0", -] - [[package]] name = "gleam" version = "0.11.0" @@ -5546,8 +5538,9 @@ dependencies = [ [[package]] name = "surfman" -version = "0.2.0" -source = "git+https://github.com/servo/surfman#2283acaa3a856c2f76028cb23b5dde7dc0030cdf" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3d85bf0eb91b66b93dda5c04627f00074ea1fa008c2980b132a065fafe7a1ab" dependencies = [ "bitflags", "cfg_aliases", @@ -5557,7 +5550,7 @@ dependencies = [ "core-graphics 0.17.3", "display-link", "euclid", - "gl_generator 0.13.1", + "gl_generator 0.14.0", "io-surface", "lazy_static", "libc", @@ -5575,8 +5568,9 @@ dependencies = [ [[package]] name = "surfman-chains" -version = "0.3.0" -source = "git+https://github.com/asajeffrey/surfman-chains#b949a240d73ef86d3c4bd22bc3d93933fac21ee9" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d51598e1772bda3dbb1b81a9dc4b46725896948ea58d0f128e5b492a92f297af" dependencies = [ "euclid", "fnv", @@ -6526,18 +6520,18 @@ dependencies = [ [[package]] name = "webxr" version = "0.0.1" -source = "git+https://github.com/servo/webxr#0d8d2affc4da259b88d251ab49c0bbcbe96acf4d" +source = "git+https://github.com/servo/webxr#e507076cc6f55ea6daa58c3ecbb1867847854722" dependencies = [ "android_injected_glue", "bindgen", "crossbeam-channel", "euclid", "gl_generator 0.13.1", - "gleam 0.9.2", "gvr-sys", "log", "openxr", "serde", + "sparkle", "surfman", "surfman-chains", "time", @@ -6549,13 +6543,12 @@ dependencies = [ [[package]] name = "webxr-api" version = "0.0.1" -source = "git+https://github.com/servo/webxr#0d8d2affc4da259b88d251ab49c0bbcbe96acf4d" +source = "git+https://github.com/servo/webxr#e507076cc6f55ea6daa58c3ecbb1867847854722" dependencies = [ "euclid", "ipc-channel", "log", "serde", - "surfman-chains-api", "time", ] diff --git a/Cargo.toml b/Cargo.toml index cf04bfa64c84..5ad9325baf83 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,5 +28,3 @@ opt-level = 3 # This is here to dedupe winapi since mio 0.6 is still using winapi 0.2. mio = { git = "https://github.com/servo/mio.git", branch = "servo" } -surfman = { git = "https://github.com/servo/surfman" } -surfman-chains = { git = "https://github.com/asajeffrey/surfman-chains" } diff --git a/components/canvas/Cargo.toml b/components/canvas/Cargo.toml index 782e9fba4f06..2281ea302425 100644 --- a/components/canvas/Cargo.toml +++ b/components/canvas/Cargo.toml @@ -38,9 +38,9 @@ servo_config = { path = "../config" } sparkle = "0.1.25" style = { path = "../style" } style_traits = { path = "../style_traits" } -# NOTE: the sm-angle feature only enables ANGLE on Windows, not other platforms! -surfman = { version = "0.2", features = ["sm-angle", "sm-angle-default"] } -surfman-chains = "0.3" +# NOTE: the sm-angle feature only enables angle on windows, not other platforms! +surfman = { version = "0.3", features = ["sm-angle","sm-angle-default"] } +surfman-chains = "0.4" surfman-chains-api = "0.2" time = { version = "0.1.0", optional = true } webrender = { git = "https://github.com/servo/webrender" } @@ -48,3 +48,4 @@ webrender_api = { git = "https://github.com/servo/webrender" } webrender_surfman = { path = "../webrender_surfman" } webrender_traits = { path = "../webrender_traits" } webxr-api = { git = "https://github.com/servo/webxr", features = ["ipc"] } +webxr = { git = "https://github.com/servo/webxr", features = ["ipc"] } diff --git a/components/canvas/lib.rs b/components/canvas/lib.rs index 074a4a00bcbb..1e5872420bc0 100644 --- a/components/canvas/lib.rs +++ b/components/canvas/lib.rs @@ -12,9 +12,6 @@ extern crate log; mod raqote_backend; pub use webgl_mode::WebGLComm; -pub use webgl_thread::SurfaceProvider; -pub use webgl_thread::SurfaceProviders; -pub use webgl_thread::WebGlExecutor; pub mod canvas_data; pub mod canvas_paint_thread; diff --git a/components/canvas/webgl_mode/inprocess.rs b/components/canvas/webgl_mode/inprocess.rs index c7b25b69d125..ca9188aee54f 100644 --- a/components/canvas/webgl_mode/inprocess.rs +++ b/components/canvas/webgl_mode/inprocess.rs @@ -2,7 +2,7 @@ * 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::webgl_thread::{SurfaceProviders, WebGLThread, WebGLThreadInit, WebGlExecutor}; +use crate::webgl_thread::{WebGLThread, WebGLThreadInit, WebXRBridgeInit}; use canvas_traits::webgl::webgl_channel; use canvas_traits::webgl::{WebGLContextId, WebGLMsg, WebGLThreads}; use euclid::default::Size2D; @@ -11,7 +11,6 @@ use gleam; use servo_config::pref; use sparkle::gl; use sparkle::gl::GlType; -use std::collections::HashMap; use std::default::Default; use std::rc::Rc; use std::sync::{Arc, Mutex}; @@ -25,15 +24,14 @@ use webrender_surfman::WebrenderSurfman; use webrender_traits::{ WebrenderExternalImageApi, WebrenderExternalImageRegistry, WebrenderImageSource, }; -use webxr_api::SwapChainId as WebXRSwapChainId; +use webxr::SurfmanGL as WebXRSurfman; +use webxr_api::LayerGrandManager as WebXRLayerGrandManager; pub struct WebGLComm { pub webgl_threads: WebGLThreads, - pub webxr_swap_chains: SwapChains, - pub webxr_surface_providers: SurfaceProviders, pub image_handler: Box, pub output_handler: Option>, - pub webgl_executor: WebGlExecutor, + pub webxr_layer_grand_manager: WebXRLayerGrandManager, } impl WebGLComm { @@ -49,9 +47,8 @@ impl WebGLComm { debug!("WebGLThreads::new()"); let (sender, receiver) = webgl_channel::().unwrap(); let webrender_swap_chains = SwapChains::new(); - let webxr_swap_chains = SwapChains::new(); - let webxr_surface_providers = Arc::new(Mutex::new(HashMap::new())); - let (runnable_sender, runnable_receiver) = crossbeam_channel::unbounded(); + let webxr_init = WebXRBridgeInit::new(sender.clone()); + let webxr_layer_grand_manager = webxr_init.layer_grand_manager(); // This implementation creates a single `WebGLThread` for all the pipelines. let init = WebGLThreadInit { @@ -61,12 +58,10 @@ impl WebGLComm { sender: sender.clone(), receiver, webrender_swap_chains: webrender_swap_chains.clone(), - webxr_swap_chains: webxr_swap_chains.clone(), - webxr_surface_providers: webxr_surface_providers.clone(), connection: surfman.connection(), adapter: surfman.adapter(), api_type, - runnable_receiver, + webxr_init, }; let output_handler = if pref!(dom.webgl.dom_to_texture.enabled) { @@ -81,11 +76,9 @@ impl WebGLComm { WebGLComm { webgl_threads: WebGLThreads(sender), - webxr_swap_chains, - webxr_surface_providers, image_handler: Box::new(external), output_handler: output_handler.map(|b| b as Box<_>), - webgl_executor: runnable_sender, + webxr_layer_grand_manager: webxr_layer_grand_manager, } } } diff --git a/components/canvas/webgl_thread.rs b/components/canvas/webgl_thread.rs index d113f0aca852..a9a76d71960f 100644 --- a/components/canvas/webgl_thread.rs +++ b/components/canvas/webgl_thread.rs @@ -5,6 +5,7 @@ use crate::webgl_limits::GLLimitsDetect; use byteorder::{ByteOrder, NativeEndian, WriteBytesExt}; use canvas_traits::webgl; +use canvas_traits::webgl::webgl_channel; use canvas_traits::webgl::ActiveAttribInfo; use canvas_traits::webgl::ActiveUniformBlockInfo; use canvas_traits::webgl::ActiveUniformInfo; @@ -15,7 +16,6 @@ use canvas_traits::webgl::GLLimits; use canvas_traits::webgl::GlType; use canvas_traits::webgl::InternalFormatIntVec; use canvas_traits::webgl::ProgramLinkInfo; -use canvas_traits::webgl::SwapChainId; use canvas_traits::webgl::TexDataType; use canvas_traits::webgl::TexFormat; use canvas_traits::webgl::WebGLBufferId; @@ -28,7 +28,6 @@ use canvas_traits::webgl::WebGLFramebufferBindingRequest; use canvas_traits::webgl::WebGLFramebufferId; use canvas_traits::webgl::WebGLMsg; use canvas_traits::webgl::WebGLMsgSender; -use canvas_traits::webgl::WebGLOpaqueFramebufferId; use canvas_traits::webgl::WebGLProgramId; use canvas_traits::webgl::WebGLQueryId; use canvas_traits::webgl::WebGLReceiver; @@ -39,9 +38,10 @@ use canvas_traits::webgl::WebGLSender; use canvas_traits::webgl::WebGLShaderId; use canvas_traits::webgl::WebGLSyncId; use canvas_traits::webgl::WebGLTextureId; -use canvas_traits::webgl::WebGLTransparentFramebufferId; use canvas_traits::webgl::WebGLVersion; use canvas_traits::webgl::WebGLVertexArrayId; +use canvas_traits::webgl::WebXRCommand; +use canvas_traits::webgl::WebXRLayerManagerId; use canvas_traits::webgl::YAxisTreatment; use euclid::default::Size2D; use fnv::FnvHashMap; @@ -68,11 +68,22 @@ use surfman::GLVersion; use surfman::SurfaceAccess; use surfman::SurfaceInfo; use surfman::SurfaceType; -use surfman_chains::{SurfmanProvider, SwapChains}; +use surfman_chains::SwapChains; use surfman_chains_api::SwapChainsAPI; use webrender_traits::{WebrenderExternalImageRegistry, WebrenderImageHandlerType}; -use webxr_api::SessionId; -use webxr_api::SwapChainId as WebXRSwapChainId; +use webxr::SurfmanGL as WebXRSurfman; +use webxr_api::ContextId as WebXRContextId; +use webxr_api::Error as WebXRError; +use webxr_api::GLContexts as WebXRContexts; +use webxr_api::GLTypes as WebXRTypes; +use webxr_api::LayerGrandManager as WebXRLayerGrandManager; +use webxr_api::LayerGrandManagerAPI as WebXRLayerGrandManagerAPI; +use webxr_api::LayerId as WebXRLayerId; +use webxr_api::LayerInit as WebXRLayerInit; +use webxr_api::LayerManager as WebXRLayerManager; +use webxr_api::LayerManagerAPI as WebXRLayerManagerAPI; +use webxr_api::LayerManagerFactory as WebXRLayerManagerFactory; +use webxr_api::SubImages as WebXRSubImages; #[cfg(feature = "xr-profile")] fn to_ms(ns: u64) -> f64 { @@ -239,35 +250,24 @@ pub(crate) struct WebGLThread { sender: WebGLSender, /// The swap chains used by webrender webrender_swap_chains: SwapChains, - /// The swap chains used by webxr - webxr_swap_chains: SwapChains, - /// The set of all surface providers corresponding to WebXR sessions. - webxr_surface_providers: SurfaceProviders, - /// A channel to allow arbitrary threads to execute tasks that run in the WebGL thread. - runnable_receiver: crossbeam_channel::Receiver, /// Whether this context is a GL or GLES context. api_type: gl::GlType, + /// The bridge to WebXR + pub webxr_bridge: WebXRBridge, } -pub type WebGlExecutor = crossbeam_channel::Sender; -pub type WebGlRunnable = Box; -pub type SurfaceProviders = Arc>>; -pub type SurfaceProvider = Box + Send>; - /// The data required to initialize an instance of the WebGLThread type. pub(crate) struct WebGLThreadInit { - pub webxr_surface_providers: SurfaceProviders, pub webrender_api_sender: webrender_api::RenderApiSender, pub webrender_doc: webrender_api::DocumentId, pub external_images: Arc>, pub sender: WebGLSender, pub receiver: WebGLReceiver, pub webrender_swap_chains: SwapChains, - pub webxr_swap_chains: SwapChains, pub connection: Connection, pub adapter: Adapter, pub api_type: gl::GlType, - pub runnable_receiver: crossbeam_channel::Receiver, + pub webxr_init: WebXRBridgeInit, } // A size at which it should be safe to create GL contexts @@ -283,12 +283,10 @@ impl WebGLThread { sender, receiver, webrender_swap_chains, - webxr_swap_chains, - webxr_surface_providers, connection, adapter, api_type, - runnable_receiver, + webxr_init, }: WebGLThreadInit, ) -> Self { WebGLThread { @@ -305,10 +303,8 @@ impl WebGLThread { sender, receiver: receiver.into_inner(), webrender_swap_chains, - webxr_swap_chains, - webxr_surface_providers, - runnable_receiver, api_type, + webxr_bridge: WebXRBridge::new(webxr_init), } } @@ -326,34 +322,18 @@ impl WebGLThread { fn process(&mut self) { let webgl_chan = WebGLChan(self.sender.clone()); - loop { - crossbeam_channel::select! { - recv(self.receiver) -> msg => { - match msg { - Ok(msg) => { - let exit = self.handle_msg(msg, &webgl_chan); - if exit { - // Call remove_context functions in order to correctly delete WebRender image keys. - let context_ids: Vec = self.contexts.keys().map(|id| *id).collect(); - for id in context_ids { - self.remove_webgl_context(id); - } - - // Block on shutting-down WebRender. - self.webrender_api.shut_down(true); - return; - } - } - _ => break, - } - } - recv(self.runnable_receiver) -> msg => { - if let Ok(msg) = msg { - msg(&self.device); - } else { - self.runnable_receiver = crossbeam_channel::never(); - } + while let Ok(msg) = self.receiver.recv() { + let exit = self.handle_msg(msg, &webgl_chan); + if exit { + // Call remove_context functions in order to correctly delete WebRender image keys. + let context_ids: Vec = self.contexts.keys().map(|id| *id).collect(); + for id in context_ids { + self.remove_webgl_context(id); } + + // Block on shutting-down WebRender. + self.webrender_api.shut_down(true); + return; } } } @@ -424,8 +404,8 @@ impl WebGLThread { WebGLMsg::WebGLCommand(ctx_id, command, backtrace) => { self.handle_webgl_command(ctx_id, command, backtrace); }, - WebGLMsg::CreateWebXRSwapChain(ctx_id, size, sender, id) => { - let _ = sender.send(self.create_webxr_swap_chain(ctx_id, size, id)); + WebGLMsg::WebXRCommand(command) => { + self.handle_webxr_command(command); }, WebGLMsg::SwapBuffers(swap_ids, sender, sent_time) => { self.handle_swap_buffers(swap_ids, sender, sent_time); @@ -441,6 +421,63 @@ impl WebGLThread { false } + /// Handles a WebXR message + fn handle_webxr_command(&mut self, command: WebXRCommand) { + trace!("processing {:?}", command); + let mut contexts = WebXRBridgeContexts { + contexts: &mut self.contexts, + bound_context_id: &mut self.bound_context_id, + }; + match command { + WebXRCommand::CreateLayerManager(sender) => { + let result = self + .webxr_bridge + .create_layer_manager(&mut self.device, &mut contexts); + let _ = sender.send(result); + }, + WebXRCommand::DestroyLayerManager(manager_id) => { + self.webxr_bridge.destroy_layer_manager(manager_id); + }, + WebXRCommand::CreateLayer(manager_id, context_id, layer_init, sender) => { + let result = self.webxr_bridge.create_layer( + manager_id, + &mut self.device, + &mut contexts, + context_id, + layer_init, + ); + let _ = sender.send(result); + }, + WebXRCommand::DestroyLayer(manager_id, context_id, layer_id) => { + self.webxr_bridge.destroy_layer( + manager_id, + &mut self.device, + &mut contexts, + context_id, + layer_id, + ); + }, + WebXRCommand::BeginFrame(manager_id, layers, sender) => { + let result = self.webxr_bridge.begin_frame( + manager_id, + &mut self.device, + &mut contexts, + &layers[..], + ); + let _ = sender.send(result); + }, + WebXRCommand::EndFrame(manager_id, layers, sender) => { + let result = self.webxr_bridge.end_frame( + manager_id, + &mut self.device, + &mut contexts, + &layers[..], + ); + let _ = sender.send(result); + }, + } + } + /// Handles a WebGLCommand for a specific WebGLContext fn handle_webgl_command( &mut self, @@ -457,36 +494,7 @@ impl WebGLThread { &mut self.contexts, &mut self.bound_context_id, ); - if let Some(data) = data { - match command { - // We have to handle framebuffer binding differently, because `apply` - // assumes that the currently attached surface is the right one for binding - // the framebuffer, and since it doesn't get passed the swap buffers - // it casn't do that itself. At some point we could refactor apply so - // it takes a self parameter, at which point that won't be necessary. - WebGLCommand::BindFramebuffer(_, request) => { - WebGLImpl::attach_surface( - context_id, - &self.webrender_swap_chains, - &self.webxr_swap_chains, - request, - &mut data.ctx, - &mut self.device, - ); - }, - // Similarly, dropping a WebGL framebuffer needs access to the swap chains, - // in order to delete the entry. - WebGLCommand::DeleteFramebuffer(WebGLFramebufferId::Opaque( - WebGLOpaqueFramebufferId::WebXR(id), - )) => { - let _ = self - .webxr_swap_chains - .destroy(id, &mut self.device, &mut data.ctx); - }, - _ => {}, - } - WebGLImpl::apply( &self.device, &data.ctx, @@ -545,11 +553,10 @@ impl WebGLThread { size: safe_size.to_i32(), }; let surface_access = self.surface_access(); - let surface_provider = Box::new(SurfmanProvider::new(surface_access)); let mut ctx = self .device - .create_context(&context_descriptor) + .create_context(&context_descriptor, None) .map_err(|err| format!("Failed to create the GL context: {:?}", err))?; let surface = self .device @@ -572,7 +579,7 @@ impl WebGLThread { ); self.webrender_swap_chains - .create_attached_swap_chain(id, &mut self.device, &mut ctx, surface_provider) + .create_attached_swap_chain(id, &mut self.device, &mut ctx, surface_access) .map_err(|err| format!("Failed to create swap chain: {:?}", err))?; let swap_chain = self @@ -766,9 +773,11 @@ impl WebGLThread { self.webrender_swap_chains .destroy(context_id, &mut self.device, &mut data.ctx) .unwrap(); - self.webxr_swap_chains - .destroy_all(&mut self.device, &mut data.ctx) - .unwrap(); + + // Destroy WebXR layers associated with this context + let webxr_context_id = WebXRContextId::from(context_id); + self.webxr_bridge + .destroy_all_layers(&mut self.device, &mut data.ctx, webxr_context_id); // Destroy the context self.device.destroy_context(&mut data.ctx).unwrap(); @@ -779,21 +788,12 @@ impl WebGLThread { fn handle_swap_buffers( &mut self, - swap_ids: Vec, + context_ids: Vec, completed_sender: WebGLSender, _sent_time: u64, ) { - #[cfg(feature = "xr-profile")] - let start_swap = time::precise_time_ns(); - #[cfg(feature = "xr-profile")] - println!( - "WEBXR PROFILING [swap request]:\t{}ms", - to_ms(start_swap - _sent_time) - ); debug!("handle_swap_buffers()"); - for swap_id in swap_ids { - let context_id = swap_id.context_id(); - + for context_id in context_ids { let data = Self::make_current_if_needed_mut( &self.device, context_id, @@ -811,16 +811,13 @@ impl WebGLThread { FramebufferRebindingInfo::detect(&self.device, &data.ctx, &*data.gl); debug_assert_eq!(data.gl.get_error(), gl::NO_ERROR); - debug!("Getting swap chain for {:?}", swap_id); - let swap_chain = match swap_id { - SwapChainId::Context(id) => self.webrender_swap_chains.get(id), - SwapChainId::Framebuffer(_, WebGLOpaqueFramebufferId::WebXR(id)) => { - self.webxr_swap_chains.get(id) - }, - } - .expect("Where's the swap chain?"); + debug!("Getting swap chain for {:?}", context_id); + let swap_chain = self + .webrender_swap_chains + .get(context_id) + .expect("Where's the swap chain?"); - debug!("Swapping {:?}", swap_id); + debug!("Swapping {:?}", context_id); swap_chain .swap_buffers(&mut self.device, &mut data.ctx) .unwrap(); @@ -828,7 +825,7 @@ impl WebGLThread { // TODO: if preserveDrawingBuffer is true, then blit the front buffer to the back buffer // https://github.com/servo/servo/issues/24604 - debug!("Clearing {:?}", swap_id); + debug!("Clearing {:?}", context_id); let alpha = data .state .requested_flags @@ -840,7 +837,7 @@ impl WebGLThread { debug_assert_eq!(data.gl.get_error(), gl::NO_ERROR); // Rebind framebuffers as appropriate. - debug!("Rebinding {:?}", swap_id); + debug!("Rebinding {:?}", context_id); framebuffer_rebinding_info.apply(&self.device, &data.ctx, &*data.gl); debug_assert_eq!(data.gl.get_error(), gl::NO_ERROR); @@ -872,36 +869,6 @@ impl WebGLThread { completed_sender.send(end_swap).unwrap(); } - /// Creates a new WebXR swap chain - #[allow(unsafe_code)] - fn create_webxr_swap_chain( - &mut self, - context_id: WebGLContextId, - size: Size2D, - session_id: SessionId, - ) -> Option { - debug!("WebGLThread::create_webxr_swap_chain()"); - let id = WebXRSwapChainId::new(); - let surface_access = self.surface_access(); - let data = Self::make_current_if_needed_mut( - &self.device, - context_id, - &mut self.contexts, - &mut self.bound_context_id, - )?; - let surface_provider = self - .webxr_surface_providers - .lock() - .unwrap() - .remove(&session_id) - .unwrap_or_else(|| Box::new(SurfmanProvider::new(surface_access))); - self.webxr_swap_chains - .create_detached_swap_chain(id, size, &mut self.device, &mut data.ctx, surface_provider) - .ok()?; - debug!("Created swap chain {:?}", id); - Some(id) - } - /// Which access mode to use fn surface_access(&self) -> SurfaceAccess { SurfaceAccess::GPUOnly @@ -1459,10 +1426,7 @@ impl WebGLImpl { Self::create_shader(gl, shader_type, chan) }, WebGLCommand::DeleteBuffer(id) => gl.delete_buffers(&[id.get()]), - WebGLCommand::DeleteFramebuffer(WebGLFramebufferId::Transparent(id)) => { - gl.delete_framebuffers(&[id.get()]) - }, - WebGLCommand::DeleteFramebuffer(WebGLFramebufferId::Opaque(_)) => {}, + WebGLCommand::DeleteFramebuffer(id) => gl.delete_framebuffers(&[id.get()]), WebGLCommand::DeleteRenderbuffer(id) => gl.delete_renderbuffers(&[id.get()]), WebGLCommand::DeleteTexture(id) => gl.delete_textures(&[id.get()]), WebGLCommand::DeleteProgram(id) => gl.delete_program(id.get()), @@ -2498,12 +2462,12 @@ impl WebGLImpl { } #[allow(unsafe_code)] - fn create_framebuffer(gl: &Gl, chan: &WebGLSender>) { + fn create_framebuffer(gl: &Gl, chan: &WebGLSender>) { let framebuffer = gl.gen_framebuffers(1)[0]; let framebuffer = if framebuffer == 0 { None } else { - Some(unsafe { WebGLTransparentFramebufferId::new(framebuffer) }) + Some(unsafe { WebGLFramebufferId::new(framebuffer) }) }; chan.send(framebuffer).unwrap(); } @@ -2611,54 +2575,6 @@ impl WebGLImpl { debug_assert_eq!(gl.get_error(), gl::NO_ERROR); } - /// Updates the swap buffers if the context surface needs to be changed - fn attach_surface( - context_id: WebGLContextId, - webrender_swap_chains: &SwapChains, - webxr_swap_chains: &SwapChains, - request: WebGLFramebufferBindingRequest, - ctx: &mut Context, - device: &mut Device, - ) -> Option<()> { - debug!( - "WebGLImpl::attach_surface({:?} in {:?})", - request, context_id - ); - let requested_framebuffer = match request { - WebGLFramebufferBindingRequest::Explicit(WebGLFramebufferId::Opaque(id)) => Some(id), - WebGLFramebufferBindingRequest::Explicit(WebGLFramebufferId::Transparent(_)) => { - return None - }, - WebGLFramebufferBindingRequest::Default => None, - }; - let attached_framebuffer = webxr_swap_chains - .iter(device, ctx) - .filter_map(|(id, swap_chain)| { - if swap_chain.is_attached() { - Some(id) - } else { - None - } - }) - .map(WebGLOpaqueFramebufferId::WebXR) - .next(); - if requested_framebuffer == attached_framebuffer { - return None; - } - let requested_swap_chain = match requested_framebuffer { - Some(WebGLOpaqueFramebufferId::WebXR(id)) => webxr_swap_chains.get(id)?, - None => webrender_swap_chains.get(context_id)?, - }; - let current_swap_chain = match attached_framebuffer { - Some(WebGLOpaqueFramebufferId::WebXR(id)) => webxr_swap_chains.get(id)?, - None => webrender_swap_chains.get(context_id)?, - }; - requested_swap_chain - .take_attachment_from(device, ctx, ¤t_swap_chain) - .unwrap(); - Some(()) - } - #[inline] fn bind_framebuffer( gl: &Gl, @@ -2669,10 +2585,7 @@ impl WebGLImpl { state: &mut GLState, ) { let id = match request { - WebGLFramebufferBindingRequest::Explicit(WebGLFramebufferId::Transparent(id)) => { - id.get() - }, - WebGLFramebufferBindingRequest::Explicit(WebGLFramebufferId::Opaque(_)) | + WebGLFramebufferBindingRequest::Explicit(id) => id.get(), WebGLFramebufferBindingRequest::Default => { device .context_surface_info(ctx) @@ -3223,3 +3136,317 @@ impl FramebufferRebindingInfo { ); } } + +/// Bridge between WebGL and WebXR +pub(crate) struct WebXRBridge { + factory_receiver: crossbeam_channel::Receiver>, + managers: HashMap>>, + next_manager_id: u32, +} + +impl WebXRBridge { + pub(crate) fn new(init: WebXRBridgeInit) -> WebXRBridge { + let WebXRBridgeInit { + factory_receiver, .. + } = init; + let managers = HashMap::new(); + let next_manager_id = 1; + WebXRBridge { + factory_receiver, + managers, + next_manager_id, + } + } +} + +impl WebXRBridge { + #[allow(unsafe_code)] + fn create_layer_manager( + &mut self, + device: &mut Device, + contexts: &mut dyn WebXRContexts, + ) -> Result { + let factory = self + .factory_receiver + .recv() + .map_err(|_| WebXRError::CommunicationError)?; + let manager = factory.build(device, contexts)?; + let manager_id = unsafe { WebXRLayerManagerId::new(self.next_manager_id) }; + self.next_manager_id = self.next_manager_id + 1; + self.managers.insert(manager_id, manager); + Ok(manager_id) + } + + fn destroy_layer_manager(&mut self, manager_id: WebXRLayerManagerId) { + self.managers.remove(&manager_id); + } + + fn create_layer( + &mut self, + manager_id: WebXRLayerManagerId, + device: &mut Device, + contexts: &mut dyn WebXRContexts, + context_id: WebXRContextId, + layer_init: WebXRLayerInit, + ) -> Result { + let manager = self + .managers + .get_mut(&manager_id) + .ok_or(WebXRError::NoMatchingDevice)?; + let context = contexts + .context(device, context_id) + .ok_or(WebXRError::NoMatchingDevice)?; + manager.create_layer(device, context, context_id, layer_init) + } + + fn destroy_layer( + &mut self, + manager_id: WebXRLayerManagerId, + device: &mut Device, + contexts: &mut dyn WebXRContexts, + context_id: WebXRContextId, + layer_id: WebXRLayerId, + ) { + if let Some(manager) = self.managers.get_mut(&manager_id) { + if let Some(context) = contexts.context(device, context_id) { + manager.destroy_layer(device, context, context_id, layer_id); + } + } + } + + fn destroy_all_layers( + &mut self, + device: &mut Device, + context: &mut Context, + context_id: WebXRContextId, + ) { + for (_, manager) in &mut self.managers { + for (other_id, layer_id) in manager.layers().to_vec() { + if other_id == context_id { + manager.destroy_layer(device, context, context_id, layer_id); + } + } + } + } + + fn begin_frame( + &mut self, + manager_id: WebXRLayerManagerId, + device: &mut Device, + contexts: &mut dyn WebXRContexts, + layers: &[(WebXRContextId, WebXRLayerId)], + ) -> Result, WebXRError> { + let manager = self + .managers + .get_mut(&manager_id) + .ok_or(WebXRError::NoMatchingDevice)?; + manager.begin_frame(device, contexts, layers) + } + + fn end_frame( + &mut self, + manager_id: WebXRLayerManagerId, + device: &mut Device, + contexts: &mut dyn WebXRContexts, + layers: &[(WebXRContextId, WebXRLayerId)], + ) -> Result<(), WebXRError> { + let manager = self + .managers + .get_mut(&manager_id) + .ok_or(WebXRError::NoMatchingDevice)?; + manager.end_frame(device, contexts, layers) + } +} + +pub(crate) struct WebXRBridgeInit { + sender: WebGLSender, + factory_receiver: crossbeam_channel::Receiver>, + factory_sender: crossbeam_channel::Sender>, +} + +impl WebXRBridgeInit { + pub(crate) fn new(sender: WebGLSender) -> WebXRBridgeInit { + let (factory_sender, factory_receiver) = crossbeam_channel::unbounded(); + WebXRBridgeInit { + sender, + factory_sender, + factory_receiver, + } + } + + pub(crate) fn layer_grand_manager(&self) -> WebXRLayerGrandManager { + WebXRLayerGrandManager::new(WebXRBridgeGrandManager { + sender: self.sender.clone(), + factory_sender: self.factory_sender.clone(), + }) + } +} + +struct WebXRBridgeGrandManager { + sender: WebGLSender, + // WebXR layer manager factories use generic trait objects under the + // hood, which aren't deserializable (even using typetag) + // so we can't send them over the regular webgl channel. + // Fortunately, the webgl thread runs in the same process as + // the webxr threads, so we can use a crossbeam channel to send + // factories. + factory_sender: crossbeam_channel::Sender>, +} + +impl WebXRLayerGrandManagerAPI for WebXRBridgeGrandManager { + fn create_layer_manager( + &self, + factory: WebXRLayerManagerFactory, + ) -> Result { + let (sender, receiver) = webgl_channel().map_err(|_| WebXRError::CommunicationError)?; + let _ = self.factory_sender.send(factory); + let _ = self + .sender + .send(WebGLMsg::WebXRCommand(WebXRCommand::CreateLayerManager( + sender, + ))); + let sender = self.sender.clone(); + let manager_id = receiver + .recv() + .map_err(|_| WebXRError::CommunicationError)??; + let layers = Vec::new(); + Ok(WebXRLayerManager::new(WebXRBridgeManager { + manager_id, + sender, + layers, + })) + } + + fn clone_layer_grand_manager(&self) -> WebXRLayerGrandManager { + WebXRLayerGrandManager::new(WebXRBridgeGrandManager { + sender: self.sender.clone(), + factory_sender: self.factory_sender.clone(), + }) + } +} + +struct WebXRBridgeManager { + sender: WebGLSender, + manager_id: WebXRLayerManagerId, + layers: Vec<(WebXRContextId, WebXRLayerId)>, +} + +impl WebXRLayerManagerAPI for WebXRBridgeManager { + fn create_layer( + &mut self, + _: &mut GL::Device, + _: &mut GL::Context, + context_id: WebXRContextId, + init: WebXRLayerInit, + ) -> Result { + let (sender, receiver) = webgl_channel().map_err(|_| WebXRError::CommunicationError)?; + let _ = self + .sender + .send(WebGLMsg::WebXRCommand(WebXRCommand::CreateLayer( + self.manager_id, + context_id, + init, + sender, + ))); + let layer_id = receiver + .recv() + .map_err(|_| WebXRError::CommunicationError)??; + self.layers.push((context_id, layer_id)); + Ok(layer_id) + } + + fn destroy_layer( + &mut self, + _: &mut GL::Device, + _: &mut GL::Context, + context_id: WebXRContextId, + layer_id: WebXRLayerId, + ) { + self.layers.retain(|&ids| ids != (context_id, layer_id)); + let _ = self + .sender + .send(WebGLMsg::WebXRCommand(WebXRCommand::DestroyLayer( + self.manager_id, + context_id, + layer_id, + ))); + } + + fn layers(&self) -> &[(WebXRContextId, WebXRLayerId)] { + &self.layers[..] + } + + fn begin_frame( + &mut self, + _: &mut GL::Device, + _: &mut dyn WebXRContexts, + layers: &[(WebXRContextId, WebXRLayerId)], + ) -> Result, WebXRError> { + let (sender, receiver) = webgl_channel().map_err(|_| WebXRError::CommunicationError)?; + let _ = self + .sender + .send(WebGLMsg::WebXRCommand(WebXRCommand::BeginFrame( + self.manager_id, + layers.to_vec(), + sender, + ))); + receiver + .recv() + .map_err(|_| WebXRError::CommunicationError)? + } + + fn end_frame( + &mut self, + _: &mut GL::Device, + _: &mut dyn WebXRContexts, + layers: &[(WebXRContextId, WebXRLayerId)], + ) -> Result<(), WebXRError> { + let (sender, receiver) = webgl_channel().map_err(|_| WebXRError::CommunicationError)?; + let _ = self + .sender + .send(WebGLMsg::WebXRCommand(WebXRCommand::EndFrame( + self.manager_id, + layers.to_vec(), + sender, + ))); + receiver + .recv() + .map_err(|_| WebXRError::CommunicationError)? + } +} + +impl Drop for WebXRBridgeManager { + fn drop(&mut self) { + let _ = self + .sender + .send(WebGLMsg::WebXRCommand(WebXRCommand::DestroyLayerManager( + self.manager_id, + ))); + } +} + +struct WebXRBridgeContexts<'a> { + contexts: &'a mut FnvHashMap, + bound_context_id: &'a mut Option, +} + +impl<'a> WebXRContexts for WebXRBridgeContexts<'a> { + fn context(&mut self, device: &Device, context_id: WebXRContextId) -> Option<&mut Context> { + let data = WebGLThread::make_current_if_needed_mut( + device, + WebGLContextId::from(context_id), + &mut self.contexts, + &mut self.bound_context_id, + )?; + Some(&mut data.ctx) + } + fn bindings(&mut self, device: &Device, context_id: WebXRContextId) -> Option<&Gl> { + let data = WebGLThread::make_current_if_needed( + device, + WebGLContextId::from(context_id), + &self.contexts, + &mut self.bound_context_id, + )?; + Some(&data.gl) + } +} diff --git a/components/canvas_traits/webgl.rs b/components/canvas_traits/webgl.rs index 2b4b9dda4824..175e5ab0937c 100644 --- a/components/canvas_traits/webgl.rs +++ b/components/canvas_traits/webgl.rs @@ -12,8 +12,11 @@ use std::fmt; use std::num::{NonZeroU32, NonZeroU64}; use std::ops::Deref; use webrender_api::{DocumentId, ImageKey, PipelineId}; -use webxr_api::SessionId; -use webxr_api::SwapChainId as WebXRSwapChainId; +use webxr_api::ContextId as WebXRContextId; +use webxr_api::Error as WebXRError; +use webxr_api::LayerId as WebXRLayerId; +use webxr_api::LayerInit as WebXRLayerInit; +use webxr_api::SubImages as WebXRSubImages; /// Helper function that creates a WebGL channel (WebGLSender, WebGLReceiver) to be used in WebGLCommands. pub use crate::webgl_channel::webgl_channel; @@ -70,21 +73,17 @@ pub enum WebGLMsg { RemoveContext(WebGLContextId), /// Runs a WebGLCommand in a specific WebGLContext. WebGLCommand(WebGLContextId, WebGLCommand, WebGLCommandBacktrace), + /// Runs a WebXRCommand (WebXR layers need to be created in the WebGL + /// thread, as they may have thread affinity). + WebXRCommand(WebXRCommand), /// Commands used for the DOMToTexture feature. DOMToTextureCommand(DOMToTextureCommand), - /// Creates a new opaque framebuffer for WebXR. - CreateWebXRSwapChain( - WebGLContextId, - Size2D, - WebGLSender>, - SessionId, - ), /// Performs a buffer swap. /// /// The third field contains the time (in ns) when the request /// was initiated. The u64 in the second field will be the time the /// request is fulfilled - SwapBuffers(Vec, WebGLSender, u64), + SwapBuffers(Vec, WebGLSender, u64), /// Frees all resources and closes the thread. Exit, } @@ -176,47 +175,6 @@ impl WebGLMsgSender { self.sender.send(WebGLMsg::RemoveContext(self.ctx_id)) } - #[inline] - pub fn send_create_webxr_swap_chain( - &self, - size: Size2D, - sender: WebGLSender>, - id: SessionId, - ) -> WebGLSendResult { - self.sender.send(WebGLMsg::CreateWebXRSwapChain( - self.ctx_id, - size, - sender, - id, - )) - } - - #[inline] - pub fn send_swap_buffers(&self, id: Option) -> WebGLSendResult { - let swap_id = id - .map(|id| SwapChainId::Framebuffer(self.ctx_id, id)) - .unwrap_or_else(|| SwapChainId::Context(self.ctx_id)); - let (sender, receiver) = webgl_channel()?; - #[allow(unused)] - let mut time = 0; - #[cfg(feature = "xr-profile")] - { - time = time::precise_time_ns(); - } - - self.sender - .send(WebGLMsg::SwapBuffers(vec![swap_id], sender, time))?; - - #[allow(unused)] - let sent_time = receiver.recv()?; - #[cfg(feature = "xr-profile")] - println!( - "WEBXR PROFILING [swap complete]:\t{}ms", - (time::precise_time_ns() - sent_time) as f64 / 1_000_000. - ); - Ok(()) - } - pub fn send_dom_to_texture(&self, command: DOMToTextureCommand) -> WebGLSendResult { self.sender.send(WebGLMsg::DOMToTextureCommand(command)) } @@ -282,7 +240,7 @@ pub enum WebGLCommand { CopyTexImage2D(u32, i32, u32, i32, i32, i32, i32, i32), CopyTexSubImage2D(u32, i32, i32, i32, i32, i32, i32, i32), CreateBuffer(WebGLSender>), - CreateFramebuffer(WebGLSender>), + CreateFramebuffer(WebGLSender>), CreateRenderbuffer(WebGLSender>), CreateTexture(WebGLSender>), CreateProgram(WebGLSender>), @@ -555,6 +513,30 @@ pub enum WebGLCommand { DrawBuffers(Vec), } +/// WebXR layer management +#[derive(Debug, Deserialize, Serialize)] +pub enum WebXRCommand { + CreateLayerManager(WebGLSender>), + DestroyLayerManager(WebXRLayerManagerId), + CreateLayer( + WebXRLayerManagerId, + WebXRContextId, + WebXRLayerInit, + WebGLSender>, + ), + DestroyLayer(WebXRLayerManagerId, WebXRContextId, WebXRLayerId), + BeginFrame( + WebXRLayerManagerId, + Vec<(WebXRContextId, WebXRLayerId)>, + WebGLSender, WebXRError>>, + ), + EndFrame( + WebXRLayerManagerId, + Vec<(WebXRContextId, WebXRLayerId)>, + WebGLSender>, + ), +} + macro_rules! nonzero_type { (u32) => { NonZeroU32 @@ -576,6 +558,11 @@ macro_rules! define_resource_id { $name(::new_unchecked(id)) } + #[inline] + pub fn maybe_new(id: $type) -> Option { + ::new(id).map($name) + } + #[inline] pub fn get(self) -> $type { self.0.get() @@ -629,7 +616,7 @@ macro_rules! define_resource_id { } define_resource_id!(WebGLBufferId, u32); -define_resource_id!(WebGLTransparentFramebufferId, u32); +define_resource_id!(WebGLFramebufferId, u32); define_resource_id!(WebGLRenderbufferId, u32); define_resource_id!(WebGLTextureId, u32); define_resource_id!(WebGLProgramId, u32); @@ -638,24 +625,22 @@ define_resource_id!(WebGLSamplerId, u32); define_resource_id!(WebGLShaderId, u32); define_resource_id!(WebGLSyncId, u64); define_resource_id!(WebGLVertexArrayId, u32); +define_resource_id!(WebXRLayerManagerId, u32); #[derive( Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, Ord, PartialEq, PartialOrd, Serialize, )] pub struct WebGLContextId(pub u64); -#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)] -pub enum SwapChainId { - Context(WebGLContextId), - Framebuffer(WebGLContextId, WebGLOpaqueFramebufferId), +impl From for WebGLContextId { + fn from(id: WebXRContextId) -> Self { + Self(id.0) + } } -impl SwapChainId { - pub fn context_id(&self) -> WebGLContextId { - match *self { - SwapChainId::Context(id) => id, - SwapChainId::Framebuffer(id, _) => id, - } +impl From for WebXRContextId { + fn from(id: WebGLContextId) -> Self { + Self(id.0) } } @@ -669,18 +654,6 @@ pub enum WebGLError { ContextLost, } -#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)] -pub enum WebGLOpaqueFramebufferId { - // At the moment the only source of opaque framebuffers is webxr - WebXR(#[ignore_malloc_size_of = "ids don't malloc"] WebXRSwapChainId), -} - -#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)] -pub enum WebGLFramebufferId { - Transparent(WebGLTransparentFramebufferId), - Opaque(WebGLOpaqueFramebufferId), -} - #[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)] pub enum WebGLFramebufferBindingRequest { Explicit(WebGLFramebufferId), diff --git a/components/compositing/windowing.rs b/components/compositing/windowing.rs index 7a2784e08fd1..ac481486d378 100644 --- a/components/compositing/windowing.rs +++ b/components/compositing/windowing.rs @@ -4,7 +4,6 @@ //! Abstract windowing methods. The concrete implementations of these can be found in `platform/`. -use canvas::{SurfaceProviders, WebGlExecutor}; use embedder_traits::{EmbedderProxy, EventLoopWaker}; use euclid::Scale; use keyboard_types::KeyboardEvent; @@ -171,14 +170,7 @@ pub trait EmbedderMethods { fn create_event_loop_waker(&mut self) -> Box; /// Register services with a WebXR Registry. - fn register_webxr( - &mut self, - _: &mut webxr::MainThreadRegistry, - _: WebGlExecutor, - _: SurfaceProviders, - _: EmbedderProxy, - ) { - } + fn register_webxr(&mut self, _: &mut webxr::MainThreadRegistry, _: EmbedderProxy) {} /// Returns the user agent string to report in network requests. fn get_user_agent_string(&self) -> Option { diff --git a/components/script/dom/bindings/trace.rs b/components/script/dom/bindings/trace.rs index d6216cdad488..5a540f3e9125 100644 --- a/components/script/dom/bindings/trace.rs +++ b/components/script/dom/bindings/trace.rs @@ -60,7 +60,6 @@ use canvas_traits::webgl::{ use canvas_traits::webgl::{GLLimits, WebGLQueryId, WebGLSamplerId}; use canvas_traits::webgl::{WebGLBufferId, WebGLChan, WebGLContextId, WebGLError}; use canvas_traits::webgl::{WebGLFramebufferId, WebGLMsgSender, WebGLPipeline, WebGLProgramId}; -use canvas_traits::webgl::{WebGLOpaqueFramebufferId, WebGLTransparentFramebufferId}; use canvas_traits::webgl::{WebGLReceiver, WebGLRenderbufferId, WebGLSLVersion, WebGLSender}; use canvas_traits::webgl::{WebGLShaderId, WebGLSyncId, WebGLTextureId, WebGLVersion}; use content_security_policy::CspList; @@ -172,7 +171,6 @@ use webgpu::{ WebGPUTexture, WebGPUTextureView, }; use webrender_api::{DocumentId, ExternalImageId, ImageKey}; -use webxr_api::SwapChainId as WebXRSwapChainId; use webxr_api::{Finger, Hand, Ray, View}; unsafe_no_jsmanaged_fields!(Tm); @@ -550,8 +548,6 @@ unsafe_no_jsmanaged_fields!(ExternalImageId); unsafe_no_jsmanaged_fields!(WebGLBufferId); unsafe_no_jsmanaged_fields!(WebGLChan); unsafe_no_jsmanaged_fields!(WebGLFramebufferId); -unsafe_no_jsmanaged_fields!(WebGLOpaqueFramebufferId); -unsafe_no_jsmanaged_fields!(WebGLTransparentFramebufferId); unsafe_no_jsmanaged_fields!(WebGLMsgSender); unsafe_no_jsmanaged_fields!(WebGLPipeline); unsafe_no_jsmanaged_fields!(WebGLProgramId); @@ -587,12 +583,12 @@ unsafe_no_jsmanaged_fields!(Option); unsafe_no_jsmanaged_fields!(GPUBufferState); unsafe_no_jsmanaged_fields!(GPUCommandEncoderState); unsafe_no_jsmanaged_fields!(Range); -unsafe_no_jsmanaged_fields!(WebXRSwapChainId); unsafe_no_jsmanaged_fields!(MediaList); unsafe_no_jsmanaged_fields!( webxr_api::Registry, webxr_api::Session, webxr_api::Frame, + webxr_api::LayerId, webxr_api::InputSource, webxr_api::InputId, webxr_api::Joint, diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs index ce3204d37971..09b802b20e5b 100644 --- a/components/script/dom/document.rs +++ b/components/script/dom/document.rs @@ -106,7 +106,7 @@ use crate::stylesheet_set::StylesheetSetRef; use crate::task::TaskBox; use crate::task_source::{TaskSource, TaskSourceName}; use crate::timers::OneshotTimerCallback; -use canvas_traits::webgl::{self, SwapChainId, WebGLContextId, WebGLMsg}; +use canvas_traits::webgl::{self, WebGLContextId, WebGLMsg}; use content_security_policy::{self as csp, CspList}; use cookie::Cookie; use devtools_traits::ScriptToDevtoolsControlMsg; @@ -2707,7 +2707,7 @@ impl Document { .borrow_mut() .drain() .filter(|(_, context)| context.onscreen()) - .map(|(id, _)| SwapChainId::Context(id)) + .map(|(id, _)| id) .collect(); if dirty_context_ids.is_empty() { diff --git a/components/script/dom/webglframebuffer.rs b/components/script/dom/webglframebuffer.rs index 9f38365c4c75..a0d8025a131c 100644 --- a/components/script/dom/webglframebuffer.rs +++ b/components/script/dom/webglframebuffer.rs @@ -14,14 +14,13 @@ use crate::dom::webglrenderbuffer::WebGLRenderbuffer; use crate::dom::webglrenderingcontext::{Operation, WebGLRenderingContext}; use crate::dom::webgltexture::WebGLTexture; use crate::dom::xrsession::XRSession; +use canvas_traits::webgl::WebGLFramebufferId; use canvas_traits::webgl::{webgl_channel, WebGLError, WebGLResult, WebGLVersion}; use canvas_traits::webgl::{WebGLCommand, WebGLFramebufferBindingRequest}; -use canvas_traits::webgl::{WebGLFramebufferId, WebGLOpaqueFramebufferId}; use canvas_traits::webgl::{WebGLRenderbufferId, WebGLTextureId}; use dom_struct::dom_struct; use euclid::Size2D; use std::cell::Cell; -use webxr_api::SwapChainId as WebXRSwapChainId; use webxr_api::Viewport; pub enum CompleteForRendering { @@ -134,7 +133,7 @@ impl WebGLFramebuffer { let (sender, receiver) = webgl_channel().unwrap(); context.send_command(WebGLCommand::CreateFramebuffer(sender)); let id = receiver.recv().unwrap()?; - let framebuffer = WebGLFramebuffer::new(context, WebGLFramebufferId::Transparent(id)); + let framebuffer = WebGLFramebuffer::new(context, id); Some(framebuffer) } @@ -144,25 +143,16 @@ impl WebGLFramebuffer { session: &XRSession, context: &XRWebGLRenderingContext, size: Size2D, - ) -> Option<(WebXRSwapChainId, DomRoot)> { - let (sender, receiver) = webgl_channel().unwrap(); + ) -> Option> { let context = match context { XRWebGLRenderingContext::WebGLRenderingContext(ref ctx) => DomRoot::from_ref(&**ctx), XRWebGLRenderingContext::WebGL2RenderingContext(ref ctx) => ctx.base_context(), }; - let _ = context.webgl_sender().send_create_webxr_swap_chain( - size.to_untyped(), - sender, - session.session_id(), - ); - let swap_chain_id = receiver.recv().unwrap()?; - let framebuffer_id = - WebGLFramebufferId::Opaque(WebGLOpaqueFramebufferId::WebXR(swap_chain_id)); - let framebuffer = WebGLFramebuffer::new(&*context, framebuffer_id); + let framebuffer = Self::maybe_new(&*context)?; framebuffer.size.set(Some((size.width, size.height))); framebuffer.status.set(constants::FRAMEBUFFER_COMPLETE); framebuffer.xr_session.set(Some(session)); - Some((swap_chain_id, framebuffer)) + Some(framebuffer) } pub fn new(context: &WebGLRenderingContext, id: WebGLFramebufferId) -> DomRoot { @@ -655,7 +645,57 @@ impl WebGLFramebuffer { // Opaque framebuffers cannot have their attachments changed // https://immersive-web.github.io/webxr/#opaque-framebuffer self.validate_transparent()?; + if let Some(texture) = texture { + // "If texture is not zero, then texture must either + // name an existing texture object with an target of + // textarget, or texture must name an existing cube + // map texture and textarget must be one of: + // TEXTURE_CUBE_MAP_POSITIVE_X, + // TEXTURE_CUBE_MAP_POSITIVE_Y, + // TEXTURE_CUBE_MAP_POSITIVE_Z, + // TEXTURE_CUBE_MAP_NEGATIVE_X, + // TEXTURE_CUBE_MAP_NEGATIVE_Y, or + // TEXTURE_CUBE_MAP_NEGATIVE_Z. Otherwise, + // INVALID_OPERATION is generated." + let is_cube = match textarget { + constants::TEXTURE_2D => false, + + constants::TEXTURE_CUBE_MAP_POSITIVE_X => true, + constants::TEXTURE_CUBE_MAP_POSITIVE_Y => true, + constants::TEXTURE_CUBE_MAP_POSITIVE_Z => true, + constants::TEXTURE_CUBE_MAP_NEGATIVE_X => true, + constants::TEXTURE_CUBE_MAP_NEGATIVE_Y => true, + constants::TEXTURE_CUBE_MAP_NEGATIVE_Z => true, + + _ => return Err(WebGLError::InvalidEnum), + }; + + match texture.target() { + Some(constants::TEXTURE_CUBE_MAP) if is_cube => {}, + Some(_) if !is_cube => {}, + _ => return Err(WebGLError::InvalidOperation), + } + + let context = self.upcast::().context(); + let max_tex_size = if is_cube { + context.limits().max_cube_map_tex_size + } else { + context.limits().max_tex_size + }; + if level < 0 || level as u32 > log2(max_tex_size) { + return Err(WebGLError::InvalidValue); + } + } + self.texture2d_even_if_opaque(attachment, textarget, texture, level) + } + pub fn texture2d_even_if_opaque( + &self, + attachment: u32, + textarget: u32, + texture: Option<&WebGLTexture>, + level: i32, + ) -> WebGLResult<()> { let binding = self .attachment_binding(attachment) .ok_or(WebGLError::InvalidEnum)?; @@ -664,46 +704,6 @@ impl WebGLFramebuffer { // Note, from the GLES 2.0.25 spec, page 113: // "If texture is zero, then textarget and level are ignored." Some(texture) => { - // "If texture is not zero, then texture must either - // name an existing texture object with an target of - // textarget, or texture must name an existing cube - // map texture and textarget must be one of: - // TEXTURE_CUBE_MAP_POSITIVE_X, - // TEXTURE_CUBE_MAP_POSITIVE_Y, - // TEXTURE_CUBE_MAP_POSITIVE_Z, - // TEXTURE_CUBE_MAP_NEGATIVE_X, - // TEXTURE_CUBE_MAP_NEGATIVE_Y, or - // TEXTURE_CUBE_MAP_NEGATIVE_Z. Otherwise, - // INVALID_OPERATION is generated." - let is_cube = match textarget { - constants::TEXTURE_2D => false, - - constants::TEXTURE_CUBE_MAP_POSITIVE_X => true, - constants::TEXTURE_CUBE_MAP_POSITIVE_Y => true, - constants::TEXTURE_CUBE_MAP_POSITIVE_Z => true, - constants::TEXTURE_CUBE_MAP_NEGATIVE_X => true, - constants::TEXTURE_CUBE_MAP_NEGATIVE_Y => true, - constants::TEXTURE_CUBE_MAP_NEGATIVE_Z => true, - - _ => return Err(WebGLError::InvalidEnum), - }; - - match texture.target() { - Some(constants::TEXTURE_CUBE_MAP) if is_cube => {}, - Some(_) if !is_cube => {}, - _ => return Err(WebGLError::InvalidOperation), - } - - let context = self.upcast::().context(); - let max_tex_size = if is_cube { - context.limits().max_cube_map_tex_size - } else { - context.limits().max_tex_size - }; - if level < 0 || level as u32 > log2(max_tex_size) { - return Err(WebGLError::InvalidValue); - } - *binding.borrow_mut() = Some(WebGLFramebufferAttachment::Texture { texture: Dom::from_ref(texture), level: level, diff --git a/components/script/dom/webglrenderingcontext.rs b/components/script/dom/webglrenderingcontext.rs index a3f78e64c914..b4efd86033bf 100644 --- a/components/script/dom/webglrenderingcontext.rs +++ b/components/script/dom/webglrenderingcontext.rs @@ -60,8 +60,8 @@ use canvas_traits::webgl::{ webgl_channel, AlphaTreatment, DOMToTextureCommand, GLContextAttributes, GLLimits, GlType, Parameter, SizedDataType, TexDataType, TexFormat, TexParameter, WebGLChan, WebGLCommand, WebGLCommandBacktrace, WebGLContextId, WebGLError, WebGLFramebufferBindingRequest, WebGLMsg, - WebGLMsgSender, WebGLOpaqueFramebufferId, WebGLProgramId, WebGLResult, WebGLSLVersion, - WebGLSendResult, WebGLSender, WebGLVersion, YAxisTreatment, + WebGLMsgSender, WebGLProgramId, WebGLResult, WebGLSLVersion, WebGLSendResult, WebGLSender, + WebGLVersion, YAxisTreatment, }; use dom_struct::dom_struct; use embedder_traits::EventLoopWaker; @@ -84,8 +84,6 @@ use std::cell::Cell; use std::cmp; use std::ptr::{self, NonNull}; use std::rc::Rc; -use webxr_api::SessionId; -use webxr_api::SwapChainId as WebXRSwapChainId; // From the GLES 2.0.25 spec, page 85: // @@ -406,10 +404,6 @@ impl WebGLRenderingContext { .send(command, capture_webgl_backtrace(self)); } - pub fn swap_buffers(&self, id: Option) { - let _ = self.webgl_sender.send_swap_buffers(id); - } - pub fn webgl_error(&self, err: WebGLError) { // TODO(emilio): Add useful debug messages to this warn!( @@ -5003,19 +4997,6 @@ impl WebGLMessageSender { self.wake_after_send(|| self.sender.send(msg, backtrace)) } - pub fn send_swap_buffers(&self, id: Option) -> WebGLSendResult { - self.wake_after_send(|| self.sender.send_swap_buffers(id)) - } - - pub fn send_create_webxr_swap_chain( - &self, - size: Size2D, - sender: WebGLSender>, - id: SessionId, - ) -> WebGLSendResult { - self.wake_after_send(|| self.sender.send_create_webxr_swap_chain(size, sender, id)) - } - pub fn send_resize( &self, size: Size2D, diff --git a/components/script/dom/webidls/XRLayer.webidl b/components/script/dom/webidls/XRLayer.webidl index eb967abf0917..d78e220b5f54 100644 --- a/components/script/dom/webidls/XRLayer.webidl +++ b/components/script/dom/webidls/XRLayer.webidl @@ -5,9 +5,6 @@ // https://immersive-web.github.io/layers/#xrlayertype [SecureContext, Exposed=Window, Pref="dom.webxr.layers.enabled"] interface XRLayer { - readonly attribute unsigned long pixelWidth; - readonly attribute unsigned long pixelHeight; - // attribute boolean blendTextureSourceAlpha; // attribute boolean chromaticAberrationCorrection; diff --git a/components/script/dom/webidls/XRWebGLLayer.webidl b/components/script/dom/webidls/XRWebGLLayer.webidl index 4d98e5067653..995f6b25bf25 100644 --- a/components/script/dom/webidls/XRWebGLLayer.webidl +++ b/components/script/dom/webidls/XRWebGLLayer.webidl @@ -12,7 +12,8 @@ dictionary XRWebGLLayerInit { boolean depth = true; boolean stencil = false; boolean alpha = true; - // double framebufferScaleFactor = 1.0; + boolean ignoreDepthValues = false; + double framebufferScaleFactor = 1.0; }; [SecureContext, Exposed=Window, Pref="dom.webxr.enabled"] diff --git a/components/script/dom/webidls/XRWebGLSubImage.webidl b/components/script/dom/webidls/XRWebGLSubImage.webidl index f25552d533e7..2682206cc0a9 100644 --- a/components/script/dom/webidls/XRWebGLSubImage.webidl +++ b/components/script/dom/webidls/XRWebGLSubImage.webidl @@ -5,7 +5,9 @@ // https://immersive-web.github.io/layers/#xrwebglsubimagetype [SecureContext, Exposed=Window, Pref="dom.webxr.layers.enabled"] interface XRWebGLSubImage : XRSubImage { - readonly attribute WebGLTexture colorTexture; - readonly attribute WebGLTexture? depthStencilTexture; + [SameObject] readonly attribute WebGLTexture colorTexture; + [SameObject] readonly attribute WebGLTexture? depthStencilTexture; readonly attribute unsigned long? imageIndex; + readonly attribute unsigned long textureWidth; + readonly attribute unsigned long textureHeight; }; diff --git a/components/script/dom/xrframe.rs b/components/script/dom/xrframe.rs index 2381d4864d90..914d96333b51 100644 --- a/components/script/dom/xrframe.rs +++ b/components/script/dom/xrframe.rs @@ -20,6 +20,8 @@ use crate::dom::xrviewerpose::XRViewerPose; use dom_struct::dom_struct; use std::cell::Cell; use webxr_api::Frame; +use webxr_api::LayerId; +use webxr_api::SubImages; #[dom_struct] pub struct XRFrame { @@ -59,6 +61,14 @@ impl XRFrame { pub fn get_pose(&self, space: &XRSpace) -> Option { space.get_pose(&self.data) } + + pub fn get_sub_images(&self, layer_id: LayerId) -> Option<&SubImages> { + self.data + .sub_images + .iter() + .filter(|sub_images| sub_images.layer_id == layer_id) + .next() + } } impl XRFrameMethods for XRFrame { diff --git a/components/script/dom/xrlayer.rs b/components/script/dom/xrlayer.rs index e70cdb5085a8..b55df545e37e 100644 --- a/components/script/dom/xrlayer.rs +++ b/components/script/dom/xrlayer.rs @@ -6,30 +6,22 @@ use crate::dom::bindings::codegen::Bindings::XRLayerBinding::XRLayerBinding::XRL use crate::dom::bindings::reflector::Reflector; use crate::dom::bindings::root::Dom; use crate::dom::webglrenderingcontext::WebGLRenderingContext; +use crate::dom::xrframe::XRFrame; use crate::dom::xrsession::XRSession; +use canvas_traits::webgl::WebGLContextId; use dom_struct::dom_struct; -use euclid::Size2D; -use webxr_api::Viewport; +use webxr_api::LayerId; #[dom_struct] pub struct XRLayer { reflector: Reflector, session: Dom, context: Dom, - size: Size2D, + #[ignore_malloc_size_of = "Layers don't heap-allocate"] + layer_id: LayerId, } impl XRLayerMethods for XRLayer { - /// https://immersive-web.github.io/layers/#dom-xrlayer-pixelwidth - fn PixelWidth(&self) -> u32 { - self.size.width - } - - /// https://immersive-web.github.io/layers/#dom-xrlayer-pixelheight - fn PixelHeight(&self) -> u32 { - self.size.height - } - /// https://immersive-web.github.io/layers/#dom-xrlayer-destroy fn Destroy(&self) { // TODO: Implement this @@ -41,13 +33,31 @@ impl XRLayer { pub fn new_inherited( session: &XRSession, context: &WebGLRenderingContext, - size: Size2D, + layer_id: LayerId, ) -> XRLayer { XRLayer { reflector: Reflector::new(), session: Dom::from_ref(session), context: Dom::from_ref(context), - size: size, + layer_id, } } + + pub(crate) fn layer_id(&self) -> LayerId { + self.layer_id + } + + pub(crate) fn context_id(&self) -> WebGLContextId { + self.context.context_id() + } + + pub fn begin_frame(&self, _frame: &XRFrame) -> Option<()> { + // TODO: Implement this + None + } + + pub fn end_frame(&self, _frame: &XRFrame) -> Option<()> { + // TODO: Implement this + None + } } diff --git a/components/script/dom/xrrenderstate.rs b/components/script/dom/xrrenderstate.rs index d174af531d0f..10ab1ba661f7 100644 --- a/components/script/dom/xrrenderstate.rs +++ b/components/script/dom/xrrenderstate.rs @@ -11,9 +11,11 @@ use crate::dom::bindings::root::{Dom, DomRoot, MutNullableDom}; use crate::dom::globalscope::GlobalScope; use crate::dom::xrlayer::XRLayer; use crate::dom::xrwebgllayer::XRWebGLLayer; +use canvas_traits::webgl::WebGLContextId; use dom_struct::dom_struct; use std::cell::Cell; -use webxr_api::SwapChainId; +use webxr_api::LayerId; +use webxr_api::SubImages; #[dom_struct] pub struct XRRenderState { @@ -21,7 +23,7 @@ pub struct XRRenderState { depth_near: Cell, depth_far: Cell, inline_vertical_fov: Cell>, - layer: MutNullableDom, + base_layer: MutNullableDom, layers: DomRefCell>, } @@ -45,17 +47,26 @@ impl XRWebGLLayerOrXRLayer { } } - pub fn swap_chain_id(&self) -> Option { + pub(crate) fn layer_id(&self) -> Option { match self { - XRWebGLLayerOrXRLayer::XRWebGLLayer(layer) => Some(layer.swap_chain_id()), - XRWebGLLayerOrXRLayer::XRLayer(_) => None, + XRWebGLLayerOrXRLayer::XRWebGLLayer(ref layer) => layer.layer_id(), + XRWebGLLayerOrXRLayer::XRLayer(ref layer) => Some(layer.layer_id()), + } + } +} + +impl RootedXRWebGLLayerOrXRLayer { + pub(crate) fn layer_id(&self) -> Option { + match self { + RootedXRWebGLLayerOrXRLayer::XRWebGLLayer(ref layer) => layer.layer_id(), + RootedXRWebGLLayerOrXRLayer::XRLayer(ref layer) => Some(layer.layer_id()), } } - pub fn swap_buffers(&self) { + pub(crate) fn context_id(&self) -> WebGLContextId { match self { - XRWebGLLayerOrXRLayer::XRWebGLLayer(layer) => layer.swap_buffers(), - XRWebGLLayerOrXRLayer::XRLayer(_) => (), + RootedXRWebGLLayerOrXRLayer::XRWebGLLayer(ref layer) => layer.context_id(), + RootedXRWebGLLayerOrXRLayer::XRLayer(ref layer) => layer.context_id(), } } } @@ -74,7 +85,7 @@ impl XRRenderState { depth_near: Cell::new(depth_near), depth_far: Cell::new(depth_far), inline_vertical_fov: Cell::new(inline_vertical_fov), - layer: MutNullableDom::new(layer), + base_layer: MutNullableDom::new(layer), layers: DomRefCell::new(layers.iter().cloned().collect()), } } @@ -106,7 +117,7 @@ impl XRRenderState { self.depth_near.get(), self.depth_far.get(), self.inline_vertical_fov.get(), - self.layer.get().as_ref().map(|x| &**x), + self.base_layer.get().as_ref().map(|x| &**x), &layers, ) } @@ -121,8 +132,8 @@ impl XRRenderState { debug_assert!(self.inline_vertical_fov.get().is_some()); self.inline_vertical_fov.set(Some(fov)) } - pub fn set_layer(&self, layer: Option<&XRWebGLLayer>) { - self.layer.set(layer) + pub fn set_base_layer(&self, layer: Option<&XRWebGLLayer>) { + self.base_layer.set(layer) } pub fn set_layers(&self, layers: &[RootedXRWebGLLayerOrXRLayer]) { *self.layers.borrow_mut() = layers.iter().map(XRWebGLLayerOrXRLayer::from_ref).collect(); @@ -134,8 +145,25 @@ impl XRRenderState { let layers = self.layers.borrow(); f(&*layers) } - pub fn has_layer(&self) -> bool { - self.layer.get().is_some() || !self.layers.borrow().is_empty() + pub fn has_sub_images(&self, sub_images: &[SubImages]) -> bool { + if let Some(base_layer) = self.base_layer.get() { + match sub_images.len() { + // For inline sessions, there may be a base layer, but it won't have a framebuffer + 0 => base_layer.layer_id() == None, + // For immersive sessions, the base layer will have a framebuffer, + // so we make sure the layer id's match up + 1 => base_layer.layer_id() == Some(sub_images[0].layer_id), + _ => false, + } + } else { + // The layers API is only for immersive sessions + let layers = self.layers.borrow(); + sub_images.len() == layers.len() && + sub_images + .iter() + .zip(layers.iter()) + .all(|(sub_image, layer)| Some(sub_image.layer_id) == layer.layer_id()) + } } } @@ -157,6 +185,6 @@ impl XRRenderStateMethods for XRRenderState { /// https://immersive-web.github.io/webxr/#dom-xrrenderstate-baselayer fn GetBaseLayer(&self) -> Option> { - self.layer.get() + self.base_layer.get() } } diff --git a/components/script/dom/xrsession.rs b/components/script/dom/xrsession.rs index ee7a865d280c..c9f7b108a943 100644 --- a/components/script/dom/xrsession.rs +++ b/components/script/dom/xrsession.rs @@ -35,6 +35,7 @@ use crate::dom::xrinputsourcearray::XRInputSourceArray; use crate::dom::xrinputsourceevent::XRInputSourceEvent; use crate::dom::xrreferencespace::XRReferenceSpace; use crate::dom::xrrenderstate::XRRenderState; +use crate::dom::xrrenderstate::XRWebGLLayerOrXRLayer; use crate::dom::xrsessionevent::XRSessionEvent; use crate::dom::xrspace::XRSpace; use crate::realms::InRealm; @@ -50,6 +51,7 @@ use std::collections::HashMap; use std::f64::consts::{FRAC_PI_2, PI}; use std::mem; use std::rc::Rc; +use webxr_api::ContextId as WebXRContextId; use webxr_api::{ self, util, ApiSpace, Display, EntityTypes, EnvironmentBlendMode, Event as XREvent, Frame, FrameUpdateEvent, HitTestId, HitTestSource, Ray, SelectEvent, SelectKind, Session, SessionId, @@ -354,7 +356,7 @@ impl XRSession { /// https://immersive-web.github.io/webxr/#xr-animation-frame fn raf_callback(&self, mut frame: Frame) { - debug!("WebXR RAF callback"); + debug!("WebXR RAF callback {:?}", frame); #[cfg(feature = "xr-profile")] let raf_start = time::precise_time_ns(); #[cfg(feature = "xr-profile")] @@ -363,7 +365,9 @@ impl XRSession { (raf_start - frame.sent_time) as f64 / 1_000_000. ); - // Step 1 + // Step 1-2 happen in the xebxr device thread + + // Step 3 if let Some(pending) = self.pending_render_state.take() { // https://immersive-web.github.io/webxr/#apply-the-pending-render-state // (Steps 1-4 are implicit) @@ -371,33 +375,38 @@ impl XRSession { self.active_render_state.set(&pending); // Step 6-7: XXXManishearth handle inlineVerticalFieldOfView - if self.is_immersive() { - let swap_chain_id = pending - .GetBaseLayer() - .map(|layer| layer.swap_chain_id()) - .or_else(|| { - self.active_render_state.get().with_layers(|layers| { - layers.get(0).and_then(|layer| layer.swap_chain_id()) - }) - }); - self.session.borrow_mut().set_swap_chain(swap_chain_id); - } else { + if !self.is_immersive() { self.update_inline_projection_matrix() } } + // TODO: how does this fit the webxr spec? for event in frame.events.drain(..) { - self.handle_frame_update(event); + self.handle_frame_event(event); } - // Step 2 - if !self.active_render_state.get().has_layer() { + // Step 4 + // TODO: what should this check be? + // This is checking that the new render state has the same + // layers as the frame. + // Related to https://github.com/immersive-web/webxr/issues/1051 + if !self + .active_render_state + .get() + .has_sub_images(&frame.sub_images[..]) + { + // If the frame has different layers than the render state, + // we just return early, drawing a blank frame. + // This can result in flickering when the render state is changed. + // TODO: it would be better to not render anything until the next frame. + warn!("Rendering blank XR frame"); + self.session.borrow_mut().render_animation_frame(); return; } - // Step 3: XXXManishearth handle inline session + // Step 5: XXXManishearth handle inline session - // Step 4-5 + // Step 6-7 { let mut current = self.current_raf_callback_list.borrow_mut(); assert!(current.is_empty()); @@ -407,11 +416,17 @@ impl XRSession { let time = reduce_timing_resolution((frame.time_ns - start).to_ms()); let frame = XRFrame::new(&self.global(), self, frame); - // Step 6,7 + // Step 8-9 frame.set_active(true); frame.set_animation_frame(true); - // Step 8 + // Step 10 + self.apply_frame_updates(&*frame); + + // TODO: how does this fit with the webxr and xr layers specs? + self.layers_begin_frame(&*frame); + + // Step 11-12 self.outside_raf.set(false); let len = self.current_raf_callback_list.borrow().len(); for i in 0..len { @@ -426,21 +441,14 @@ impl XRSession { self.outside_raf.set(true); *self.current_raf_callback_list.borrow_mut() = vec![]; + // TODO: how does this fit with the webxr and xr layers specs? + self.layers_end_frame(&*frame); + + // Step 13 frame.set_active(false); - if self.is_immersive() { - if let Some(base_layer) = self.active_render_state.get().GetBaseLayer() { - base_layer.swap_buffers(); - } else { - self.active_render_state.get().with_layers(|layers| { - for layer in layers { - layer.swap_buffers(); - } - }); - } - self.session.borrow_mut().render_animation_frame(); - } else { - self.session.borrow_mut().start_render_loop(); - } + + // TODO: how does this fit the webxr spec? + self.session.borrow_mut().render_animation_frame(); #[cfg(feature = "xr-profile")] println!( @@ -498,7 +506,50 @@ impl XRSession { } } - fn handle_frame_update(&self, event: FrameUpdateEvent) { + // TODO: how does this align with the layers spec? + fn layers_begin_frame(&self, frame: &XRFrame) { + if let Some(layer) = self.active_render_state.get().GetBaseLayer() { + layer.begin_frame(frame); + } + self.active_render_state.get().with_layers(|layers| { + for layer in layers { + match layer { + XRWebGLLayerOrXRLayer::XRWebGLLayer(layer) => { + layer.begin_frame(frame); + }, + XRWebGLLayerOrXRLayer::XRLayer(layer) => { + layer.begin_frame(frame); + }, + } + } + }); + } + + // TODO: how does this align with the layers spec? + fn layers_end_frame(&self, frame: &XRFrame) { + if let Some(layer) = self.active_render_state.get().GetBaseLayer() { + layer.end_frame(frame); + } + self.active_render_state.get().with_layers(|layers| { + for layer in layers { + match layer { + XRWebGLLayerOrXRLayer::XRWebGLLayer(layer) => { + layer.end_frame(frame); + }, + XRWebGLLayerOrXRLayer::XRLayer(layer) => { + layer.end_frame(frame); + }, + } + } + }); + } + + /// https://immersive-web.github.io/webxr/#xrframe-apply-frame-updates + fn apply_frame_updates(&self, _frame: &XRFrame) { + // TODO: add a comment about why this is empty right now! + } + + fn handle_frame_event(&self, event: FrameUpdateEvent) { match event { FrameUpdateEvent::HitTestSourceAdded(id) => { if let Some(promise) = self.pending_hit_test_promises.borrow_mut().remove(&id) { @@ -624,8 +675,16 @@ impl XRSessionMethods for XRSession { pending.set_inline_vertical_fov(fov); } if let Some(ref layer) = init.baseLayer { - pending.set_layer(Some(&layer)); + pending.set_base_layer(Some(&layer)); pending.set_layers(&[]); + let layers = std::iter::once(layer) + .filter_map(|layer| { + let context_id = WebXRContextId::from(layer.context_id()); + let layer_id = layer.layer_id()?; + Some((context_id, layer_id)) + }) + .collect(); + self.session.borrow_mut().set_layers(layers); } if init.depthFar.is_some() || init.depthNear.is_some() { @@ -637,8 +696,17 @@ impl XRSessionMethods for XRSession { // TODO: add spec link for this step once XR layers has settled down // https://immersive-web.github.io/layers/ if let Some(ref layers) = init.layers { - pending.set_layer(None); + pending.set_base_layer(None); pending.set_layers(layers); + let layers = layers + .iter() + .filter_map(|layer| { + let context_id = WebXRContextId::from(layer.context_id()); + let layer_id = layer.layer_id()?; + Some((context_id, layer_id)) + }) + .collect(); + self.session.borrow_mut().set_layers(layers); } Ok(()) diff --git a/components/script/dom/xrwebglbinding.rs b/components/script/dom/xrwebglbinding.rs index 27435aa3ddc3..4f5efaa3cf78 100644 --- a/components/script/dom/xrwebglbinding.rs +++ b/components/script/dom/xrwebglbinding.rs @@ -16,6 +16,7 @@ use crate::dom::xrlayer::XRLayer; use crate::dom::xrsession::XRSession; use crate::dom::xrview::XRView; use crate::dom::xrwebglsubimage::XRWebGLSubImage; +use canvas_traits::webgl::WebGLContextId; use dom_struct::dom_struct; #[dom_struct] @@ -53,6 +54,19 @@ impl WebGLRenderingContextOrWebGL2RenderingContext { } } +impl RootedWebGLRenderingContextOrWebGL2RenderingContext { + pub(crate) fn context_id(&self) -> WebGLContextId { + match self { + RootedWebGLRenderingContextOrWebGL2RenderingContext::WebGLRenderingContext( + ref context, + ) => context.context_id(), + RootedWebGLRenderingContextOrWebGL2RenderingContext::WebGL2RenderingContext( + ref context, + ) => context.base_context().context_id(), + } + } +} + impl XRWebGLBindingMethods for XRWebGLBinding { /// https://immersive-web.github.io/layers/#dom-xrwebglbinding-getsubimage fn GetSubImage(&self, _layer: &XRLayer, _frame: &XRFrame) -> Option> { diff --git a/components/script/dom/xrwebgllayer.rs b/components/script/dom/xrwebgllayer.rs index f93c4c22bc2f..c4dd59996365 100644 --- a/components/script/dom/xrwebgllayer.rs +++ b/components/script/dom/xrwebgllayer.rs @@ -2,6 +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::inheritance::Castable; +use crate::dom::bindings::codegen::Bindings::WebGL2RenderingContextBinding::WebGL2RenderingContextConstants as constants; use crate::dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::WebGLRenderingContextMethods; use crate::dom::bindings::codegen::Bindings::WebGL2RenderingContextBinding::WebGL2RenderingContextBinding::WebGL2RenderingContextMethods; use crate::dom::bindings::codegen::Bindings::XRWebGLLayerBinding::XRWebGLLayerInit; @@ -13,17 +15,24 @@ 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::webglframebuffer::WebGLFramebuffer; +use crate::dom::webglobject::WebGLObject; +use crate::dom::webgltexture::WebGLTexture; use crate::dom::webglrenderingcontext::WebGLRenderingContext; use crate::dom::webgl2renderingcontext::WebGL2RenderingContext; use crate::dom::window::Window; +use crate::dom::xrframe::XRFrame; use crate::dom::xrsession::XRSession; use crate::dom::xrview::XRView; use crate::dom::xrviewport::XRViewport; -use canvas_traits::webgl::WebGLFramebufferId; +use canvas_traits::webgl::WebGLContextId; +use canvas_traits::webgl::WebGLCommand; +use canvas_traits::webgl::WebGLTextureId; use dom_struct::dom_struct; use euclid::{Rect, Size2D}; use std::convert::TryInto; -use webxr_api::SwapChainId as WebXRSwapChainId; +use webxr_api::ContextId as WebXRContextId; +use webxr_api::LayerId; +use webxr_api::LayerInit; use webxr_api::Viewport; #[derive(JSTraceable, MallocSizeOf)] @@ -33,6 +42,28 @@ pub enum RenderingContext { WebGL2(Dom), } +impl RenderingContext { + fn context_id(&self) -> WebGLContextId { + match self { + RenderingContext::WebGL1(ref ctx) => ctx.context_id(), + RenderingContext::WebGL2(ref ctx) => ctx.base_context().context_id(), + } + } +} + +impl<'a> From<&'a XRWebGLLayerInit> for LayerInit { + fn from(init: &'a XRWebGLLayerInit) -> LayerInit { + LayerInit::WebGLLayer { + alpha: init.alpha, + antialias: init.antialias, + depth: init.depth, + stencil: init.stencil, + framebuffer_scale_factor: *init.framebufferScaleFactor as f32, + ignore_depth_values: init.ignoreDepthValues, + } + } +} + #[dom_struct] pub struct XRWebGLLayer { reflector_: Reflector, @@ -40,21 +71,22 @@ pub struct XRWebGLLayer { depth: bool, stencil: bool, alpha: bool, - #[ignore_malloc_size_of = "ids don't malloc"] - swap_chain_id: Option, context: RenderingContext, session: Dom, /// If none, this is an inline session (the composition disabled flag is true) framebuffer: Option>, + /// If none, this is an inline session (the composition disabled flag is true) + #[ignore_malloc_size_of = "Layer ids don't heap-allocate"] + layer_id: Option, } impl XRWebGLLayer { pub fn new_inherited( - swap_chain_id: Option, session: &XRSession, context: XRWebGLRenderingContext, init: &XRWebGLLayerInit, framebuffer: Option<&WebGLFramebuffer>, + layer_id: Option, ) -> XRWebGLLayer { XRWebGLLayer { reflector_: Reflector::new(), @@ -62,7 +94,7 @@ impl XRWebGLLayer { depth: init.depth, stencil: init.stencil, alpha: init.alpha, - swap_chain_id, + layer_id, context: match context { XRWebGLRenderingContext::WebGLRenderingContext(ctx) => { RenderingContext::WebGL1(Dom::from_ref(&*ctx)) @@ -78,19 +110,19 @@ impl XRWebGLLayer { pub fn new( global: &GlobalScope, - swap_chain_id: Option, session: &XRSession, context: XRWebGLRenderingContext, init: &XRWebGLLayerInit, framebuffer: Option<&WebGLFramebuffer>, + layer_id: Option, ) -> DomRoot { reflect_dom_object( Box::new(XRWebGLLayer::new_inherited( - swap_chain_id, session, context, init, framebuffer, + layer_id, )), global, ) @@ -104,7 +136,6 @@ impl XRWebGLLayer { context: XRWebGLRenderingContext, init: &XRWebGLLayerInit, ) -> Fallible> { - let framebuffer; // Step 2 if session.is_ended() { return Err(Error::InvalidState); @@ -112,27 +143,29 @@ impl XRWebGLLayer { // XXXManishearth step 3: throw error if context is lost // XXXManishearth step 4: check XR compat flag for immersive sessions - // Step 9.2. "Initialize layer’s framebuffer to a new opaque framebuffer created with context." - let (swap_chain_id, framebuffer) = if session.is_immersive() { - let size = session.with_session(|session| { - session - .recommended_framebuffer_resolution() - .expect("immersive session must have viewports") - }); - let (swap_chain_id, fb) = WebGLFramebuffer::maybe_new_webxr(session, &context, size) + let (framebuffer, layer_id) = if session.is_immersive() { + // Step 9.2. "Initialize layer’s framebuffer to a new opaque framebuffer created with context." + let size = session + .with_session(|session| session.recommended_framebuffer_resolution()) .ok_or(Error::Operation)?; - framebuffer = fb; - (Some(swap_chain_id), Some(&*framebuffer)) + let framebuffer = WebGLFramebuffer::maybe_new_webxr(session, &context, size) + .ok_or(Error::Operation)?; + + // Step 9.3. "Allocate and initialize resources compatible with session’s XR device, + // including GPU accessible memory buffers, as required to support the compositing of layer." + let context_id = WebXRContextId::from(context.context_id()); + let layer_init = LayerInit::from(init); + let layer_id = session + .with_session(|session| session.create_layer(context_id, layer_init)) + .map_err(|_| Error::Operation)?; + + // Step 9.4: "If layer’s resources were unable to be created for any reason, + // throw an OperationError and abort these steps." + (Some(framebuffer), Some(layer_id)) } else { (None, None) }; - // Step 9.3. "Allocate and initialize resources compatible with session’s XR device, - // including GPU accessible memory buffers, as required to support the compositing of layer." - - // Step 9.4: "If layer’s resources were unable to be created for any reason, - // throw an OperationError and abort these steps." - // Ensure that we finish setting up this layer before continuing. match context { XRWebGLRenderingContext::WebGLRenderingContext(ref ctx) => ctx.Finish(), @@ -142,35 +175,24 @@ impl XRWebGLLayer { // Step 10. "Return layer." Ok(XRWebGLLayer::new( &global.global(), - swap_chain_id, session, context, init, - framebuffer, + framebuffer.as_deref(), + layer_id, )) } - pub fn swap_chain_id(&self) -> WebXRSwapChainId { - self.swap_chain_id - .expect("swap_chain_id must not be called for inline sessions") + pub fn layer_id(&self) -> Option { + self.layer_id } - pub fn session(&self) -> &XRSession { - &self.session + pub fn context_id(&self) -> WebGLContextId { + self.context.context_id() } - pub fn swap_buffers(&self) { - if let WebGLFramebufferId::Opaque(id) = self - .framebuffer - .as_ref() - .expect("swap_buffers must not be called for inline sessions") - .id() - { - match self.context { - RenderingContext::WebGL1(ref ctx) => ctx.swap_buffers(Some(id)), - RenderingContext::WebGL2(ref ctx) => ctx.base_context().swap_buffers(Some(id)), - } - } + pub fn session(&self) -> &XRSession { + &self.session } pub fn size(&self) -> Size2D { @@ -188,6 +210,52 @@ impl XRWebGLLayer { Size2D::from_untyped(size) } } + + fn texture_target(&self) -> u32 { + if cfg!(target_os = "macos") { + sparkle::gl::TEXTURE_RECTANGLE + } else { + sparkle::gl::TEXTURE_2D + } + } + + pub fn begin_frame(&self, frame: &XRFrame) -> Option<()> { + debug!("XRWebGLLayer begin frame"); + let framebuffer = self.framebuffer.as_ref()?; + let context = framebuffer.upcast::().context(); + let sub_images = frame.get_sub_images(self.layer_id?)?; + // TODO: Cache this texture + let color_texture_id = + WebGLTextureId::maybe_new(sub_images.sub_image.as_ref()?.color_texture)?; + let color_texture = WebGLTexture::new(context, color_texture_id); + let target = self.texture_target(); + // TODO: rebind the current bindings + context.send_command(WebGLCommand::BindTexture(target, Some(color_texture_id))); + framebuffer.bind(constants::FRAMEBUFFER); + framebuffer + .texture2d_even_if_opaque( + constants::COLOR_ATTACHMENT0, + self.texture_target(), + Some(&color_texture), + 0, + ) + .ok()?; + // TODO: depth/stencil + Some(()) + } + + pub fn end_frame(&self, _frame: &XRFrame) -> Option<()> { + debug!("XRWebGLLayer end frame"); + // TODO: invalidate the old texture + let framebuffer = self.framebuffer.as_ref()?; + // TODO: rebind the current bindings + framebuffer.bind(constants::FRAMEBUFFER); + framebuffer + .texture2d_even_if_opaque(constants::COLOR_ATTACHMENT0, self.texture_target(), None, 0) + .ok()?; + framebuffer.upcast::().context().Flush(); + Some(()) + } } impl XRWebGLLayerMethods for XRWebGLLayer { diff --git a/components/script/dom/xrwebglsubimage.rs b/components/script/dom/xrwebglsubimage.rs index 0331d36c4c28..0813bd85d9e0 100644 --- a/components/script/dom/xrwebglsubimage.rs +++ b/components/script/dom/xrwebglsubimage.rs @@ -8,6 +8,8 @@ use crate::dom::bindings::root::DomRoot; use crate::dom::webgltexture::WebGLTexture; use crate::dom::xrsubimage::XRSubImage; use dom_struct::dom_struct; +use euclid::Size2D; +use webxr_api::Viewport; #[dom_struct] pub struct XRWebGLSubImage { @@ -15,6 +17,7 @@ pub struct XRWebGLSubImage { color_texture: Dom, depth_stencil_texture: Option>, image_index: Option, + size: Size2D, } impl XRWebGLSubImageMethods for XRWebGLSubImage { @@ -32,4 +35,14 @@ impl XRWebGLSubImageMethods for XRWebGLSubImage { fn GetImageIndex(&self) -> Option { self.image_index } + + /// https://immersive-web.github.io/layers/#dom-xrwebglsubimage-texturewidth + fn TextureWidth(&self) -> u32 { + self.size.width + } + + /// https://immersive-web.github.io/layers/#dom-xrwebglsubimage-textureheight + fn TextureHeight(&self) -> u32 { + self.size.height + } } diff --git a/components/servo/Cargo.toml b/components/servo/Cargo.toml index 2b52339e6281..87c5e713f60c 100644 --- a/components/servo/Cargo.toml +++ b/components/servo/Cargo.toml @@ -79,7 +79,7 @@ servo_url = { path = "../url" } sparkle = "0.1" style = { path = "../style", features = ["servo"] } style_traits = { path = "../style_traits", features = ["servo"] } -surfman = "0.2" +surfman = "0.3" webdriver_server = { path = "../webdriver_server", optional = true } webgpu = { path = "../webgpu" } webrender = { git = "https://github.com/servo/webrender" } diff --git a/components/servo/lib.rs b/components/servo/lib.rs index e518d1aaa3d3..57dee7557dc9 100644 --- a/components/servo/lib.rs +++ b/components/servo/lib.rs @@ -65,7 +65,7 @@ fn webdriver(_port: u16, _constellation: Sender) {} use bluetooth::BluetoothThreadFactory; use bluetooth_traits::BluetoothRequest; use canvas::canvas_paint_thread::{self, CanvasPaintThread}; -use canvas::{SurfaceProviders, WebGLComm, WebGlExecutor}; +use canvas::WebGLComm; use canvas_traits::webgl::WebGLThreads; use compositing::compositor_thread::{ CompositorProxy, CompositorReceiver, InitialCompositorState, Msg, WebrenderCanvasMsg, @@ -118,12 +118,13 @@ use std::cmp::max; use std::collections::HashMap; use std::path::PathBuf; use std::rc::Rc; -use std::sync::{Arc, Mutex}; +use std::sync::Arc; +use std::sync::Mutex; use surfman::GLApi; use webrender::ShaderPrecacheFlags; -use webrender_surfman::WebrenderSurfman; +use webrender_traits::WebrenderExternalImageHandlers; +use webrender_traits::WebrenderExternalImageRegistry; use webrender_traits::WebrenderImageHandlerType; -use webrender_traits::{WebrenderExternalImageHandlers, WebrenderExternalImageRegistry}; pub use gleam::gl; pub use keyboard_types; @@ -446,32 +447,43 @@ where None }; + // Create the webgl thread + let gl_type = match webrender_gl.get_type() { + gleam::gl::GlType::Gl => sparkle::gl::GlType::Gl, + gleam::gl::GlType::Gles => sparkle::gl::GlType::Gles, + }; + let (external_image_handlers, external_images) = WebrenderExternalImageHandlers::new(); let mut external_image_handlers = Box::new(external_image_handlers); - let mut webxr_main_thread = webxr::MainThreadRegistry::new(event_loop_waker) - .expect("Failed to create WebXR device registry"); - - let (webgl_threads, webgl_extras) = create_webgl_threads( + let WebGLComm { + webgl_threads, + webxr_layer_grand_manager, + image_handler, + output_handler, + } = WebGLComm::new( webrender_surfman.clone(), webrender_gl.clone(), - &mut webrender, webrender_api.create_sender(), webrender_document, - &mut webxr_main_thread, - &mut external_image_handlers, external_images.clone(), + gl_type, ); + // Set webrender external image handler for WebGL textures + external_image_handlers.set_handler(image_handler, WebrenderImageHandlerType::WebGL); + + // Set DOM to texture handler, if enabled. + if let Some(output_handler) = output_handler { + webrender.set_output_image_handler(output_handler); + } + + // Create the WebXR main thread + let mut webxr_main_thread = + webxr::MainThreadRegistry::new(event_loop_waker, webxr_layer_grand_manager) + .expect("Failed to create WebXR device registry"); if pref!(dom.webxr.enabled) { - if let Some((webxr_surface_providers, webgl_executor)) = webgl_extras { - embedder.register_webxr( - &mut webxr_main_thread, - webgl_executor, - webxr_surface_providers, - embedder_proxy.clone(), - ); - } + embedder.register_webxr(&mut webxr_main_thread, embedder_proxy.clone()); } let glplayer_threads = match window.get_gl_context() { @@ -526,7 +538,7 @@ where webrender_api_sender, webxr_main_thread.registry(), player_context, - webgl_threads, + Some(webgl_threads), glplayer_threads, event_loop_waker, window_size, @@ -1095,58 +1107,6 @@ fn create_sandbox() { panic!("Sandboxing is not supported on Windows, iOS, ARM targets and android."); } -// Initializes the WebGL thread. -fn create_webgl_threads( - webrender_surfman: WebrenderSurfman, - webrender_gl: Rc, - webrender: &mut webrender::Renderer, - webrender_api_sender: webrender_api::RenderApiSender, - webrender_doc: webrender_api::DocumentId, - webxr_main_thread: &mut webxr::MainThreadRegistry, - external_image_handlers: &mut WebrenderExternalImageHandlers, - external_images: Arc>, -) -> ( - Option, - Option<(SurfaceProviders, WebGlExecutor)>, -) { - let gl_type = match webrender_gl.get_type() { - gleam::gl::GlType::Gl => sparkle::gl::GlType::Gl, - gleam::gl::GlType::Gles => sparkle::gl::GlType::Gles, - }; - - let WebGLComm { - webgl_threads, - webxr_swap_chains, - webxr_surface_providers, - image_handler, - output_handler, - webgl_executor, - } = WebGLComm::new( - webrender_surfman, - webrender_gl, - webrender_api_sender, - webrender_doc, - external_images, - gl_type, - ); - - // Set webrender external image handler for WebGL textures - external_image_handlers.set_handler(image_handler, WebrenderImageHandlerType::WebGL); - - // Set webxr external image handler for WebGL textures - webxr_main_thread.set_swap_chains(webxr_swap_chains); - - // Set DOM to texture handler, if enabled. - if let Some(output_handler) = output_handler { - webrender.set_output_image_handler(output_handler); - } - - ( - Some(webgl_threads), - Some((webxr_surface_providers, webgl_executor)), - ) -} - enum UserAgent { Desktop, Android, diff --git a/components/webrender_surfman/#Cargo.toml# b/components/webrender_surfman/#Cargo.toml# new file mode 100644 index 000000000000..8370ff4457d5 --- /dev/null +++ b/components/webrender_surfman/#Cargo.toml# @@ -0,0 +1,17 @@ +[package] +name = "webrender_surfman" +version = "0.0.1" +authors = ["The Servo Project Developers"] +license = "MPL-2.0" +edition = "2018" +publish = false + +[lib] +name = "webrender_surfman" +path = "lib.rs" + +[dependencies] +euclid = "0.20" +surfman = "0.3" +surfman-chains = "0.4i" + diff --git a/components/webrender_surfman/.#Cargo.toml b/components/webrender_surfman/.#Cargo.toml new file mode 120000 index 000000000000..0ab6459308ac --- /dev/null +++ b/components/webrender_surfman/.#Cargo.toml @@ -0,0 +1 @@ +ajeffrey@ajeffrey-home.4753:1592856534 \ No newline at end of file diff --git a/components/webrender_surfman/Cargo.toml b/components/webrender_surfman/Cargo.toml index e82f553d2cc2..82ae827cbb7e 100644 --- a/components/webrender_surfman/Cargo.toml +++ b/components/webrender_surfman/Cargo.toml @@ -12,6 +12,6 @@ path = "lib.rs" [dependencies] euclid = "0.20" -surfman = "0.2" -surfman-chains = "0.3" +surfman = "0.3" +surfman-chains = "0.4" diff --git a/components/webrender_surfman/lib.rs b/components/webrender_surfman/lib.rs index 193298808bc2..530ca0ebfc78 100644 --- a/components/webrender_surfman/lib.rs +++ b/components/webrender_surfman/lib.rs @@ -26,7 +26,6 @@ use surfman::SurfaceAccess; use surfman::SurfaceInfo; use surfman::SurfaceTexture; use surfman::SurfaceType; -use surfman_chains::SurfmanProvider; use surfman_chains::SwapChain; /// A bridge between webrender and surfman @@ -68,7 +67,7 @@ impl WebrenderSurfman { }; let context_attributes = ContextAttributes { flags, version }; let context_descriptor = device.create_context_descriptor(&context_attributes)?; - let mut context = device.create_context(&context_descriptor)?; + let mut context = device.create_context(&context_descriptor, None)?; let surface_access = SurfaceAccess::GPUOnly; let headless = match surface_type { SurfaceType::Widget { .. } => false, @@ -82,11 +81,10 @@ impl WebrenderSurfman { err })?; let swap_chain = if headless { - let surface_provider = Box::new(SurfmanProvider::new(surface_access)); Some(SwapChain::create_attached( &mut device, &mut context, - surface_provider, + surface_access, )?) } else { None diff --git a/ports/gstplugin/Cargo.toml b/ports/gstplugin/Cargo.toml index ad7dc426431f..dd45c6225a8b 100644 --- a/ports/gstplugin/Cargo.toml +++ b/ports/gstplugin/Cargo.toml @@ -29,8 +29,8 @@ libservo = { path = "../../components/servo" } log = "0.4" servo-media = { git = "https://github.com/servo/media" } sparkle = "0.1" -surfman = { git = "https://github.com/servo/surfman" } -surfman-chains = { git = "https://github.com/asajeffrey/surfman-chains" } +surfman = "0.3" +surfman-chains = "0.4" surfman-chains-api = "0.2" [build-dependencies] diff --git a/ports/libsimpleservo/api/Cargo.toml b/ports/libsimpleservo/api/Cargo.toml index 9fd37846f8ed..17e914f5468e 100644 --- a/ports/libsimpleservo/api/Cargo.toml +++ b/ports/libsimpleservo/api/Cargo.toml @@ -12,7 +12,7 @@ ipc-channel = "0.14" libservo = { path = "../../../components/servo" } log = "0.4" servo-media = { git = "https://github.com/servo/media" } -surfman = { version = "0.2", features = ["sm-angle-default"] } +surfman = { version = "0.3", features = ["sm-angle-default"] } webxr = { git = "https://github.com/servo/webxr"} webxr-api = { git = "https://github.com/servo/webxr", features = ["ipc"] } diff --git a/ports/libsimpleservo/api/src/lib.rs b/ports/libsimpleservo/api/src/lib.rs index cc2d84f9814d..e0d2f46e71af 100644 --- a/ports/libsimpleservo/api/src/lib.rs +++ b/ports/libsimpleservo/api/src/lib.rs @@ -15,7 +15,6 @@ pub use servo::script_traits::{MediaSessionActionType, MouseButton}; use getopts::Options; use ipc_channel::ipc::IpcSender; -use servo::canvas::{SurfaceProviders, WebGlExecutor}; use servo::compositing::windowing::{ AnimationState, EmbedderCoordinates, EmbedderMethods, MouseWindowEvent, WindowEvent, WindowMethods, @@ -794,8 +793,6 @@ impl EmbedderMethods for ServoEmbedderCallbacks { fn register_webxr( &mut self, registry: &mut webxr::MainThreadRegistry, - executor: WebGlExecutor, - surface_providers: SurfaceProviders, embedder_proxy: EmbedderProxy, ) { use ipc_channel::ipc::{self, IpcReceiver}; @@ -806,16 +803,6 @@ impl EmbedderMethods for ServoEmbedderCallbacks { "UWP builds should not be initialized with a WebXR Discovery object" ); - struct ProviderRegistration(SurfaceProviders); - impl openxr::SurfaceProviderRegistration for ProviderRegistration { - fn register(&self, id: webxr_api::SessionId, provider: servo::canvas::SurfaceProvider) { - self.0.lock().unwrap().insert(id, provider); - } - fn clone(&self) -> Box { - Box::new(ProviderRegistration(self.0.clone())) - } - } - #[derive(Clone)] struct ContextMenuCallback(EmbedderProxy); @@ -854,22 +841,9 @@ impl EmbedderMethods for ServoEmbedderCallbacks { } } - struct GlThread(WebGlExecutor); - impl openxr::GlThread for GlThread { - fn execute(&self, runnable: Box) { - let _ = self.0.send(runnable); - } - fn clone(&self) -> Box { - Box::new(GlThread(self.0.clone())) - } - } - if openxr::create_instance(false).is_ok() { - let discovery = openxr::OpenXrDiscovery::new( - Box::new(GlThread(executor)), - Box::new(ProviderRegistration(surface_providers)), - Box::new(ContextMenuCallback(embedder_proxy)), - ); + let discovery = + openxr::OpenXrDiscovery::new(Box::new(ContextMenuCallback(embedder_proxy))); registry.register(discovery); } else { let msg = @@ -891,8 +865,6 @@ impl EmbedderMethods for ServoEmbedderCallbacks { fn register_webxr( &mut self, registry: &mut webxr::MainThreadRegistry, - _executor: WebGlExecutor, - _surface_provider_registration: SurfaceProviders, _embedder_proxy: EmbedderProxy, ) { debug!("EmbedderMethods::register_xr"); diff --git a/ports/libsimpleservo/capi/Cargo.toml b/ports/libsimpleservo/capi/Cargo.toml index ff481da0672a..334a77f9198b 100644 --- a/ports/libsimpleservo/capi/Cargo.toml +++ b/ports/libsimpleservo/capi/Cargo.toml @@ -18,7 +18,7 @@ env_logger = "0.7" lazy_static = "1" log = "0.4" simpleservo = { path = "../api" } -surfman = "0.2" +surfman = "0.3" [target.'cfg(target_os = "windows")'.dependencies] libc = "0.2" diff --git a/ports/winit/Cargo.toml b/ports/winit/Cargo.toml index 5b6cc3b3c37a..1091cdc4b172 100644 --- a/ports/winit/Cargo.toml +++ b/ports/winit/Cargo.toml @@ -57,7 +57,7 @@ libservo = { path = "../../components/servo" } log = "0.4" servo-media = { git = "https://github.com/servo/media" } shellwords = "1.0.0" -surfman = { version = "0.2", features = ["sm-winit", "sm-x11"] } +surfman = { version = "0.3", features = ["sm-winit", "sm-x11"] } tinyfiledialogs = "3.0" webxr = { git = "https://github.com/servo/webxr", features = ["ipc", "glwindow", "headless"] } winit = "0.19" diff --git a/ports/winit/embedder.rs b/ports/winit/embedder.rs index e770911cff86..039f003da19c 100644 --- a/ports/winit/embedder.rs +++ b/ports/winit/embedder.rs @@ -5,7 +5,6 @@ //! Implements the global methods required by Servo (not window/gl/compositor related). use crate::events_loop::EventsLoop; -use servo::canvas::{SurfaceProviders, WebGlExecutor}; use servo::compositing::windowing::EmbedderMethods; use servo::embedder_traits::{EmbedderProxy, EventLoopWaker}; use servo::servo_config::pref; @@ -38,8 +37,6 @@ impl EmbedderMethods for EmbedderCallbacks { fn register_webxr( &mut self, xr: &mut webxr::MainThreadRegistry, - _executor: WebGlExecutor, - _surface_provider_registration: SurfaceProviders, _embedder_proxy: EmbedderProxy, ) { if pref!(dom.webxr.test) {