diff --git a/Cargo.lock b/Cargo.lock index 864ca86d567..c702bd07cd0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -410,6 +410,7 @@ dependencies = [ "servo_config 0.0.1", "webrender 0.60.0 (git+https://github.com/jdm/webrender?branch=servo-hl)", "webrender_api 0.60.0 (git+https://github.com/jdm/webrender?branch=servo-hl)", + "webrender_traits 0.0.1", ] [[package]] @@ -2539,6 +2540,7 @@ dependencies = [ "webdriver_server 0.0.1", "webrender 0.60.0 (git+https://github.com/jdm/webrender?branch=servo-hl)", "webrender_api 0.60.0 (git+https://github.com/jdm/webrender?branch=servo-hl)", + "webrender_traits 0.0.1", "webvr 0.0.1", "webvr_traits 0.0.1", "webxr-api 0.0.1 (git+https://github.com/servo/webxr)", @@ -2725,6 +2727,7 @@ dependencies = [ "servo_config 0.0.1", "webrender 0.60.0 (git+https://github.com/servo/webrender)", "webrender_api 0.60.0 (git+https://github.com/servo/webrender)", + "webrender_traits 0.0.1", ] [[package]] @@ -5399,6 +5402,15 @@ dependencies = [ "sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "webrender_traits" +version = "0.0.1" +dependencies = [ + "euclid 0.19.8 (registry+https://github.com/rust-lang/crates.io-index)", + "webrender 0.60.0 (git+https://github.com/servo/webrender)", + "webrender_api 0.60.0 (git+https://github.com/servo/webrender)", +] + [[package]] name = "webvr" version = "0.0.1" diff --git a/components/canvas/Cargo.toml b/components/canvas/Cargo.toml index 906fa84b434..8211619ca91 100644 --- a/components/canvas/Cargo.toml +++ b/components/canvas/Cargo.toml @@ -37,3 +37,4 @@ serde_bytes = "0.10" servo_config = {path = "../config"} webrender = {git = "https://github.com/servo/webrender"} webrender_api = {git = "https://github.com/servo/webrender", features = ["ipc"]} +webrender_traits = {path = "../webrender_traits"} diff --git a/components/canvas/webgl_mode/inprocess.rs b/components/canvas/webgl_mode/inprocess.rs index b93b2fb0a19..6e53879c501 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::{WebGLExternalImageApi, WebGLExternalImageHandler, WebGLThread}; +use crate::webgl_thread::WebGLThread; use canvas_traits::webgl::webgl_channel; use canvas_traits::webgl::DOMToTextureCommand; use canvas_traits::webgl::{WebGLChan, WebGLContextId, WebGLMsg, WebGLPipeline, WebGLReceiver}; @@ -13,6 +13,7 @@ use fnv::FnvHashMap; use gleam::gl; use servo_config::pref; use std::rc::Rc; +use webrender_traits::WebrenderExternalImageApi; /// WebGL Threading API entry point that lives in the constellation. pub struct WebGLThreads(WebGLSender); @@ -26,7 +27,7 @@ impl WebGLThreads { webvr_compositor: Option>, ) -> ( WebGLThreads, - Box, + Box, Option>, ) { // This implementation creates a single `WebGLThread` for all the pipelines. @@ -43,8 +44,7 @@ impl WebGLThreads { } else { None }; - let external = - WebGLExternalImageHandler::new(WebGLExternalImages::new(webrender_gl, channel.clone())); + let external = WebGLExternalImages::new(webrender_gl, channel.clone()); ( WebGLThreads(channel), Box::new(external), @@ -87,12 +87,15 @@ impl WebGLExternalImages { } } -impl WebGLExternalImageApi for WebGLExternalImages { - fn lock(&mut self, ctx_id: WebGLContextId) -> (u32, Size2D) { +impl WebrenderExternalImageApi for WebGLExternalImages { + fn lock(&mut self, id: u64) -> (u32, Size2D) { // 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(ctx_id, self.lock_channel.0.clone())) + .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 @@ -103,8 +106,10 @@ impl WebGLExternalImageApi for WebGLExternalImages { (image_id, size) } - fn unlock(&mut self, ctx_id: WebGLContextId) { - self.webgl_channel.send(WebGLMsg::Unlock(ctx_id)).unwrap(); + fn unlock(&mut self, id: u64) { + self.webgl_channel + .send(WebGLMsg::Unlock(WebGLContextId(id as usize))) + .unwrap(); } } diff --git a/components/canvas/webgl_thread.rs b/components/canvas/webgl_thread.rs index cec8cc929d6..229a7f3eca3 100644 --- a/components/canvas/webgl_thread.rs +++ b/components/canvas/webgl_thread.rs @@ -730,53 +730,6 @@ struct WebGLContextInfo { render_state: ContextRenderState, } -/// This trait is used as a bridge between the `WebGLThreads` implementation and -/// the WR ExternalImageHandler API implemented in the `WebGLExternalImageHandler` struct. -/// `WebGLExternalImageHandler` takes care of type conversions between WR and WebGL info (e.g keys, uvs). -/// It uses this trait to notify lock/unlock messages and get the required info that WR needs. -/// `WebGLThreads` receives lock/unlock message notifications and takes care of sending -/// the unlock/lock messages to the appropiate `WebGLThread`. -pub trait WebGLExternalImageApi { - fn lock(&mut self, ctx_id: WebGLContextId) -> (u32, Size2D); - fn unlock(&mut self, ctx_id: WebGLContextId); -} - -/// WebRender External Image Handler implementation -pub struct WebGLExternalImageHandler { - handler: T, -} - -impl WebGLExternalImageHandler { - pub fn new(handler: T) -> Self { - Self { handler: handler } - } -} - -impl webrender::ExternalImageHandler for WebGLExternalImageHandler { - /// Lock the external image. Then, WR could start to read the image content. - /// The WR client should not change the image content until the unlock() call. - fn lock( - &mut self, - key: webrender_api::ExternalImageId, - _channel_index: u8, - _rendering: webrender_api::ImageRendering, - ) -> webrender::ExternalImage { - let ctx_id = WebGLContextId(key.0 as _); - let (texture_id, size) = self.handler.lock(ctx_id); - - webrender::ExternalImage { - uv: webrender_api::TexelRect::new(0.0, size.height as f32, size.width as f32, 0.0), - source: webrender::ExternalImageSource::NativeTexture(texture_id), - } - } - /// Unlock the external image. The WR should not read the image content - /// after this call. - fn unlock(&mut self, key: webrender_api::ExternalImageId, _channel_index: u8) { - let ctx_id = WebGLContextId(key.0 as _); - self.handler.unlock(ctx_id); - } -} - /// Data about the linked DOM<->WebGLTexture elements. struct DOMToTextureData { context_id: WebGLContextId, diff --git a/components/media/Cargo.toml b/components/media/Cargo.toml index 53f531a26cf..254b4246f7e 100644 --- a/components/media/Cargo.toml +++ b/components/media/Cargo.toml @@ -21,3 +21,4 @@ servo_config = {path = "../config"} servo-media = {git = "https://github.com/servo/media"} webrender = {git = "https://github.com/servo/webrender"} webrender_api = {git = "https://github.com/servo/webrender", features = ["ipc"]} +webrender_traits = {path = "../webrender_traits"} diff --git a/components/media/lib.rs b/components/media/lib.rs index c98d97df597..69697c3cecb 100644 --- a/components/media/lib.rs +++ b/components/media/lib.rs @@ -13,16 +13,15 @@ extern crate log; #[macro_use] extern crate serde; -use euclid::Size2D; -use servo_media::player::context::{GlApi, GlContext, NativeDisplay, PlayerGLContext}; - mod media_channel; mod media_thread; pub use crate::media_channel::glplayer_channel; - use crate::media_channel::{GLPlayerChan, GLPlayerPipeline, GLPlayerReceiver, GLPlayerSender}; -use crate::media_thread::{GLPlayerExternalImageApi, GLPlayerExternalImageHandler, GLPlayerThread}; +use crate::media_thread::GLPlayerThread; +use euclid::Size2D; +use servo_media::player::context::{GlApi, GlContext, NativeDisplay, PlayerGLContext}; +use webrender_traits::WebrenderExternalImageApi; /// These are the messages that the GLPlayer thread will forward to /// the video player which lives in htmlmediaelement @@ -100,10 +99,9 @@ impl PlayerGLContext for WindowGLContext { pub struct GLPlayerThreads(GLPlayerSender); impl GLPlayerThreads { - pub fn new() -> (GLPlayerThreads, Box) { + pub fn new() -> (GLPlayerThreads, Box) { let channel = GLPlayerThread::start(); - let external = - GLPlayerExternalImageHandler::new(GLPlayerExternalImages::new(channel.clone())); + let external = GLPlayerExternalImages::new(channel.clone()); (GLPlayerThreads(channel), Box::new(external)) } @@ -146,7 +144,7 @@ impl GLPlayerExternalImages { } } -impl GLPlayerExternalImageApi for GLPlayerExternalImages { +impl WebrenderExternalImageApi for GLPlayerExternalImages { fn lock(&mut self, id: u64) -> (u32, Size2D) { // The GLPlayerMsgForward::Lock message inserts a fence in the // GLPlayer command queue. diff --git a/components/media/media_thread.rs b/components/media/media_thread.rs index e47e7c799f9..09d5a00b69b 100644 --- a/components/media/media_thread.rs +++ b/components/media/media_thread.rs @@ -6,7 +6,6 @@ use crate::media_channel::{glplayer_channel, GLPlayerSender}; /// GL player threading API entry point that lives in the /// constellation. use crate::{GLPlayerMsg, GLPlayerMsgForward}; -use euclid::Size2D; use fnv::FnvHashMap; use std::thread; @@ -78,60 +77,3 @@ impl GLPlayerThread { false } } - -/// This trait is used as a bridge between the `GLPlayerThreads` -/// implementation and the WR ExternalImageHandler API implemented in -/// the `GLPlayerExternalImageHandler` struct. -// -/// `GLPlayerExternalImageHandler` takes care of type conversions -/// between WR and GLPlayer info (e.g keys, uvs). -// -/// It uses this trait to notify lock/unlock messages and get the -/// required info that WR needs. -// -/// `GLPlayerThreads` receives lock/unlock message notifications and -/// takes care of sending the unlock/lock messages to the appropiate -/// `GLPlayerThread`. -pub trait GLPlayerExternalImageApi { - fn lock(&mut self, id: u64) -> (u32, Size2D); - fn unlock(&mut self, id: u64); -} - -/// WebRender External Image Handler implementation -pub struct GLPlayerExternalImageHandler { - handler: T, -} - -impl GLPlayerExternalImageHandler { - pub fn new(handler: T) -> Self { - Self { handler: handler } - } -} - -impl webrender::ExternalImageHandler - for GLPlayerExternalImageHandler -{ - /// Lock the external image. Then, WR could start to read the - /// image content. - /// The WR client should not change the image content until the - /// unlock() call. - fn lock( - &mut self, - key: webrender_api::ExternalImageId, - _channel_index: u8, - _rendering: webrender_api::ImageRendering, - ) -> webrender::ExternalImage { - let (texture_id, size) = self.handler.lock(key.0); - - webrender::ExternalImage { - uv: webrender_api::TexelRect::new(0.0, 0.0, size.width as f32, size.height as f32), - source: webrender::ExternalImageSource::NativeTexture(texture_id), - } - } - - /// Unlock the external image. The WR should not read the image - /// content after this call. - fn unlock(&mut self, key: webrender_api::ExternalImageId, _channel_index: u8) { - self.handler.unlock(key.0); - } -} diff --git a/components/servo/Cargo.toml b/components/servo/Cargo.toml index 10ad4319651..5b0b8a651a9 100644 --- a/components/servo/Cargo.toml +++ b/components/servo/Cargo.toml @@ -72,6 +72,7 @@ style = {path = "../style", features = ["servo"]} style_traits = {path = "../style_traits", features = ["servo"]} webrender = {git = "https://github.com/servo/webrender"} webrender_api = {git = "https://github.com/servo/webrender", features = ["ipc"]} +webrender_traits = {path = "../webrender_traits"} webdriver_server = {path = "../webdriver_server", optional = true} webvr = {path = "../webvr"} webvr_traits = {path = "../webvr_traits"} diff --git a/components/servo/lib.rs b/components/servo/lib.rs index 1496e1ce054..5321e4720b8 100644 --- a/components/servo/lib.rs +++ b/components/servo/lib.rs @@ -50,6 +50,7 @@ pub use servo_url; pub use style; pub use style_traits; pub use webrender_api; +pub use webrender_traits; pub use webvr; pub use webvr_traits; @@ -112,6 +113,7 @@ use std::cmp::max; use std::path::PathBuf; use std::rc::Rc; use webrender::{RendererKind, ShaderPrecacheFlags}; +use webrender_traits::{WebrenderExternalImageHandler, WebrenderImageHandlerType}; use webvr::{VRServiceManager, WebVRCompositorHandler, WebVRThread}; pub use gleam::gl; @@ -688,9 +690,11 @@ fn create_constellation( GLContextFactory::current_native_handle(&compositor_proxy) }; + let mut webrender_external_image_handler = Box::new(WebrenderExternalImageHandler::new()); + // Initialize WebGL Thread entry point. let webgl_threads = gl_factory.map(|factory| { - let (webgl_threads, _image_handler, output_handler) = WebGLThreads::new( + let (webgl_threads, image_handler, output_handler) = WebGLThreads::new( factory, window_gl, webrender_api_sender.clone(), @@ -698,7 +702,8 @@ fn create_constellation( ); // Set webrender external image handler for WebGL textures - //webrender.set_external_image_handler(image_handler); + webrender_external_image_handler + .set_handler(image_handler, WebrenderImageHandlerType::WebGL); // Set DOM to texture handler, if enabled. if let Some(output_handler) = output_handler { @@ -712,11 +717,14 @@ fn create_constellation( GlContext::Unknown => None, _ => { let (glplayer_threads, image_handler) = GLPlayerThreads::new(); - webrender.set_external_image_handler(image_handler); + webrender_external_image_handler + .set_handler(image_handler, WebrenderImageHandlerType::Media); Some(glplayer_threads) }, }; + webrender.set_external_image_handler(webrender_external_image_handler); + let player_context = WindowGLContext { glplayer_chan: glplayer_threads.as_ref().map(|threads| threads.pipeline()), ..player_context diff --git a/components/webrender_traits/Cargo.toml b/components/webrender_traits/Cargo.toml new file mode 100644 index 00000000000..01e2ca2f2e3 --- /dev/null +++ b/components/webrender_traits/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "webrender_traits" +version = "0.0.1" +authors = ["The Servo Project Developers"] +license = "MPL-2.0" +edition = "2018" +publish = false + +[lib] +name = "webrender_traits" +path = "lib.rs" + +[dependencies] +euclid = "0.19" +webrender = {git = "https://github.com/servo/webrender"} +webrender_api = {git = "https://github.com/servo/webrender", features = ["ipc"]} + diff --git a/components/webrender_traits/lib.rs b/components/webrender_traits/lib.rs new file mode 100644 index 00000000000..7a2f3b4b69b --- /dev/null +++ b/components/webrender_traits/lib.rs @@ -0,0 +1,108 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +#![crate_name = "webrender_traits"] +#![crate_type = "rlib"] +#![deny(unsafe_code)] + +use euclid::Size2D; +use std::collections::HashMap; + +/// This trait is used as a bridge between the different GL clients +/// in Servo that handles WebRender ExternalImages and the WebRender +/// ExternalImageHandler API. +// +/// This trait is used to notify lock/unlock messages and get the +/// required info that WR needs. +pub trait WebrenderExternalImageApi { + fn lock(&mut self, id: u64) -> (u32, Size2D); + fn unlock(&mut self, id: u64); +} + +/// Type of Webrender External Image Handler. +pub enum WebrenderImageHandlerType { + WebGL, + Media, +} + +/// WebRender External Image Handler implementation. +pub struct WebrenderExternalImageHandler { + webgl_handler: Option>, + media_handler: Option>, + //XXX(ferjm) register external images. + external_images: HashMap, +} + +impl WebrenderExternalImageHandler { + pub fn new() -> Self { + Self { + webgl_handler: None, + media_handler: None, + external_images: HashMap::new(), + } + } + + pub fn set_handler( + &mut self, + handler: Box, + handler_type: WebrenderImageHandlerType, + ) { + match handler_type { + WebrenderImageHandlerType::WebGL => self.webgl_handler = Some(handler), + WebrenderImageHandlerType::Media => self.media_handler = Some(handler), + } + } +} + +impl webrender::ExternalImageHandler for WebrenderExternalImageHandler { + /// Lock the external image. Then, WR could start to read the + /// image content. + /// The WR client should not change the image content until the + /// unlock() call. + fn lock( + &mut self, + key: webrender_api::ExternalImageId, + _channel_index: u8, + _rendering: webrender_api::ImageRendering, + ) -> webrender::ExternalImage { + if let Some(handler_type) = self.external_images.get(&key) { + // It is safe to unwrap the handlers here because we forbid registration + // for specific types that has no handler set. + // XXX(ferjm) make this ^ true. + let (texture_id, size) = match handler_type { + WebrenderImageHandlerType::WebGL => { + self.webgl_handler.as_mut().unwrap().lock(key.0) + }, + WebrenderImageHandlerType::Media => { + self.media_handler.as_mut().unwrap().lock(key.0) + }, + }; + webrender::ExternalImage { + uv: webrender_api::TexelRect::new(0.0, 0.0, size.width as f32, size.height as f32), + source: webrender::ExternalImageSource::NativeTexture(texture_id), + } + } else { + unreachable!() + } + } + + /// Unlock the external image. The WR should not read the image + /// content after this call. + fn unlock(&mut self, key: webrender_api::ExternalImageId, _channel_index: u8) { + if let Some(handler_type) = self.external_images.get(&key) { + // It is safe to unwrap the handlers here because we forbid registration + // for specific types that has no handler set. + match handler_type { + WebrenderImageHandlerType::WebGL => { + self.webgl_handler.as_mut().unwrap().unlock(key.0) + }, + WebrenderImageHandlerType::Media => { + self.media_handler.as_mut().unwrap().unlock(key.0) + }, + }; + } else { + unreachable!(); + } + } +}