aboutsummaryrefslogtreecommitdiffstats
path: root/src/api/glx
diff options
context:
space:
mode:
authorPierre Krieger <pierre.krieger1708@gmail.com>2015-07-19 13:53:40 +0200
committerPierre Krieger <pierre.krieger1708@gmail.com>2015-07-19 13:53:40 +0200
commitbaf9b92d3f8a62c6a10d2ea1506e262597e70ac9 (patch)
tree91f8a1c9c3b4a255e6b2aacc6668733edecb1204 /src/api/glx
parent896640f2e0fd659e952e492c1b74841624db8d08 (diff)
downloadglutin-baf9b92d3f8a62c6a10d2ea1506e262597e70ac9.tar.gz
glutin-baf9b92d3f8a62c6a10d2ea1506e262597e70ac9.zip
Correct window creation on X11
Diffstat (limited to 'src/api/glx')
-rw-r--r--src/api/glx/mod.rs311
1 files changed, 222 insertions, 89 deletions
diff --git a/src/api/glx/mod.rs b/src/api/glx/mod.rs
index d286813..3779597 100644
--- a/src/api/glx/mod.rs
+++ b/src/api/glx/mod.rs
@@ -23,6 +23,7 @@ pub struct Context {
display: *mut ffi::Display,
window: ffi::Window,
context: ffi::GLXContext,
+ pixel_format: PixelFormat,
}
// TODO: remove me
@@ -33,11 +34,157 @@ fn with_c_str<F, T>(s: &str, f: F) -> T where F: FnOnce(*const libc::c_char) ->
}
impl Context {
- pub fn new(glx: ffi::glx::Glx, 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>
+ pub fn new<'a>(glx: ffi::glx::Glx, xlib: &ffi::Xlib, builder: &'a BuilderAttribs<'a>,
+ display: *mut ffi::Display)
+ -> Result<ContextPrototype<'a>, CreationError>
{
- let share = if let Some(win) = builder.sharing {
+ // finding the pixel format we want
+ // TODO: enumerate them instead
+ let fb_config = unsafe {
+ let mut visual_attributes = vec![
+ ffi::glx::X_RENDERABLE as libc::c_int, 1,
+ ffi::glx::DRAWABLE_TYPE as libc::c_int, ffi::glx::WINDOW_BIT as libc::c_int,
+ ffi::glx::RENDER_TYPE as libc::c_int, ffi::glx::RGBA_BIT as libc::c_int,
+ ffi::glx::X_VISUAL_TYPE as libc::c_int, ffi::glx::TRUE_COLOR as libc::c_int,
+ ffi::glx::RED_SIZE as libc::c_int, 8,
+ ffi::glx::GREEN_SIZE as libc::c_int, 8,
+ ffi::glx::BLUE_SIZE as libc::c_int, 8,
+ ffi::glx::ALPHA_SIZE as libc::c_int, 8,
+ ffi::glx::DEPTH_SIZE as libc::c_int, 24,
+ ffi::glx::STENCIL_SIZE as libc::c_int, 8,
+ ffi::glx::DOUBLEBUFFER as libc::c_int, 1,
+ ];
+
+ if let Some(val) = builder.multisampling {
+ visual_attributes.push(ffi::glx::SAMPLE_BUFFERS as libc::c_int);
+ visual_attributes.push(1);
+ visual_attributes.push(ffi::glx::SAMPLES as libc::c_int);
+ visual_attributes.push(val as libc::c_int);
+ }
+
+ if let Some(val) = builder.srgb {
+ visual_attributes.push(ffi::glx_extra::FRAMEBUFFER_SRGB_CAPABLE_ARB as libc::c_int);
+ visual_attributes.push(if val {1} else {0});
+ }
+
+ visual_attributes.push(0);
+
+ let mut num_fb: libc::c_int = mem::uninitialized();
+
+ let fb = glx.ChooseFBConfig(display as *mut _, (xlib.XDefaultScreen)(display),
+ visual_attributes.as_ptr(), &mut num_fb);
+ if fb.is_null() {
+ return Err(CreationError::OsError(format!("glxChooseFBConfig failed")));
+ }
+
+ let preferred_fb = if builder.transparent {
+ let mut best_fbi_for_transparent = 0isize;
+
+ for i in 0isize..num_fb as isize {
+ let vi = glx.GetVisualFromFBConfig(display as *mut _, *fb.offset(i));
+ if (*vi).depth == 32 {
+ best_fbi_for_transparent = i;
+ break;
+ }
+ }
+
+ *fb.offset(best_fbi_for_transparent)
+ } else {
+ *fb // TODO: choose more wisely
+ };
+
+ (xlib.XFree)(fb as *mut _);
+ preferred_fb
+ };
+
+ // getting the visual infos
+ let visual_infos: ffi::glx::types::XVisualInfo = unsafe {
+ let vi = glx.GetVisualFromFBConfig(display as *mut _, fb_config);
+ if vi.is_null() {
+ return Err(CreationError::OsError(format!("glxGetVisualFromFBConfig failed")));
+ }
+ let vi_copy = ptr::read(vi as *const _);
+ (xlib.XFree)(vi as *mut _);
+ vi_copy
+ };
+
+ Ok(ContextPrototype {
+ glx: glx,
+ builder: builder,
+ display: display,
+ fb_config: fb_config,
+ visual_infos: unsafe { mem::transmute(visual_infos) },
+ })
+ }
+}
+
+impl GlContext for Context {
+ unsafe fn make_current(&self) -> Result<(), ContextError> {
+ // TODO: glutin needs some internal changes for proper error recovery
+ let res = self.glx.MakeCurrent(self.display as *mut _, self.window, self.context);
+ if res == 0 {
+ panic!("glx::MakeCurrent failed");
+ }
+ Ok(())
+ }
+
+ fn is_current(&self) -> bool {
+ unsafe { self.glx.GetCurrentContext() == self.context }
+ }
+
+ fn get_proc_address(&self, addr: &str) -> *const libc::c_void {
+ let addr = CString::new(addr.as_bytes()).unwrap();
+ let addr = addr.as_ptr();
+ unsafe {
+ self.glx.GetProcAddress(addr as *const _) as *const _
+ }
+ }
+
+ fn swap_buffers(&self) -> Result<(), ContextError> {
+ // TODO: glutin needs some internal changes for proper error recovery
+ unsafe { self.glx.SwapBuffers(self.display as *mut _, self.window); }
+ Ok(())
+ }
+
+ fn get_api(&self) -> ::Api {
+ ::Api::OpenGl
+ }
+
+ fn get_pixel_format(&self) -> PixelFormat {
+ self.pixel_format.clone()
+ }
+}
+
+unsafe impl Send for Context {}
+unsafe impl Sync for Context {}
+
+impl Drop for Context {
+ fn drop(&mut self) {
+ unsafe {
+ if self.is_current() {
+ self.glx.MakeCurrent(self.display as *mut _, 0, ptr::null_mut());
+ }
+
+ self.glx.DestroyContext(self.display as *mut _, self.context);
+ }
+ }
+}
+
+pub struct ContextPrototype<'a> {
+ glx: ffi::glx::Glx,
+ builder: &'a BuilderAttribs<'a>,
+ display: *mut ffi::Display,
+ fb_config: ffi::glx::types::GLXFBConfig,
+ visual_infos: ffi::XVisualInfo,
+}
+
+impl<'a> ContextPrototype<'a> {
+ pub fn get_visual_infos(&self) -> &ffi::XVisualInfo {
+ &self.visual_infos
+ }
+
+ pub fn finish(self, window: ffi::Window) -> Result<Context, CreationError> {
+ let share = if let Some(win) = self.builder.sharing {
match win {
&PlatformWindow::X(ref win) => match win.x.context {
::api::x11::Context::Glx(ref c) => c.context,
@@ -51,7 +198,7 @@ impl Context {
// loading the list of extensions
let extensions = unsafe {
- let extensions = glx.QueryExtensionsString(display as *mut _, 0); // FIXME: screen number
+ let extensions = self.glx.QueryExtensionsString(self.display as *mut _, 0); // FIXME: screen number
let extensions = CStr::from_ptr(extensions).to_bytes().to_vec();
String::from_utf8(extensions).unwrap()
};
@@ -59,62 +206,66 @@ impl Context {
// loading the extra GLX functions
let extra_functions = ffi::glx_extra::Glx::load_with(|addr| {
with_c_str(addr, |s| {
- unsafe { glx.GetProcAddress(s as *const u8) as *const _ }
+ unsafe { self.glx.GetProcAddress(s as *const u8) as *const _ }
})
});
// creating GL context
- let context = match builder.gl_version {
+ let context = match self.builder.gl_version {
GlRequest::Latest => {
- if let Ok(ctxt) = create_context(&glx, &extra_functions, &extensions, (3, 2),
- builder.gl_profile, builder.gl_debug,
- builder.gl_robustness, share,
- display, fb_config, &mut visual_infos)
+ if let Ok(ctxt) = create_context(&self.glx, &extra_functions, &extensions, (3, 2),
+ self.builder.gl_profile, self.builder.gl_debug,
+ self.builder.gl_robustness, share,
+ self.display, self.fb_config, &self.visual_infos)
{
ctxt
- } else if let Ok(ctxt) = create_context(&glx, &extra_functions, &extensions, (3, 1),
- builder.gl_profile, builder.gl_debug,
- builder.gl_robustness, share, display,
- fb_config, &mut visual_infos)
+ } else if let Ok(ctxt) = create_context(&self.glx, &extra_functions, &extensions,
+ (3, 1), self.builder.gl_profile,
+ self.builder.gl_debug,
+ self.builder.gl_robustness, share, self.display,
+ self.fb_config, &self.visual_infos)
{
ctxt
} else {
- try!(create_context(&glx, &extra_functions, &extensions, (1, 0),
- builder.gl_profile, builder.gl_debug, builder.gl_robustness,
- share, display, fb_config, &mut visual_infos))
+ try!(create_context(&self.glx, &extra_functions, &extensions, (1, 0),
+ self.builder.gl_profile, self.builder.gl_debug,
+ self.builder.gl_robustness,
+ share, self.display, self.fb_config, &self.visual_infos))
}
},
GlRequest::Specific(Api::OpenGl, (major, minor)) => {
- try!(create_context(&glx, &extra_functions, &extensions, (major, minor),
- builder.gl_profile, builder.gl_debug, builder.gl_robustness,
- share, display, fb_config, &mut visual_infos))
+ try!(create_context(&self.glx, &extra_functions, &extensions, (major, minor),
+ self.builder.gl_profile, self.builder.gl_debug,
+ self.builder.gl_robustness, share, self.display, self.fb_config,
+ &self.visual_infos))
},
GlRequest::Specific(_, _) => panic!("Only OpenGL is supported"),
GlRequest::GlThenGles { opengl_version: (major, minor), .. } => {
- try!(create_context(&glx, &extra_functions, &extensions, (major, minor),
- builder.gl_profile, builder.gl_debug, builder.gl_robustness,
- share, display, fb_config, &mut visual_infos))
+ try!(create_context(&self.glx, &extra_functions, &extensions, (major, minor),
+ self.builder.gl_profile, self.builder.gl_debug,
+ self.builder.gl_robustness, share, self.display, self.fb_config,
+ &self.visual_infos))
},
};
// vsync
- if builder.vsync {
- unsafe { glx.MakeCurrent(display as *mut _, window, context) };
+ if self.builder.vsync {
+ unsafe { self.glx.MakeCurrent(self.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);
+ extra_functions.SwapIntervalEXT(self.display as *mut _, window, 1);
}
// checking that it worked
- if builder.strict {
+ if self.builder.strict {
let mut swap = unsafe { mem::uninitialized() };
unsafe {
- glx.QueryDrawable(display as *mut _, window,
- ffi::glx_extra::SWAP_INTERVAL_EXT as i32,
- &mut swap);
+ self.glx.QueryDrawable(self.display as *mut _, window,
+ ffi::glx_extra::SWAP_INTERVAL_EXT as i32,
+ &mut swap);
}
if swap != 1 {
@@ -134,79 +285,30 @@ impl Context {
extra_functions.SwapIntervalSGI(1);
}
- } else if builder.strict {
+ } else if self.builder.strict {
return Err(CreationError::OsError(format!("Couldn't find any available vsync extension")));
}
- unsafe { glx.MakeCurrent(display as *mut _, 0, ptr::null()) };
+ unsafe { self.glx.MakeCurrent(self.display as *mut _, 0, ptr::null()) };
}
+ let pixel_format = unsafe { get_pixel_format(&self.glx, self.display, self.fb_config) };
+
Ok(Context {
- glx: glx,
- display: display,
+ glx: self.glx,
+ display: self.display,
window: window,
context: context,
+ pixel_format: pixel_format,
})
}
}
-impl GlContext for Context {
- unsafe fn make_current(&self) -> Result<(), ContextError> {
- // TODO: glutin needs some internal changes for proper error recovery
- let res = self.glx.MakeCurrent(self.display as *mut _, self.window, self.context);
- if res == 0 {
- panic!("glx::MakeCurrent failed");
- }
- Ok(())
- }
-
- fn is_current(&self) -> bool {
- unsafe { self.glx.GetCurrentContext() == self.context }
- }
-
- fn get_proc_address(&self, addr: &str) -> *const libc::c_void {
- let addr = CString::new(addr.as_bytes()).unwrap();
- let addr = addr.as_ptr();
- unsafe {
- self.glx.GetProcAddress(addr as *const _) as *const _
- }
- }
-
- fn swap_buffers(&self) -> Result<(), ContextError> {
- // TODO: glutin needs some internal changes for proper error recovery
- unsafe { self.glx.SwapBuffers(self.display as *mut _, self.window); }
- Ok(())
- }
-
- fn get_api(&self) -> ::Api {
- ::Api::OpenGl
- }
-
- fn get_pixel_format(&self) -> PixelFormat {
- unimplemented!();
- }
-}
-
-unsafe impl Send for Context {}
-unsafe impl Sync for Context {}
-
-impl Drop for Context {
- fn drop(&mut self) {
- unsafe {
- if self.is_current() {
- self.glx.MakeCurrent(self.display as *mut _, 0, ptr::null_mut());
- }
-
- self.glx.DestroyContext(self.display as *mut _, self.context);
- }
- }
-}
-
fn create_context(glx: &ffi::glx::Glx, extra_functions: &ffi::glx_extra::Glx, extensions: &str,
version: (u8, u8), profile: Option<GlProfile>, debug: bool,
robustness: Robustness, share: ffi::GLXContext, display: *mut ffi::Display,
fb_config: ffi::glx::types::GLXFBConfig,
- visual_infos: &mut ffi::glx::types::XVisualInfo)
+ visual_infos: &ffi::XVisualInfo)
-> Result<ffi::GLXContext, CreationError>
{
unsafe {
@@ -274,7 +376,8 @@ fn create_context(glx: &ffi::glx::Glx, extra_functions: &ffi::glx_extra::Glx, ex
attributes.as_ptr())
} else {
- glx.CreateContext(display as *mut _, visual_infos, share, 1)
+ let visual_infos: *const ffi::XVisualInfo = visual_infos;
+ glx.CreateContext(display as *mut _, visual_infos as *mut _, share, 1)
};
if context.is_null() {
@@ -284,3 +387,33 @@ fn create_context(glx: &ffi::glx::Glx, extra_functions: &ffi::glx_extra::Glx, ex
Ok(context)
}
}
+
+unsafe fn get_pixel_format(glx: &ffi::glx::Glx, display: *mut ffi::Display,
+ fb_config: ffi::glx::types::GLXFBConfig) -> PixelFormat
+{
+ let get_attrib = |attrib: libc::c_int| -> i32 {
+ let mut value = 0;
+ glx.GetFBConfigAttrib(display as *mut _, fb_config, attrib, &mut value);
+ // TODO: check return value
+ value
+ };
+
+ // TODO: make sure everything is supported
+ PixelFormat {
+ hardware_accelerated: true,
+ color_bits: get_attrib(ffi::glx::RED_SIZE as libc::c_int) as u8 +
+ get_attrib(ffi::glx::GREEN_SIZE as libc::c_int) as u8 +
+ get_attrib(ffi::glx::BLUE_SIZE as libc::c_int) as u8,
+ alpha_bits: get_attrib(ffi::glx::ALPHA_SIZE as libc::c_int) as u8,
+ depth_bits: get_attrib(ffi::glx::DEPTH_SIZE as libc::c_int) as u8,
+ stencil_bits: get_attrib(ffi::glx::STENCIL_SIZE as libc::c_int) as u8,
+ stereoscopy: get_attrib(ffi::glx::STEREO as libc::c_int) != 0,
+ double_buffer: get_attrib(ffi::glx::DOUBLEBUFFER as libc::c_int) != 0,
+ multisampling: if get_attrib(ffi::glx::SAMPLE_BUFFERS as libc::c_int) != 0 {
+ Some(get_attrib(ffi::glx::SAMPLES as libc::c_int) as u16)
+ } else {
+ None
+ },
+ srgb: get_attrib(ffi::glx_extra::FRAMEBUFFER_SRGB_CAPABLE_ARB as libc::c_int) != 0,
+ }
+}