diff --git a/components/canvas/media_mode/inprocess.rs b/components/canvas/media_mode/inprocess.rs index 0fa132efd169..7a1c781bfee8 100644 --- a/components/canvas/media_mode/inprocess.rs +++ b/components/canvas/media_mode/inprocess.rs @@ -2,8 +2,12 @@ * 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::media_thread::GLPlayerThread; -use canvas_traits::media::{GLPlayerChan, GLPlayerMsg, GLPlayerPipeline, GLPlayerSender}; +use crate::media_thread::{GLPlayerExternalImageApi, GLPlayerExternalImageHandler, GLPlayerThread}; +use canvas_traits::media::glplayer_channel; +use canvas_traits::media::{ + GLPlayerChan, GLPlayerMsg, GLPlayerPipeline, GLPlayerReceiver, GLPlayerSender, +}; +use euclid::Size2D; /// GLPlayer Threading API entry point that lives in the constellation. pub struct GLPlayerThreads(GLPlayerSender); @@ -28,3 +32,50 @@ impl GLPlayerThreads { .map_err(|_| "Failed to send Exit message") } } + +/// Bridge between the webrender::ExternalImage callbacks and the +/// GLPlayerThreads. +struct GLPlayerExternalImages { + // @FIXME(victor): this should be added when GstGLSyncMeta is + // added + //webrender_gl: Rc, + glplayer_channel: GLPlayerSender, + // Used to avoid creating a new channel on each received WebRender + // request. + lock_channel: ( + GLPlayerSender<(u32, Size2D, usize)>, + GLPlayerReceiver<(u32, Size2D, usize)>, + ), +} + +impl GLPlayerExternalImages { + fn new(channel: GLPlayerSender) -> Self { + Self { + glplayer_channel: channel, + lock_channel: glplayer_channel().unwrap(), + } + } +} + +impl GLPlayerExternalImageApi for GLPlayerExternalImages { + fn lock(&mut self, id: u64) -> (u32, Size2D) { + // The GLPlayerMsgForward::Lock message inserts a fence in the + // GLPlayer command queue. + self.glplayer_channel + .send(GLPlayerMsg::Lock(id, 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 GLPlayer 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) { + self.glplayer_channel.send(GLPlayerMsg::Unlock(id)).unwrap(); + } +} diff --git a/components/canvas/media_thread.rs b/components/canvas/media_thread.rs index efcd6792d366..c8a104a46585 100644 --- a/components/canvas/media_thread.rs +++ b/components/canvas/media_thread.rs @@ -3,6 +3,7 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ use canvas_traits::media::*; +use euclid::Size2D; use fnv::FnvHashMap; use std::thread; @@ -80,3 +81,60 @@ 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); + } +}