aboutsummaryrefslogtreecommitdiffstats
path: root/src/api/glx
diff options
context:
space:
mode:
Diffstat (limited to 'src/api/glx')
-rw-r--r--src/api/glx/mod.rs245
1 files changed, 158 insertions, 87 deletions
diff --git a/src/api/glx/mod.rs b/src/api/glx/mod.rs
index 61a7d2f..9f3e084 100644
--- a/src/api/glx/mod.rs
+++ b/src/api/glx/mod.rs
@@ -9,9 +9,11 @@ use GlRequest;
use Api;
use PixelFormat;
use PixelFormatRequirements;
+use ReleaseBehavior;
use Robustness;
use libc;
+use libc::c_int;
use std::ffi::{CStr, CString};
use std::{mem, ptr, slice};
@@ -39,10 +41,17 @@ impl Context {
opengl: &'a GlAttributes<&'a Context>, display: *mut ffi::Display)
-> Result<ContextPrototype<'a>, CreationError>
{
+ // loading the list of extensions
+ let extensions = unsafe {
+ let extensions = glx.QueryExtensionsString(display as *mut _, 0); // FIXME: screen number
+ let extensions = CStr::from_ptr(extensions).to_bytes().to_vec();
+ String::from_utf8(extensions).unwrap()
+ };
+
// finding the pixel format we want
- let (fb_config, pixel_format) = {
- let configs = unsafe { try!(enumerate_configs(&glx, xlib, display)) };
- try!(pf_reqs.choose_pixel_format(configs.into_iter()))
+ let (fb_config, pixel_format) = unsafe {
+ try!(choose_fbconfig(&glx, &extensions, xlib, display, pf_reqs)
+ .map_err(|_| CreationError::NoAvailablePixelFormat))
};
// getting the visual infos
@@ -58,6 +67,7 @@ impl Context {
Ok(ContextPrototype {
glx: glx,
+ extensions: extensions,
opengl: opengl,
display: display,
fb_config: fb_config,
@@ -125,6 +135,7 @@ impl Drop for Context {
pub struct ContextPrototype<'a> {
glx: ffi::glx::Glx,
+ extensions: String,
opengl: &'a GlAttributes<&'a Context>,
display: *mut ffi::Display,
fb_config: ffi::glx::types::GLXFBConfig,
@@ -144,13 +155,6 @@ impl<'a> ContextPrototype<'a> {
None => ptr::null()
};
- // loading the list of extensions
- let extensions = unsafe {
- 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()
- };
-
// loading the extra GLX functions
let extra_functions = ffi::glx_extra::Glx::load_with(|addr| {
with_c_str(addr, |s| {
@@ -161,13 +165,13 @@ impl<'a> ContextPrototype<'a> {
// creating GL context
let context = match self.opengl.version {
GlRequest::Latest => {
- if let Ok(ctxt) = create_context(&self.glx, &extra_functions, &extensions, (3, 2),
+ if let Ok(ctxt) = create_context(&self.glx, &extra_functions, &self.extensions, (3, 2),
self.opengl.profile, self.opengl.debug,
self.opengl.robustness, share,
self.display, self.fb_config, &self.visual_infos)
{
ctxt
- } else if let Ok(ctxt) = create_context(&self.glx, &extra_functions, &extensions,
+ } else if let Ok(ctxt) = create_context(&self.glx, &extra_functions, &self.extensions,
(3, 1), self.opengl.profile,
self.opengl.debug,
self.opengl.robustness, share, self.display,
@@ -176,21 +180,21 @@ impl<'a> ContextPrototype<'a> {
ctxt
} else {
- try!(create_context(&self.glx, &extra_functions, &extensions, (1, 0),
+ try!(create_context(&self.glx, &extra_functions, &self.extensions, (1, 0),
self.opengl.profile, self.opengl.debug,
self.opengl.robustness,
share, self.display, self.fb_config, &self.visual_infos))
}
},
GlRequest::Specific(Api::OpenGl, (major, minor)) => {
- try!(create_context(&self.glx, &extra_functions, &extensions, (major, minor),
+ try!(create_context(&self.glx, &extra_functions, &self.extensions, (major, minor),
self.opengl.profile, self.opengl.debug,
self.opengl.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(&self.glx, &extra_functions, &extensions, (major, minor),
+ try!(create_context(&self.glx, &extra_functions, &self.extensions, (major, minor),
self.opengl.profile, self.opengl.debug,
self.opengl.robustness, share, self.display, self.fb_config,
&self.visual_infos))
@@ -263,10 +267,10 @@ fn create_context(glx: &ffi::glx::Glx, extra_functions: &ffi::glx_extra::Glx, ex
let context = if extensions.split(' ').find(|&i| i == "GLX_ARB_create_context").is_some() {
let mut attributes = Vec::with_capacity(9);
- attributes.push(ffi::glx_extra::CONTEXT_MAJOR_VERSION_ARB as libc::c_int);
- attributes.push(version.0 as libc::c_int);
- attributes.push(ffi::glx_extra::CONTEXT_MINOR_VERSION_ARB as libc::c_int);
- attributes.push(version.1 as libc::c_int);
+ attributes.push(ffi::glx_extra::CONTEXT_MAJOR_VERSION_ARB as c_int);
+ attributes.push(version.0 as c_int);
+ attributes.push(ffi::glx_extra::CONTEXT_MINOR_VERSION_ARB as c_int);
+ attributes.push(version.1 as c_int);
if let Some(profile) = profile {
let flag = match profile {
@@ -276,8 +280,8 @@ fn create_context(glx: &ffi::glx::Glx, extra_functions: &ffi::glx_extra::Glx, ex
ffi::glx_extra::CONTEXT_CORE_PROFILE_BIT_ARB,
};
- attributes.push(ffi::glx_extra::CONTEXT_PROFILE_MASK_ARB as libc::c_int);
- attributes.push(flag as libc::c_int);
+ attributes.push(ffi::glx_extra::CONTEXT_PROFILE_MASK_ARB as c_int);
+ attributes.push(flag as c_int);
}
let flags = {
@@ -287,14 +291,14 @@ fn create_context(glx: &ffi::glx::Glx, extra_functions: &ffi::glx_extra::Glx, ex
if extensions.split(' ').find(|&i| i == "GLX_ARB_create_context_robustness").is_some() {
match robustness {
Robustness::RobustNoResetNotification | Robustness::TryRobustNoResetNotification => {
- attributes.push(ffi::glx_extra::CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB as libc::c_int);
- attributes.push(ffi::glx_extra::NO_RESET_NOTIFICATION_ARB as libc::c_int);
- flags = flags | ffi::glx_extra::CONTEXT_ROBUST_ACCESS_BIT_ARB as libc::c_int;
+ attributes.push(ffi::glx_extra::CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB as c_int);
+ attributes.push(ffi::glx_extra::NO_RESET_NOTIFICATION_ARB as c_int);
+ flags = flags | ffi::glx_extra::CONTEXT_ROBUST_ACCESS_BIT_ARB as c_int;
},
Robustness::RobustLoseContextOnReset | Robustness::TryRobustLoseContextOnReset => {
- attributes.push(ffi::glx_extra::CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB as libc::c_int);
- attributes.push(ffi::glx_extra::LOSE_CONTEXT_ON_RESET_ARB as libc::c_int);
- flags = flags | ffi::glx_extra::CONTEXT_ROBUST_ACCESS_BIT_ARB as libc::c_int;
+ attributes.push(ffi::glx_extra::CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB as c_int);
+ attributes.push(ffi::glx_extra::LOSE_CONTEXT_ON_RESET_ARB as c_int);
+ flags = flags | ffi::glx_extra::CONTEXT_ROBUST_ACCESS_BIT_ARB as c_int;
},
Robustness::NotRobust => (),
Robustness::NoError => (),
@@ -309,13 +313,13 @@ fn create_context(glx: &ffi::glx::Glx, extra_functions: &ffi::glx_extra::Glx, ex
}
if debug {
- flags = flags | ffi::glx_extra::CONTEXT_DEBUG_BIT_ARB as libc::c_int;
+ flags = flags | ffi::glx_extra::CONTEXT_DEBUG_BIT_ARB as c_int;
}
flags
};
- attributes.push(ffi::glx_extra::CONTEXT_FLAGS_ARB as libc::c_int);
+ attributes.push(ffi::glx_extra::CONTEXT_FLAGS_ARB as c_int);
attributes.push(flags);
attributes.push(0);
@@ -338,78 +342,145 @@ fn create_context(glx: &ffi::glx::Glx, extra_functions: &ffi::glx_extra::Glx, ex
}
/// Enumerates all available FBConfigs
-unsafe fn enumerate_configs(glx: &ffi::glx::Glx, xlib: &ffi::Xlib, display: *mut ffi::Display)
- -> Result<Vec<(ffi::glx::types::GLXFBConfig, PixelFormat)>, CreationError>
+unsafe fn choose_fbconfig(glx: &ffi::glx::Glx, extensions: &str, xlib: &ffi::Xlib,
+ display: *mut ffi::Display, reqs: &PixelFormatRequirements)
+ -> Result<(ffi::glx::types::GLXFBConfig, PixelFormat), ()>
{
- let configs: Vec<ffi::glx::types::GLXFBConfig> = {
- let mut num_configs = 0;
- let vals = glx.GetFBConfigs(display as *mut _, 0, &mut num_configs); // TODO: screen number
- assert!(!vals.is_null());
- let configs = slice::from_raw_parts(vals, num_configs as usize);
- let ret = configs.to_vec();
- (xlib.XFree)(vals as *mut _);
- ret
- };
+ let descriptor = {
+ let mut out: Vec<c_int> = Vec::with_capacity(37);
- let get_attrib = |attrib: libc::c_int, fb_config: ffi::glx::types::GLXFBConfig| -> i32 {
- let mut value = 0;
- glx.GetFBConfigAttrib(display as *mut _, fb_config, attrib, &mut value);
- // TODO: check return value
- value
- };
+ out.push(ffi::glx::X_RENDERABLE as c_int);
+ out.push(1);
+
+ out.push(ffi::glx::X_VISUAL_TYPE as c_int);
+ out.push(ffi::glx::TRUE_COLOR as c_int);
+
+ out.push(ffi::glx::DRAWABLE_TYPE as c_int);
+ out.push(ffi::glx::WINDOW_BIT as c_int);
+
+ out.push(ffi::glx::RENDER_TYPE as c_int);
+ if reqs.float_color_buffer {
+ if extensions.split(' ').find(|&i| i == "GLX_ARB_fbconfig_float").is_some() {
+ out.push(ffi::glx_extra::RGBA_FLOAT_BIT_ARB as c_int);
+ } else {
+ return Err(());
+ }
+ } else {
+ out.push(ffi::glx::RGBA_BIT as c_int);
+ }
+
+ if let Some(hardware_accelerated) = reqs.hardware_accelerated {
+ out.push(ffi::glx::CONFIG_CAVEAT as c_int);
+ out.push(if hardware_accelerated {
+ ffi::glx::NONE as c_int
+ } else {
+ ffi::glx::SLOW_CONFIG as c_int
+ });
+ }
- Ok(configs.into_iter().filter_map(|config| {
- if get_attrib(ffi::glx::X_RENDERABLE as libc::c_int, config) == 0 {
- return None;
+ if let Some(color) = reqs.color_bits {
+ out.push(ffi::glx::RED_SIZE as c_int);
+ out.push((color / 3) as c_int);
+ out.push(ffi::glx::GREEN_SIZE as c_int);
+ out.push((color / 3 + if color % 3 != 0 { 1 } else { 0 }) as c_int);
+ out.push(ffi::glx::BLUE_SIZE as c_int);
+ out.push((color / 3 + if color % 3 == 2 { 1 } else { 0 }) as c_int);
}
- if get_attrib(ffi::glx::X_VISUAL_TYPE as libc::c_int, config) !=
- ffi::glx::TRUE_COLOR as libc::c_int
- {
- return None;
+ if let Some(alpha) = reqs.alpha_bits {
+ out.push(ffi::glx::ALPHA_SIZE as c_int);
+ out.push(alpha as c_int);
}
- if get_attrib(ffi::glx::DRAWABLE_TYPE as libc::c_int, config) &
- ffi::glx::WINDOW_BIT as libc::c_int == 0
- {
- return None;
+ if let Some(depth) = reqs.depth_bits {
+ out.push(ffi::glx::DEPTH_SIZE as c_int);
+ out.push(depth as c_int);
}
- if get_attrib(ffi::glx::VISUAL_ID as libc::c_int, config) == 0 {
- return None;
+ if let Some(stencil) = reqs.stencil_bits {
+ out.push(ffi::glx::STENCIL_SIZE as c_int);
+ out.push(stencil as c_int);
}
- if get_attrib(ffi::glx::RENDER_TYPE as libc::c_int, config) &
- ffi::glx::RGBA_BIT as libc::c_int == 0
- {
- return None;
+ if let Some(double_buffer) = reqs.double_buffer {
+ out.push(ffi::glx::DOUBLEBUFFER as c_int);
+ out.push(if double_buffer { 1 } else { 0 });
}
- // TODO: add a flag to PixelFormat for non-conformant configs
- let caveat = get_attrib(ffi::glx::CONFIG_CAVEAT as libc::c_int, config);
- /*if caveat == ffi::glx::NON_CONFORMANT_CONFIG as libc::c_int {
- return None;
- }*/
-
- // TODO: make sure everything is supported
- let pf = PixelFormat {
- hardware_accelerated: caveat != ffi::glx::SLOW_CONFIG as libc::c_int,
- color_bits: get_attrib(ffi::glx::RED_SIZE as libc::c_int, config) as u8 +
- get_attrib(ffi::glx::GREEN_SIZE as libc::c_int, config) as u8 +
- get_attrib(ffi::glx::BLUE_SIZE as libc::c_int, config) as u8,
- alpha_bits: get_attrib(ffi::glx::ALPHA_SIZE as libc::c_int, config) as u8,
- depth_bits: get_attrib(ffi::glx::DEPTH_SIZE as libc::c_int, config) as u8,
- stencil_bits: get_attrib(ffi::glx::STENCIL_SIZE as libc::c_int, config) as u8,
- stereoscopy: get_attrib(ffi::glx::STEREO as libc::c_int, config) != 0,
- double_buffer: get_attrib(ffi::glx::DOUBLEBUFFER as libc::c_int, config) != 0,
- multisampling: if get_attrib(ffi::glx::SAMPLE_BUFFERS as libc::c_int, config) != 0 {
- Some(get_attrib(ffi::glx::SAMPLES as libc::c_int, config) as u16)
+ if let Some(multisampling) = reqs.multisampling {
+ if extensions.split(' ').find(|&i| i == "GLX_ARB_multisample").is_some() {
+ out.push(ffi::glx_extra::SAMPLE_BUFFERS_ARB as c_int);
+ out.push(if multisampling == 0 { 0 } else { 1 });
+ out.push(ffi::glx_extra::SAMPLES_ARB as c_int);
+ out.push(multisampling as c_int);
+ } else {
+ return Err(());
+ }
+ }
+
+ out.push(ffi::glx::STEREO as c_int);
+ out.push(if reqs.stereoscopy { 1 } else { 0 });
+
+ if reqs.srgb {
+ if extensions.split(' ').find(|&i| i == "GLX_ARB_framebuffer_sRGB").is_some() {
+ out.push(ffi::glx_extra::FRAMEBUFFER_SRGB_CAPABLE_ARB as c_int);
+ out.push(1);
} else {
- None
+ return Err(());
+ }
+ }
+
+ match reqs.release_behavior {
+ ReleaseBehavior::Flush => (),
+ ReleaseBehavior::None => {
+ if extensions.split(' ').find(|&i| i == "GLX_ARB_context_flush_control").is_some() {
+ out.push(ffi::glx_extra::CONTEXT_RELEASE_BEHAVIOR_ARB as c_int);
+ out.push(ffi::glx_extra::CONTEXT_RELEASE_BEHAVIOR_NONE_ARB as c_int);
+ }
},
- srgb: get_attrib(ffi::glx_extra::FRAMEBUFFER_SRGB_CAPABLE_ARB as libc::c_int, config) != 0,
- };
+ }
+
+ out.push(0);
+ out
+ };
+
+ // calling glXChooseFBConfig
+ let fb_config = {
+ let mut num_configs = 1;
+ let result = glx.ChooseFBConfig(display as *mut _, 0, descriptor.as_ptr(),
+ &mut num_configs);
+ if result.is_null() { return Err(()); }
+ if num_configs == 0 { return Err(()); }
+ let val = *result;
+ (xlib.XFree)(result as *mut _);
+ val
+ };
+
+ let get_attrib = |attrib: c_int| -> i32 {
+ let mut value = 0;
+ glx.GetFBConfigAttrib(display as *mut _, fb_config, attrib, &mut value);
+ // TODO: check return value
+ value
+ };
+
+ let pf_desc = PixelFormat {
+ hardware_accelerated: get_attrib(ffi::glx::CONFIG_CAVEAT as c_int) !=
+ ffi::glx::SLOW_CONFIG as c_int,
+ color_bits: get_attrib(ffi::glx::RED_SIZE as c_int) as u8 +
+ get_attrib(ffi::glx::GREEN_SIZE as c_int) as u8 +
+ get_attrib(ffi::glx::BLUE_SIZE as c_int) as u8,
+ alpha_bits: get_attrib(ffi::glx::ALPHA_SIZE as c_int) as u8,
+ depth_bits: get_attrib(ffi::glx::DEPTH_SIZE as c_int) as u8,
+ stencil_bits: get_attrib(ffi::glx::STENCIL_SIZE as c_int) as u8,
+ stereoscopy: get_attrib(ffi::glx::STEREO as c_int) != 0,
+ double_buffer: get_attrib(ffi::glx::DOUBLEBUFFER as c_int) != 0,
+ multisampling: if get_attrib(ffi::glx::SAMPLE_BUFFERS as c_int) != 0 {
+ Some(get_attrib(ffi::glx::SAMPLES as c_int) as u16)
+ } else {
+ None
+ },
+ srgb: get_attrib(ffi::glx_extra::FRAMEBUFFER_SRGB_CAPABLE_ARB as c_int) != 0,
+ };
- Some((config, pf))
- }).collect())
+ Ok((fb_config, pf_desc))
}