Introduce WebrenderExternalImageRegistry

This commit is contained in:
Fernando Jiménez Moreno 2019-06-28 18:08:08 +02:00
parent ba9cf85fb3
commit 0da87ad169
6 changed files with 115 additions and 43 deletions

View file

@ -13,7 +13,8 @@ use fnv::FnvHashMap;
use gleam::gl; use gleam::gl;
use servo_config::pref; use servo_config::pref;
use std::rc::Rc; use std::rc::Rc;
use webrender_traits::WebrenderExternalImageApi; use std::sync::{Arc, Mutex};
use webrender_traits::{WebrenderExternalImageApi, WebrenderExternalImageRegistry};
/// WebGL Threading API entry point that lives in the constellation. /// WebGL Threading API entry point that lives in the constellation.
pub struct WebGLThreads(WebGLSender<WebGLMsg>); pub struct WebGLThreads(WebGLSender<WebGLMsg>);
@ -25,6 +26,7 @@ impl WebGLThreads {
webrender_gl: Rc<dyn gl::Gl>, webrender_gl: Rc<dyn gl::Gl>,
webrender_api_sender: webrender_api::RenderApiSender, webrender_api_sender: webrender_api::RenderApiSender,
webvr_compositor: Option<Box<dyn WebVRRenderHandler>>, webvr_compositor: Option<Box<dyn WebVRRenderHandler>>,
external_images: Arc<Mutex<WebrenderExternalImageRegistry>>,
) -> ( ) -> (
WebGLThreads, WebGLThreads,
Box<dyn WebrenderExternalImageApi>, Box<dyn WebrenderExternalImageApi>,
@ -35,6 +37,7 @@ impl WebGLThreads {
gl_factory, gl_factory,
webrender_api_sender, webrender_api_sender,
webvr_compositor.map(|c| WebVRRenderWrapper(c)), webvr_compositor.map(|c| WebVRRenderWrapper(c)),
external_images,
); );
let output_handler = if pref!(dom.webgl.dom_to_texture.enabled) { let output_handler = if pref!(dom.webgl.dom_to_texture.enabled) {
Some(Box::new(OutputHandler::new( Some(Box::new(OutputHandler::new(

View file

@ -12,7 +12,9 @@ use half::f16;
use offscreen_gl_context::{DrawBuffer, GLContext, NativeGLContextMethods}; use offscreen_gl_context::{DrawBuffer, GLContext, NativeGLContextMethods};
use pixels::{self, PixelFormat}; use pixels::{self, PixelFormat};
use std::borrow::Cow; use std::borrow::Cow;
use std::sync::{Arc, Mutex};
use std::thread; use std::thread;
use webrender_traits::{WebrenderExternalImageRegistry, WebrenderImageHandlerType};
/// WebGL Threading API entry point that lives in the constellation. /// WebGL Threading API entry point that lives in the constellation.
/// It allows to get a WebGLThread handle for each script pipeline. /// It allows to get a WebGLThread handle for each script pipeline.
@ -58,12 +60,13 @@ pub struct WebGLThread<VR: WebVRRenderHandler + 'static> {
cached_context_info: FnvHashMap<WebGLContextId, WebGLContextInfo>, cached_context_info: FnvHashMap<WebGLContextId, WebGLContextInfo>,
/// Current bound context. /// Current bound context.
bound_context_id: Option<WebGLContextId>, bound_context_id: Option<WebGLContextId>,
/// Id generator for new WebGLContexts.
next_webgl_id: usize,
/// Handler user to send WebVR commands. /// Handler user to send WebVR commands.
webvr_compositor: Option<VR>, webvr_compositor: Option<VR>,
/// Texture ids and sizes used in DOM to texture outputs. /// Texture ids and sizes used in DOM to texture outputs.
dom_outputs: FnvHashMap<webrender_api::PipelineId, DOMToTextureData>, dom_outputs: FnvHashMap<webrender_api::PipelineId, DOMToTextureData>,
/// List of registered webrender external images.
/// We use it to get an unique ID for new WebGLContexts.
external_images: Arc<Mutex<WebrenderExternalImageRegistry>>,
} }
impl<VR: WebVRRenderHandler + 'static> WebGLThread<VR> { impl<VR: WebVRRenderHandler + 'static> WebGLThread<VR> {
@ -71,6 +74,7 @@ impl<VR: WebVRRenderHandler + 'static> WebGLThread<VR> {
gl_factory: GLContextFactory, gl_factory: GLContextFactory,
webrender_api_sender: webrender_api::RenderApiSender, webrender_api_sender: webrender_api::RenderApiSender,
webvr_compositor: Option<VR>, webvr_compositor: Option<VR>,
external_images: Arc<Mutex<WebrenderExternalImageRegistry>>,
) -> Self { ) -> Self {
WebGLThread { WebGLThread {
gl_factory, gl_factory,
@ -78,9 +82,9 @@ impl<VR: WebVRRenderHandler + 'static> WebGLThread<VR> {
contexts: Default::default(), contexts: Default::default(),
cached_context_info: Default::default(), cached_context_info: Default::default(),
bound_context_id: None, bound_context_id: None,
next_webgl_id: 0,
webvr_compositor, webvr_compositor,
dom_outputs: Default::default(), dom_outputs: Default::default(),
external_images,
} }
} }
@ -90,14 +94,19 @@ impl<VR: WebVRRenderHandler + 'static> WebGLThread<VR> {
gl_factory: GLContextFactory, gl_factory: GLContextFactory,
webrender_api_sender: webrender_api::RenderApiSender, webrender_api_sender: webrender_api::RenderApiSender,
webvr_compositor: Option<VR>, webvr_compositor: Option<VR>,
external_images: Arc<Mutex<WebrenderExternalImageRegistry>>,
) -> WebGLSender<WebGLMsg> { ) -> WebGLSender<WebGLMsg> {
let (sender, receiver) = webgl_channel::<WebGLMsg>().unwrap(); let (sender, receiver) = webgl_channel::<WebGLMsg>().unwrap();
let result = sender.clone(); let result = sender.clone();
thread::Builder::new() thread::Builder::new()
.name("WebGLThread".to_owned()) .name("WebGLThread".to_owned())
.spawn(move || { .spawn(move || {
let mut renderer = let mut renderer = WebGLThread::new(
WebGLThread::new(gl_factory, webrender_api_sender, webvr_compositor); gl_factory,
webrender_api_sender,
webvr_compositor,
external_images,
);
let webgl_chan = WebGLChan(sender); let webgl_chan = WebGLChan(sender);
loop { loop {
let msg = receiver.recv().unwrap(); let msg = receiver.recv().unwrap();
@ -287,9 +296,14 @@ impl<VR: WebVRRenderHandler + 'static> WebGLThread<VR> {
}) })
.map_err(|msg: &str| msg.to_owned())?; .map_err(|msg: &str| msg.to_owned())?;
let id = WebGLContextId(self.next_webgl_id); let id = WebGLContextId(
self.external_images
.lock()
.unwrap()
.next_id(WebrenderImageHandlerType::WebGL)
.0 as usize,
);
let (size, texture_id, limits) = ctx.get_info(); let (size, texture_id, limits) = ctx.get_info();
self.next_webgl_id += 1;
self.contexts.insert( self.contexts.insert(
id, id,
GLContextData { GLContextData {

View file

@ -21,7 +21,8 @@ use crate::media_channel::{GLPlayerChan, GLPlayerPipeline, GLPlayerReceiver, GLP
use crate::media_thread::GLPlayerThread; use crate::media_thread::GLPlayerThread;
use euclid::Size2D; use euclid::Size2D;
use servo_media::player::context::{GlApi, GlContext, NativeDisplay, PlayerGLContext}; use servo_media::player::context::{GlApi, GlContext, NativeDisplay, PlayerGLContext};
use webrender_traits::WebrenderExternalImageApi; use std::sync::{Arc, Mutex};
use webrender_traits::{WebrenderExternalImageApi, WebrenderExternalImageRegistry};
/// These are the messages that the GLPlayer thread will forward to /// These are the messages that the GLPlayer thread will forward to
/// the video player which lives in htmlmediaelement /// the video player which lives in htmlmediaelement
@ -99,8 +100,10 @@ impl PlayerGLContext for WindowGLContext {
pub struct GLPlayerThreads(GLPlayerSender<GLPlayerMsg>); pub struct GLPlayerThreads(GLPlayerSender<GLPlayerMsg>);
impl GLPlayerThreads { impl GLPlayerThreads {
pub fn new() -> (GLPlayerThreads, Box<dyn WebrenderExternalImageApi>) { pub fn new(
let channel = GLPlayerThread::start(); external_images: Arc<Mutex<WebrenderExternalImageRegistry>>,
) -> (GLPlayerThreads, Box<dyn WebrenderExternalImageApi>) {
let channel = GLPlayerThread::start(external_images);
let external = GLPlayerExternalImages::new(channel.clone()); let external = GLPlayerExternalImages::new(channel.clone());
(GLPlayerThreads(channel), Box::new(external)) (GLPlayerThreads(channel), Box::new(external))
} }

View file

@ -7,31 +7,36 @@ use crate::media_channel::{glplayer_channel, GLPlayerSender};
/// constellation. /// constellation.
use crate::{GLPlayerMsg, GLPlayerMsgForward}; use crate::{GLPlayerMsg, GLPlayerMsgForward};
use fnv::FnvHashMap; use fnv::FnvHashMap;
use std::sync::{Arc, Mutex};
use std::thread; use std::thread;
use webrender_traits::{WebrenderExternalImageRegistry, WebrenderImageHandlerType};
/// A GLPlayerThrx1ead manages the life cycle and message multiplexign of /// A GLPlayerThrx1ead manages the life cycle and message multiplexign of
/// a set of video players with GL render. /// a set of video players with GL render.
pub struct GLPlayerThread { pub struct GLPlayerThread {
// Map of live players. // Map of live players.
players: FnvHashMap<u64, GLPlayerSender<GLPlayerMsgForward>>, players: FnvHashMap<u64, GLPlayerSender<GLPlayerMsgForward>>,
/// Id generator for new WebGLContexts. /// List of registered webrender external images.
next_player_id: u64, /// We use it to get an unique ID for new players.
external_images: Arc<Mutex<WebrenderExternalImageRegistry>>,
} }
impl GLPlayerThread { impl GLPlayerThread {
pub fn new() -> Self { pub fn new(external_images: Arc<Mutex<WebrenderExternalImageRegistry>>) -> Self {
GLPlayerThread { GLPlayerThread {
players: Default::default(), players: Default::default(),
next_player_id: 1, external_images,
} }
} }
pub fn start() -> GLPlayerSender<GLPlayerMsg> { pub fn start(
external_images: Arc<Mutex<WebrenderExternalImageRegistry>>,
) -> GLPlayerSender<GLPlayerMsg> {
let (sender, receiver) = glplayer_channel::<GLPlayerMsg>().unwrap(); let (sender, receiver) = glplayer_channel::<GLPlayerMsg>().unwrap();
thread::Builder::new() thread::Builder::new()
.name("GLPlayerThread".to_owned()) .name("GLPlayerThread".to_owned())
.spawn(move || { .spawn(move || {
let mut renderer = GLPlayerThread::new(); let mut renderer = GLPlayerThread::new(external_images);
loop { loop {
let msg = receiver.recv().unwrap(); let msg = receiver.recv().unwrap();
let exit = renderer.handle_msg(msg); let exit = renderer.handle_msg(msg);
@ -51,12 +56,20 @@ impl GLPlayerThread {
trace!("processing {:?}", msg); trace!("processing {:?}", msg);
match msg { match msg {
GLPlayerMsg::RegisterPlayer(sender) => { GLPlayerMsg::RegisterPlayer(sender) => {
let id = self.next_player_id; let id = self
.external_images
.lock()
.unwrap()
.next_id(WebrenderImageHandlerType::Media)
.0;
self.players.insert(id, sender.clone()); self.players.insert(id, sender.clone());
sender.send(GLPlayerMsgForward::PlayerId(id)).unwrap(); sender.send(GLPlayerMsgForward::PlayerId(id)).unwrap();
self.next_player_id += 1;
}, },
GLPlayerMsg::UnregisterPlayer(id) => { GLPlayerMsg::UnregisterPlayer(id) => {
self.external_images
.lock()
.unwrap()
.remove(&webrender_api::ExternalImageId(id));
if self.players.remove(&id).is_none() { if self.players.remove(&id).is_none() {
warn!("Tried to remove an unknown player"); warn!("Tried to remove an unknown player");
} }

View file

@ -113,7 +113,7 @@ use std::cmp::max;
use std::path::PathBuf; use std::path::PathBuf;
use std::rc::Rc; use std::rc::Rc;
use webrender::{RendererKind, ShaderPrecacheFlags}; use webrender::{RendererKind, ShaderPrecacheFlags};
use webrender_traits::{WebrenderExternalImageHandler, WebrenderImageHandlerType}; use webrender_traits::{WebrenderExternalImageHandlers, WebrenderImageHandlerType};
use webvr::{VRServiceManager, WebVRCompositorHandler, WebVRThread}; use webvr::{VRServiceManager, WebVRCompositorHandler, WebVRThread};
pub use gleam::gl; pub use gleam::gl;
@ -690,7 +690,8 @@ fn create_constellation(
GLContextFactory::current_native_handle(&compositor_proxy) GLContextFactory::current_native_handle(&compositor_proxy)
}; };
let mut webrender_external_image_handler = Box::new(WebrenderExternalImageHandler::new()); let (external_image_handlers, external_images) = WebrenderExternalImageHandlers::new();
let mut external_image_handlers = Box::new(external_image_handlers);
// Initialize WebGL Thread entry point. // Initialize WebGL Thread entry point.
let webgl_threads = gl_factory.map(|factory| { let webgl_threads = gl_factory.map(|factory| {
@ -699,11 +700,11 @@ fn create_constellation(
window_gl, window_gl,
webrender_api_sender.clone(), webrender_api_sender.clone(),
webvr_compositor.map(|c| c as Box<_>), webvr_compositor.map(|c| c as Box<_>),
external_images.clone(),
); );
// Set webrender external image handler for WebGL textures // Set webrender external image handler for WebGL textures
webrender_external_image_handler external_image_handlers.set_handler(image_handler, WebrenderImageHandlerType::WebGL);
.set_handler(image_handler, WebrenderImageHandlerType::WebGL);
// Set DOM to texture handler, if enabled. // Set DOM to texture handler, if enabled.
if let Some(output_handler) = output_handler { if let Some(output_handler) = output_handler {
@ -716,14 +717,13 @@ fn create_constellation(
let glplayer_threads = match player_context.gl_context { let glplayer_threads = match player_context.gl_context {
GlContext::Unknown => None, GlContext::Unknown => None,
_ => { _ => {
let (glplayer_threads, image_handler) = GLPlayerThreads::new(); let (glplayer_threads, image_handler) = GLPlayerThreads::new(external_images);
webrender_external_image_handler external_image_handlers.set_handler(image_handler, WebrenderImageHandlerType::Media);
.set_handler(image_handler, WebrenderImageHandlerType::Media);
Some(glplayer_threads) Some(glplayer_threads)
}, },
}; };
webrender.set_external_image_handler(webrender_external_image_handler); webrender.set_external_image_handler(external_image_handlers);
let player_context = WindowGLContext { let player_context = WindowGLContext {
glplayer_chan: glplayer_threads.as_ref().map(|threads| threads.pipeline()), glplayer_chan: glplayer_threads.as_ref().map(|threads| threads.pipeline()),

View file

@ -8,6 +8,7 @@
use euclid::Size2D; use euclid::Size2D;
use std::collections::HashMap; use std::collections::HashMap;
use std::sync::{Arc, Mutex};
/// This trait is used as a bridge between the different GL clients /// This trait is used as a bridge between the different GL clients
/// in Servo that handles WebRender ExternalImages and the WebRender /// in Servo that handles WebRender ExternalImages and the WebRender
@ -26,21 +27,64 @@ pub enum WebrenderImageHandlerType {
Media, Media,
} }
/// WebRender External Image Handler implementation. /// List of Webrender external images to be shared among all external image
pub struct WebrenderExternalImageHandler { /// consumers (WebGL, Media).
webgl_handler: Option<Box<dyn WebrenderExternalImageApi>>, /// It ensures that external image identifiers are unique.
media_handler: Option<Box<dyn WebrenderExternalImageApi>>, pub struct WebrenderExternalImageRegistry {
//XXX(ferjm) register external images. /// Map of all generated external images.
external_images: HashMap<webrender_api::ExternalImageId, WebrenderImageHandlerType>, external_images: HashMap<webrender_api::ExternalImageId, WebrenderImageHandlerType>,
/// Id generator for the next external image identifier.
next_image_id: u64,
} }
impl WebrenderExternalImageHandler { impl WebrenderExternalImageRegistry {
pub fn new() -> Self { pub fn new() -> Self {
Self {
external_images: HashMap::new(),
next_image_id: 0,
}
}
pub fn next_id(
&mut self,
handler_type: WebrenderImageHandlerType,
) -> webrender_api::ExternalImageId {
self.next_image_id += 1;
let key = webrender_api::ExternalImageId(self.next_image_id);
self.external_images.insert(key, handler_type);
key
}
pub fn remove(&mut self, key: &webrender_api::ExternalImageId) {
self.external_images.remove(key);
}
pub fn get(&self, key: &webrender_api::ExternalImageId) -> Option<&WebrenderImageHandlerType> {
self.external_images.get(key)
}
}
/// WebRender External Image Handler implementation.
pub struct WebrenderExternalImageHandlers {
/// WebGL handler.
webgl_handler: Option<Box<dyn WebrenderExternalImageApi>>,
/// Media player handler.
media_handler: Option<Box<dyn WebrenderExternalImageApi>>,
/// Webrender external images.
external_images: Arc<Mutex<WebrenderExternalImageRegistry>>,
}
impl WebrenderExternalImageHandlers {
pub fn new() -> (Self, Arc<Mutex<WebrenderExternalImageRegistry>>) {
let external_images = Arc::new(Mutex::new(WebrenderExternalImageRegistry::new()));
(
Self { Self {
webgl_handler: None, webgl_handler: None,
media_handler: None, media_handler: None,
external_images: HashMap::new(), external_images: external_images.clone(),
} },
external_images,
)
} }
pub fn set_handler( pub fn set_handler(
@ -55,7 +99,7 @@ impl WebrenderExternalImageHandler {
} }
} }
impl webrender::ExternalImageHandler for WebrenderExternalImageHandler { impl webrender::ExternalImageHandler for WebrenderExternalImageHandlers {
/// Lock the external image. Then, WR could start to read the /// Lock the external image. Then, WR could start to read the
/// image content. /// image content.
/// The WR client should not change the image content until the /// The WR client should not change the image content until the
@ -66,10 +110,7 @@ impl webrender::ExternalImageHandler for WebrenderExternalImageHandler {
_channel_index: u8, _channel_index: u8,
_rendering: webrender_api::ImageRendering, _rendering: webrender_api::ImageRendering,
) -> webrender::ExternalImage { ) -> webrender::ExternalImage {
if let Some(handler_type) = self.external_images.get(&key) { if let Some(handler_type) = self.external_images.lock().unwrap().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 { let (texture_id, size) = match handler_type {
WebrenderImageHandlerType::WebGL => { WebrenderImageHandlerType::WebGL => {
self.webgl_handler.as_mut().unwrap().lock(key.0) self.webgl_handler.as_mut().unwrap().lock(key.0)
@ -90,9 +131,7 @@ impl webrender::ExternalImageHandler for WebrenderExternalImageHandler {
/// Unlock the external image. The WR should not read the image /// Unlock the external image. The WR should not read the image
/// content after this call. /// content after this call.
fn unlock(&mut self, key: webrender_api::ExternalImageId, _channel_index: u8) { fn unlock(&mut self, key: webrender_api::ExternalImageId, _channel_index: u8) {
if let Some(handler_type) = self.external_images.get(&key) { if let Some(handler_type) = self.external_images.lock().unwrap().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 { match handler_type {
WebrenderImageHandlerType::WebGL => { WebrenderImageHandlerType::WebGL => {
self.webgl_handler.as_mut().unwrap().unlock(key.0) self.webgl_handler.as_mut().unwrap().unlock(key.0)