mirror of
https://github.com/italicsjenga/winit-sonoma-fix.git
synced 2024-12-24 06:11:30 +11:00
Split GLX and X11 in "api"
This commit is contained in:
parent
7eeb96909c
commit
5561e58646
187
src/api/glx/mod.rs
Normal file
187
src/api/glx/mod.rs
Normal file
|
@ -0,0 +1,187 @@
|
|||
#![cfg(all(target_os = "linux", feature = "window"))]
|
||||
|
||||
use BuilderAttribs;
|
||||
use CreationError;
|
||||
use GlRequest;
|
||||
use Api;
|
||||
|
||||
use libc;
|
||||
use std::ffi::CString;
|
||||
use std::{mem, ptr};
|
||||
|
||||
use api::x11::ffi;
|
||||
|
||||
pub struct Context {
|
||||
display: *mut ffi::Display,
|
||||
window: ffi::Window,
|
||||
context: ffi::GLXContext,
|
||||
}
|
||||
|
||||
// TODO: remove me
|
||||
fn with_c_str<F, T>(s: &str, f: F) -> T where F: FnOnce(*const libc::c_char) -> T {
|
||||
use std::ffi::CString;
|
||||
let c_str = CString::new(s.as_bytes().to_vec()).unwrap();
|
||||
f(c_str.as_ptr())
|
||||
}
|
||||
|
||||
impl Context {
|
||||
pub fn new(builder: BuilderAttribs, display: *mut ffi::Display, window: ffi::Window,
|
||||
fb_config: ffi::glx::types::GLXFBConfig, mut visual_infos: ffi::glx::types::XVisualInfo)
|
||||
-> Result<Context, CreationError>
|
||||
{
|
||||
// creating GL context
|
||||
let (context, extra_functions) = unsafe {
|
||||
let mut attributes = Vec::new();
|
||||
|
||||
match builder.gl_version {
|
||||
GlRequest::Latest => {},
|
||||
GlRequest::Specific(Api::OpenGl, (major, minor)) => {
|
||||
attributes.push(ffi::glx_extra::CONTEXT_MAJOR_VERSION_ARB as libc::c_int);
|
||||
attributes.push(major as libc::c_int);
|
||||
attributes.push(ffi::glx_extra::CONTEXT_MINOR_VERSION_ARB as libc::c_int);
|
||||
attributes.push(minor as libc::c_int);
|
||||
},
|
||||
GlRequest::Specific(_, _) => panic!("Only OpenGL is supported"),
|
||||
GlRequest::GlThenGles { opengl_version: (major, minor), .. } => {
|
||||
attributes.push(ffi::glx_extra::CONTEXT_MAJOR_VERSION_ARB as libc::c_int);
|
||||
attributes.push(major as libc::c_int);
|
||||
attributes.push(ffi::glx_extra::CONTEXT_MINOR_VERSION_ARB as libc::c_int);
|
||||
attributes.push(minor as libc::c_int);
|
||||
},
|
||||
}
|
||||
|
||||
if builder.gl_debug {
|
||||
attributes.push(ffi::glx_extra::CONTEXT_FLAGS_ARB as libc::c_int);
|
||||
attributes.push(ffi::glx_extra::CONTEXT_DEBUG_BIT_ARB as libc::c_int);
|
||||
}
|
||||
|
||||
attributes.push(0);
|
||||
|
||||
// loading the extra GLX functions
|
||||
let extra_functions = ffi::glx_extra::Glx::load_with(|addr| {
|
||||
with_c_str(addr, |s| {
|
||||
ffi::glx::GetProcAddress(s as *const u8) as *const libc::c_void
|
||||
})
|
||||
});
|
||||
|
||||
let share = if let Some(win) = builder.sharing {
|
||||
match win.x.context {
|
||||
::api::x11::Context::Glx(ref c) => c.context,
|
||||
_ => panic!("Cannot share contexts between different APIs")
|
||||
}
|
||||
} else {
|
||||
ptr::null()
|
||||
};
|
||||
|
||||
let mut context = if extra_functions.CreateContextAttribsARB.is_loaded() {
|
||||
extra_functions.CreateContextAttribsARB(display as *mut ffi::glx_extra::types::Display,
|
||||
fb_config, share, 1, attributes.as_ptr())
|
||||
} else {
|
||||
ptr::null()
|
||||
};
|
||||
|
||||
if context.is_null() {
|
||||
context = ffi::glx::CreateContext(display as *mut _, &mut visual_infos, share, 1)
|
||||
}
|
||||
|
||||
if context.is_null() {
|
||||
return Err(CreationError::OsError(format!("GL context creation failed")));
|
||||
}
|
||||
|
||||
(context, extra_functions)
|
||||
};
|
||||
|
||||
// vsync
|
||||
if builder.vsync {
|
||||
unsafe { ffi::glx::MakeCurrent(display as *mut _, window, context) };
|
||||
|
||||
if extra_functions.SwapIntervalEXT.is_loaded() {
|
||||
// this should be the most common extension
|
||||
unsafe {
|
||||
extra_functions.SwapIntervalEXT(display as *mut _, window, 1);
|
||||
}
|
||||
|
||||
// checking that it worked
|
||||
if builder.strict {
|
||||
let mut swap = unsafe { mem::uninitialized() };
|
||||
unsafe {
|
||||
ffi::glx::QueryDrawable(display as *mut _, window,
|
||||
ffi::glx_extra::SWAP_INTERVAL_EXT as i32,
|
||||
&mut swap);
|
||||
}
|
||||
|
||||
if swap != 1 {
|
||||
return Err(CreationError::OsError(format!("Couldn't setup vsync: expected \
|
||||
interval `1` but got `{}`", swap)));
|
||||
}
|
||||
}
|
||||
|
||||
// GLX_MESA_swap_control is not official
|
||||
/*} else if extra_functions.SwapIntervalMESA.is_loaded() {
|
||||
unsafe {
|
||||
extra_functions.SwapIntervalMESA(1);
|
||||
}*/
|
||||
|
||||
} else if extra_functions.SwapIntervalSGI.is_loaded() {
|
||||
unsafe {
|
||||
extra_functions.SwapIntervalSGI(1);
|
||||
}
|
||||
|
||||
} else if builder.strict {
|
||||
return Err(CreationError::OsError(format!("Couldn't find any available vsync extension")));
|
||||
}
|
||||
|
||||
unsafe { ffi::glx::MakeCurrent(display as *mut _, 0, ptr::null()) };
|
||||
}
|
||||
|
||||
Ok(Context {
|
||||
display: display,
|
||||
window: window,
|
||||
context: context,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn make_current(&self) {
|
||||
let res = unsafe { ffi::glx::MakeCurrent(self.display as *mut _, self.window, self.context) };
|
||||
if res == 0 {
|
||||
panic!("glx::MakeCurrent failed");
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_current(&self) -> bool {
|
||||
unsafe { ffi::glx::GetCurrentContext() == self.context }
|
||||
}
|
||||
|
||||
pub fn get_proc_address(&self, addr: &str) -> *const () {
|
||||
let addr = CString::new(addr.as_bytes()).unwrap();
|
||||
let addr = addr.as_ptr();
|
||||
unsafe {
|
||||
ffi::glx::GetProcAddress(addr as *const _) as *const ()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn swap_buffers(&self) {
|
||||
unsafe {
|
||||
ffi::glx::SwapBuffers(self.display as *mut _, self.window)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_api(&self) -> ::Api {
|
||||
::Api::OpenGl
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl Send for Context {}
|
||||
unsafe impl Sync for Context {}
|
||||
|
||||
impl Drop for Context {
|
||||
fn drop(&mut self) {
|
||||
use std::ptr;
|
||||
|
||||
unsafe {
|
||||
// we don't call MakeCurrent(0, 0) because we are not sure that the context
|
||||
// is still the current one
|
||||
ffi::glx::DestroyContext(self.display as *mut _, self.context);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
pub mod android;
|
||||
pub mod cocoa;
|
||||
pub mod egl;
|
||||
pub mod glx;
|
||||
pub mod osmesa;
|
||||
pub mod win32;
|
||||
pub mod x11;
|
||||
|
|
|
@ -15,11 +15,13 @@ use CursorState;
|
|||
use GlRequest;
|
||||
use PixelFormat;
|
||||
|
||||
use api::glx::Context as GlxContext;
|
||||
|
||||
pub use self::monitor::{MonitorID, get_available_monitors, get_primary_monitor};
|
||||
|
||||
mod events;
|
||||
mod ffi;
|
||||
mod monitor;
|
||||
pub mod ffi;
|
||||
|
||||
static THREAD_INIT: Once = ONCE_INIT;
|
||||
|
||||
|
@ -42,16 +44,17 @@ fn ensure_thread_init() {
|
|||
});
|
||||
}
|
||||
|
||||
// TODO: remove me
|
||||
fn with_c_str<F, T>(s: &str, f: F) -> T where F: FnOnce(*const libc::c_char) -> T {
|
||||
use std::ffi::CString;
|
||||
let c_str = CString::new(s.as_bytes().to_vec()).unwrap();
|
||||
f(c_str.as_ptr())
|
||||
}
|
||||
|
||||
struct XWindow {
|
||||
pub struct XWindow {
|
||||
display: *mut ffi::Display,
|
||||
window: ffi::Window,
|
||||
context: ffi::GLXContext,
|
||||
pub context: Context,
|
||||
is_fullscreen: bool,
|
||||
screen_id: libc::c_int,
|
||||
xf86_desk_mode: *mut ffi::XF86VidModeModeInfo,
|
||||
|
@ -59,6 +62,11 @@ struct XWindow {
|
|||
im: ffi::XIM,
|
||||
}
|
||||
|
||||
pub enum Context {
|
||||
Glx(GlxContext),
|
||||
None,
|
||||
}
|
||||
|
||||
unsafe impl Send for XWindow {}
|
||||
unsafe impl Sync for XWindow {}
|
||||
|
||||
|
@ -70,7 +78,7 @@ impl Drop for XWindow {
|
|||
unsafe {
|
||||
// we don't call MakeCurrent(0, 0) because we are not sure that the context
|
||||
// is still the current one
|
||||
ffi::glx::DestroyContext(self.display as *mut _, self.context);
|
||||
self.context = Context::None;
|
||||
|
||||
if self.is_fullscreen {
|
||||
ffi::XF86VidModeSwitchToMode(self.display, self.screen_id, self.xf86_desk_mode);
|
||||
|
@ -282,7 +290,7 @@ impl<'a> Iterator for WaitEventsIterator<'a> {
|
|||
}
|
||||
|
||||
pub struct Window {
|
||||
x: Arc<XWindow>,
|
||||
pub x: Arc<XWindow>,
|
||||
is_closed: AtomicBool,
|
||||
wm_delete_window: ffi::Atom,
|
||||
current_size: Cell<(libc::c_int, libc::c_int)>,
|
||||
|
@ -528,109 +536,22 @@ impl Window {
|
|||
});
|
||||
}
|
||||
|
||||
// creating GL context
|
||||
let (context, extra_functions) = unsafe {
|
||||
let mut attributes = Vec::new();
|
||||
|
||||
match builder.gl_version {
|
||||
GlRequest::Latest => {},
|
||||
GlRequest::Specific(Api::OpenGl, (major, minor)) => {
|
||||
attributes.push(ffi::glx_extra::CONTEXT_MAJOR_VERSION_ARB as libc::c_int);
|
||||
attributes.push(major as libc::c_int);
|
||||
attributes.push(ffi::glx_extra::CONTEXT_MINOR_VERSION_ARB as libc::c_int);
|
||||
attributes.push(minor as libc::c_int);
|
||||
},
|
||||
GlRequest::Specific(_, _) => panic!("Only OpenGL is supported"),
|
||||
GlRequest::GlThenGles { opengl_version: (major, minor), .. } => {
|
||||
attributes.push(ffi::glx_extra::CONTEXT_MAJOR_VERSION_ARB as libc::c_int);
|
||||
attributes.push(major as libc::c_int);
|
||||
attributes.push(ffi::glx_extra::CONTEXT_MINOR_VERSION_ARB as libc::c_int);
|
||||
attributes.push(minor as libc::c_int);
|
||||
},
|
||||
}
|
||||
|
||||
if builder.gl_debug {
|
||||
attributes.push(ffi::glx_extra::CONTEXT_FLAGS_ARB as libc::c_int);
|
||||
attributes.push(ffi::glx_extra::CONTEXT_DEBUG_BIT_ARB as libc::c_int);
|
||||
}
|
||||
|
||||
attributes.push(0);
|
||||
|
||||
// loading the extra GLX functions
|
||||
let extra_functions = ffi::glx_extra::Glx::load_with(|addr| {
|
||||
with_c_str(addr, |s| {
|
||||
use libc;
|
||||
ffi::glx::GetProcAddress(s as *const u8) as *const libc::c_void
|
||||
})
|
||||
});
|
||||
|
||||
let share = if let Some(win) = builder.sharing {
|
||||
win.x.context
|
||||
} else {
|
||||
ptr::null()
|
||||
};
|
||||
|
||||
let mut context = if extra_functions.CreateContextAttribsARB.is_loaded() {
|
||||
extra_functions.CreateContextAttribsARB(display as *mut ffi::glx_extra::types::Display,
|
||||
fb_config, share, 1, attributes.as_ptr())
|
||||
} else {
|
||||
ptr::null()
|
||||
};
|
||||
|
||||
if context.is_null() {
|
||||
context = ffi::glx::CreateContext(display as *mut _, &mut visual_infos, share, 1)
|
||||
}
|
||||
|
||||
if context.is_null() {
|
||||
return Err(OsError(format!("GL context creation failed")));
|
||||
}
|
||||
|
||||
(context, extra_functions)
|
||||
let is_fullscreen = builder.monitor.is_some();
|
||||
// creating the context
|
||||
let context = match builder.gl_version {
|
||||
GlRequest::Latest | GlRequest::Specific(Api::OpenGl, _) | GlRequest::GlThenGles { .. } => {
|
||||
Context::Glx(try!(GlxContext::new(builder, display, window,
|
||||
fb_config, visual_infos)))
|
||||
},
|
||||
/*GlRequest::Specific(Api::OpenGlEs, _) => {
|
||||
let egl = ::egl::ffi::egl::Egl;
|
||||
Context::Egl(try!(EglContext::new(egl, builder, Some(display as *const _), window)))
|
||||
},*/
|
||||
GlRequest::Specific(_, _) => {
|
||||
return Err(CreationError::NotSupported);
|
||||
},
|
||||
};
|
||||
|
||||
// vsync
|
||||
if builder.vsync {
|
||||
unsafe { ffi::glx::MakeCurrent(display as *mut _, window, context) };
|
||||
|
||||
if extra_functions.SwapIntervalEXT.is_loaded() {
|
||||
// this should be the most common extension
|
||||
unsafe {
|
||||
extra_functions.SwapIntervalEXT(display as *mut _, window, 1);
|
||||
}
|
||||
|
||||
// checking that it worked
|
||||
if builder.strict {
|
||||
let mut swap = unsafe { mem::uninitialized() };
|
||||
unsafe {
|
||||
ffi::glx::QueryDrawable(display as *mut _, window,
|
||||
ffi::glx_extra::SWAP_INTERVAL_EXT as i32,
|
||||
&mut swap);
|
||||
}
|
||||
|
||||
if swap != 1 {
|
||||
return Err(OsError(format!("Couldn't setup vsync: expected \
|
||||
interval `1` but got `{}`", swap)));
|
||||
}
|
||||
}
|
||||
|
||||
// GLX_MESA_swap_control is not official
|
||||
/*} else if extra_functions.SwapIntervalMESA.is_loaded() {
|
||||
unsafe {
|
||||
extra_functions.SwapIntervalMESA(1);
|
||||
}*/
|
||||
|
||||
} else if extra_functions.SwapIntervalSGI.is_loaded() {
|
||||
unsafe {
|
||||
extra_functions.SwapIntervalSGI(1);
|
||||
}
|
||||
|
||||
} else if builder.strict {
|
||||
return Err(OsError(format!("Couldn't find any available vsync extension")));
|
||||
}
|
||||
|
||||
unsafe { ffi::glx::MakeCurrent(display as *mut _, 0, ptr::null()) };
|
||||
}
|
||||
|
||||
// creating the window object
|
||||
let window = Window {
|
||||
x: Arc::new(XWindow {
|
||||
|
@ -640,7 +561,7 @@ impl Window {
|
|||
ic: ic,
|
||||
context: context,
|
||||
screen_id: screen_id,
|
||||
is_fullscreen: builder.monitor.is_some(),
|
||||
is_fullscreen: is_fullscreen,
|
||||
xf86_desk_mode: xf86_desk_mode,
|
||||
}),
|
||||
is_closed: AtomicBool::new(false),
|
||||
|
@ -743,28 +664,35 @@ impl Window {
|
|||
}
|
||||
|
||||
pub unsafe fn make_current(&self) {
|
||||
let res = ffi::glx::MakeCurrent(self.x.display as *mut _, self.x.window, self.x.context);
|
||||
if res == 0 {
|
||||
panic!("glx::MakeCurrent failed");
|
||||
match self.x.context {
|
||||
Context::Glx(ref ctxt) => ctxt.make_current(),
|
||||
//Context::Egl(ref ctxt) => ctxt.make_current(),
|
||||
Context::None => {}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_current(&self) -> bool {
|
||||
unsafe { ffi::glx::GetCurrentContext() == self.x.context }
|
||||
match self.x.context {
|
||||
Context::Glx(ref ctxt) => ctxt.is_current(),
|
||||
//Context::Egl(ref ctxt) => ctxt.is_current(),
|
||||
Context::None => panic!()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_proc_address(&self, addr: &str) -> *const () {
|
||||
use std::mem;
|
||||
|
||||
unsafe {
|
||||
with_c_str(addr, |s| {
|
||||
ffi::glx::GetProcAddress(mem::transmute(s)) as *const ()
|
||||
})
|
||||
match self.x.context {
|
||||
Context::Glx(ref ctxt) => ctxt.get_proc_address(addr),
|
||||
//Context::Egl(ref ctxt) => ctxt.get_proc_address(addr),
|
||||
Context::None => ptr::null()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn swap_buffers(&self) {
|
||||
unsafe { ffi::glx::SwapBuffers(self.x.display as *mut _, self.x.window) }
|
||||
match self.x.context {
|
||||
Context::Glx(ref ctxt) => ctxt.swap_buffers(),
|
||||
//Context::Egl(ref ctxt) => ctxt.swap_buffers(),
|
||||
Context::None => {}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn platform_display(&self) -> *mut libc::c_void {
|
||||
|
@ -777,7 +705,11 @@ impl Window {
|
|||
|
||||
/// See the docs in the crate root file.
|
||||
pub fn get_api(&self) -> ::Api {
|
||||
::Api::OpenGl
|
||||
match self.x.context {
|
||||
Context::Glx(ref ctxt) => ctxt.get_api(),
|
||||
//Context::Egl(ref ctxt) => ctxt.get_api(),
|
||||
Context::None => panic!()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_pixel_format(&self) -> PixelFormat {
|
||||
|
|
Loading…
Reference in a new issue