diff options
Diffstat (limited to 'components/canvas')
-rw-r--r-- | components/canvas/Cargo.toml | 2 | ||||
-rw-r--r-- | components/canvas/lib.rs | 3 | ||||
-rw-r--r-- | components/canvas/webgl_mode/inprocess.rs | 11 | ||||
-rw-r--r-- | components/canvas/webgl_thread.rs | 107 |
4 files changed, 67 insertions, 56 deletions
diff --git a/components/canvas/Cargo.toml b/components/canvas/Cargo.toml index ffb12a7a4ce..86cd3c4e440 100644 --- a/components/canvas/Cargo.toml +++ b/components/canvas/Cargo.toml @@ -42,5 +42,5 @@ webrender_traits = {path = "../webrender_traits"} webxr-api = {git = "https://github.com/servo/webxr", features = ["ipc"]} # NOTE: the sm-angle feature only enables angle on windows, not other platforms! surfman = { version = "0.1", features = ["sm-angle", "sm-osmesa"] } -surfman-chains = "0.2" +surfman-chains = "0.3" surfman-chains-api = "0.2" diff --git a/components/canvas/lib.rs b/components/canvas/lib.rs index 1e5872420bc..074a4a00bcb 100644 --- a/components/canvas/lib.rs +++ b/components/canvas/lib.rs @@ -12,6 +12,9 @@ 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 d84b27684d5..b46b1608101 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::{WebGLThread, WebGLThreadInit}; +use crate::webgl_thread::{SurfaceProviders, WebGLThread, WebGLThreadInit, WebGlExecutor}; use canvas_traits::webgl::{webgl_channel, WebVRRenderHandler}; use canvas_traits::webgl::{WebGLContextId, WebGLMsg, WebGLThreads}; use euclid::default::Size2D; @@ -11,6 +11,7 @@ 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}; @@ -27,8 +28,10 @@ use webxr_api::SwapChainId as WebXRSwapChainId; pub struct WebGLComm { pub webgl_threads: WebGLThreads, pub webxr_swap_chains: SwapChains<WebXRSwapChainId>, + pub webxr_surface_providers: SurfaceProviders, pub image_handler: Box<dyn WebrenderExternalImageApi>, pub output_handler: Option<Box<dyn webrender_api::OutputImageHandler>>, + pub webgl_executor: WebGlExecutor, } impl WebGLComm { @@ -46,6 +49,8 @@ impl WebGLComm { let (sender, receiver) = webgl_channel::<WebGLMsg>().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(); // This implementation creates a single `WebGLThread` for all the pipelines. let init = WebGLThreadInit { @@ -56,9 +61,11 @@ impl WebGLComm { receiver, webrender_swap_chains: webrender_swap_chains.clone(), webxr_swap_chains: webxr_swap_chains.clone(), + webxr_surface_providers: webxr_surface_providers.clone(), connection: device.connection(), adapter: device.adapter(), api_type, + runnable_receiver, }; let output_handler = if pref!(dom.webgl.dom_to_texture.enabled) { @@ -74,8 +81,10 @@ 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, } } } diff --git a/components/canvas/webgl_thread.rs b/components/canvas/webgl_thread.rs index 1658ebf94a5..f72e2c79bc1 100644 --- a/components/canvas/webgl_thread.rs +++ b/components/canvas/webgl_thread.rs @@ -54,7 +54,7 @@ use sparkle::gl::GLint; use sparkle::gl::GLuint; use sparkle::gl::Gl; use std::borrow::Cow; -use std::cell::{Cell, RefCell}; +use std::collections::HashMap; use std::rc::Rc; use std::slice; use std::sync::{Arc, Mutex}; @@ -70,9 +70,10 @@ use surfman::GLVersion; use surfman::SurfaceAccess; use surfman::SurfaceInfo; use surfman::SurfaceType; -use surfman_chains::SwapChains; +use surfman_chains::{SurfmanProvider, SwapChains}; use surfman_chains_api::SwapChainsAPI; use webrender_traits::{WebrenderExternalImageRegistry, WebrenderImageHandlerType}; +use webxr_api::SessionId; use webxr_api::SwapChainId as WebXRSwapChainId; #[cfg(feature = "xr-profile")] @@ -138,25 +139,29 @@ pub(crate) struct WebGLThread { /// We use it to get an unique ID for new WebGLContexts. external_images: Arc<Mutex<WebrenderExternalImageRegistry>>, /// The receiver that will be used for processing WebGL messages. - receiver: WebGLReceiver<WebGLMsg>, + receiver: crossbeam_channel::Receiver<WebGLMsg>, /// The receiver that should be used to send WebGL messages for processing. sender: WebGLSender<WebGLMsg>, /// The swap chains used by webrender webrender_swap_chains: SwapChains<WebGLContextId>, /// The swap chains used by webxr webxr_swap_chains: SwapChains<WebXRSwapChainId>, + /// 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<WebGlRunnable>, /// Whether this context is a GL or GLES context. api_type: gl::GlType, } -#[derive(PartialEq)] -enum EventLoop { - Blocking, - Nonblocking, -} +pub type WebGlExecutor = crossbeam_channel::Sender<WebGlRunnable>; +pub type WebGlRunnable = Box<dyn FnOnce() + Send>; +pub type SurfaceProviders = Arc<Mutex<HashMap<SessionId, SurfaceProvider>>>; +pub type SurfaceProvider = Box<dyn surfman_chains::SurfaceProvider + 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 webvr_compositor: Option<Box<dyn WebVRRenderHandler>>, pub external_images: Arc<Mutex<WebrenderExternalImageRegistry>>, @@ -167,37 +172,7 @@ pub(crate) struct WebGLThreadInit { pub connection: Connection, pub adapter: Adapter, pub api_type: gl::GlType, -} - -/// The extra data required to run an instance of WebGLThread when it is -/// not running in its own thread. -pub struct WebGLMainThread { - pub(crate) thread_data: RefCell<WebGLThread>, - shut_down: Cell<bool>, -} - -impl WebGLMainThread { - /// Synchronously process all outstanding WebGL messages. - pub fn process(&self) { - if self.shut_down.get() { - return; - } - - // Any context could be current when we start. - self.thread_data.borrow_mut().bound_context_id = None; - let result = self - .thread_data - .borrow_mut() - .process(EventLoop::Nonblocking); - if !result { - self.shut_down.set(true); - WEBGL_MAIN_THREAD.with(|thread_data| thread_data.borrow_mut().take()); - } - } -} - -thread_local! { - static WEBGL_MAIN_THREAD: RefCell<Option<Rc<WebGLMainThread>>> = RefCell::new(None); + pub runnable_receiver: crossbeam_channel::Receiver<WebGlRunnable>, } // A size at which it should be safe to create GL contexts @@ -214,9 +189,11 @@ impl WebGLThread { receiver, webrender_swap_chains, webxr_swap_chains, + webxr_surface_providers, connection, adapter, api_type, + runnable_receiver, }: WebGLThreadInit, ) -> Self { WebGLThread { @@ -229,9 +206,11 @@ impl WebGLThread { dom_outputs: Default::default(), external_images, sender, - receiver, + receiver: receiver.into_inner(), webrender_swap_chains, webxr_swap_chains, + webxr_surface_providers, + runnable_receiver, api_type, } } @@ -243,23 +222,35 @@ impl WebGLThread { .name("WebGL thread".to_owned()) .spawn(move || { let mut data = WebGLThread::new(init); - data.process(EventLoop::Blocking); + data.process(); }) .expect("Thread spawning failed"); } - fn process(&mut self, loop_type: EventLoop) -> bool { + fn process(&mut self) { let webgl_chan = WebGLChan(self.sender.clone()); - while let Ok(msg) = match loop_type { - EventLoop::Blocking => self.receiver.recv(), - EventLoop::Nonblocking => self.receiver.try_recv(), - } { - let exit = self.handle_msg(msg, &webgl_chan); - if exit { - return false; + loop { + crossbeam_channel::select! { + recv(self.receiver) -> msg => { + match msg { + Ok(msg) => { + let exit = self.handle_msg(msg, &webgl_chan); + if exit { + return; + } + } + _ => break, + } + } + recv(self.runnable_receiver) -> msg => { + if let Ok(msg) = msg { + msg(); + } else { + self.runnable_receiver = crossbeam_channel::never(); + } + } } } - true } /// Handles a generic WebGLMsg message @@ -331,8 +322,8 @@ impl WebGLThread { WebGLMsg::WebVRCommand(ctx_id, command) => { self.handle_webvr_command(ctx_id, command); }, - WebGLMsg::CreateWebXRSwapChain(ctx_id, size, sender) => { - let _ = sender.send(self.create_webxr_swap_chain(ctx_id, size)); + WebGLMsg::CreateWebXRSwapChain(ctx_id, size, sender, id) => { + let _ = sender.send(self.create_webxr_swap_chain(ctx_id, size, id)); }, WebGLMsg::SwapBuffers(swap_ids, sender, sent_time) => { self.handle_swap_buffers(swap_ids, sender, sent_time); @@ -443,6 +434,7 @@ 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 @@ -469,7 +461,7 @@ impl WebGLThread { ); self.webrender_swap_chains - .create_attached_swap_chain(id, &mut self.device, &mut ctx, surface_access) + .create_attached_swap_chain(id, &mut self.device, &mut ctx, surface_provider) .expect("Failed to create the swap chain"); let swap_chain = self @@ -765,6 +757,7 @@ impl WebGLThread { &mut self, context_id: WebGLContextId, size: Size2D<i32>, + session_id: SessionId, ) -> Option<WebXRSwapChainId> { debug!("WebGLThread::create_webxr_swap_chain()"); let id = WebXRSwapChainId::new(); @@ -775,8 +768,14 @@ impl WebGLThread { &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_access) + .create_detached_swap_chain(id, size, &mut self.device, &mut data.ctx, surface_provider) .ok()?; debug!("Created swap chain {:?}", id); Some(id) |