Auto merge of #25334 - asajeffrey:gstplugins-misc-tidying-up, r=jdm

Gstreamer plugin running in wayland with surfman 0.2

<!-- Please describe your changes on the following line: -->

Tidying up the gstreamer plugin. The plugin now:

* uses surfman 0.2
* runs in wayland (but can't render WebGL content yet)
* gets its GL configuration from gstreamer
* uses GLsync if needed

---
<!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `___` with appropriate data: -->
- [x] `./mach build -d` does not report any errors
- [x] `./mach test-tidy` does not report any errors
- [x] These changes fix #24843
- [X] These changes do not require tests because

<!-- Also, please make sure that "Allow edits from maintainers" checkbox is checked, so that we can help you if you get stuck somewhere along the way.-->

<!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. -->
This commit is contained in:
bors-servo 2019-12-20 16:09:16 -05:00 committed by GitHub
commit 62899c0f52
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 316 additions and 133 deletions

56
Cargo.lock generated
View file

@ -478,8 +478,8 @@ dependencies = [
"raqote",
"servo_config",
"sparkle",
"surfman",
"surfman-chains",
"surfman 0.1.3",
"surfman-chains 0.2.1",
"surfman-chains-api",
"webrender",
"webrender_api",
@ -3000,7 +3000,7 @@ dependencies = [
"sparkle",
"style",
"style_traits",
"surfman",
"surfman 0.1.3",
"webdriver_server",
"webgpu",
"webrender",
@ -4816,8 +4816,8 @@ dependencies = [
"log",
"servo-media",
"sparkle",
"surfman",
"surfman-chains",
"surfman 0.2.0",
"surfman-chains 0.3.0",
"surfman-chains-api",
]
@ -5500,6 +5500,33 @@ dependencies = [
"x11",
]
[[package]]
name = "surfman"
version = "0.2.0"
source = "git+https://github.com/pcwalton/surfman?branch=multi#808e5c5906dbcc6707536c8bac8bcc9389b4e1eb"
dependencies = [
"bitflags",
"cgl 0.3.2",
"cocoa 0.19.1",
"core-foundation",
"core-graphics",
"display-link",
"euclid",
"gl_generator 0.11.0",
"io-surface",
"lazy_static",
"libc",
"log",
"mach",
"objc",
"parking_lot",
"wayland-sys 0.24.0",
"winapi",
"winit",
"wio",
"x11",
]
[[package]]
name = "surfman-chains"
version = "0.2.1"
@ -5510,7 +5537,20 @@ dependencies = [
"fnv",
"log",
"sparkle",
"surfman",
"surfman 0.1.3",
"surfman-chains-api",
]
[[package]]
name = "surfman-chains"
version = "0.3.0"
source = "git+https://github.com/asajeffrey/surfman-chains?branch=multi#80a71b1a2df71ae70c3c194d0af40b8ebf72968a"
dependencies = [
"euclid",
"fnv",
"log",
"sparkle",
"surfman 0.2.0",
"surfman-chains-api",
]
@ -6420,8 +6460,8 @@ dependencies = [
"log",
"openxr",
"serde",
"surfman",
"surfman-chains",
"surfman 0.1.3",
"surfman-chains 0.2.1",
"time",
"webxr-api",
"winapi",

View file

@ -491,9 +491,9 @@ def windows_unit(cached=True):
"mach smoketest --angle",
"mach package --dev",
"mach build --dev --libsimpleservo",
# We're getting link errors on windows, due to the x11 feature being
# enabled on gstreamer-gl. https://github.com/servo/media/pull/304/
"mach build --dev --media-stack=dummy -p servo-gst-plugin",
# The GStreamer plugin currently doesn't support Windows
# https://github.com/servo/servo/issues/25353
# "mach build --dev -p servo-gst-plugin",
)
.with_artifacts("repo/target/debug/msi/Servo.exe",

View file

@ -22,7 +22,7 @@ glib = { version = "0.8", features = ["subclassing"] }
gstreamer = { version = "0.14", features = ["subclassing"] }
gstreamer-base = { version = "0.14", features = ["subclassing"] }
gstreamer-gl = { version = "0.14" }
gstreamer-gl-sys = { version = "0.8" }
gstreamer-gl-sys = { version = "0.8", features = ["wayland"] }
gstreamer-sys = { version = "0.8" }
gstreamer-video = { version = "0.14", features = ["subclassing"] }
log = "0.4"
@ -30,10 +30,9 @@ lazy_static = "1.4"
libservo = {path = "../../components/servo"}
servo-media = {git = "https://github.com/servo/media"}
sparkle = "0.1"
# NOTE: the sm-angle-default feature only enables angle on windows, not other platforms!
surfman = { version = "0.1", features = ["sm-angle-default", "sm-osmesa"] }
surfman = { git = "https://github.com/pcwalton/surfman", branch = "multi" }
surfman-chains-api = "0.2"
surfman-chains = "0.2.1"
surfman-chains = { git = "https://github.com/asajeffrey/surfman-chains", branch = "multi" }
[build-dependencies]
gst-plugin-version-helper = "0.1"

View file

@ -1,5 +1,10 @@
# A GStreamer plugin which runs servo
## Supported platforms
* MacOS + CGL
* Linux + Wayland (currently no WebGL content)
## Build
```
@ -68,8 +73,6 @@ LD_LIBRARY_PATH=$PWD/support/linux/gstreamer/gst/lib \
## Troubleshooting running the plugin
*Currently x11 support is broken!*
First try:
```
GST_PLUGIN_PATH=target/gstplugins \

View file

@ -9,7 +9,7 @@ use lazy_static::lazy_static;
lazy_static! {
pub static ref CATEGORY: DebugCategory =
DebugCategory::new("servosrc", DebugColorFlags::empty(), Some("Servo"));
DebugCategory::new("servowebsrc", DebugColorFlags::empty(), Some("Servo"));
}
pub static LOGGER: ServoSrcLogger = ServoSrcLogger;

View file

@ -25,6 +25,7 @@ use glib::subclass::object::Property;
use glib::subclass::simple::ClassStruct;
use glib::subclass::types::ObjectSubclass;
use glib::translate::FromGlibPtrBorrow;
use glib::translate::ToGlibPtr;
use glib::value::Value;
use glib::ParamSpec;
use gstreamer::gst_element_error;
@ -55,6 +56,7 @@ use gstreamer_base::BaseSrcExt;
use gstreamer_gl::GLContext;
use gstreamer_gl::GLContextExt;
use gstreamer_gl::GLContextExtManual;
use gstreamer_gl::GLSyncMeta;
use gstreamer_gl_sys::gst_gl_context_thread_add;
use gstreamer_gl_sys::gst_gl_texture_target_to_gl;
use gstreamer_gl_sys::gst_is_gl_memory;
@ -63,6 +65,7 @@ use gstreamer_gl_sys::GstGLMemory;
use gstreamer_video::VideoInfo;
use log::debug;
use log::error;
use log::info;
use servo::compositing::windowing::AnimationState;
@ -80,14 +83,28 @@ use sparkle::gl;
use sparkle::gl::types::GLuint;
use sparkle::gl::Gl;
use surfman::platform::generic::universal::context::Context;
use surfman::platform::generic::universal::device::Device;
use surfman::connection::Connection as ConnectionAPI;
use surfman::device::Device as DeviceAPI;
use surfman::ContextAttributeFlags;
use surfman::ContextAttributes;
use surfman::GLApi;
use surfman::GLVersion;
use surfman::SurfaceAccess;
use surfman::SurfaceType;
use surfman_chains::SwapChain;
use surfman_chains_api::SwapChainAPI;
// For the moment, we only support wayland and cgl.
#[cfg(target_os = "macos")]
use surfman::platform::macos::cgl::device::Device;
#[cfg(all(unix, not(target_os = "macos")))]
use surfman::platform::unix::wayland::device::Device;
type Context = <Device as DeviceAPI>::Context;
type Connection = <Device as DeviceAPI>::Connection;
type NativeContext = <Device as DeviceAPI>::NativeContext;
type NativeConnection = <Connection as ConnectionAPI>::NativeConnection;
use std::cell::RefCell;
use std::collections::HashMap;
use std::convert::TryFrom;
@ -102,10 +119,11 @@ use std::time::Instant;
pub struct ServoWebSrc {
sender: Sender<ServoWebSrcMsg>,
swap_chain: SwapChain,
url: Mutex<Option<String>>,
info: Mutex<Option<VideoInfo>>,
buffer_pool: Mutex<Option<BufferPool>>,
gl_context: Mutex<Option<GLContext>>,
connection: Mutex<Option<Connection>>,
// When did the plugin get created?
start: Instant,
// How long should each frame last?
@ -119,6 +137,7 @@ pub struct ServoWebSrc {
struct ServoWebSrcGfx {
device: Device,
context: Context,
swap_chain: SwapChain<Device>,
gl: Rc<Gl>,
read_fbo: GLuint,
draw_fbo: GLuint,
@ -135,10 +154,18 @@ thread_local! {
static GFX_CACHE: RefCell<HashMap<GLContext, ServoWebSrcGfx>> = RefCell::new(HashMap::new());
}
struct ConnectionWhichImplementsDebug(Connection);
impl std::fmt::Debug for ConnectionWhichImplementsDebug {
fn fmt(&self, fmt: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
"Connection".fmt(fmt)
}
}
#[derive(Debug)]
enum ServoWebSrcMsg {
Start(ServoUrl),
GetSwapChain(Sender<SwapChain>),
Start(ConnectionWhichImplementsDebug, GLVersion, ServoUrl),
GetSwapChain(Sender<SwapChain<Device>>),
Resize(Size2D<i32, DevicePixel>),
Heartbeat,
Stop,
@ -152,18 +179,35 @@ const DEFAULT_FRAME_DURATION: Duration = Duration::from_micros(16_667);
struct ServoThread {
receiver: Receiver<ServoWebSrcMsg>,
swap_chain: SwapChain,
gfx: Rc<RefCell<ServoWebSrcGfx>>,
swap_chain: SwapChain<Device>,
gfx: Rc<RefCell<ServoThreadGfx>>,
servo: Servo<ServoWebSrcWindow>,
}
struct ServoThreadGfx {
device: Device,
context: Context,
gl: Rc<Gl>,
}
impl ServoThread {
fn new(receiver: Receiver<ServoWebSrcMsg>) -> Self {
let (connection, version, url) = match receiver.recv() {
Ok(ServoWebSrcMsg::Start(connection, version, url)) => (connection.0, version, url),
e => panic!("Failed to start ({:?})", e),
};
info!(
"Created new servo thread (GL v{}.{} for {})",
version.major, version.minor, url
);
let embedder = Box::new(ServoWebSrcEmbedder);
let window = Rc::new(ServoWebSrcWindow::new());
let window = Rc::new(ServoWebSrcWindow::new(connection, version));
let swap_chain = window.swap_chain.clone();
let gfx = window.gfx.clone();
let servo = Servo::new(embedder, window);
let mut servo = Servo::new(embedder, window);
let id = TopLevelBrowsingContextId::new();
servo.handle_events(vec![WindowEvent::NewBrowser(url, id)]);
Self {
receiver,
swap_chain,
@ -176,7 +220,7 @@ impl ServoThread {
while let Ok(msg) = self.receiver.recv() {
debug!("Servo thread handling message {:?}", msg);
match msg {
ServoWebSrcMsg::Start(url) => self.new_browser(url),
ServoWebSrcMsg::Start(..) => error!("Already started"),
ServoWebSrcMsg::GetSwapChain(sender) => sender
.send(self.swap_chain.clone())
.expect("Failed to send swap chain"),
@ -188,12 +232,6 @@ impl ServoThread {
self.servo.handle_events(vec![WindowEvent::Quit]);
}
fn new_browser(&mut self, url: ServoUrl) {
let id = TopLevelBrowsingContextId::new();
self.servo
.handle_events(vec![WindowEvent::NewBrowser(url, id)]);
}
fn resize(&mut self, size: Size2D<i32, DevicePixel>) {
{
let mut gfx = self.gfx.borrow_mut();
@ -251,53 +289,57 @@ impl EventLoopWaker for ServoWebSrcEmbedder {
}
struct ServoWebSrcWindow {
swap_chain: SwapChain,
gfx: Rc<RefCell<ServoWebSrcGfx>>,
swap_chain: SwapChain<Device>,
gfx: Rc<RefCell<ServoThreadGfx>>,
gl: Rc<dyn gleam::gl::Gl>,
}
impl ServoWebSrcWindow {
fn new() -> Self {
let version = surfman::GLVersion { major: 4, minor: 3 };
let flags = surfman::ContextAttributeFlags::empty();
let attributes = surfman::ContextAttributes { version, flags };
fn new(connection: Connection, version: GLVersion) -> Self {
let flags = ContextAttributeFlags::DEPTH |
ContextAttributeFlags::STENCIL |
ContextAttributeFlags::ALPHA;
let attributes = ContextAttributes { version, flags };
let connection = surfman::Connection::new().expect("Failed to create connection");
let adapter = surfman::Adapter::default().expect("Failed to create adapter");
let mut device =
surfman::Device::new(&connection, &adapter).expect("Failed to create device");
let adapter = connection
.create_adapter()
.expect("Failed to create adapter");
let mut device = connection
.create_device(&adapter)
.expect("Failed to create device");
let descriptor = device
.create_context_descriptor(&attributes)
.expect("Failed to create descriptor");
let context = device
let mut context = device
.create_context(&descriptor)
.expect("Failed to create context");
// This is a workaround for surfman having a different bootstrap API with Angle
#[cfg(target_os = "windows")]
let mut device = device;
#[cfg(not(target_os = "windows"))]
let mut device = Device::Hardware(device);
#[cfg(target_os = "windows")]
let mut context = context;
#[cfg(not(target_os = "windows"))]
let mut context = Context::Hardware(context);
let gleam =
unsafe { gleam::gl::GlFns::load_with(|s| device.get_proc_address(&context, s)) };
let gl = Gl::gl_fns(gl::ffi_gl::Gl::load_with(|s| {
let (gleam, gl) = unsafe {
match device.gl_api() {
GLApi::GL => (
gleam::gl::GlFns::load_with(|s| device.get_proc_address(&context, s)),
Gl::gl_fns(gl::ffi_gl::Gl::load_with(|s| {
device.get_proc_address(&context, s)
}));
})),
),
GLApi::GLES => (
gleam::gl::GlesFns::load_with(|s| device.get_proc_address(&context, s)),
Gl::gles_fns(gl::ffi_gles::Gles2::load_with(|s| {
device.get_proc_address(&context, s)
})),
),
}
};
device
.make_context_current(&mut context)
.expect("Failed to make context current");
debug_assert_eq!(gl.get_error(), gl::NO_ERROR);
let access = SurfaceAccess::GPUCPU;
let access = SurfaceAccess::GPUOnly;
let size = Size2D::new(512, 512);
let surface_type = SurfaceType::Generic { size };
let surface = device
.create_surface(&mut context, access, &surface_type)
.create_surface(&mut context, access, surface_type)
.expect("Failed to create surface");
device
@ -310,6 +352,8 @@ impl ServoWebSrcWindow {
.framebuffer_object;
gl.viewport(0, 0, size.width, size.height);
gl.bind_framebuffer(gl::FRAMEBUFFER, fbo);
gl.clear_color(0.0, 0.0, 0.0, 1.0);
gl.clear(gl::COLOR_BUFFER_BIT);
debug_assert_eq!(
(gl.check_framebuffer_status(gl::FRAMEBUFFER), gl.get_error()),
(gl::FRAMEBUFFER_COMPLETE, gl::NO_ERROR)
@ -318,17 +362,12 @@ impl ServoWebSrcWindow {
let swap_chain = SwapChain::create_attached(&mut device, &mut context, access)
.expect("Failed to create swap chain");
let read_fbo = gl.gen_framebuffers(1)[0];
let draw_fbo = gl.gen_framebuffers(1)[0];
device.make_no_context_current().unwrap();
let gfx = Rc::new(RefCell::new(ServoWebSrcGfx {
let gfx = Rc::new(RefCell::new(ServoThreadGfx {
device,
context,
gl,
read_fbo,
draw_fbo,
}));
Self {
@ -354,9 +393,9 @@ impl WindowMethods for ServoWebSrcWindow {
),
(gl::FRAMEBUFFER_COMPLETE, gl::NO_ERROR)
);
let _ = self
.swap_chain
.swap_buffers(&mut gfx.device, &mut gfx.context);
self.swap_chain
.swap_buffers(&mut gfx.device, &mut gfx.context)
.expect("Failed to swap buffers");
let fbo = gfx
.device
.context_surface_info(&gfx.context)
@ -381,6 +420,7 @@ impl WindowMethods for ServoWebSrcWindow {
gfx.device
.make_context_current(&mut gfx.context)
.expect("Failed to make context current");
debug!("EMBEDDER done make_context_current");
debug_assert_eq!(
(
gfx.gl.check_framebuffer_status(gl::FRAMEBUFFER),
@ -450,21 +490,21 @@ impl ObjectSubclass for ServoWebSrc {
fn new() -> Self {
let (sender, receiver) = crossbeam_channel::bounded(1);
thread::spawn(move || ServoThread::new(receiver).run());
let (acks, ackr) = crossbeam_channel::bounded(1);
let _ = sender.send(ServoWebSrcMsg::GetSwapChain(acks));
let swap_chain = ackr.recv().expect("Failed to get swap chain");
let info = Mutex::new(None);
let url = Mutex::new(None);
let buffer_pool = Mutex::new(None);
let gl_context = Mutex::new(None);
let connection = Mutex::new(None);
let start = Instant::now();
let frame_duration_micros = AtomicU64::new(DEFAULT_FRAME_DURATION.as_micros() as u64);
let next_frame_micros = AtomicU64::new(0);
Self {
sender,
swap_chain,
info,
url,
buffer_pool,
gl_context,
connection,
start,
frame_duration_micros,
next_frame_micros,
@ -527,7 +567,9 @@ impl ObjectImpl for ServoWebSrc {
impl ElementImpl for ServoWebSrc {}
impl BaseSrcImpl for ServoWebSrc {
fn set_caps(&self, src: &BaseSrc, outcaps: &Caps) -> Result<(), LoggableError> {
fn set_caps(&self, _src: &BaseSrc, outcaps: &Caps) -> Result<(), LoggableError> {
info!("Setting caps {:?}", outcaps);
// Save the video info for later use
let info = VideoInfo::from_caps(outcaps)
.ok_or_else(|| gst_loggable_error!(CATEGORY, "Failed to get video info"))?;
@ -545,21 +587,15 @@ impl BaseSrcImpl for ServoWebSrc {
.store(frame_duration_micros, Ordering::SeqCst);
}
// Get the downstream GL context
let mut gst_gl_context = std::ptr::null_mut();
let el = src.upcast_ref::<Element>();
unsafe {
gstreamer_gl_sys::gst_gl_query_local_gl_context(
el.as_ptr(),
gstreamer_sys::GST_PAD_SRC,
&mut gst_gl_context,
);
}
if gst_gl_context.is_null() {
return Err(gst_loggable_error!(CATEGORY, "Failed to get GL context"));
}
// Create a new buffer pool for GL memory
let gst_gl_context = self
.gl_context
.lock()
.unwrap()
.as_ref()
.expect("Set caps before starting")
.to_glib_none()
.0;
let gst_gl_buffer_pool =
unsafe { gstreamer_gl_sys::gst_gl_buffer_pool_new(gst_gl_context) };
if gst_gl_buffer_pool.is_null() {
@ -591,16 +627,63 @@ impl BaseSrcImpl for ServoWebSrc {
false
}
fn start(&self, _src: &BaseSrc) -> Result<(), ErrorMessage> {
fn start(&self, src: &BaseSrc) -> Result<(), ErrorMessage> {
info!("Starting");
let guard = self
// Get the URL
let url_guard = self
.url
.lock()
.map_err(|_| gst_error_msg!(ResourceError::Settings, ["Failed to lock mutex"]))?;
let url = guard.as_ref().map(|s| &**s).unwrap_or(DEFAULT_URL);
let url = ServoUrl::parse(url)
let url_string = url_guard.as_ref().map(|s| &**s).unwrap_or(DEFAULT_URL);
let url = ServoUrl::parse(url_string)
.map_err(|_| gst_error_msg!(ResourceError::Settings, ["Failed to parse url"]))?;
let _ = self.sender.send(ServoWebSrcMsg::Start(url));
// Get the downstream GL context
let mut gst_gl_context = std::ptr::null_mut();
let el = src.upcast_ref::<Element>();
unsafe {
gstreamer_gl_sys::gst_gl_query_local_gl_context(
el.as_ptr(),
gstreamer_sys::GST_PAD_SRC,
&mut gst_gl_context,
);
}
if gst_gl_context.is_null() {
return Err(gst_error_msg!(
ResourceError::Settings,
["Failed to get GL context"]
));
}
let gl_context = unsafe { GLContext::from_glib_borrow(gst_gl_context) };
let gl_version = gl_context.get_gl_version();
let version = GLVersion {
major: gl_version.0 as u8,
minor: gl_version.1 as u8,
};
// Get the surfman connection on the GL thread
let mut task = BootstrapSurfmanOnGLThread {
servo_web_src: self,
result: None,
};
let data = &mut task as *mut BootstrapSurfmanOnGLThread as *mut c_void;
unsafe {
gst_gl_context_thread_add(gst_gl_context, Some(bootstrap_surfman_on_gl_thread), data)
};
let connection = task.result.expect("Failed to get connection");
// Save the GL context and connection for later use
*self.gl_context.lock().expect("Poisoned lock") = Some(gl_context);
*self.connection.lock().expect("Poisoned lock") = Some(connection.clone());
// Inform servo we're starting
let _ = self.sender.send(ServoWebSrcMsg::Start(
ConnectionWhichImplementsDebug(connection),
version,
url,
));
Ok(())
}
@ -634,10 +717,12 @@ impl BaseSrcImpl for ServoWebSrc {
// Activate the pool if necessary
if !pool.is_active() {
debug!("Activating the buffer pool");
pool.set_active(true).map_err(|_| FlowError::Error)?;
}
// Get a buffer to fill
debug!("Acquiring a buffer");
let buffer = pool.acquire_buffer(None)?;
// Get the GL memory from the buffer
@ -657,23 +742,55 @@ impl BaseSrcImpl for ServoWebSrc {
// Fill the buffer on the GL thread
let result = Err(FlowError::Error);
let mut task = RunOnGLThread {
let mut task = FillOnGLThread {
servo_web_src: self,
src,
gl_memory,
result,
};
let data = &mut task as *mut RunOnGLThread as *mut c_void;
let data = &mut task as *mut FillOnGLThread as *mut c_void;
unsafe { gst_gl_context_thread_add(gl_memory.mem.context, Some(fill_on_gl_thread), data) };
task.result?;
// Put down a GL sync point if needed
if let Some(meta) = buffer.get_meta::<GLSyncMeta>() {
let gl_context = unsafe { GLContext::from_glib_borrow(gl_memory.mem.context) };
meta.set_sync_point(&gl_context);
}
// Wake up Servo
let _ = self.sender.send(ServoWebSrcMsg::Heartbeat);
Ok(buffer)
}
}
struct RunOnGLThread<'a> {
struct BootstrapSurfmanOnGLThread<'a> {
servo_web_src: &'a ServoWebSrc,
result: Option<Connection>,
}
unsafe extern "C" fn bootstrap_surfman_on_gl_thread(context: *mut GstGLContext, data: *mut c_void) {
let task = &mut *(data as *mut BootstrapSurfmanOnGLThread);
let gl_context = GLContext::from_glib_borrow(context);
task.result = task.servo_web_src.bootstrap_surfman(gl_context);
}
impl ServoWebSrc {
// Runs on the GL thread
fn bootstrap_surfman(&self, gl_context: GLContext) -> Option<Connection> {
gl_context
.activate(true)
.expect("Failed to activate GL context");
let native_connection =
NativeConnection::current().expect("Failed to bootstrap native connection");
let connection = unsafe { Connection::from_native_connection(native_connection) }
.expect("Failed to bootstrap surfman connection");
Some(connection)
}
}
struct FillOnGLThread<'a> {
servo_web_src: &'a ServoWebSrc,
src: &'a BaseSrc,
gl_memory: &'a GstGLMemory,
@ -681,7 +798,7 @@ struct RunOnGLThread<'a> {
}
unsafe extern "C" fn fill_on_gl_thread(context: *mut GstGLContext, data: *mut c_void) {
let task = &mut *(data as *mut RunOnGLThread);
let task = &mut *(data as *mut FillOnGLThread);
let gl_context = GLContext::from_glib_borrow(context);
task.result = task
.servo_web_src
@ -713,32 +830,51 @@ impl ServoWebSrc {
let mut gfx_cache = gfx_cache.borrow_mut();
let gfx = gfx_cache.entry(gl_context.clone()).or_insert_with(|| {
debug!("Bootstrapping surfman");
let (device, context) = unsafe { surfman::Device::from_current_context() }
.expect("Failed to bootstrap surfman");
// This is a workaround for surfman having a different bootstrap API with Angle
#[cfg(not(target_os = "windows"))]
let device = Device::Hardware(device);
#[cfg(not(target_os = "windows"))]
let context = Context::Hardware(context);
let connection_guard = self.connection.lock().unwrap();
let connection = connection_guard.as_ref().expect("Failed to get surfman");
let adapter = connection
.create_adapter()
.expect("Failed to bootstrap surfman adapter");
let device = connection
.create_device(&adapter)
.expect("Failed to bootstrap surfman device");
let native_context =
NativeContext::current().expect("Failed to bootstrap native context");
let context = unsafe {
device
.create_context_from_native_context(native_context)
.expect("Failed to bootstrap surfman context")
};
debug!("Creating GL bindings");
let gl = Gl::gl_fns(gl::ffi_gl::Gl::load_with(|s| {
gl_context.get_proc_address(s) as *const _
}));
let draw_fbo = gl.gen_framebuffers(1)[0];
let read_fbo = gl.gen_framebuffers(1)[0];
debug!("Getting the swap chain");
let (acks, ackr) = crossbeam_channel::bounded(1);
let _ = self.sender.send(ServoWebSrcMsg::GetSwapChain(acks));
let swap_chain = ackr.recv().expect("Failed to get swap chain");
ServoWebSrcGfx {
device,
context,
swap_chain,
gl,
read_fbo,
draw_fbo,
}
});
gfx.device
.make_context_current(&gfx.context)
.expect("Failed to make surfman context current");
debug_assert_eq!(gfx.gl.get_error(), gl::NO_ERROR);
// Save the current GL state
debug!("Saving the GL context");
let mut bound_fbos = [0, 0];
unsafe {
gfx.gl
@ -751,17 +887,18 @@ impl ServoWebSrc {
gfx.gl.framebuffer_texture_2d(
gl::FRAMEBUFFER,
gl::COLOR_ATTACHMENT0,
gl::TEXTURE_2D,
draw_texture_target,
draw_texture_id,
0,
);
debug_assert_eq!(gfx.gl.get_error(), gl::NO_ERROR);
gfx.gl.clear_color(0.3, 0.2, 0.1, 1.0);
gfx.gl.clear_color(0.0, 0.0, 0.0, 1.0);
gfx.gl.clear(gl::COLOR_BUFFER_BIT);
debug_assert_eq!(gfx.gl.get_error(), gl::NO_ERROR);
if let Some(surface) = self.swap_chain.take_surface() {
if let Some(surface) = gfx.swap_chain.take_surface() {
debug!("Rendering surface");
let surface_size = Size2D::from_untyped(gfx.device.surface_info(&surface).size);
if size != surface_size {
// If we're being asked to fill frames that are a different size than servo is providing,
@ -769,13 +906,23 @@ impl ServoWebSrc {
let _ = self.sender.send(ServoWebSrcMsg::Resize(size));
}
if size.width <= 0 || size.height <= 0 {
info!("Surface is zero-sized");
gfx.swap_chain.recycle_surface(surface);
return;
}
let surface_texture = gfx
.device
.create_surface_texture(&mut gfx.context, surface)
.unwrap();
let read_texture_id = surface_texture.gl_texture();
let read_texture_id = gfx.device.surface_texture_object(&surface_texture);
let read_texture_target = gfx.device.surface_gl_texture_target();
debug!(
"Filling with {}/{} {}",
read_texture_id, read_texture_target, surface_size
);
gfx.gl.bind_framebuffer(gl::READ_FRAMEBUFFER, gfx.read_fbo);
gfx.gl.framebuffer_texture_2d(
gl::READ_FRAMEBUFFER,
@ -794,26 +941,18 @@ impl ServoWebSrc {
);
debug_assert_eq!(
(
gfx.gl.check_framebuffer_status(gl::FRAMEBUFFER),
gfx.gl.check_framebuffer_status(gl::READ_FRAMEBUFFER),
gfx.gl.check_framebuffer_status(gl::DRAW_FRAMEBUFFER),
gfx.gl.get_error()
),
(gl::FRAMEBUFFER_COMPLETE, gl::NO_ERROR)
);
gfx.gl.clear_color(0.3, 0.7, 0.3, 0.0);
gfx.gl.clear(gl::COLOR_BUFFER_BIT);
debug_assert_eq!(
(
gfx.gl.check_framebuffer_status(gl::FRAMEBUFFER),
gfx.gl.get_error()
),
(gl::FRAMEBUFFER_COMPLETE, gl::NO_ERROR)
gl::FRAMEBUFFER_COMPLETE,
gl::FRAMEBUFFER_COMPLETE,
gl::NO_ERROR
)
);
debug!(
"Filling with {}/{} {}",
read_texture_id, read_texture_target, surface_size
);
debug!("Blitting");
gfx.gl.blit_framebuffer(
0,
0,
@ -838,7 +977,7 @@ impl ServoWebSrc {
.device
.destroy_surface_texture(&mut gfx.context, surface_texture)
.unwrap();
self.swap_chain.recycle_surface(surface);
gfx.swap_chain.recycle_surface(surface);
} else {
debug!("Failed to get current surface");
}
@ -851,11 +990,8 @@ impl ServoWebSrc {
debug_assert_eq!(gfx.gl.get_error(), gl::NO_ERROR);
});
gl_context.activate(false).map_err(|_| {
gst_element_error!(src, CoreError::Failed, ["Failed to deactivate GL context"]);
FlowError::Error
})?;
Ok(())
}
}
// TODO: Implement that trait for more platforms

View file

@ -44,6 +44,11 @@ packages = [
# https://github.com/servo/servo/issues/24421
"proc-macro2",
"quote",
# These can be removed once servo is updated to surfman 0.2
"surfman",
"surfman-chains",
"syn",
"smallvec",
"unicode-xid",