diff options
| author | Pierre Krieger <pierre.krieger1708@gmail.com> | 2015-04-24 18:52:07 +0200 | 
|---|---|---|
| committer | Pierre Krieger <pierre.krieger1708@gmail.com> | 2015-04-25 12:10:40 +0200 | 
| commit | 5561e586462f87df39c2fab6a9bbdc734f35c073 (patch) | |
| tree | bc109354b8d762b6ed6c0d8f23a97326d812aa91 | |
| parent | 7eeb96909c4008398e88a9d32e958b75ab7113de (diff) | |
| download | glutin-5561e586462f87df39c2fab6a9bbdc734f35c073.tar.gz glutin-5561e586462f87df39c2fab6a9bbdc734f35c073.zip | |
Split GLX and X11 in "api"
| -rw-r--r-- | src/api/glx/mod.rs | 187 | ||||
| -rw-r--r-- | src/api/mod.rs | 1 | ||||
| -rw-r--r-- | src/api/x11/mod.rs | 170 | 
3 files changed, 239 insertions, 119 deletions
| diff --git a/src/api/glx/mod.rs b/src/api/glx/mod.rs new file mode 100644 index 0000000..fb86dfd --- /dev/null +++ b/src/api/glx/mod.rs @@ -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); +        } +    } +} diff --git a/src/api/mod.rs b/src/api/mod.rs index a99cef7..c71c239 100644 --- a/src/api/mod.rs +++ b/src/api/mod.rs @@ -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; diff --git a/src/api/x11/mod.rs b/src/api/x11/mod.rs index c4c5a76..0bb5c88 100644 --- a/src/api/x11/mod.rs +++ b/src/api/x11/mod.rs @@ -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 { | 
