From d7d0451424faf1bf9c705068bea1aa8cf582d6ad Mon Sep 17 00:00:00 2001 From: Martin Robinson Date: Sat, 3 Feb 2024 15:38:48 +0100 Subject: [PATCH] libservo: Handle GL video decoding setup internally (#31209) Instead of making the client set up GL video decoding, have this done inside libservo. The details necessary for decoding are fetched via Surfman now. This also removes the setup for the context on Android -- which has no GStreamer support now anyway. In the future, this could be enabled, but should likely be done using Surfman, instead of passing on all these details manually. --- components/compositing/windowing.rs | 9 +- components/servo/lib.rs | 137 ++++++++++++++++++++++++---- ports/jniapi/src/lib.rs | 10 +- ports/jniapi/src/simpleservo.rs | 25 ----- ports/servoshell/app.rs | 4 +- ports/servoshell/headed_window.rs | 83 +---------------- ports/servoshell/headless_window.rs | 13 --- 7 files changed, 125 insertions(+), 156 deletions(-) diff --git a/components/compositing/windowing.rs b/components/compositing/windowing.rs index 7dfc7d6bf9e3..98e610d9921d 100644 --- a/components/compositing/windowing.rs +++ b/components/compositing/windowing.rs @@ -15,7 +15,6 @@ use libc::c_void; use msg::constellation_msg::{PipelineId, TopLevelBrowsingContextId, TraversalDirection}; use script_traits::{MediaSessionActionType, MouseButton, TouchEventType, TouchId, WheelDelta}; use servo_geometry::DeviceIndependentPixel; -use servo_media::player::context::{GlApi, GlContext, NativeDisplay}; use servo_url::ServoUrl; use style_traits::DevicePixel; use webrender_api::units::{DeviceIntPoint, DeviceIntRect, DeviceIntSize, DevicePoint}; @@ -171,13 +170,7 @@ pub trait WindowMethods { /// will want to avoid blocking on UI events, and just /// run the event loop at the vsync interval. fn set_animation_state(&self, _state: AnimationState); - /// Get the media GL context - fn get_gl_context(&self) -> GlContext; - /// Get the media native display - fn get_native_display(&self) -> NativeDisplay; - /// Get the GL api - fn get_gl_api(&self) -> GlApi; - /// Get the RenderingContext instance. + /// Get the [`RenderingContext`] of this Window. fn rendering_context(&self) -> RenderingContext; } diff --git a/components/servo/lib.rs b/components/servo/lib.rs index 5f1a09d8e716..92278eab1b7e 100644 --- a/components/servo/lib.rs +++ b/components/servo/lib.rs @@ -17,7 +17,7 @@ //! `Servo` is fed events from a generic type that implements the //! `WindowMethods` trait. -use std::borrow::Cow; +use std::borrow::{BorrowMut, Cow}; use std::cmp::max; use std::collections::HashMap; use std::path::PathBuf; @@ -62,10 +62,11 @@ use euclid::Scale; use gaol::sandbox::{ChildSandbox, ChildSandboxMethods}; use gfx::font_cache_thread::FontCacheThread; pub use gfx::rendering_context; +use gfx::rendering_context::RenderingContext; pub use gleam::gl; use ipc_channel::ipc::{self, IpcSender}; use log::{error, trace, warn, Log, Metadata, Record}; -use media::{GLPlayerThreads, WindowGLContext}; +use media::{GLPlayerThreads, GlApi, NativeDisplay, WindowGLContext}; pub use msg::constellation_msg::TopLevelBrowsingContextId; use msg::constellation_msg::{PipelineNamespace, PipelineNamespaceId}; use net::resource_thread::new_resource_threads; @@ -78,7 +79,13 @@ use script_traits::{ScriptToConstellationChan, WindowSizeData}; use servo_config::{opts, pref, prefs}; use servo_media::player::context::GlContext; use servo_media::ServoMedia; -use surfman::GLApi; +#[cfg(target_os = "linux")] +use surfman::platform::generic::multi::connection::NativeConnection as LinuxNativeConnection; +#[cfg(target_os = "linux")] +use surfman::platform::generic::multi::context::NativeContext as LinuxNativeContext; +use surfman::{GLApi, GLVersion}; +#[cfg(target_os = "linux")] +use surfman::{NativeConnection, NativeContext}; use webrender::{RenderApiSender, ShaderPrecacheFlags}; use webrender_api::{DocumentId, FontInstanceKey, FontKey, ImageKey}; use webrender_traits::{ @@ -388,17 +395,6 @@ where embedder.register_webxr(&mut webxr_main_thread, embedder_proxy.clone()); } - let glplayer_threads = match window.get_gl_context() { - GlContext::Unknown => None, - _ => { - let (glplayer_threads, image_handler) = - GLPlayerThreads::new(external_images.clone()); - external_image_handlers - .set_handler(image_handler, WebrenderImageHandlerType::Media); - Some(glplayer_threads) - }, - }; - let wgpu_image_handler = webgpu::WGPUExternalImages::new(); let wgpu_image_map = wgpu_image_handler.images.clone(); external_image_handlers.set_handler( @@ -406,12 +402,11 @@ where WebrenderImageHandlerType::WebGPU, ); - let player_context = WindowGLContext { - gl_context: window.get_gl_context(), - native_display: window.get_native_display(), - gl_api: window.get_gl_api(), - glplayer_chan: glplayer_threads.as_ref().map(GLPlayerThreads::pipeline), - }; + let (player_context, glplayer_threads) = Self::create_media_window_gl_context( + external_image_handlers.borrow_mut(), + external_images.clone(), + &rendering_context, + ); webrender.set_external_image_handler(external_image_handlers); @@ -494,6 +489,108 @@ where } } + #[cfg(target_os = "linux")] + fn get_native_media_display_and_gl_context( + rendering_context: &RenderingContext, + ) -> Option<(NativeDisplay, GlContext)> { + let gl_context = match rendering_context.native_context() { + NativeContext::Default(LinuxNativeContext::Default(native_context)) => { + GlContext::Egl(native_context.egl_context as usize) + }, + NativeContext::Default(LinuxNativeContext::Alternate(native_context)) => { + GlContext::Egl(native_context.egl_context as usize) + }, + NativeContext::Alternate(_) => return None, + }; + + let native_display = match rendering_context.connection().native_connection() { + NativeConnection::Default(LinuxNativeConnection::Default(connection)) => { + NativeDisplay::Egl(connection.0 as usize) + }, + NativeConnection::Default(LinuxNativeConnection::Alternate(connection)) => { + NativeDisplay::X11(connection.x11_display as usize) + }, + NativeConnection::Alternate(_) => return None, + }; + Some((native_display, gl_context)) + } + + // @TODO(victor): https://github.com/servo/media/pull/315 + #[cfg(target_os = "windows")] + fn get_native_media_display_and_gl_context( + rendering_context: &RenderingContext, + ) -> Option<(NativeDisplay, GlContext)> { + let gl_context = GlContext::Egl(rendering_context.native_context().egl_context as usize); + let native_display = + NativeDisplay::Egl(rendering_context.native_device().egl_display as usize); + Some((native_display, gl_context)) + } + + #[cfg(not(any(target_os = "windows", target_os = "linux")))] + fn get_native_media_display_and_gl_context( + _rendering_context: &RenderingContext, + ) -> Option<(NativeDisplay, GlContext)> { + None + } + + fn create_media_window_gl_context( + external_image_handlers: &mut WebrenderExternalImageHandlers, + external_images: Arc>, + rendering_context: &RenderingContext, + ) -> (WindowGLContext, Option) { + if !pref!(media.glvideo.enabled) { + return ( + WindowGLContext { + gl_context: GlContext::Unknown, + gl_api: GlApi::None, + native_display: NativeDisplay::Unknown, + glplayer_chan: None, + }, + None, + ); + } + + let (native_display, gl_context) = + match Self::get_native_media_display_and_gl_context(rendering_context) { + Some((native_display, gl_context)) => (native_display, gl_context), + None => { + return ( + WindowGLContext { + gl_context: GlContext::Unknown, + gl_api: GlApi::None, + native_display: NativeDisplay::Unknown, + glplayer_chan: None, + }, + None, + ); + }, + }; + + let api = rendering_context.connection().gl_api(); + let attributes = rendering_context.context_attributes(); + let GLVersion { major, minor } = attributes.version; + let gl_api = match api { + GLApi::GL if major >= 3 && minor >= 2 => GlApi::OpenGL3, + GLApi::GL => GlApi::OpenGL, + GLApi::GLES if major > 1 => GlApi::Gles2, + GLApi::GLES => GlApi::Gles1, + }; + + assert!(!matches!(gl_context, GlContext::Unknown)); + let (glplayer_threads, image_handler) = GLPlayerThreads::new(external_images.clone()); + external_image_handlers.set_handler(image_handler, WebrenderImageHandlerType::Media); + + ( + WindowGLContext { + gl_context, + native_display, + gl_api, + glplayer_chan: Some(GLPlayerThreads::pipeline(&glplayer_threads)), + }, + Some(glplayer_threads), + ) + } + fn handle_window_event(&mut self, event: EmbedderEvent) -> bool { match event { EmbedderEvent::Idle => {}, diff --git a/ports/jniapi/src/lib.rs b/ports/jniapi/src/lib.rs index 5475f68a2529..9f2d186d57dc 100644 --- a/ports/jniapi/src/lib.rs +++ b/ports/jniapi/src/lib.rs @@ -126,11 +126,9 @@ pub fn Java_org_mozilla_servoview_JNIServo_init( let wakeup = Box::new(WakeupCallback::new(callbacks_ref.clone(), &env)); let callbacks = Box::new(HostCallbacks::new(callbacks_ref, &env)); - if let Err(err) = gl_glue::egl::init().and_then(|egl_init| { - opts.gl_context_pointer = Some(egl_init.gl_context); - opts.native_display_pointer = Some(egl_init.display); - simpleservo::init(opts, egl_init.gl_wrapper, wakeup, callbacks) - }) { + if let Err(err) = gl_glue::egl::init() + .and_then(|egl_init| simpleservo::init(opts, egl_init.gl_wrapper, wakeup, callbacks)) + { throw(&env, err) }; } @@ -852,8 +850,6 @@ fn get_options( coordinates, density, xr_discovery: None, - gl_context_pointer: None, - native_display_pointer: None, surfman_integration: simpleservo::SurfmanIntegration::Widget(native_window), prefs: None, }; diff --git a/ports/jniapi/src/simpleservo.rs b/ports/jniapi/src/simpleservo.rs index 214bf43fde3f..3238eb182d1d 100644 --- a/ports/jniapi/src/simpleservo.rs +++ b/ports/jniapi/src/simpleservo.rs @@ -39,7 +39,6 @@ pub use servo::webrender_api::units::DeviceIntRect; use servo::webrender_api::units::DevicePixel; use servo::webrender_api::ScrollLocation; use servo::{self, gl, Servo, TopLevelBrowsingContextId}; -use servo_media::player::context as MediaPlayerContext; use surfman::{Connection, SurfaceType}; thread_local! { @@ -56,8 +55,6 @@ pub struct InitOptions { pub coordinates: Coordinates, pub density: f32, pub xr_discovery: Option, - pub gl_context_pointer: Option<*const c_void>, - pub native_display_pointer: Option<*const c_void>, pub surfman_integration: SurfmanIntegration, pub prefs: Option>, } @@ -292,8 +289,6 @@ pub fn init( host_callbacks: callbacks, coordinates: RefCell::new(init_opts.coordinates), density: init_opts.density, - gl_context_pointer: init_opts.gl_context_pointer, - native_display_pointer: init_opts.native_display_pointer, rendering_context: rendering_context.clone(), }); @@ -861,8 +856,6 @@ struct ServoWindowCallbacks { host_callbacks: Box, coordinates: RefCell, density: f32, - gl_context_pointer: Option<*const c_void>, - native_display_pointer: Option<*const c_void>, rendering_context: RenderingContext, } @@ -906,24 +899,6 @@ impl WindowMethods for ServoWindowCallbacks { hidpi_factor: Scale::new(self.density), } } - - fn get_gl_context(&self) -> MediaPlayerContext::GlContext { - match self.gl_context_pointer { - Some(context) => MediaPlayerContext::GlContext::Egl(context as usize), - None => MediaPlayerContext::GlContext::Unknown, - } - } - - fn get_native_display(&self) -> MediaPlayerContext::NativeDisplay { - match self.native_display_pointer { - Some(display) => MediaPlayerContext::NativeDisplay::Egl(display as usize), - None => MediaPlayerContext::NativeDisplay::Unknown, - } - } - - fn get_gl_api(&self) -> MediaPlayerContext::GlApi { - MediaPlayerContext::GlApi::Gles2 - } } struct ResourceReaderInstance; diff --git a/ports/servoshell/app.rs b/ports/servoshell/app.rs index 8059d05c171b..5221c59d63b3 100644 --- a/ports/servoshell/app.rs +++ b/ports/servoshell/app.rs @@ -14,7 +14,7 @@ use gleam::gl; use log::{info, trace, warn}; use servo::compositing::windowing::EmbedderEvent; use servo::compositing::CompositeTarget; -use servo::config::opts; +use servo::config::{opts, set_pref}; use servo::servo_config::pref; use servo::Servo; use surfman::GLApi; @@ -67,6 +67,8 @@ impl App { // Implements window methods, used by compositor. let window = if opts::get().headless { + // GL video rendering is not supported on headless windows. + set_pref!(media.glvideo.enabled, false); headless_window::Window::new( opts::get().initial_window_size, device_pixel_ratio_override, diff --git a/ports/servoshell/headed_window.rs b/ports/servoshell/headed_window.rs index 1b5edcf4700c..756e8531267a 100644 --- a/ports/servoshell/headed_window.rs +++ b/ports/servoshell/headed_window.rs @@ -24,12 +24,7 @@ use servo::servo_geometry::DeviceIndependentPixel; use servo::style_traits::DevicePixel; use servo::webrender_api::units::{DeviceIntPoint, DeviceIntRect, DeviceIntSize}; use servo::webrender_api::ScrollLocation; -use servo_media::player::context::{GlApi, GlContext as PlayerGLContext, NativeDisplay}; -#[cfg(target_os = "linux")] -use surfman::platform::generic::multi::connection::NativeConnection; -#[cfg(target_os = "linux")] -use surfman::platform::generic::multi::context::NativeContext; -use surfman::{Connection, Context, Device, GLApi, GLVersion, SurfaceType}; +use surfman::{Connection, Context, Device, SurfaceType}; #[cfg(target_os = "windows")] use winapi; use winit::dpi::{LogicalPosition, PhysicalPosition, PhysicalSize}; @@ -553,82 +548,6 @@ impl WindowMethods for Window { fn rendering_context(&self) -> RenderingContext { self.rendering_context.clone() } - - fn get_gl_context(&self) -> PlayerGLContext { - if !pref!(media.glvideo.enabled) { - return PlayerGLContext::Unknown; - } - - #[allow(unused_variables)] - let native_context = self.rendering_context.native_context(); - - #[cfg(target_os = "windows")] - return PlayerGLContext::Egl(native_context.egl_context as usize); - - #[cfg(target_os = "linux")] - return match native_context { - NativeContext::Default(NativeContext::Default(native_context)) => { - PlayerGLContext::Egl(native_context.egl_context as usize) - }, - NativeContext::Default(NativeContext::Alternate(native_context)) => { - PlayerGLContext::Egl(native_context.egl_context as usize) - }, - NativeContext::Alternate(_) => unimplemented!(), - }; - - // @TODO(victor): https://github.com/servo/media/pull/315 - #[cfg(target_os = "macos")] - #[allow(unreachable_code)] - return unimplemented!(); - - #[cfg(not(any(target_os = "linux", target_os = "windows", target_os = "macos")))] - return unimplemented!(); - } - - fn get_native_display(&self) -> NativeDisplay { - if !pref!(media.glvideo.enabled) { - return NativeDisplay::Unknown; - } - - #[allow(unused_variables)] - let native_connection = self.rendering_context.connection().native_connection(); - #[allow(unused_variables)] - let native_device = self.rendering_context.native_device(); - - #[cfg(target_os = "windows")] - return NativeDisplay::Egl(native_device.egl_display as usize); - - #[cfg(target_os = "linux")] - return match native_connection { - NativeConnection::Default(NativeConnection::Default(conn)) => { - NativeDisplay::Egl(conn.0 as usize) - }, - NativeConnection::Default(NativeConnection::Alternate(conn)) => { - NativeDisplay::X11(conn.x11_display as usize) - }, - NativeConnection::Alternate(_) => unimplemented!(), - }; - - // @TODO(victor): https://github.com/servo/media/pull/315 - #[cfg(target_os = "macos")] - #[allow(unreachable_code)] - return unimplemented!(); - - #[cfg(not(any(target_os = "linux", target_os = "windows", target_os = "macos")))] - return unimplemented!(); - } - - fn get_gl_api(&self) -> GlApi { - let api = self.rendering_context.connection().gl_api(); - let attributes = self.rendering_context.context_attributes(); - let GLVersion { major, minor } = attributes.version; - match api { - GLApi::GL if major >= 3 && minor >= 2 => GlApi::OpenGL3, - GLApi::GL => GlApi::OpenGL, - GLApi::GLES if major > 1 => GlApi::Gles2, - GLApi::GLES => GlApi::Gles1, - } - } } fn winit_phase_to_touch_event_type(phase: TouchPhase) -> TouchEventType { diff --git a/ports/servoshell/headless_window.rs b/ports/servoshell/headless_window.rs index d962362d64fb..ba87ffd388c8 100644 --- a/ports/servoshell/headless_window.rs +++ b/ports/servoshell/headless_window.rs @@ -15,7 +15,6 @@ use servo::rendering_context::RenderingContext; use servo::servo_geometry::DeviceIndependentPixel; use servo::style_traits::DevicePixel; use servo::webrender_api::units::DeviceIntRect; -use servo_media::player::context as MediaPlayerCtxt; use surfman::{Connection, Context, Device, SurfaceType}; use crate::events_loop::WakerEvent; @@ -144,18 +143,6 @@ impl WindowMethods for Window { self.animation_state.set(state); } - fn get_gl_context(&self) -> MediaPlayerCtxt::GlContext { - MediaPlayerCtxt::GlContext::Unknown - } - - fn get_native_display(&self) -> MediaPlayerCtxt::NativeDisplay { - MediaPlayerCtxt::NativeDisplay::Unknown - } - - fn get_gl_api(&self) -> MediaPlayerCtxt::GlApi { - MediaPlayerCtxt::GlApi::None - } - fn rendering_context(&self) -> RenderingContext { self.rendering_context.clone() }