aboutsummaryrefslogtreecommitdiffstats
path: root/components/canvas/webgl_mode
diff options
context:
space:
mode:
authorAlan Jeffrey <ajeffrey@mozilla.com>2019-07-26 16:52:23 -0500
committerAlan Jeffrey <ajeffrey@mozilla.com>2019-07-26 17:39:40 -0500
commit0178fcae4ec29824a3f1d35969457bed1ca104e9 (patch)
tree0e624cc98fbbfb9e70ed107e0f1a7391aa30e52f /components/canvas/webgl_mode
parent8ec28978cdc3e0fa66652a7a0a57911ca414254c (diff)
downloadservo-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.rs239
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);
}
}
}