diff options
author | Alan Jeffrey <ajeffrey@mozilla.com> | 2019-07-26 16:52:23 -0500 |
---|---|---|
committer | Alan Jeffrey <ajeffrey@mozilla.com> | 2019-07-26 17:39:40 -0500 |
commit | 0178fcae4ec29824a3f1d35969457bed1ca104e9 (patch) | |
tree | 0e624cc98fbbfb9e70ed107e0f1a7391aa30e52f /components/canvas/webgl_mode | |
parent | 8ec28978cdc3e0fa66652a7a0a57911ca414254c (diff) | |
download | servo-0178fcae4ec29824a3f1d35969457bed1ca104e9.tar.gz servo-0178fcae4ec29824a3f1d35969457bed1ca104e9.zip |
When using the WebGL external image API, use sync calls if we happen to be on the WebGL thread
Diffstat (limited to 'components/canvas/webgl_mode')
-rw-r--r-- | components/canvas/webgl_mode/inprocess.rs | 239 |
1 files changed, 99 insertions, 140 deletions
diff --git a/components/canvas/webgl_mode/inprocess.rs b/components/canvas/webgl_mode/inprocess.rs index d499a1cb148..34a3f0eeb7a 100644 --- a/components/canvas/webgl_mode/inprocess.rs +++ b/components/canvas/webgl_mode/inprocess.rs @@ -3,7 +3,7 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ use crate::gl_context::GLContextFactory; -use crate::webgl_thread::{TexturesMap, WebGLMainThread, WebGLThread, WebGLThreadInit}; +use crate::webgl_thread::{WebGLMainThread, WebGLThread, WebGLThreadInit}; use canvas_traits::webgl::webgl_channel; use canvas_traits::webgl::DOMToTextureCommand; use canvas_traits::webgl::{WebGLChan, WebGLContextId, WebGLMsg, WebGLPipeline, WebGLReceiver}; @@ -13,8 +13,6 @@ use euclid::default::Size2D; use fnv::FnvHashMap; use gleam::gl; use servo_config::pref; -use std::cell::RefCell; -use std::collections::HashMap; use std::default::Default; use std::rc::Rc; use std::sync::{Arc, Mutex}; @@ -25,20 +23,21 @@ pub struct WebGLThreads(WebGLSender<WebGLMsg>); pub enum ThreadMode { MainThread(Box<dyn EventLoopWaker>), - OffThread(Rc<dyn gl::Gl>), + OffThread, } impl WebGLThreads { /// Creates a new WebGLThreads object pub fn new( gl_factory: GLContextFactory, + webrender_gl: Rc<dyn gl::Gl>, webrender_api_sender: webrender_api::RenderApiSender, webvr_compositor: Option<Box<dyn WebVRRenderHandler>>, external_images: Arc<Mutex<WebrenderExternalImageRegistry>>, mode: ThreadMode, ) -> ( WebGLThreads, - Option<WebGLMainThread>, + Option<Rc<WebGLMainThread>>, Box<dyn WebrenderExternalImageApi>, Option<Box<dyn webrender::OutputImageHandler>>, ) { @@ -54,33 +53,24 @@ impl WebGLThreads { }; let output_handler = if pref!(dom.webgl.dom_to_texture.enabled) { - Some(Box::new(match mode { - ThreadMode::MainThread(..) => OutputHandler::new_main_thread(), - ThreadMode::OffThread(ref webrender_gl) => { - OutputHandler::new_off_thread(webrender_gl.clone(), sender.clone()) - }, - })) + Some(Box::new(OutputHandler::new( + webrender_gl.clone(), + sender.clone(), + ))) } else { None }; - let (external, webgl_thread) = match mode { + let external = WebGLExternalImages::new(webrender_gl, sender.clone()); + + let webgl_thread = match mode { ThreadMode::MainThread(event_loop_waker) => { - let textures = Rc::new(RefCell::new(HashMap::new())); - let thread_data = - WebGLThread::run_on_current_thread(init, event_loop_waker, textures.clone()); - ( - WebGLExternalImages::new_main_thread(textures), - Some(thread_data), - ) + let thread = WebGLThread::run_on_current_thread(init, event_loop_waker); + Some(thread) }, - - ThreadMode::OffThread(webrender_gl) => { + ThreadMode::OffThread => { WebGLThread::run_on_own_thread(init); - ( - WebGLExternalImages::new_off_thread(webrender_gl, sender.clone()), - None, - ) + None }, }; @@ -107,113 +97,90 @@ impl WebGLThreads { } /// Bridge between the webrender::ExternalImage callbacks and the WebGLThreads. -enum WebGLExternalImages { - OffThread { - webrender_gl: Rc<dyn gl::Gl>, - webgl_channel: WebGLSender<WebGLMsg>, - // Used to avoid creating a new channel on each received WebRender request. - lock_channel: ( - WebGLSender<(u32, Size2D<i32>, usize)>, - WebGLReceiver<(u32, Size2D<i32>, usize)>, - ), - }, - MainThread { - textures: TexturesMap, - }, +struct WebGLExternalImages { + webrender_gl: Rc<dyn gl::Gl>, + webgl_channel: WebGLSender<WebGLMsg>, + // Used to avoid creating a new channel on each received WebRender request. + lock_channel: ( + WebGLSender<(u32, Size2D<i32>, usize)>, + WebGLReceiver<(u32, Size2D<i32>, usize)>, + ), } impl WebGLExternalImages { - fn new_off_thread(webrender_gl: Rc<dyn gl::Gl>, channel: WebGLSender<WebGLMsg>) -> Self { - WebGLExternalImages::OffThread { + fn new(webrender_gl: Rc<dyn gl::Gl>, channel: WebGLSender<WebGLMsg>) -> Self { + WebGLExternalImages { webrender_gl, webgl_channel: channel, lock_channel: webgl_channel().unwrap(), } } - - fn new_main_thread(textures: TexturesMap) -> Self { - WebGLExternalImages::MainThread { textures } - } } impl WebrenderExternalImageApi for WebGLExternalImages { fn lock(&mut self, id: u64) -> (u32, Size2D<i32>) { - match *self { - WebGLExternalImages::OffThread { - ref webgl_channel, - ref webrender_gl, - ref lock_channel, - } => { - // WebGL Thread has it's own GL command queue that we need to synchronize with the WR GL command queue. - // The WebGLMsg::Lock message inserts a fence in the WebGL command queue. - webgl_channel - .send(WebGLMsg::Lock( - WebGLContextId(id as usize), - lock_channel.0.clone(), - )) - .unwrap(); - let (image_id, size, gl_sync) = lock_channel.1.recv().unwrap(); - // The next glWaitSync call is run on the WR thread and it's used to synchronize the two - // flows of OpenGL commands in order to avoid WR using a semi-ready WebGL texture. - // glWaitSync doesn't block WR thread, it affects only internal OpenGL subsystem. - webrender_gl.wait_sync(gl_sync as gl::GLsync, 0, gl::TIMEOUT_IGNORED); - (image_id, size) - }, - - WebGLExternalImages::MainThread { ref textures } => { - let textures = textures.borrow(); - let entry = textures - .get(&WebGLContextId(id as usize)) - .expect("no texture entry???"); - (entry.0, entry.1) - }, + if let Some(main_thread) = WebGLMainThread::on_current_thread() { + // If we're on the same thread as WebGL, we can get the data directly + main_thread + .thread_data + .borrow_mut() + .handle_lock_unsync(WebGLContextId(id as usize)) + } else { + // WebGL Thread has it's own GL command queue that we need to synchronize with the WR GL command queue. + // The WebGLMsg::Lock message inserts a fence in the WebGL command queue. + self.webgl_channel + .send(WebGLMsg::Lock( + WebGLContextId(id as usize), + self.lock_channel.0.clone(), + )) + .unwrap(); + let (image_id, size, gl_sync) = self.lock_channel.1.recv().unwrap(); + // The next glWaitSync call is run on the WR thread and it's used to synchronize the two + // flows of OpenGL commands in order to avoid WR using a semi-ready WebGL texture. + // glWaitSync doesn't block WR thread, it affects only internal OpenGL subsystem. + self.webrender_gl + .wait_sync(gl_sync as gl::GLsync, 0, gl::TIMEOUT_IGNORED); + (image_id, size) } } fn unlock(&mut self, id: u64) { - match *self { - WebGLExternalImages::OffThread { - ref webgl_channel, .. - } => { - webgl_channel - .send(WebGLMsg::Unlock(WebGLContextId(id as usize))) - .unwrap(); - }, - - WebGLExternalImages::MainThread { .. } => {}, + if let Some(main_thread) = WebGLMainThread::on_current_thread() { + // If we're on the same thread as WebGL, we can unlock directly + main_thread + .thread_data + .borrow_mut() + .handle_unlock(WebGLContextId(id as usize)) + } else { + self.webgl_channel + .send(WebGLMsg::Unlock(WebGLContextId(id as usize))) + .unwrap() } } } /// struct used to implement DOMToTexture feature and webrender::OutputImageHandler trait. type OutputHandlerData = Option<(u32, Size2D<i32>)>; -enum OutputHandler { - OffThread { - webrender_gl: Rc<dyn gl::Gl>, - webgl_channel: WebGLSender<WebGLMsg>, - // Used to avoid creating a new channel on each received WebRender request. - lock_channel: ( - WebGLSender<OutputHandlerData>, - WebGLReceiver<OutputHandlerData>, - ), - sync_objects: FnvHashMap<webrender_api::PipelineId, gl::GLsync>, - }, - MainThread, +struct OutputHandler { + webrender_gl: Rc<dyn gl::Gl>, + webgl_channel: WebGLSender<WebGLMsg>, + // Used to avoid creating a new channel on each received WebRender request. + lock_channel: ( + WebGLSender<OutputHandlerData>, + WebGLReceiver<OutputHandlerData>, + ), + sync_objects: FnvHashMap<webrender_api::PipelineId, gl::GLsync>, } impl OutputHandler { - fn new_off_thread(webrender_gl: Rc<dyn gl::Gl>, channel: WebGLSender<WebGLMsg>) -> Self { - OutputHandler::OffThread { + fn new(webrender_gl: Rc<dyn gl::Gl>, channel: WebGLSender<WebGLMsg>) -> Self { + OutputHandler { webrender_gl, webgl_channel: channel, lock_channel: webgl_channel().unwrap(), sync_objects: Default::default(), } } - - fn new_main_thread() -> Self { - OutputHandler::MainThread - } } /// Bridge between the WR frame outputs and WebGL to implement DOMToTexture synchronization. @@ -222,49 +189,41 @@ impl webrender::OutputImageHandler for OutputHandler { &mut self, id: webrender_api::PipelineId, ) -> Option<(u32, webrender_api::units::FramebufferIntSize)> { - match *self { - OutputHandler::OffThread { - ref webrender_gl, - ref lock_channel, - ref webgl_channel, - .. - } => { - // Insert a fence in the WR command queue - let gl_sync = webrender_gl.fence_sync(gl::SYNC_GPU_COMMANDS_COMPLETE, 0); - // The lock command adds a WaitSync call on the WebGL command flow. - let command = - DOMToTextureCommand::Lock(id, gl_sync as usize, lock_channel.0.clone()); - webgl_channel - .send(WebGLMsg::DOMToTextureCommand(command)) - .unwrap(); - lock_channel.1.recv().unwrap().map(|(tex_id, size)| { - ( - tex_id, - webrender_api::units::FramebufferIntSize::new(size.width, size.height), - ) - }) - }, + // Insert a fence in the WR command queue + let gl_sync = self + .webrender_gl + .fence_sync(gl::SYNC_GPU_COMMANDS_COMPLETE, 0); + self.sync_objects.insert(id, gl_sync); + + let result = if let Some(main_thread) = WebGLMainThread::on_current_thread() { + main_thread + .thread_data + .borrow_mut() + .handle_dom_to_texture_lock(id, gl_sync as usize) + } else { + // The lock command adds a WaitSync call on the WebGL command flow. + let command = + DOMToTextureCommand::Lock(id, gl_sync as usize, self.lock_channel.0.clone()); + self.webgl_channel + .send(WebGLMsg::DOMToTextureCommand(command)) + .unwrap(); + self.lock_channel.1.recv().unwrap() + }; - OutputHandler::MainThread => unimplemented!(), - } + result.map(|(tex_id, size)| { + ( + tex_id, + webrender_api::units::FramebufferIntSize::new(size.width, size.height), + ) + }) } fn unlock(&mut self, id: webrender_api::PipelineId) { - match *self { - OutputHandler::OffThread { - ref webrender_gl, - ref mut sync_objects, - .. - } => { - if let Some(gl_sync) = sync_objects.remove(&id) { - // Flush the Sync object into the GPU's command queue to guarantee that it it's signaled. - webrender_gl.flush(); - // Mark the sync object for deletion. - webrender_gl.delete_sync(gl_sync); - } - }, - - OutputHandler::MainThread => {}, + if let Some(gl_sync) = self.sync_objects.remove(&id) { + // Flush the Sync object into the GPU's command queue to guarantee that it it's signaled. + self.webrender_gl.flush(); + // Mark the sync object for deletion. + self.webrender_gl.delete_sync(gl_sync); } } } |