mirror of
https://github.com/italicsjenga/winit-sonoma-fix.git
synced 2024-12-24 22:31: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 android;
|
||||||
pub mod cocoa;
|
pub mod cocoa;
|
||||||
pub mod egl;
|
pub mod egl;
|
||||||
|
pub mod glx;
|
||||||
pub mod osmesa;
|
pub mod osmesa;
|
||||||
pub mod win32;
|
pub mod win32;
|
||||||
pub mod x11;
|
pub mod x11;
|
||||||
|
|
|
@ -15,11 +15,13 @@ use CursorState;
|
||||||
use GlRequest;
|
use GlRequest;
|
||||||
use PixelFormat;
|
use PixelFormat;
|
||||||
|
|
||||||
|
use api::glx::Context as GlxContext;
|
||||||
|
|
||||||
pub use self::monitor::{MonitorID, get_available_monitors, get_primary_monitor};
|
pub use self::monitor::{MonitorID, get_available_monitors, get_primary_monitor};
|
||||||
|
|
||||||
mod events;
|
mod events;
|
||||||
mod ffi;
|
|
||||||
mod monitor;
|
mod monitor;
|
||||||
|
pub mod ffi;
|
||||||
|
|
||||||
static THREAD_INIT: Once = ONCE_INIT;
|
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 {
|
fn with_c_str<F, T>(s: &str, f: F) -> T where F: FnOnce(*const libc::c_char) -> T {
|
||||||
use std::ffi::CString;
|
use std::ffi::CString;
|
||||||
let c_str = CString::new(s.as_bytes().to_vec()).unwrap();
|
let c_str = CString::new(s.as_bytes().to_vec()).unwrap();
|
||||||
f(c_str.as_ptr())
|
f(c_str.as_ptr())
|
||||||
}
|
}
|
||||||
|
|
||||||
struct XWindow {
|
pub struct XWindow {
|
||||||
display: *mut ffi::Display,
|
display: *mut ffi::Display,
|
||||||
window: ffi::Window,
|
window: ffi::Window,
|
||||||
context: ffi::GLXContext,
|
pub context: Context,
|
||||||
is_fullscreen: bool,
|
is_fullscreen: bool,
|
||||||
screen_id: libc::c_int,
|
screen_id: libc::c_int,
|
||||||
xf86_desk_mode: *mut ffi::XF86VidModeModeInfo,
|
xf86_desk_mode: *mut ffi::XF86VidModeModeInfo,
|
||||||
|
@ -59,6 +62,11 @@ struct XWindow {
|
||||||
im: ffi::XIM,
|
im: ffi::XIM,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub enum Context {
|
||||||
|
Glx(GlxContext),
|
||||||
|
None,
|
||||||
|
}
|
||||||
|
|
||||||
unsafe impl Send for XWindow {}
|
unsafe impl Send for XWindow {}
|
||||||
unsafe impl Sync for XWindow {}
|
unsafe impl Sync for XWindow {}
|
||||||
|
|
||||||
|
@ -70,7 +78,7 @@ impl Drop for XWindow {
|
||||||
unsafe {
|
unsafe {
|
||||||
// we don't call MakeCurrent(0, 0) because we are not sure that the context
|
// we don't call MakeCurrent(0, 0) because we are not sure that the context
|
||||||
// is still the current one
|
// is still the current one
|
||||||
ffi::glx::DestroyContext(self.display as *mut _, self.context);
|
self.context = Context::None;
|
||||||
|
|
||||||
if self.is_fullscreen {
|
if self.is_fullscreen {
|
||||||
ffi::XF86VidModeSwitchToMode(self.display, self.screen_id, self.xf86_desk_mode);
|
ffi::XF86VidModeSwitchToMode(self.display, self.screen_id, self.xf86_desk_mode);
|
||||||
|
@ -282,7 +290,7 @@ impl<'a> Iterator for WaitEventsIterator<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Window {
|
pub struct Window {
|
||||||
x: Arc<XWindow>,
|
pub x: Arc<XWindow>,
|
||||||
is_closed: AtomicBool,
|
is_closed: AtomicBool,
|
||||||
wm_delete_window: ffi::Atom,
|
wm_delete_window: ffi::Atom,
|
||||||
current_size: Cell<(libc::c_int, libc::c_int)>,
|
current_size: Cell<(libc::c_int, libc::c_int)>,
|
||||||
|
@ -528,109 +536,22 @@ impl Window {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// creating GL context
|
let is_fullscreen = builder.monitor.is_some();
|
||||||
let (context, extra_functions) = unsafe {
|
// creating the context
|
||||||
let mut attributes = Vec::new();
|
let context = match builder.gl_version {
|
||||||
|
GlRequest::Latest | GlRequest::Specific(Api::OpenGl, _) | GlRequest::GlThenGles { .. } => {
|
||||||
match builder.gl_version {
|
Context::Glx(try!(GlxContext::new(builder, display, window,
|
||||||
GlRequest::Latest => {},
|
fb_config, visual_infos)))
|
||||||
GlRequest::Specific(Api::OpenGl, (major, minor)) => {
|
},
|
||||||
attributes.push(ffi::glx_extra::CONTEXT_MAJOR_VERSION_ARB as libc::c_int);
|
/*GlRequest::Specific(Api::OpenGlEs, _) => {
|
||||||
attributes.push(major as libc::c_int);
|
let egl = ::egl::ffi::egl::Egl;
|
||||||
attributes.push(ffi::glx_extra::CONTEXT_MINOR_VERSION_ARB as libc::c_int);
|
Context::Egl(try!(EglContext::new(egl, builder, Some(display as *const _), window)))
|
||||||
attributes.push(minor as libc::c_int);
|
},*/
|
||||||
},
|
GlRequest::Specific(_, _) => {
|
||||||
GlRequest::Specific(_, _) => panic!("Only OpenGL is supported"),
|
return Err(CreationError::NotSupported);
|
||||||
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)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// 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
|
// creating the window object
|
||||||
let window = Window {
|
let window = Window {
|
||||||
x: Arc::new(XWindow {
|
x: Arc::new(XWindow {
|
||||||
|
@ -640,7 +561,7 @@ impl Window {
|
||||||
ic: ic,
|
ic: ic,
|
||||||
context: context,
|
context: context,
|
||||||
screen_id: screen_id,
|
screen_id: screen_id,
|
||||||
is_fullscreen: builder.monitor.is_some(),
|
is_fullscreen: is_fullscreen,
|
||||||
xf86_desk_mode: xf86_desk_mode,
|
xf86_desk_mode: xf86_desk_mode,
|
||||||
}),
|
}),
|
||||||
is_closed: AtomicBool::new(false),
|
is_closed: AtomicBool::new(false),
|
||||||
|
@ -743,28 +664,35 @@ impl Window {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn make_current(&self) {
|
pub unsafe fn make_current(&self) {
|
||||||
let res = ffi::glx::MakeCurrent(self.x.display as *mut _, self.x.window, self.x.context);
|
match self.x.context {
|
||||||
if res == 0 {
|
Context::Glx(ref ctxt) => ctxt.make_current(),
|
||||||
panic!("glx::MakeCurrent failed");
|
//Context::Egl(ref ctxt) => ctxt.make_current(),
|
||||||
|
Context::None => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_current(&self) -> bool {
|
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 () {
|
pub fn get_proc_address(&self, addr: &str) -> *const () {
|
||||||
use std::mem;
|
match self.x.context {
|
||||||
|
Context::Glx(ref ctxt) => ctxt.get_proc_address(addr),
|
||||||
unsafe {
|
//Context::Egl(ref ctxt) => ctxt.get_proc_address(addr),
|
||||||
with_c_str(addr, |s| {
|
Context::None => ptr::null()
|
||||||
ffi::glx::GetProcAddress(mem::transmute(s)) as *const ()
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn swap_buffers(&self) {
|
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 {
|
pub fn platform_display(&self) -> *mut libc::c_void {
|
||||||
|
@ -777,7 +705,11 @@ impl Window {
|
||||||
|
|
||||||
/// See the docs in the crate root file.
|
/// See the docs in the crate root file.
|
||||||
pub fn get_api(&self) -> ::Api {
|
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 {
|
pub fn get_pixel_format(&self) -> PixelFormat {
|
||||||
|
|
Loading…
Reference in a new issue