Skip to content

Commit

Permalink
libservo: Handle GL video decoding setup internally (servo#31209)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
mrobinson authored and Taym95 committed Feb 11, 2024
1 parent 4a9906d commit 41000dd
Show file tree
Hide file tree
Showing 7 changed files with 125 additions and 156 deletions.
9 changes: 1 addition & 8 deletions components/compositing/windowing.rs
Expand Up @@ -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};
Expand Down Expand Up @@ -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;
}

Expand Down
137 changes: 117 additions & 20 deletions components/servo/lib.rs
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -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::{
Expand Down Expand Up @@ -388,30 +395,18 @@ 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(
Box::new(wgpu_image_handler),
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);

Expand Down Expand Up @@ -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<Mutex<WebrenderExternalImageRegistry>>,
rendering_context: &RenderingContext,
) -> (WindowGLContext, Option<GLPlayerThreads>) {
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 => {},
Expand Down
10 changes: 3 additions & 7 deletions ports/jniapi/src/lib.rs
Expand Up @@ -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)
};
}
Expand Down Expand Up @@ -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,
};
Expand Down
25 changes: 0 additions & 25 deletions ports/jniapi/src/simpleservo.rs
Expand Up @@ -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! {
Expand All @@ -56,8 +55,6 @@ pub struct InitOptions {
pub coordinates: Coordinates,
pub density: f32,
pub xr_discovery: Option<webxr::Discovery>,
pub gl_context_pointer: Option<*const c_void>,
pub native_display_pointer: Option<*const c_void>,
pub surfman_integration: SurfmanIntegration,
pub prefs: Option<HashMap<String, PrefValue>>,
}
Expand Down Expand Up @@ -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(),
});

Expand Down Expand Up @@ -861,8 +856,6 @@ struct ServoWindowCallbacks {
host_callbacks: Box<dyn HostTrait>,
coordinates: RefCell<Coordinates>,
density: f32,
gl_context_pointer: Option<*const c_void>,
native_display_pointer: Option<*const c_void>,
rendering_context: RenderingContext,
}

Expand Down Expand Up @@ -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;
Expand Down
4 changes: 3 additions & 1 deletion ports/servoshell/app.rs
Expand Up @@ -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;
Expand Down Expand Up @@ -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,
Expand Down

0 comments on commit 41000dd

Please sign in to comment.