From 0b6418fabbeb0ec9cd326c5397969aceb06f1b41 Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Sat, 19 Dec 2015 11:24:09 +0100 Subject: [PATCH 1/8] Change PixelFormatRequirements --- src/lib.rs | 82 +++++++++++++++++++++++++++++++++++++++++---------- src/window.rs | 2 +- 2 files changed, 68 insertions(+), 16 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index c5431559..32c37e38 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -300,6 +300,16 @@ pub enum Robustness { TryRobustLoseContextOnReset, } +/// The behavior of the driver when you change the current context. +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum ReleaseBehavior { + /// Doesn't do anything. Most notably doesn't flush. + None, + + /// Flushes the context that was previously current as if `glFlush` was called. + Flush, +} + #[derive(Debug, Copy, Clone)] pub enum MouseCursor { /// The platform-dependent default cursor. @@ -388,17 +398,53 @@ pub struct PixelFormat { pub srgb: bool, } -/// VERY UNSTABLE! Describes how the backend should choose a pixel format. +/// Describes how the backend should choose a pixel format. #[derive(Clone, Debug)] -#[allow(missing_docs)] pub struct PixelFormatRequirements { - pub multisampling: Option, - pub depth_bits: Option, - pub stencil_bits: Option, + /// If true, only hardware-accelerated formats will be conisdered. If false, only software + /// renderers. `None` means "don't care". Default is `Some(true)`. + pub hardware_accelerated: Option, + + /// Minimum number of bits for the color buffer, excluding alpha. `None` means "don't care". + /// The default is `Some(24)`. pub color_bits: Option, + + /// If true, the color buffer must be in a floating point format. Default is `false`. + /// + /// Using floating points allows you to write values outside of the `[0.0, 1.0]` range. + pub float_color_buffer: bool, + + /// Minimum number of bits for the alpha in the color buffer. `None` means "don't care". + /// The default is `Some(8)`. pub alpha_bits: Option, + + /// Minimum number of bits for the depth buffer. `None` means "don't care". + /// The default value is `Some(24)`. + pub depth_bits: Option, + + /// Minimum number of bits for the depth buffer. `None` means "don't care". + /// The default value is `Some(8)`. + pub stencil_bits: Option, + + /// If true, only double-buffered formats will be considered. If false, only single-buffer + /// formats. `None` means "don't care". The default is `Some(true)`. + pub double_buffer: Option, + + /// Contains the minimum number of samples per pixel in the color, depth and stencil buffers. + /// `None` means "don't care". Default is `None`. + /// A value of `Some(0)` indicates that multisampling must not be enabled. + pub multisampling: Option, + + /// If true, only stereoscopic formats will be considered. If false, only non-stereoscopic + /// formats. The default is `false`. pub stereoscopy: bool, - pub srgb: Option, + + /// If true, only sRGB-capable formats will be considered. If false, don't care. + /// The default is `false`. + pub srgb: bool, + + /// The behavior when changing the current context. Default is `Flush`. + pub release_behavior: ReleaseBehavior, } impl PixelFormatRequirements { @@ -406,6 +452,10 @@ impl PixelFormatRequirements { fn choose_pixel_format(&self, iter: I) -> Result<(T, PixelFormat), CreationError> where I: IntoIterator, T: Clone { + if self.release_behavior != ReleaseBehavior::Flush { return Err(CreationError::NoAvailablePixelFormat); } + if self.double_buffer == Some(false) { return Err(CreationError::NoAvailablePixelFormat); } + if self.float_color_buffer { return Err(CreationError::NoAvailablePixelFormat); } + // filtering formats that don't match the requirements let iter = iter.into_iter().filter(|&(_, ref format)| { if format.color_bits < self.color_bits.unwrap_or(0) { @@ -439,10 +489,8 @@ impl PixelFormatRequirements { } } - if let Some(srgb) = self.srgb { - if srgb != format.srgb { - return false; - } + if self.srgb && !format.srgb { + return false; } true @@ -507,13 +555,17 @@ impl Default for PixelFormatRequirements { #[inline] fn default() -> PixelFormatRequirements { PixelFormatRequirements { + hardware_accelerated: Some(true), + color_bits: Some(24), + float_color_buffer: false, + alpha_bits: Some(8), + depth_bits: Some(24), + stencil_bits: Some(8), + double_buffer: Some(true), multisampling: None, - depth_bits: None, - stencil_bits: None, - color_bits: None, - alpha_bits: None, stereoscopy: false, - srgb: None, + srgb: false, + release_behavior: ReleaseBehavior::Flush, } } } diff --git a/src/window.rs b/src/window.rs index f2d65807..f672ed5e 100644 --- a/src/window.rs +++ b/src/window.rs @@ -186,7 +186,7 @@ impl<'a> WindowBuilder<'a> { /// Sets whether sRGB should be enabled on the window. `None` means "I don't care". #[inline] pub fn with_srgb(mut self, srgb_enabled: Option) -> WindowBuilder<'a> { - self.pf_reqs.srgb = srgb_enabled; + self.pf_reqs.srgb = srgb_enabled.unwrap_or(false); self } From 95a60ee32965fa523aa8e9d8694df7c08b9da0ff Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Sat, 19 Dec 2015 13:06:50 +0100 Subject: [PATCH 2/8] Switch WGL to ChoosePixelFormat --- build.rs | 2 + src/api/wgl/mod.rs | 430 +++++++++++++++++++++++++++++++++------------ src/lib.rs | 1 + 3 files changed, 317 insertions(+), 116 deletions(-) diff --git a/build.rs b/build.rs index e137ad77..7afeb894 100644 --- a/build.rs +++ b/build.rs @@ -28,10 +28,12 @@ fn main() { "WGL_ARB_create_context".to_string(), "WGL_ARB_create_context_profile".to_string(), "WGL_ARB_create_context_robustness".to_string(), + "WGL_ARB_context_flush_control".to_string(), "WGL_ARB_extensions_string".to_string(), "WGL_ARB_framebuffer_sRGB".to_string(), "WGL_ARB_multisample".to_string(), "WGL_ARB_pixel_format".to_string(), + "WGL_ARB_pixel_format_float".to_string(), "WGL_EXT_create_context_es2_profile".to_string(), "WGL_EXT_extensions_string".to_string(), "WGL_EXT_framebuffer_sRGB".to_string(), diff --git a/src/api/wgl/mod.rs b/src/api/wgl/mod.rs index 77e3f837..dcd16b68 100644 --- a/src/api/wgl/mod.rs +++ b/src/api/wgl/mod.rs @@ -8,6 +8,7 @@ use GlRequest; use GlProfile; use PixelFormat; use PixelFormatRequirements; +use ReleaseBehavior; use Robustness; use Api; @@ -107,20 +108,16 @@ impl Context { // calling SetPixelFormat let pixel_format = { - let formats = if extensions.split(' ').find(|&i| i == "WGL_ARB_pixel_format") + let (id, f) = if extensions.split(' ').find(|&i| i == "WGL_ARB_pixel_format") .is_some() { - let f = enumerate_arb_pixel_formats(&extra_functions, &extensions, hdc); - if f.is_empty() { - enumerate_native_pixel_formats(hdc) - } else { - f - } + try!(choose_arb_pixel_format(&extra_functions, &extensions, hdc, pf_reqs) + .map_err(|_| CreationError::NoAvailablePixelFormat)) } else { - enumerate_native_pixel_formats(hdc) + try!(choose_native_pixel_format(hdc, pf_reqs) + .map_err(|_| CreationError::NoAvailablePixelFormat)) }; - let (id, f) = try!(pf_reqs.choose_pixel_format(formats)); try!(set_pixel_format(hdc, id)); f }; @@ -349,117 +346,297 @@ unsafe fn create_context(extra: Option<(&gl::wgl_extra::Wgl, &PixelFormatRequire Ok(ContextWrapper(ctxt as winapi::HGLRC)) } -/// Enumerates the list of pixel formats without using WGL. +/// Chooses a pixel formats without using WGL. /// /// Gives less precise results than `enumerate_arb_pixel_formats`. -unsafe fn enumerate_native_pixel_formats(hdc: winapi::HDC) -> Vec<(c_int, PixelFormat)> { - let size_of_pxfmtdescr = mem::size_of::() as u32; - let num = gdi32::DescribePixelFormat(hdc, 1, size_of_pxfmtdescr, ptr::null_mut()); +unsafe fn choose_native_pixel_format(hdc: winapi::HDC, reqs: &PixelFormatRequirements) + -> Result<(c_int, PixelFormat), ()> +{ + // TODO: hardware acceleration is not handled - let mut result = Vec::new(); - - for index in (0 .. num) { - let mut output: winapi::PIXELFORMATDESCRIPTOR = mem::zeroed(); - - if gdi32::DescribePixelFormat(hdc, index, size_of_pxfmtdescr, &mut output) == 0 { - continue; - } - - if (output.dwFlags & winapi::PFD_DRAW_TO_WINDOW) == 0 { - continue; - } - - if (output.dwFlags & winapi::PFD_SUPPORT_OPENGL) == 0 { - continue; - } - - if output.iPixelType != winapi::PFD_TYPE_RGBA { - continue; - } - - result.push((index, PixelFormat { - hardware_accelerated: (output.dwFlags & winapi::PFD_GENERIC_FORMAT) == 0, - color_bits: output.cRedBits + output.cGreenBits + output.cBlueBits, - alpha_bits: output.cAlphaBits, - depth_bits: output.cDepthBits, - stencil_bits: output.cStencilBits, - stereoscopy: (output.dwFlags & winapi::PFD_STEREO) != 0, - double_buffer: (output.dwFlags & winapi::PFD_DOUBLEBUFFER) != 0, - multisampling: None, - srgb: false, - })); + // handling non-supported stuff + if reqs.float_color_buffer { + return Err(()); } - result + match reqs.multisampling { + Some(0) => (), + None => (), + Some(_) => return Err(()) + }; + + if reqs.stereoscopy { + return Err(()); + } + + if reqs.srgb { + return Err(()); + } + + if reqs.release_behavior != ReleaseBehavior::Flush { + return Err(()); + } + + // building the descriptor to pass to ChoosePixelFormat + let descriptor = winapi::PIXELFORMATDESCRIPTOR { + nSize: mem::size_of::() as u16, + nVersion: 1, + dwFlags: { + let f1 = match reqs.double_buffer { + None => winapi::PFD_DOUBLEBUFFER_DONTCARE, + Some(true) => winapi::PFD_DOUBLEBUFFER, + Some(false) => 0, + }; + + let f2 = if reqs.stereoscopy { + winapi::PFD_STEREO + } else { + 0 + }; + + winapi::PFD_DRAW_TO_WINDOW | winapi::PFD_SUPPORT_OPENGL | f1 | f2 + }, + iPixelType: winapi::PFD_TYPE_RGBA, + cColorBits: reqs.color_bits.unwrap_or(0), + cRedBits: 0, + cRedShift: 0, + cGreenBits: 0, + cGreenShift: 0, + cBlueBits: 0, + cBlueShift: 0, + cAlphaBits: reqs.alpha_bits.unwrap_or(0), + cAlphaShift: 0, + cAccumBits: 0, + cAccumRedBits: 0, + cAccumGreenBits: 0, + cAccumBlueBits: 0, + cAccumAlphaBits: 0, + cDepthBits: reqs.depth_bits.unwrap_or(0), + cStencilBits: reqs.stencil_bits.unwrap_or(0), + cAuxBuffers: 0, + iLayerType: winapi::PFD_MAIN_PLANE, + bReserved: 0, + dwLayerMask: 0, + dwVisibleMask: 0, + dwDamageMask: 0, + }; + + // now querying + let pf_id = gdi32::ChoosePixelFormat(hdc, &descriptor); + if pf_id == 0 { + return Err(()); + } + + // querying back the capabilities of what windows told us + let mut output: winapi::PIXELFORMATDESCRIPTOR = mem::zeroed(); + if gdi32::DescribePixelFormat(hdc, pf_id, mem::size_of::() as u32, + &mut output) == 0 + { + return Err(()); + } + + // windows may return us a non-conforming pixel format if none are supported, so we have to + // check this + if (output.dwFlags & winapi::PFD_DRAW_TO_WINDOW) == 0 { + return Err(()); + } + if (output.dwFlags & winapi::PFD_SUPPORT_OPENGL) == 0 { + return Err(()); + } + if output.iPixelType != winapi::PFD_TYPE_RGBA { + return Err(()); + } + + let pf_desc = PixelFormat { + hardware_accelerated: (output.dwFlags & winapi::PFD_GENERIC_FORMAT) == 0, + color_bits: output.cRedBits + output.cGreenBits + output.cBlueBits, + alpha_bits: output.cAlphaBits, + depth_bits: output.cDepthBits, + stencil_bits: output.cStencilBits, + stereoscopy: (output.dwFlags & winapi::PFD_STEREO) != 0, + double_buffer: (output.dwFlags & winapi::PFD_DOUBLEBUFFER) != 0, + multisampling: None, + srgb: false, + }; + + if pf_desc.alpha_bits < reqs.alpha_bits.unwrap_or(0) { + return Err(()); + } + if pf_desc.depth_bits < reqs.depth_bits.unwrap_or(0) { + return Err(()); + } + if pf_desc.stencil_bits < reqs.stencil_bits.unwrap_or(0) { + return Err(()); + } + if pf_desc.color_bits < reqs.color_bits.unwrap_or(0) { + return Err(()); + } + if let Some(req) = reqs.hardware_accelerated { + if pf_desc.hardware_accelerated != req { + return Err(()); + } + } + if let Some(req) = reqs.double_buffer { + if pf_desc.double_buffer != req { + return Err(()); + } + } + + Ok((pf_id, pf_desc)) } /// Enumerates the list of pixel formats by using extra WGL functions. /// /// Gives more precise results than `enumerate_native_pixel_formats`. -unsafe fn enumerate_arb_pixel_formats(extra: &gl::wgl_extra::Wgl, extensions: &str, - hdc: winapi::HDC) -> Vec<(c_int, PixelFormat)> +unsafe fn choose_arb_pixel_format(extra: &gl::wgl_extra::Wgl, extensions: &str, + hdc: winapi::HDC, reqs: &PixelFormatRequirements) + -> Result<(c_int, PixelFormat), ()> { - let get_info = |index: u32, attrib: u32| { + let descriptor = { + let mut out: Vec = Vec::with_capacity(37); + + out.push(gl::wgl_extra::DRAW_TO_WINDOW_ARB as c_int); + out.push(1); + + out.push(gl::wgl_extra::SUPPORT_OPENGL_ARB as c_int); + out.push(1); + + out.push(gl::wgl_extra::PIXEL_TYPE_ARB as c_int); + if reqs.float_color_buffer { + if extensions.split(' ').find(|&i| i == "WGL_ARB_pixel_format_float").is_some() { + out.push(gl::wgl_extra::TYPE_RGBA_FLOAT_ARB as c_int); + } else { + return Err(()); + } + } else { + out.push(gl::wgl_extra::TYPE_RGBA_ARB as c_int); + } + + if let Some(hardware_accelerated) = reqs.hardware_accelerated { + out.push(gl::wgl_extra::ACCELERATION_ARB as c_int); + out.push(if hardware_accelerated { + gl::wgl_extra::FULL_ACCELERATION_ARB as c_int + } else { + gl::wgl_extra::NO_ACCELERATION_ARB as c_int + }); + } + + if let Some(color) = reqs.color_bits { + out.push(gl::wgl_extra::COLOR_BITS_ARB as c_int); + out.push(color as c_int); + } + + if let Some(alpha) = reqs.alpha_bits { + out.push(gl::wgl_extra::ALPHA_BITS_ARB as c_int); + out.push(alpha as c_int); + } + + if let Some(depth) = reqs.depth_bits { + out.push(gl::wgl_extra::DEPTH_BITS_ARB as c_int); + out.push(depth as c_int); + } + + if let Some(stencil) = reqs.stencil_bits { + out.push(gl::wgl_extra::STENCIL_BITS_ARB as c_int); + out.push(stencil as c_int); + } + + if let Some(double_buffer) = reqs.double_buffer { + out.push(gl::wgl_extra::DOUBLE_BUFFER_ARB as c_int); + out.push(if double_buffer { 1 } else { 0 }); + } + + if let Some(multisampling) = reqs.multisampling { + if extensions.split(' ').find(|&i| i == "WGL_ARB_multisample").is_some() { + out.push(gl::wgl_extra::SAMPLE_BUFFERS_ARB as c_int); + out.push(if multisampling == 0 { 0 } else { 1 }); + out.push(gl::wgl_extra::SAMPLES_ARB as c_int); + out.push(multisampling as c_int); + } else { + return Err(()); + } + } + + out.push(gl::wgl_extra::STEREO_ARB as c_int); + out.push(if reqs.stereoscopy { 1 } else { 0 }); + + if reqs.srgb { + if extensions.split(' ').find(|&i| i == "WGL_ARB_framebuffer_sRGB").is_some() { + out.push(gl::wgl_extra::FRAMEBUFFER_SRGB_CAPABLE_ARB as c_int); + out.push(1); + } else if extensions.split(' ').find(|&i| i == "WGL_EXT_framebuffer_sRGB").is_some() { + out.push(gl::wgl_extra::FRAMEBUFFER_SRGB_CAPABLE_EXT as c_int); + out.push(1); + } else { + return Err(()); + } + } + + match reqs.release_behavior { + ReleaseBehavior::Flush => (), + ReleaseBehavior::None => { + if extensions.split(' ').find(|&i| i == "WGL_ARB_context_flush_control").is_some() { + out.push(gl::wgl_extra::CONTEXT_RELEASE_BEHAVIOR_ARB as c_int); + out.push(gl::wgl_extra::CONTEXT_RELEASE_BEHAVIOR_NONE_ARB as c_int); + } + }, + } + + out.push(0); + out + }; + + let mut format_id = mem::uninitialized(); + let mut num_formats = mem::uninitialized(); + if extra.ChoosePixelFormatARB(hdc as *const _, descriptor.as_ptr(), ptr::null(), 1, + &mut format_id, &mut num_formats) == 0 + { + return Err(()); + } + + if num_formats == 0 { + return Err(()); + } + + let get_info = |attrib: u32| { let mut value = mem::uninitialized(); - extra.GetPixelFormatAttribivARB(hdc as *const _, index as c_int, + extra.GetPixelFormatAttribivARB(hdc as *const _, format_id as c_int, 0, 1, [attrib as c_int].as_ptr(), &mut value); value as u32 }; - // getting the number of formats - // the `1` is ignored - let num = get_info(1, gl::wgl_extra::NUMBER_PIXEL_FORMATS_ARB); - - let mut result = Vec::new(); - - for index in (0 .. num) { - if get_info(index, gl::wgl_extra::DRAW_TO_WINDOW_ARB) == 0 { - continue; - } - if get_info(index, gl::wgl_extra::SUPPORT_OPENGL_ARB) == 0 { - continue; - } - - if get_info(index, gl::wgl_extra::ACCELERATION_ARB) == gl::wgl_extra::NO_ACCELERATION_ARB { - continue; - } - - if get_info(index, gl::wgl_extra::PIXEL_TYPE_ARB) != gl::wgl_extra::TYPE_RGBA_ARB { - continue; - } - - result.push((index as c_int, PixelFormat { - hardware_accelerated: true, - color_bits: get_info(index, gl::wgl_extra::RED_BITS_ARB) as u8 + - get_info(index, gl::wgl_extra::GREEN_BITS_ARB) as u8 + - get_info(index, gl::wgl_extra::BLUE_BITS_ARB) as u8, - alpha_bits: get_info(index, gl::wgl_extra::ALPHA_BITS_ARB) as u8, - depth_bits: get_info(index, gl::wgl_extra::DEPTH_BITS_ARB) as u8, - stencil_bits: get_info(index, gl::wgl_extra::STENCIL_BITS_ARB) as u8, - stereoscopy: get_info(index, gl::wgl_extra::STEREO_ARB) != 0, - double_buffer: get_info(index, gl::wgl_extra::DOUBLE_BUFFER_ARB) != 0, - multisampling: { - if extensions.split(' ').find(|&i| i == "WGL_ARB_multisample").is_some() { - match get_info(index, gl::wgl_extra::SAMPLES_ARB) { - 0 => None, - a => Some(a as u16), - } - } else { - None + let pf_desc = PixelFormat { + hardware_accelerated: get_info(gl::wgl_extra::ACCELERATION_ARB) != + gl::wgl_extra::NO_ACCELERATION_ARB, + color_bits: get_info(gl::wgl_extra::RED_BITS_ARB) as u8 + + get_info(gl::wgl_extra::GREEN_BITS_ARB) as u8 + + get_info(gl::wgl_extra::BLUE_BITS_ARB) as u8, + alpha_bits: get_info(gl::wgl_extra::ALPHA_BITS_ARB) as u8, + depth_bits: get_info(gl::wgl_extra::DEPTH_BITS_ARB) as u8, + stencil_bits: get_info(gl::wgl_extra::STENCIL_BITS_ARB) as u8, + stereoscopy: get_info(gl::wgl_extra::STEREO_ARB) != 0, + double_buffer: get_info(gl::wgl_extra::DOUBLE_BUFFER_ARB) != 0, + multisampling: { + if extensions.split(' ').find(|&i| i == "WGL_ARB_multisample").is_some() { + match get_info(gl::wgl_extra::SAMPLES_ARB) { + 0 => None, + a => Some(a as u16), } - }, - srgb: if extensions.split(' ').find(|&i| i == "WGL_ARB_framebuffer_sRGB").is_some() { - get_info(index, gl::wgl_extra::FRAMEBUFFER_SRGB_CAPABLE_ARB) != 0 - } else if extensions.split(' ').find(|&i| i == "WGL_EXT_framebuffer_sRGB").is_some() { - get_info(index, gl::wgl_extra::FRAMEBUFFER_SRGB_CAPABLE_EXT) != 0 } else { - false - }, - })); - } + None + } + }, + srgb: if extensions.split(' ').find(|&i| i == "WGL_ARB_framebuffer_sRGB").is_some() { + get_info(gl::wgl_extra::FRAMEBUFFER_SRGB_CAPABLE_ARB) != 0 + } else if extensions.split(' ').find(|&i| i == "WGL_EXT_framebuffer_sRGB").is_some() { + get_info(gl::wgl_extra::FRAMEBUFFER_SRGB_CAPABLE_EXT) != 0 + } else { + false + }, + }; - result + Ok((format_id, pf_desc)) } /// Calls `SetPixelFormat` on a window. @@ -550,8 +727,7 @@ unsafe fn load_extra_functions(window: winapi::HWND) -> Result Result(iter: I) -> Result - where I: Iterator -{ - let mut backup_id = None; +fn choose_dummy_pixel_format(hdc: winapi::HDC) -> Result { + // building the descriptor to pass to ChoosePixelFormat + let descriptor = winapi::PIXELFORMATDESCRIPTOR { + nSize: mem::size_of::() as u16, + nVersion: 1, + dwFlags: winapi::PFD_DRAW_TO_WINDOW | winapi::PFD_SUPPORT_OPENGL | winapi::PFD_DOUBLEBUFFER, + iPixelType: winapi::PFD_TYPE_RGBA, + cColorBits: 24, + cRedBits: 0, + cRedShift: 0, + cGreenBits: 0, + cGreenShift: 0, + cBlueBits: 0, + cBlueShift: 0, + cAlphaBits: 8, + cAlphaShift: 0, + cAccumBits: 0, + cAccumRedBits: 0, + cAccumGreenBits: 0, + cAccumBlueBits: 0, + cAccumAlphaBits: 0, + cDepthBits: 24, + cStencilBits: 8, + cAuxBuffers: 0, + iLayerType: winapi::PFD_MAIN_PLANE, + bReserved: 0, + dwLayerMask: 0, + dwVisibleMask: 0, + dwDamageMask: 0, + }; - for (id, format) in iter { - if backup_id.is_none() { - backup_id = Some(id); - } - - if format.hardware_accelerated { - return Ok(id); - } + // now querying + let pf_id = unsafe { gdi32::ChoosePixelFormat(hdc, &descriptor) }; + if pf_id == 0 { + return Err(CreationError::OsError("No available pixel format".to_owned())); } - backup_id.ok_or(CreationError::OsError("No available pixel format".to_string())) + Ok(pf_id) } diff --git a/src/lib.rs b/src/lib.rs index 32c37e38..794dcb06 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -399,6 +399,7 @@ pub struct PixelFormat { } /// Describes how the backend should choose a pixel format. +// TODO: swap method? (swap, copy) #[derive(Clone, Debug)] pub struct PixelFormatRequirements { /// If true, only hardware-accelerated formats will be conisdered. If false, only software From 6b3a3a45770b870c241c1244863c4a0b5cd791d2 Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Sat, 19 Dec 2015 13:52:06 +0100 Subject: [PATCH 3/8] Update GLX to use glXChooseFBConfig --- build.rs | 1 + src/api/glx/mod.rs | 188 ++++++++++++++++++++++++++++++--------------- 2 files changed, 127 insertions(+), 62 deletions(-) diff --git a/build.rs b/build.rs index 7afeb894..d1c5390e 100644 --- a/build.rs +++ b/build.rs @@ -80,6 +80,7 @@ fn main() { "GLX_ARB_create_context".to_string(), "GLX_ARB_create_context_profile".to_string(), "GLX_ARB_create_context_robustness".to_string(), + "GLX_ARB_fbconfig_float".to_string(), "GLX_ARB_framebuffer_sRGB".to_string(), "GLX_EXT_framebuffer_sRGB".to_string(), "GLX_EXT_swap_control".to_string(), diff --git a/src/api/glx/mod.rs b/src/api/glx/mod.rs index 61a7d2fe..bd56d1b3 100644 --- a/src/api/glx/mod.rs +++ b/src/api/glx/mod.rs @@ -9,6 +9,7 @@ use GlRequest; use Api; use PixelFormat; use PixelFormatRequirements; +use ReleaseBehavior; use Robustness; use libc; @@ -341,75 +342,138 @@ fn create_context(glx: &ffi::glx::Glx, extra_functions: &ffi::glx_extra::Glx, ex unsafe fn enumerate_configs(glx: &ffi::glx::Glx, xlib: &ffi::Xlib, display: *mut ffi::Display) -> Result, CreationError> { - let configs: Vec = { - 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 = Vec::with_capacity(37); + + 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::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 + }); + } + + 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 let Some(alpha) = reqs.alpha_bits { + out.push(ffi::glx::ALPHA_SIZE as c_int); + out.push(alpha as c_int); + } + + if let Some(depth) = reqs.depth_bits { + out.push(ffi::glx::DEPTH_SIZE as c_int); + out.push(depth as c_int); + } + + if let Some(stencil) = reqs.stencil_bits { + out.push(ffi::glx::STENCIL_SIZE as c_int); + out.push(stencil as c_int); + } + + if let Some(double_buffer) = reqs.double_buffer { + out.push(ffi::glx::DOUBLEBUFFER as c_int); + out.push(if double_buffer { 1 } else { 0 }); + } + + if let Some(multisampling) = reqs.multisampling { + if extensions.split(' ').find(|&i| i == "GLX_ARB_multisample").is_some() { + out.push(ffi::glx::SAMPLE_BUFFERS_ARB as c_int); + out.push(if multisampling == 0 { 0 } else { 1 }); + out.push(ffi::glx::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::FRAMEBUFFER_SRGB_CAPABLE_ARB as c_int); + out.push(1); + } else { + 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::CONTEXT_RELEASE_BEHAVIOR_ARB as c_int); + out.push(ffi::glx::CONTEXT_RELEASE_BEHAVIOR_NONE_ARB as c_int); + } + }, + } + + out.push(0); + out }; - let get_attrib = |attrib: libc::c_int, fb_config: ffi::glx::types::GLXFBConfig| -> i32 { + // calling glXChooseFBConfig + let fb_config = { + let result = glx.ChooseFBConfig(display as *mut _, 0, descriptor.as_ptr(), &1); + if result.is_null() { return Err(()); } + let val = *result; + (xlib.XFree)(result as *mut _); + val + }; + + 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 }; - Ok(configs.into_iter().filter_map(|config| { - if get_attrib(ffi::glx::X_RENDERABLE as libc::c_int, config) == 0 { - return None; - } + let pf_desc = PixelFormat { + hardware_accelerated: get_attrib(ffi::glx::CONFIG_CAVEAT as libc::c_int, config) != + 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) + } else { + None + }, + srgb: get_attrib(ffi::glx_extra::FRAMEBUFFER_SRGB_CAPABLE_ARB as libc::c_int, config) != 0, + }; - if get_attrib(ffi::glx::X_VISUAL_TYPE as libc::c_int, config) != - ffi::glx::TRUE_COLOR as libc::c_int - { - return None; - } - - if get_attrib(ffi::glx::DRAWABLE_TYPE as libc::c_int, config) & - ffi::glx::WINDOW_BIT as libc::c_int == 0 - { - return None; - } - - if get_attrib(ffi::glx::VISUAL_ID as libc::c_int, config) == 0 { - return None; - } - - if get_attrib(ffi::glx::RENDER_TYPE as libc::c_int, config) & - ffi::glx::RGBA_BIT as libc::c_int == 0 - { - return None; - } - - // 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) - } else { - None - }, - srgb: get_attrib(ffi::glx_extra::FRAMEBUFFER_SRGB_CAPABLE_ARB as libc::c_int, config) != 0, - }; - - Some((config, pf)) - }).collect()) + Ok((fb_config, pf_desc)) } From a428e0608fa4104a5c79208f94f6f5bc6ce04b9d Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Sat, 19 Dec 2015 13:56:25 +0100 Subject: [PATCH 4/8] Update cocoa implementation with changes to pf_reqs --- src/api/cocoa/mod.rs | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/src/api/cocoa/mod.rs b/src/api/cocoa/mod.rs index b7e0239e..2ae2c23a 100644 --- a/src/api/cocoa/mod.rs +++ b/src/api/cocoa/mod.rs @@ -13,6 +13,7 @@ use GlProfile; use GlRequest; use PixelFormat; use PixelFormatRequirements; +use ReleaseBehavior; use Robustness; use WindowAttributes; use native_monitor::NativeMonitorId; @@ -493,6 +494,8 @@ impl Window { let alpha_depth = pf_reqs.alpha_bits.unwrap_or(8); let color_depth = pf_reqs.color_bits.unwrap_or(24) + alpha_depth; + // TODO: handle hardware_accelerated parameter of pf_reqs + let mut attributes = vec![ NSOpenGLPFADoubleBuffer as u32, NSOpenGLPFAClosestPolicy as u32, @@ -503,10 +506,19 @@ impl Window { NSOpenGLPFAOpenGLProfile as u32, profile, ]; - // A color depth higher than 64 implies we're using either 16-bit - // floats or 32-bit floats and OS X requires a flag to be set - // accordingly. - if color_depth >= 64 { + if reqs.release_behavior != ReleaseBehavior::Flush { + return Err(CreationError::NoAvailablePixelFormat); + } + + if reqs.stereoscopy { + unimplemented!(); // TODO: + } + + if reqs.double_buffer == Some(false) { + unimplemented!(); // TODO: + } + + if pf_reqs.float_color_buffer { attributes.push(NSOpenGLPFAColorFloat as u32); } From 4c9348ab5019da04fcd092b79a113f91aed8f2b0 Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Sat, 19 Dec 2015 14:36:16 +0100 Subject: [PATCH 5/8] Update EGL implementation --- src/api/egl/mod.rs | 230 ++++++++++++++++++++++++++++----------------- 1 file changed, 143 insertions(+), 87 deletions(-) diff --git a/src/api/egl/mod.rs b/src/api/egl/mod.rs index 5e800680..582e376e 100644 --- a/src/api/egl/mod.rs +++ b/src/api/egl/mod.rs @@ -9,6 +9,7 @@ use GlContext; use GlRequest; use PixelFormat; use PixelFormatRequirements; +use ReleaseBehavior; use Robustness; use Api; @@ -247,8 +248,9 @@ impl Context { } }; - let configs = unsafe { try!(enumerate_configs(&egl, display, &egl_version, api, version)) }; - let (config_id, pixel_format) = try!(pf_reqs.choose_pixel_format(configs.into_iter())); + let (config_id, pixel_format) = unsafe { + try!(choose_fbconfig(&egl, display, &egl_version, api, version, pf_reqs)) + }; Ok(ContextPrototype { opengl: opengl, @@ -451,108 +453,162 @@ impl<'a> ContextPrototype<'a> { } } -unsafe fn enumerate_configs(egl: &ffi::egl::Egl, display: ffi::egl::types::EGLDisplay, - egl_version: &(ffi::egl::types::EGLint, ffi::egl::types::EGLint), - api: Api, version: Option<(u8, u8)>) - -> Result, CreationError> +unsafe fn choose_fbconfig(egl: &ffi::egl::Egl, display: ffi::egl::types::EGLDisplay, + egl_version: &(ffi::egl::types::EGLint, ffi::egl::types::EGLint), + api: Api, version: Option<(u8, u8)>, reqs: &PixelFormatRequirements) + -> Result<(ffi::egl::types::EGLConfig, PixelFormat), CreationError> { - let mut num_configs = mem::uninitialized(); - if egl.GetConfigs(display, ptr::null_mut(), 0, &mut num_configs) == 0 { - return Err(CreationError::OsError(format!("eglGetConfigs failed"))); - } + let descriptor = { + let mut out: Vec = Vec::with_capacity(37); - let mut configs_ids = Vec::with_capacity(num_configs as usize); - if egl.GetConfigs(display, configs_ids.as_mut_ptr(), - configs_ids.capacity() as ffi::egl::types::EGLint, - &mut num_configs) == 0 - { - return Err(CreationError::OsError(format!("eglGetConfigs failed"))); - } - configs_ids.set_len(num_configs as usize); + if egl_version >= &(1, 2) { + out.push(ffi::egl::COLOR_BUFFER_TYPE as c_int); + out.push(ffi::egl::RGB_BUFFER as c_int); + } - // analyzing each config - let mut result = Vec::with_capacity(num_configs as usize); - for config_id in configs_ids { - macro_rules! attrib { - ($egl:expr, $display:expr, $config:expr, $attr:expr) => ( - { - let mut value = mem::uninitialized(); - let res = $egl.GetConfigAttrib($display, $config, - $attr as ffi::egl::types::EGLint, &mut value); - if res == 0 { - return Err(CreationError::OsError(format!("eglGetConfigAttrib failed"))); - } - value + if egl_version >= &(1, 3) { + out.push(ffi::egl::SURFACE_TYPE as c_int); + out.push((ffi::egl::WINDOW_BIT | ffi::egl::PBUFFER_BIT) as c_int); + } + + match (api, version) { + (Api::OpenGlEs, Some((3, _))) => { + if egl_version < &(1, 3) { return Err(CreationError::NoAvailablePixelFormat); } + out.push(ffi::egl::RENDERABLE_TYPE as c_int); + out.push(ffi::egl::OPENGL_ES3_BIT as c_int); + out.push(ffi::egl::CONFORMANT as c_int); + out.push(ffi::egl::OPENGL_ES3_BIT as c_int); + }, + (Api::OpenGlEs, Some((2, _))) => { + if egl_version < &(1, 3) { return Err(CreationError::NoAvailablePixelFormat); } + out.push(ffi::egl::RENDERABLE_TYPE as c_int); + out.push(ffi::egl::OPENGL_ES2_BIT as c_int); + out.push(ffi::egl::CONFORMANT as c_int); + out.push(ffi::egl::OPENGL_ES2_BIT as c_int); + }, + (Api::OpenGlEs, Some((1, _))) => { + if egl_version >= &(1, 3) { + out.push(ffi::egl::RENDERABLE_TYPE as c_int); + out.push(ffi::egl::OPENGL_ES_BIT as c_int); + out.push(ffi::egl::CONFORMANT as c_int); + out.push(ffi::egl::OPENGL_ES_BIT as c_int); } - ) + }, + (Api::OpenGlEs, _) => unimplemented!(), + (Api::OpenGl, Some((1, _))) => { + if egl_version < &(1, 3) { return Err(CreationError::NoAvailablePixelFormat); } + out.push(ffi::egl::RENDERABLE_TYPE as c_int); + out.push(ffi::egl::OPENGL_BIT as c_int); + out.push(ffi::egl::CONFORMANT as c_int); + out.push(ffi::egl::OPENGL_BIT as c_int); + }, + (_, _) => unimplemented!(), }; - let renderable = attrib!(egl, display, config_id, ffi::egl::RENDERABLE_TYPE) as u32; - let conformant = attrib!(egl, display, config_id, ffi::egl::CONFORMANT) as u32; - - if api == Api::OpenGlEs { - if let Some(version) = version { - if version.0 == 3 && (renderable & ffi::egl::OPENGL_ES3_BIT == 0 || - conformant & ffi::egl::OPENGL_ES3_BIT == 0) - { - continue; - } - - if version.0 == 2 && (renderable & ffi::egl::OPENGL_ES2_BIT == 0 || - conformant & ffi::egl::OPENGL_ES2_BIT == 0) - { - continue; - } - - if version.0 == 1 && (renderable & ffi::egl::OPENGL_ES_BIT == 0 || - conformant & ffi::egl::OPENGL_ES_BIT == 0) - { - continue; - } - } - - } else if api == Api::OpenGl { - if renderable & ffi::egl::OPENGL_BIT == 0 || - conformant & ffi::egl::OPENGL_BIT == 0 - { - continue; - } + if let Some(hardware_accelerated) = reqs.hardware_accelerated { + out.push(ffi::egl::CONFIG_CAVEAT as c_int); + out.push(if hardware_accelerated { + ffi::egl::NONE as c_int + } else { + ffi::egl::SLOW_CONFIG as c_int + }); } - if attrib!(egl, display, config_id, ffi::egl::SURFACE_TYPE) & - (ffi::egl::WINDOW_BIT | ffi::egl::PBUFFER_BIT) as i32 == 0 - { - continue; + if let Some(color) = reqs.color_bits { + out.push(ffi::egl::RED_SIZE as c_int); + out.push((color / 3) as c_int); + out.push(ffi::egl::GREEN_SIZE as c_int); + out.push((color / 3 + if color % 3 != 0 { 1 } else { 0 }) as c_int); + out.push(ffi::egl::BLUE_SIZE as c_int); + out.push((color / 3 + if color % 3 == 2 { 1 } else { 0 }) as c_int); } - if attrib!(egl, display, config_id, ffi::egl::TRANSPARENT_TYPE) != ffi::egl::NONE as i32 { - continue; + if let Some(alpha) = reqs.alpha_bits { + out.push(ffi::egl::ALPHA_SIZE as c_int); + out.push(alpha as c_int); } - if attrib!(egl, display, config_id, ffi::egl::COLOR_BUFFER_TYPE) != ffi::egl::RGB_BUFFER as i32 { - continue; + if let Some(depth) = reqs.depth_bits { + out.push(ffi::egl::DEPTH_SIZE as c_int); + out.push(depth as c_int); } - result.push((config_id, PixelFormat { - hardware_accelerated: attrib!(egl, display, config_id, ffi::egl::CONFIG_CAVEAT) - != ffi::egl::SLOW_CONFIG as i32, - color_bits: attrib!(egl, display, config_id, ffi::egl::RED_SIZE) as u8 + - attrib!(egl, display, config_id, ffi::egl::BLUE_SIZE) as u8 + - attrib!(egl, display, config_id, ffi::egl::GREEN_SIZE) as u8, - alpha_bits: attrib!(egl, display, config_id, ffi::egl::ALPHA_SIZE) as u8, - depth_bits: attrib!(egl, display, config_id, ffi::egl::DEPTH_SIZE) as u8, - stencil_bits: attrib!(egl, display, config_id, ffi::egl::STENCIL_SIZE) as u8, - stereoscopy: false, - double_buffer: true, - multisampling: match attrib!(egl, display, config_id, ffi::egl::SAMPLES) { - 0 | 1 => None, - a => Some(a as u16), + if let Some(stencil) = reqs.stencil_bits { + out.push(ffi::egl::STENCIL_SIZE as c_int); + out.push(stencil as c_int); + } + + if let Some(true) = reqs.double_buffer { + return Err(CreationError::NoAvailablePixelFormat); + } + + if let Some(multisampling) = reqs.multisampling { + out.push(ffi::egl::SAMPLES as c_int); + out.push(multisampling as c_int); + } + + if reqs.stereoscopy { + return Err(CreationError::NoAvailablePixelFormat); + } + + // FIXME: srgb is not taken into account + + match reqs.release_behavior { + ReleaseBehavior::Flush => (), + ReleaseBehavior::None => { + // TODO: with EGL you need to manually set the behavior + unimplemented!() }, - srgb: false, // TODO: use EGL_KHR_gl_colorspace to know that - })); + } + + out.push(0); + out + }; + + // calling `eglChooseConfig` + let mut config_id = mem::uninitialized(); + let mut num_configs = mem::uninitialized(); + if egl.ChooseConfig(display, descriptor.as_ptr(), &mut config_id, 1, &mut num_configs) == 0 { + return Err(CreationError::OsError(format!("eglChooseConfig failed"))); + } + if num_configs == 0 { + return Err(CreationError::NoAvailablePixelFormat); } - Ok(result) + // analyzing each config + macro_rules! attrib { + ($egl:expr, $display:expr, $config:expr, $attr:expr) => ( + { + let mut value = mem::uninitialized(); + let res = $egl.GetConfigAttrib($display, $config, + $attr as ffi::egl::types::EGLint, &mut value); + if res == 0 { + return Err(CreationError::OsError(format!("eglGetConfigAttrib failed"))); + } + value + } + ) + }; + + let desc = PixelFormat { + hardware_accelerated: attrib!(egl, display, config_id, ffi::egl::CONFIG_CAVEAT) + != ffi::egl::SLOW_CONFIG as i32, + color_bits: attrib!(egl, display, config_id, ffi::egl::RED_SIZE) as u8 + + attrib!(egl, display, config_id, ffi::egl::BLUE_SIZE) as u8 + + attrib!(egl, display, config_id, ffi::egl::GREEN_SIZE) as u8, + alpha_bits: attrib!(egl, display, config_id, ffi::egl::ALPHA_SIZE) as u8, + depth_bits: attrib!(egl, display, config_id, ffi::egl::DEPTH_SIZE) as u8, + stencil_bits: attrib!(egl, display, config_id, ffi::egl::STENCIL_SIZE) as u8, + stereoscopy: false, + double_buffer: true, + multisampling: match attrib!(egl, display, config_id, ffi::egl::SAMPLES) { + 0 | 1 => None, + a => Some(a as u16), + }, + srgb: false, // TODO: use EGL_KHR_gl_colorspace to know that + }; + + Ok((config_id, desc)) } unsafe fn create_context(egl: &ffi::egl::Egl, display: ffi::egl::types::EGLDisplay, From ed1d76aaee193a2e5cec558930a25302bda35713 Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Sat, 19 Dec 2015 14:36:49 +0100 Subject: [PATCH 6/8] Remove now unneeded function --- src/lib.rs | 104 ----------------------------------------------------- 1 file changed, 104 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 794dcb06..5b1aa03a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -448,110 +448,6 @@ pub struct PixelFormatRequirements { pub release_behavior: ReleaseBehavior, } -impl PixelFormatRequirements { - #[cfg(not(target_os = "macos"))] - fn choose_pixel_format(&self, iter: I) -> Result<(T, PixelFormat), CreationError> - where I: IntoIterator, T: Clone - { - if self.release_behavior != ReleaseBehavior::Flush { return Err(CreationError::NoAvailablePixelFormat); } - if self.double_buffer == Some(false) { return Err(CreationError::NoAvailablePixelFormat); } - if self.float_color_buffer { return Err(CreationError::NoAvailablePixelFormat); } - - // filtering formats that don't match the requirements - let iter = iter.into_iter().filter(|&(_, ref format)| { - if format.color_bits < self.color_bits.unwrap_or(0) { - return false; - } - - if format.alpha_bits < self.alpha_bits.unwrap_or(0) { - return false; - } - - if format.depth_bits < self.depth_bits.unwrap_or(0) { - return false; - } - - if format.stencil_bits < self.stencil_bits.unwrap_or(0) { - return false; - } - - if !format.stereoscopy && self.stereoscopy { - return false; - } - - if let Some(req_ms) = self.multisampling { - match format.multisampling { - Some(val) if val >= req_ms => (), - _ => return false - } - } else { - if format.multisampling.is_some() { - return false; - } - } - - if self.srgb && !format.srgb { - return false; - } - - true - }); - - // sorting so that the preferred format comes first - let mut formats = iter.collect::>(); - formats.sort_by(|&(_, ref left), &(_, ref right)| { - // prefer hardware-accelerated formats - if left.hardware_accelerated && !right.hardware_accelerated { - return Ordering::Less; - } else if right.hardware_accelerated && !left.hardware_accelerated { - return Ordering::Greater; - } - - // prefer sRGB formats - if left.srgb && !right.srgb { - return Ordering::Less; - } else if right.srgb && !left.srgb { - return Ordering::Greater; - } - - // prefer formats with the highest color+alpha bits - if left.color_bits + left.alpha_bits != right.color_bits + right.alpha_bits { - return (right.color_bits + right.alpha_bits) - .cmp(&(left.color_bits + left.alpha_bits)); - } - - // prefer double-buffering formats - if left.double_buffer && !right.double_buffer { - return Ordering::Less; - } else if right.double_buffer && !left.double_buffer { - return Ordering::Greater; - } - - // prefer formats with the highest depth bits - if left.depth_bits != right.depth_bits { - return (right.depth_bits).cmp(&left.depth_bits); - } - - // prefer formats with the highest stencil bits - if left.stencil_bits != right.stencil_bits { - return (right.stencil_bits).cmp(&left.stencil_bits); - } - - // prefer formats with multisampling - if left.multisampling.is_some() && right.multisampling.is_none() { - return Ordering::Less; - } else if right.multisampling.is_some() && left.multisampling.is_none() { - return Ordering::Greater; - } - - // default - return Ordering::Equal; - }); - - formats.into_iter().next().ok_or(CreationError::NoAvailablePixelFormat) - } -} - impl Default for PixelFormatRequirements { #[inline] fn default() -> PixelFormatRequirements { From 67356b45a3ff10f87e51dee254994670af8cdfce Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Sat, 19 Dec 2015 14:42:51 +0100 Subject: [PATCH 7/8] Fix compilation on cocoa --- src/api/cocoa/mod.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/api/cocoa/mod.rs b/src/api/cocoa/mod.rs index 2ae2c23a..5bc7e803 100644 --- a/src/api/cocoa/mod.rs +++ b/src/api/cocoa/mod.rs @@ -506,15 +506,15 @@ impl Window { NSOpenGLPFAOpenGLProfile as u32, profile, ]; - if reqs.release_behavior != ReleaseBehavior::Flush { + if pf_reqs.release_behavior != ReleaseBehavior::Flush { return Err(CreationError::NoAvailablePixelFormat); } - if reqs.stereoscopy { + if pf_reqs.stereoscopy { unimplemented!(); // TODO: } - if reqs.double_buffer == Some(false) { + if pf_reqs.double_buffer == Some(false) { unimplemented!(); // TODO: } From 61bca52217471eca4c4aff1dd84b980966be4bfc Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Sat, 19 Dec 2015 15:00:32 +0100 Subject: [PATCH 8/8] Fix compilation on linux --- build.rs | 2 + src/api/glx/mod.rs | 111 ++++++++++++++++++++++++--------------------- 2 files changed, 61 insertions(+), 52 deletions(-) diff --git a/build.rs b/build.rs index d1c5390e..bf25c959 100644 --- a/build.rs +++ b/build.rs @@ -80,9 +80,11 @@ fn main() { "GLX_ARB_create_context".to_string(), "GLX_ARB_create_context_profile".to_string(), "GLX_ARB_create_context_robustness".to_string(), + "GLX_ARB_context_flush_control".to_string(), "GLX_ARB_fbconfig_float".to_string(), "GLX_ARB_framebuffer_sRGB".to_string(), "GLX_EXT_framebuffer_sRGB".to_string(), + "GLX_ARB_multisample".to_string(), "GLX_EXT_swap_control".to_string(), "GLX_SGI_swap_control".to_string() ], diff --git a/src/api/glx/mod.rs b/src/api/glx/mod.rs index bd56d1b3..9f3e084e 100644 --- a/src/api/glx/mod.rs +++ b/src/api/glx/mod.rs @@ -13,6 +13,7 @@ use ReleaseBehavior; use Robustness; use libc; +use libc::c_int; use std::ffi::{CStr, CString}; use std::{mem, ptr, slice}; @@ -40,10 +41,17 @@ impl Context { opengl: &'a GlAttributes<&'a Context>, display: *mut ffi::Display) -> Result, 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 @@ -59,6 +67,7 @@ impl Context { Ok(ContextPrototype { glx: glx, + extensions: extensions, opengl: opengl, display: display, fb_config: fb_config, @@ -126,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, @@ -145,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| { @@ -162,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, @@ -177,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)) @@ -264,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 { @@ -277,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 = { @@ -288,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 => (), @@ -310,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); @@ -339,8 +342,9 @@ 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, 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 descriptor = { let mut out: Vec = Vec::with_capacity(37); @@ -357,7 +361,7 @@ unsafe fn enumerate_configs(glx: &ffi::glx::Glx, xlib: &ffi::Xlib, display: *mut 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::RGBA_FLOAT_BIT_ARB as c_int); + out.push(ffi::glx_extra::RGBA_FLOAT_BIT_ARB as c_int); } else { return Err(()); } @@ -405,9 +409,9 @@ unsafe fn enumerate_configs(glx: &ffi::glx::Glx, xlib: &ffi::Xlib, display: *mut if let Some(multisampling) = reqs.multisampling { if extensions.split(' ').find(|&i| i == "GLX_ARB_multisample").is_some() { - out.push(ffi::glx::SAMPLE_BUFFERS_ARB as c_int); + out.push(ffi::glx_extra::SAMPLE_BUFFERS_ARB as c_int); out.push(if multisampling == 0 { 0 } else { 1 }); - out.push(ffi::glx::SAMPLES_ARB as c_int); + out.push(ffi::glx_extra::SAMPLES_ARB as c_int); out.push(multisampling as c_int); } else { return Err(()); @@ -419,7 +423,7 @@ unsafe fn enumerate_configs(glx: &ffi::glx::Glx, xlib: &ffi::Xlib, display: *mut if reqs.srgb { if extensions.split(' ').find(|&i| i == "GLX_ARB_framebuffer_sRGB").is_some() { - out.push(ffi::glx::FRAMEBUFFER_SRGB_CAPABLE_ARB as c_int); + out.push(ffi::glx_extra::FRAMEBUFFER_SRGB_CAPABLE_ARB as c_int); out.push(1); } else { return Err(()); @@ -430,8 +434,8 @@ unsafe fn enumerate_configs(glx: &ffi::glx::Glx, xlib: &ffi::Xlib, display: *mut ReleaseBehavior::Flush => (), ReleaseBehavior::None => { if extensions.split(' ').find(|&i| i == "GLX_ARB_context_flush_control").is_some() { - out.push(ffi::glx::CONTEXT_RELEASE_BEHAVIOR_ARB as c_int); - out.push(ffi::glx::CONTEXT_RELEASE_BEHAVIOR_NONE_ARB as c_int); + 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); } }, } @@ -442,14 +446,17 @@ unsafe fn enumerate_configs(glx: &ffi::glx::Glx, xlib: &ffi::Xlib, display: *mut // calling glXChooseFBConfig let fb_config = { - let result = glx.ChooseFBConfig(display as *mut _, 0, descriptor.as_ptr(), &1); + 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: libc::c_int| -> i32 { + 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 @@ -457,22 +464,22 @@ unsafe fn enumerate_configs(glx: &ffi::glx::Glx, xlib: &ffi::Xlib, display: *mut }; let pf_desc = PixelFormat { - hardware_accelerated: get_attrib(ffi::glx::CONFIG_CAVEAT as libc::c_int, config) != - 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) + 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 libc::c_int, config) != 0, + srgb: get_attrib(ffi::glx_extra::FRAMEBUFFER_SRGB_CAPABLE_ARB as c_int) != 0, }; Ok((fb_config, pf_desc))