From 6bec85e0cc7251e9e12952ad38ef8aa24c772ee8 Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Mon, 16 Feb 2015 15:36:32 +0100 Subject: [PATCH] Implement better handling for pixel formats --- src/lib.rs | 53 +++++++++++++++++++++++++++++- src/win32/init.rs | 82 +++++++++++++++++++++++++++++++++-------------- 2 files changed, 110 insertions(+), 25 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index b251a7a3..1bd29bb3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -170,6 +170,21 @@ pub enum MouseCursor { RowResize, } +/// Describes a possible format. Unused. +#[allow(missing_docs)] +pub struct PixelFormat { + pub red_bits: u8, + pub green_bits: u8, + pub blue_bits: u8, + pub alpha_bits: u8, + pub depth_bits: u8, + pub stencil_bits: u8, + pub stereoscopy: bool, + pub double_buffer: bool, + pub multisampling: Option, + pub srgb: bool, +} + /// Attributes struct BuilderAttribs<'a> { #[allow(dead_code)] @@ -239,5 +254,41 @@ impl<'a> BuilderAttribs<'a> { (new_attribs, sharing) } -} + fn choose_pixel_format(&self, iter: I) -> (T, PixelFormat) + where I: Iterator, T: Clone + { + let mut current_result = None; + + // TODO: do this more properly + for (id, format) in iter { + if format.red_bits + format.green_bits + format.blue_bits < self.color_bits.unwrap_or(0) { + continue; + } + + if format.alpha_bits < self.alpha_bits.unwrap_or(0) { + continue; + } + + if format.depth_bits < self.depth_bits.unwrap_or(0) { + continue; + } + + if format.stencil_bits < self.stencil_bits.unwrap_or(0) { + continue; + } + + if !format.stereoscopy && self.stereoscopy { + continue; + } + + if self.multisampling.is_some() && format.multisampling.is_none() { + continue; + } + + current_result = Some((id, format)); + } + + current_result.expect("Could not find compliant pixel format") + } +} diff --git a/src/win32/init.rs b/src/win32/init.rs index fcb23f51..357b87db 100644 --- a/src/win32/init.rs +++ b/src/win32/init.rs @@ -8,6 +8,7 @@ use super::MonitorID; use BuilderAttribs; use CreationError; use CreationError::OsError; +use PixelFormat; use std::ffi::CString; use std::sync::mpsc::channel; @@ -130,31 +131,11 @@ fn init(title: Vec, builder: BuilderAttribs<'static>, builder_sharelists: O // getting the pixel format that we will use let pixel_format = { - // initializing a PIXELFORMATDESCRIPTOR that indicates what we want + let formats = enumerate_native_pixel_formats(dummy_hdc); + let (id, _) = builder.choose_pixel_format(formats.into_iter().map(|(a, b)| (b, a))); + let mut output: winapi::PIXELFORMATDESCRIPTOR = unsafe { mem::zeroed() }; - output.nSize = mem::size_of::() as winapi::WORD; - output.nVersion = 1; - output.dwFlags = winapi::PFD_DRAW_TO_WINDOW | winapi::PFD_DOUBLEBUFFER | - winapi::PFD_SUPPORT_OPENGL | winapi::PFD_GENERIC_ACCELERATED; - output.iPixelType = winapi::PFD_TYPE_RGBA; - output.cColorBits = 24; - output.cAlphaBits = 8; - output.cAccumBits = 0; - output.cDepthBits = 24; - output.cStencilBits = 8; - output.cAuxBuffers = 0; - output.iLayerType = winapi::PFD_MAIN_PLANE; - - let pf_index = unsafe { gdi32::ChoosePixelFormat(dummy_hdc, &output) }; - - if pf_index == 0 { - let err = Err(OsError(format!("ChoosePixelFormat function failed: {}", - os::error_string(os::errno() as usize)))); - unsafe { user32::DestroyWindow(dummy_window); } - return err; - } - - if unsafe { gdi32::DescribePixelFormat(dummy_hdc, pf_index, + if unsafe { gdi32::DescribePixelFormat(dummy_hdc, id, mem::size_of::() as winapi::UINT, &mut output) } == 0 { let err = Err(OsError(format!("DescribePixelFormat function failed: {}", @@ -475,3 +456,56 @@ fn create_context(extra: Option<(&gl::wgl_extra::Wgl, &BuilderAttribs<'static>)> Ok(ctxt as winapi::HGLRC) } + +fn enumerate_native_pixel_formats(hdc: winapi::HDC) -> Vec<(PixelFormat, libc::c_int)> { + let size_of_pxfmtdescr = mem::size_of::() as u32; + let num = unsafe { gdi32::DescribePixelFormat(hdc, 1, size_of_pxfmtdescr, ptr::null_mut()) }; + + let mut result = Vec::new(); + + for index in (0 .. num) { + let mut output: winapi::PIXELFORMATDESCRIPTOR = unsafe { mem::zeroed() }; + + if unsafe { 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.dwFlags & winapi::PFD_GENERIC_ACCELERATED) == 0 && + (output.dwFlags & winapi::PFD_GENERIC_FORMAT) == 0 + { + continue; + } + + if output.iPixelType != winapi::PFD_TYPE_RGBA { + continue; + } + + result.push((PixelFormat { + red_bits: output.cRedBits, + green_bits: output.cGreenBits, + blue_bits: 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, + }, index)); + } + + result +} + +fn enumerate_arb_pixel_formats(extra: &gl::wgl_extra::Wgl, hdc: winapi::HDC) -> Vec { + unimplemented!() +}