aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorbors-servo <lbergstrom+bors@mozilla.com>2019-12-20 16:09:16 -0500
committerGitHub <noreply@github.com>2019-12-20 16:09:16 -0500
commit62899c0f52dd7ecbae89690109e2d50806a1ca9c (patch)
treefeae175f0ed4cb874b99b1f0cc09cd9923e7c237
parent352e2277eb2cd0a72393e20aac9ac40d1e44de44 (diff)
parentb5943f5ab36b3ef718a7908a1b624f077b9ab79c (diff)
downloadservo-62899c0f52dd7ecbae89690109e2d50806a1ca9c.tar.gz
servo-62899c0f52dd7ecbae89690109e2d50806a1ca9c.zip
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. -->
-rw-r--r--Cargo.lock56
-rw-r--r--etc/taskcluster/decision_task.py6
-rw-r--r--ports/gstplugin/Cargo.toml7
-rw-r--r--ports/gstplugin/README.md7
-rw-r--r--ports/gstplugin/logging.rs2
-rw-r--r--ports/gstplugin/servowebsrc.rs370
-rw-r--r--servo-tidy.toml5
7 files changed, 318 insertions, 135 deletions
diff --git a/Cargo.lock b/Cargo.lock
index a34068606bd..74c26708e59 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -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",
]
@@ -5501,6 +5501,33 @@ dependencies = [
]
[[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"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -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",
diff --git a/etc/taskcluster/decision_task.py b/etc/taskcluster/decision_task.py
index 7c9b521dac8..a3d70653794 100644
--- a/etc/taskcluster/decision_task.py
+++ b/etc/taskcluster/decision_task.py
@@ -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",
diff --git a/ports/gstplugin/Cargo.toml b/ports/gstplugin/Cargo.toml
index 33c97e04648..04393709477 100644
--- a/ports/gstplugin/Cargo.toml
+++ b/ports/gstplugin/Cargo.toml
@@ -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"
diff --git a/ports/gstplugin/README.md b/ports/gstplugin/README.md
index ca9d30ed87d..a2827161c82 100644
--- a/ports/gstplugin/README.md
+++ b/ports/gstplugin/README.md
@@ -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 \
diff --git a/ports/gstplugin/logging.rs b/ports/gstplugin/logging.rs
index f4838ec015d..5f12bd1ad24 100644
--- a/ports/gstplugin/logging.rs
+++ b/ports/gstplugin/logging.rs
@@ -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;
diff --git a/ports/gstplugin/servowebsrc.rs b/ports/gstplugin/servowebsrc.rs
index 57572e3b0d2..fc2320ad0ba 100644
--- a/ports/gstplugin/servowebsrc.rs
+++ b/ports/gstplugin/servowebsrc.rs
@@ -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 };
-
- 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");
+ fn new(connection: Connection, version: GLVersion) -> Self {
+ let flags = ContextAttributeFlags::DEPTH |
+ ContextAttributeFlags::STENCIL |
+ ContextAttributeFlags::ALPHA;
+ let attributes = ContextAttributes { version, flags };
+
+ 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| {
- device.get_proc_address(&context, 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
diff --git a/servo-tidy.toml b/servo-tidy.toml
index 3996a058c74..6482c47eeb7 100644
--- a/servo-tidy.toml
+++ b/servo-tidy.toml
@@ -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",