Skip to content

Commit

Permalink
Make wayland happier by sharing a Connection between servo and gstreamer
Browse files Browse the repository at this point in the history
  • Loading branch information
Alan Jeffrey committed Dec 19, 2019
1 parent aca438a commit 9f52997
Show file tree
Hide file tree
Showing 2 changed files with 74 additions and 26 deletions.
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

98 changes: 73 additions & 25 deletions ports/gstplugin/servowebsrc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ pub struct ServoWebSrc {
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?
Expand Down Expand Up @@ -156,9 +157,17 @@ 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(GLVersion, ServoUrl),
Start(ConnectionWhichImplementsDebug, GLVersion, ServoUrl),
GetSwapChain(Sender<SwapChain<Device>>),
Resize(Size2D<i32, DevicePixel>),
Heartbeat,
Expand Down Expand Up @@ -186,16 +195,16 @@ struct ServoThreadGfx {

impl ServoThread {
fn new(receiver: Receiver<ServoWebSrcMsg>) -> Self {
let (version, url) = match receiver.recv() {
Ok(ServoWebSrcMsg::Start(version, url)) => (version, url),
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(version));
let window = Rc::new(ServoWebSrcWindow::new(connection, version));
let swap_chain = window.swap_chain.clone();
let gfx = window.gfx.clone();
let mut servo = Servo::new(embedder, window);
Expand Down Expand Up @@ -289,13 +298,12 @@ struct ServoWebSrcWindow {
}

impl ServoWebSrcWindow {
fn new(version: GLVersion) -> Self {
fn new(connection: Connection, version: GLVersion) -> Self {
let flags = ContextAttributeFlags::DEPTH |
ContextAttributeFlags::STENCIL |
ContextAttributeFlags::ALPHA;
let attributes = ContextAttributes { version, flags };

let connection = Connection::new().expect("Failed to create connection");
let adapter = connection
.create_adapter()
.expect("Failed to create adapter");
Expand Down Expand Up @@ -330,7 +338,7 @@ impl ServoWebSrcWindow {
.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
Expand Down Expand Up @@ -489,6 +497,7 @@ impl ObjectSubclass for ServoWebSrc {
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);
Expand All @@ -498,6 +507,7 @@ impl ObjectSubclass for ServoWebSrc {
url,
buffer_pool,
gl_context,
connection,
start,
frame_duration_micros,
next_frame_micros,
Expand Down Expand Up @@ -650,21 +660,33 @@ impl BaseSrcImpl for ServoWebSrc {
}
let gl_context = unsafe { GLContext::from_glib_borrow(gst_gl_context) };
let gl_version = gl_context.get_gl_version();
let version = if cfg!(all(unix, not(target_os = "macos"))) {
// TODO this is just a workaround. Fix it!
GLVersion { major: 3, minor: 0 }
} else {
GLVersion {
major: gl_version.0 as u8,
minor: gl_version.1 as u8,
}
let version = GLVersion {
major: gl_version.0 as u8,
minor: gl_version.1 as u8,
};

// Save the GL context for later use
// 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(version, url));
let _ = self.sender.send(ServoWebSrcMsg::Start(
ConnectionWhichImplementsDebug(connection),
version,
url,
));
Ok(())
}

Expand Down Expand Up @@ -723,14 +745,14 @@ 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?;

Expand All @@ -749,15 +771,40 @@ impl BaseSrcImpl for ServoWebSrc {
}
}

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,
result: Result<(), FlowError>,
}

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
Expand Down Expand Up @@ -789,10 +836,8 @@ 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 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");
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");
Expand Down Expand Up @@ -829,6 +874,9 @@ impl ServoWebSrc {
}
});

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
Expand Down

0 comments on commit 9f52997

Please sign in to comment.