Skip to content

Commit

Permalink
Added headless guards to EGL and GLX. Gets rid of libc dependency.
Browse files Browse the repository at this point in the history
Signed-off-by: Hal Gentz <[email protected]>
  • Loading branch information
goddessfreya committed Mar 20, 2019
1 parent 600030a commit caf5a2b
Show file tree
Hide file tree
Showing 16 changed files with 372 additions and 210 deletions.
1 change: 0 additions & 1 deletion glutin/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ serde = ["winit/serde"]

[dependencies]
lazy_static = "1.1"
libc = "0.2"
winit = "0.19"

[target.'cfg(target_os = "android")'.dependencies]
Expand Down
1 change: 0 additions & 1 deletion glutin/src/api/android/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ use crate::{
};

use glutin_egl_sys as ffi;
use libc;
use winit;
use winit::dpi;
use winit::os::android::EventsLoopExt;
Expand Down
30 changes: 15 additions & 15 deletions glutin/src/api/caca/ffi.rs
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@
#![allow(non_camel_case_types)]

use libc;
use std::os::raw;

pub type caca_display_t = libc::c_void;
pub type caca_canvas_t = libc::c_void;
pub type caca_dither_t = libc::c_void;
pub type caca_display_t = raw::c_void;
pub type caca_canvas_t = raw::c_void;
pub type caca_dither_t = raw::c_void;

shared_library!(LibCaca, "libcaca.so.0",
pub fn caca_create_display(cv: *mut caca_canvas_t) -> *mut caca_display_t,
pub fn caca_free_display(dp: *mut caca_display_t) -> libc::c_int,
pub fn caca_free_display(dp: *mut caca_display_t) -> raw::c_int,
pub fn caca_get_canvas(dp: *mut caca_display_t) -> *mut caca_canvas_t,
pub fn caca_refresh_display(dp: *mut caca_display_t) -> libc::c_int,
pub fn caca_dither_bitmap(cv: *mut caca_canvas_t, x: libc::c_int, y: libc::c_int,
w: libc::c_int, h: libc::c_int, d: *const caca_dither_t,
pixels: *const libc::c_void) -> libc::c_int,
pub fn caca_free_dither(d: *mut caca_dither_t) -> libc::c_int,
pub fn caca_create_dither(bpp: libc::c_int, w: libc::c_int, h: libc::c_int,
pitch: libc::c_int, rmask: libc::uint32_t, gmask: libc::uint32_t,
bmask: libc::uint32_t, amask: libc::uint32_t) -> *mut caca_dither_t,
pub fn caca_get_canvas_width(cv: *mut caca_canvas_t) -> libc::c_int,
pub fn caca_get_canvas_height(cv: *mut caca_canvas_t) -> libc::c_int,
pub fn caca_refresh_display(dp: *mut caca_display_t) -> raw::c_int,
pub fn caca_dither_bitmap(cv: *mut caca_canvas_t, x: raw::c_int, y: raw::c_int,
w: raw::c_int, h: raw::c_int, d: *const caca_dither_t,
pixels: *const raw::c_void) -> raw::c_int,
pub fn caca_free_dither(d: *mut caca_dither_t) -> raw::c_int,
pub fn caca_create_dither(bpp: raw::c_int, w: raw::c_int, h: raw::c_int,
pitch: raw::c_int, rmask: u32, gmask: u32,
bmask: u32, amask: u32) -> *mut caca_dither_t,
pub fn caca_get_canvas_width(cv: *mut caca_canvas_t) -> raw::c_int,
pub fn caca_get_canvas_height(cv: *mut caca_canvas_t) -> raw::c_int,
);
12 changes: 6 additions & 6 deletions glutin/src/api/caca/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ use crate::{
PixelFormatRequirements,
};

use libc;
use winit::dpi;

use std::os::raw;
use std::path::Path;

#[derive(DebugStub)]
Expand Down Expand Up @@ -71,9 +71,9 @@ impl Context {
let masks = get_masks();
(libcaca.caca_create_dither)(
32,
dims.0 as libc::c_int,
dims.1 as libc::c_int,
dims.0 as libc::c_int * 4,
dims.0 as raw::c_int,
dims.1 as raw::c_int,
dims.0 as raw::c_int * 4,
masks.0,
masks.1,
masks.2,
Expand Down Expand Up @@ -130,8 +130,8 @@ impl Context {
canvas,
0,
0,
width as libc::c_int,
height as libc::c_int,
width as raw::c_int,
height as raw::c_int,
self.dither,
buffer.as_ptr() as *const _,
);
Expand Down
108 changes: 108 additions & 0 deletions glutin/src/api/egl/make_current_guard.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
use glutin_egl_sys as ffi;

/// A guard for when you want to make the context current. Destroying the guard
/// restores the previously-current context.
#[derive(Debug)]
pub struct MakeCurrentGuard {
old_display: ffi::egl::types::EGLDisplay,
possibly_invalid: Option<MakeCurrentGuardInner>,
}

#[derive(Debug, PartialEq)]
struct MakeCurrentGuardInner {
old_draw_surface: ffi::egl::types::EGLSurface,
old_read_surface: ffi::egl::types::EGLSurface,
old_context: ffi::egl::types::EGLContext,
}

impl MakeCurrentGuard {
pub fn new(
display: ffi::egl::types::EGLDisplay,
draw_surface: ffi::egl::types::EGLSurface,
read_surface: ffi::egl::types::EGLSurface,
context: ffi::egl::types::EGLContext,
) -> Result<Self, String> {
unsafe {
let egl = super::EGL.as_ref().unwrap();

let ret = MakeCurrentGuard {
old_display: egl.GetCurrentDisplay(),
possibly_invalid: Some(MakeCurrentGuardInner {
old_draw_surface: egl
.GetCurrentSurface(ffi::egl::DRAW as i32),
old_read_surface: egl
.GetCurrentSurface(ffi::egl::READ as i32),
old_context: egl.GetCurrentContext(),
}),
};

let res =
egl.MakeCurrent(display, draw_surface, read_surface, context);

if res == 0 {
let err = egl.GetError();
Err(format!("`eglMakeCurrent` failed: {:?}", err))
} else {
Ok(ret)
}
}
}

pub fn if_any_same_then_invalidate(
&mut self,
display: ffi::egl::types::EGLDisplay,
draw_surface: ffi::egl::types::EGLSurface,
read_surface: ffi::egl::types::EGLSurface,
context: ffi::egl::types::EGLContext,
) {
if self.possibly_invalid.is_some() {
let mgi = MakeCurrentGuardInner {
old_draw_surface: draw_surface,
old_read_surface: read_surface,
old_context: context,
};

if self.old_display == display || self.possibly_invalid == Some(mgi)
{
self.invalidate();
}
}
}

pub fn invalidate(&mut self) {
self.possibly_invalid.take();
}
}

impl Drop for MakeCurrentGuard {
fn drop(&mut self) {
let egl = super::EGL.as_ref().unwrap();
let (draw_surface, read_surface, context) =
match self.possibly_invalid.take() {
Some(inner) => (
inner.old_draw_surface,
inner.old_read_surface,
inner.old_context,
),
None => (
ffi::egl::NO_SURFACE,
ffi::egl::NO_SURFACE,
ffi::egl::NO_CONTEXT,
),
};

unsafe {
let res = egl.MakeCurrent(
self.old_display,
draw_surface,
read_surface,
context,
);

if res == 0 {
let err = egl.GetError();
panic!("`eglMakeCurrent` failed: {:?}", err)
}
}
}
}
43 changes: 20 additions & 23 deletions glutin/src/api/egl/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ mod egl {
#[derive(Clone)]
pub struct Egl(pub SymWrapper<ffi::egl::Egl>);

/// Because `*const libc::c_void` doesn't implement `Sync`.
/// Because `*const raw::c_void` doesn't implement `Sync`.
unsafe impl Sync for Egl {}

impl SymTrait for ffi::egl::Egl {
Expand Down Expand Up @@ -56,7 +56,10 @@ mod egl {
}
}

mod make_current_guard;

pub use self::egl::Egl;
use self::make_current_guard::MakeCurrentGuard;
use crate::{
Api, ContextError, CreationError, GlAttributes, GlRequest, PixelFormat,
PixelFormatRequirements, ReleaseBehavior, Robustness,
Expand Down Expand Up @@ -565,36 +568,30 @@ impl Drop for Context {
let egl = EGL.as_ref().unwrap();
unsafe {
// Ok, so we got to call `glFinish` before destroying the context to
// insure it actually gets destroyed. This requires making the this
// ensure it actually gets destroyed. This requires making the this
// context current.
//
// Now, if the user has multiple contexts, and they drop this one
// unintentionally between calls to the other context, this could
// result in a !FUN! time debuging.
//
// Then again, if they're **unintentionally** dropping contexts, I
// think they got bigger problems.
self.make_current().unwrap();
let mut guard = MakeCurrentGuard::new(
self.display,
self.surface.get(),
self.surface.get(),
self.context,
)
.map_err(|err| ContextError::OsError(err))
.unwrap();

guard.if_any_same_then_invalidate(
self.display,
self.surface.get(),
self.surface.get(),
self.context,
);

let gl_finish_fn = self.get_proc_address("glFinish");
assert!(gl_finish_fn != std::ptr::null());
let gl_finish_fn =
std::mem::transmute::<_, extern "system" fn()>(gl_finish_fn);
gl_finish_fn();

let ret = egl.MakeCurrent(
self.display,
ffi::egl::NO_SURFACE,
ffi::egl::NO_SURFACE,
ffi::egl::NO_CONTEXT,
);
if ret == 0 {
panic!(
"drop: eglMakeCurrent failed with 0x{:x}",
egl.GetError()
)
}

egl.DestroyContext(self.display, self.context);
egl.DestroySurface(self.display, self.surface.get());
self.surface.set(ffi::egl::NO_SURFACE);
Expand Down
77 changes: 77 additions & 0 deletions glutin/src/api/glx/make_current_guard.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
use glutin_glx_sys as ffi;
use winit::os::unix::x11::XConnection;

use std::sync::Arc;

/// A guard for when you want to make the context current. Destroying the guard
/// restores the previously-current context.
#[derive(Debug)]
pub struct MakeCurrentGuard {
old_display: *mut ffi::Display,
xconn: Arc<XConnection>,
possibly_invalid: Option<MakeCurrentGuardInner>,
}

#[derive(Debug)]
struct MakeCurrentGuardInner {
old_drawable: ffi::glx::types::GLXDrawable,
old_context: ffi::GLXContext,
}

impl MakeCurrentGuard {
pub fn new(
xconn: &Arc<XConnection>,
drawable: ffi::glx::types::GLXDrawable,
context: ffi::GLXContext,
) -> Result<Self, String> {
unsafe {
let glx = super::GLX.as_ref().unwrap();

let ret = MakeCurrentGuard {
old_display: glx.GetCurrentDisplay() as *mut _,
xconn: Arc::clone(xconn),
possibly_invalid: Some(MakeCurrentGuardInner {
old_drawable: glx.GetCurrentDrawable(),
old_context: glx.GetCurrentContext(),
}),
};

let res =
glx.MakeCurrent(xconn.display as *mut _, drawable, context);

if res == 0 {
let err = xconn.check_errors();
Err(format!("`glXMakeCurrent` failed: {:?}", err))
} else {
Ok(ret)
}
}
}

pub fn old_context(&mut self) -> Option<ffi::GLXContext> {
self.possibly_invalid.as_ref().map(|pi| pi.old_context)
}

pub fn invalidate(&mut self) {
self.possibly_invalid.take();
}
}

impl Drop for MakeCurrentGuard {
fn drop(&mut self) {
let glx = super::GLX.as_ref().unwrap();
let (drawable, context) = match self.possibly_invalid.take() {
Some(inner) => (inner.old_drawable, inner.old_context),
None => (0, std::ptr::null()),
};

let res = unsafe {
glx.MakeCurrent(self.old_display as *mut _, drawable, context)
};

if res == 0 {
let err = self.xconn.check_errors();
panic!("`glXMakeCurrent` failed: {:?}", err);
}
}
}
Loading

0 comments on commit caf5a2b

Please sign in to comment.