mirror of
https://github.com/italicsjenga/winit-sonoma-fix.git
synced 2024-12-25 14:51:30 +11:00
commit
e606281862
|
@ -39,13 +39,13 @@ glutin_core_foundation = "0"
|
||||||
[target.i686-pc-windows-gnu.dependencies]
|
[target.i686-pc-windows-gnu.dependencies]
|
||||||
winapi = "0.1"
|
winapi = "0.1"
|
||||||
gdi32-sys = "0.1"
|
gdi32-sys = "0.1"
|
||||||
user32-sys = "0.1"
|
user32-sys = "~0.1.1"
|
||||||
kernel32-sys = "0.1"
|
kernel32-sys = "0.1"
|
||||||
|
|
||||||
[target.x86_64-pc-windows-gnu.dependencies]
|
[target.x86_64-pc-windows-gnu.dependencies]
|
||||||
winapi = "0.1"
|
winapi = "0.1"
|
||||||
gdi32-sys = "0.1"
|
gdi32-sys = "0.1"
|
||||||
user32-sys = "0.1"
|
user32-sys = "~0.1.1"
|
||||||
kernel32-sys = "0.1"
|
kernel32-sys = "0.1"
|
||||||
|
|
||||||
[target.i686-unknown-linux-gnu.dependencies]
|
[target.i686-unknown-linux-gnu.dependencies]
|
||||||
|
|
|
@ -7,5 +7,6 @@ pub mod emscripten;
|
||||||
pub mod glx;
|
pub mod glx;
|
||||||
pub mod osmesa;
|
pub mod osmesa;
|
||||||
pub mod wayland;
|
pub mod wayland;
|
||||||
|
pub mod wgl;
|
||||||
pub mod win32;
|
pub mod win32;
|
||||||
pub mod x11;
|
pub mod x11;
|
||||||
|
|
|
@ -6,9 +6,6 @@ use winapi;
|
||||||
use CreationError;
|
use CreationError;
|
||||||
|
|
||||||
use super::gl;
|
use super::gl;
|
||||||
use super::ContextWrapper;
|
|
||||||
use super::WindowWrapper;
|
|
||||||
|
|
||||||
/// A guard for when you want to make the context current. Destroying the guard restores the
|
/// A guard for when you want to make the context current. Destroying the guard restores the
|
||||||
/// previously-current context.
|
/// previously-current context.
|
||||||
pub struct CurrentContextGuard<'a, 'b> {
|
pub struct CurrentContextGuard<'a, 'b> {
|
||||||
|
@ -19,15 +16,13 @@ pub struct CurrentContextGuard<'a, 'b> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b> CurrentContextGuard<'a, 'b> {
|
impl<'a, 'b> CurrentContextGuard<'a, 'b> {
|
||||||
pub unsafe fn make_current(window: &'a WindowWrapper, context: &'b ContextWrapper)
|
pub unsafe fn make_current(hdc: winapi::HDC, context: winapi::HGLRC)
|
||||||
-> Result<CurrentContextGuard<'a, 'b>, CreationError>
|
-> Result<CurrentContextGuard<'a, 'b>, CreationError>
|
||||||
{
|
{
|
||||||
let previous_hdc = gl::wgl::GetCurrentDC() as winapi::HDC;
|
let previous_hdc = gl::wgl::GetCurrentDC() as winapi::HDC;
|
||||||
let previous_hglrc = gl::wgl::GetCurrentContext() as winapi::HGLRC;
|
let previous_hglrc = gl::wgl::GetCurrentContext() as winapi::HGLRC;
|
||||||
|
|
||||||
let result = gl::wgl::MakeCurrent(window.1 as *const libc::c_void,
|
let result = gl::wgl::MakeCurrent(hdc as *const _, context as *const _);
|
||||||
context.0 as *const libc::c_void);
|
|
||||||
|
|
||||||
if result == 0 {
|
if result == 0 {
|
||||||
return Err(CreationError::OsError(format!("wglMakeCurrent function failed: {}",
|
return Err(CreationError::OsError(format!("wglMakeCurrent function failed: {}",
|
||||||
format!("{}", io::Error::last_os_error()))));
|
format!("{}", io::Error::last_os_error()))));
|
507
src/api/wgl/mod.rs
Normal file
507
src/api/wgl/mod.rs
Normal file
|
@ -0,0 +1,507 @@
|
||||||
|
#![cfg(any(target_os = "windows"))]
|
||||||
|
|
||||||
|
use BuilderAttribs;
|
||||||
|
use CreationError;
|
||||||
|
use GlContext;
|
||||||
|
use GlRequest;
|
||||||
|
use GlProfile;
|
||||||
|
use PixelFormat;
|
||||||
|
use Api;
|
||||||
|
|
||||||
|
use self::make_current_guard::CurrentContextGuard;
|
||||||
|
|
||||||
|
use libc;
|
||||||
|
use std::ffi::{CStr, CString, OsStr};
|
||||||
|
use std::os::windows::ffi::OsStrExt;
|
||||||
|
use std::{mem, ptr};
|
||||||
|
use std::io;
|
||||||
|
|
||||||
|
use winapi;
|
||||||
|
use kernel32;
|
||||||
|
use user32;
|
||||||
|
use gdi32;
|
||||||
|
|
||||||
|
mod make_current_guard;
|
||||||
|
mod gl;
|
||||||
|
|
||||||
|
pub struct Context {
|
||||||
|
context: ContextWrapper,
|
||||||
|
|
||||||
|
hdc: winapi::HDC,
|
||||||
|
|
||||||
|
/// Binded to `opengl32.dll`.
|
||||||
|
///
|
||||||
|
/// `wglGetProcAddress` returns null for GL 1.1 functions because they are
|
||||||
|
/// already defined by the system. This module contains them.
|
||||||
|
gl_library: winapi::HMODULE,
|
||||||
|
|
||||||
|
/// The pixel format that has been used to create this context.
|
||||||
|
pixel_format: PixelFormat,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A simple wrapper that destroys the window when it is destroyed.
|
||||||
|
struct WindowWrapper(winapi::HWND, winapi::HDC);
|
||||||
|
|
||||||
|
impl Drop for WindowWrapper {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
unsafe {
|
||||||
|
user32::DestroyWindow(self.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ContextWrapper(winapi::HGLRC);
|
||||||
|
|
||||||
|
impl Drop for ContextWrapper {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
unsafe {
|
||||||
|
gl::wgl::DeleteContext(self.0 as *const _);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Context {
|
||||||
|
/// Attempt to build a new WGL context on a window.
|
||||||
|
///
|
||||||
|
/// The window must **not** have had `SetPixelFormat` called on it.
|
||||||
|
pub fn new(builder: &BuilderAttribs<'static>, window: winapi::HWND,
|
||||||
|
builder_sharelists: Option<winapi::HGLRC>)
|
||||||
|
-> Result<Context, CreationError>
|
||||||
|
{
|
||||||
|
unsafe {
|
||||||
|
let hdc = user32::GetDC(window);
|
||||||
|
if hdc.is_null() {
|
||||||
|
let err = Err(CreationError::OsError(format!("GetDC function failed: {}",
|
||||||
|
format!("{}", io::Error::last_os_error()))));
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
// the first step is to create a dummy window and a dummy context which we will use
|
||||||
|
// to load the pointers to some functions in the OpenGL driver in `extra_functions`
|
||||||
|
let extra_functions = {
|
||||||
|
let (ex_style, style) = (winapi::WS_EX_APPWINDOW, winapi::WS_POPUP |
|
||||||
|
winapi::WS_CLIPSIBLINGS | winapi::WS_CLIPCHILDREN);
|
||||||
|
|
||||||
|
// creating a dummy invisible window
|
||||||
|
let dummy_window = {
|
||||||
|
let rect = {
|
||||||
|
let mut placement: winapi::WINDOWPLACEMENT = unsafe { mem::zeroed() };
|
||||||
|
placement.length = mem::size_of::<winapi::WINDOWPLACEMENT>() as winapi::UINT;
|
||||||
|
if unsafe { user32::GetWindowPlacement(window, &mut placement) } == 0 {
|
||||||
|
panic!();
|
||||||
|
}
|
||||||
|
placement.rcNormalPosition
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut class_name = [0u16; 128];
|
||||||
|
if user32::GetClassNameW(window, class_name.as_mut_ptr(), 128) == 0 {
|
||||||
|
return Err(CreationError::OsError(format!("GetClassNameW function failed: {}",
|
||||||
|
format!("{}", io::Error::last_os_error()))));
|
||||||
|
}
|
||||||
|
|
||||||
|
let handle = user32::CreateWindowExW(ex_style, class_name.as_ptr(),
|
||||||
|
b"dummy window\0".as_ptr() as *const _, style,
|
||||||
|
winapi::CW_USEDEFAULT, winapi::CW_USEDEFAULT,
|
||||||
|
rect.right - rect.left, rect.bottom - rect.top,
|
||||||
|
ptr::null_mut(), ptr::null_mut(),
|
||||||
|
kernel32::GetModuleHandleW(ptr::null()),
|
||||||
|
ptr::null_mut());
|
||||||
|
|
||||||
|
if handle.is_null() {
|
||||||
|
return Err(CreationError::OsError(format!("CreateWindowEx function failed: {}",
|
||||||
|
format!("{}", io::Error::last_os_error()))));
|
||||||
|
}
|
||||||
|
|
||||||
|
let hdc = user32::GetDC(handle);
|
||||||
|
if hdc.is_null() {
|
||||||
|
let err = Err(CreationError::OsError(format!("GetDC function failed: {}",
|
||||||
|
format!("{}", io::Error::last_os_error()))));
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
WindowWrapper(handle, hdc)
|
||||||
|
};
|
||||||
|
|
||||||
|
// getting the pixel format that we will use and setting it
|
||||||
|
{
|
||||||
|
let formats = enumerate_native_pixel_formats(dummy_window.1);
|
||||||
|
let id = try!(choose_dummy_pixel_format(formats.into_iter()));
|
||||||
|
try!(set_pixel_format(dummy_window.1, id));
|
||||||
|
}
|
||||||
|
|
||||||
|
// creating the dummy OpenGL context and making it current
|
||||||
|
let dummy_context = try!(create_context(None, dummy_window.0, dummy_window.1, None));
|
||||||
|
let _current_context = try!(CurrentContextGuard::make_current(dummy_window.1,
|
||||||
|
dummy_context.0));
|
||||||
|
|
||||||
|
// loading the extra WGL functions
|
||||||
|
gl::wgl_extra::Wgl::load_with(|addr| {
|
||||||
|
let addr = CString::new(addr.as_bytes()).unwrap();
|
||||||
|
let addr = addr.as_ptr();
|
||||||
|
gl::wgl::GetProcAddress(addr) as *const libc::c_void
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
// calling SetPixelFormat
|
||||||
|
let pixel_format = {
|
||||||
|
let formats = if extra_functions.GetPixelFormatAttribivARB.is_loaded() {
|
||||||
|
let f = enumerate_arb_pixel_formats(&extra_functions, hdc);
|
||||||
|
if f.is_empty() {
|
||||||
|
enumerate_native_pixel_formats(hdc)
|
||||||
|
} else {
|
||||||
|
f
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
enumerate_native_pixel_formats(hdc)
|
||||||
|
};
|
||||||
|
|
||||||
|
let (id, f) = try!(builder.choose_pixel_format(formats.into_iter().map(|(a, b)| (b, a))));
|
||||||
|
try!(set_pixel_format(hdc, id));
|
||||||
|
f
|
||||||
|
};
|
||||||
|
|
||||||
|
// creating the OpenGL context
|
||||||
|
let context = try!(create_context(Some((&extra_functions, builder)), window, hdc,
|
||||||
|
builder_sharelists));
|
||||||
|
|
||||||
|
// loading the opengl32 module
|
||||||
|
let gl_library = try!(load_opengl32_dll());
|
||||||
|
|
||||||
|
// handling vsync
|
||||||
|
if builder.vsync {
|
||||||
|
if extra_functions.SwapIntervalEXT.is_loaded() {
|
||||||
|
let _guard = try!(CurrentContextGuard::make_current(hdc, context.0));
|
||||||
|
|
||||||
|
if extra_functions.SwapIntervalEXT(1) == 0 {
|
||||||
|
return Err(CreationError::OsError(format!("wglSwapIntervalEXT failed")));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Context {
|
||||||
|
context: context,
|
||||||
|
hdc: hdc,
|
||||||
|
gl_library: gl_library,
|
||||||
|
pixel_format: pixel_format,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the raw HGLRC.
|
||||||
|
pub fn get_hglrc(&self) -> winapi::HGLRC {
|
||||||
|
self.context.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GlContext for Context {
|
||||||
|
unsafe fn make_current(&self) {
|
||||||
|
// TODO: check return value
|
||||||
|
gl::wgl::MakeCurrent(self.hdc as *const _, self.context.0 as *const _);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_current(&self) -> bool {
|
||||||
|
unsafe { gl::wgl::GetCurrentContext() == self.context.0 as *const libc::c_void }
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {
|
||||||
|
let p = gl::wgl::GetProcAddress(addr) as *const _;
|
||||||
|
if !p.is_null() { return p; }
|
||||||
|
kernel32::GetProcAddress(self.gl_library, addr) as *const _
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn swap_buffers(&self) {
|
||||||
|
unsafe {
|
||||||
|
gdi32::SwapBuffers(self.hdc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_api(&self) -> Api {
|
||||||
|
// FIXME: can be opengl es
|
||||||
|
Api::OpenGl
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_pixel_format(&self) -> PixelFormat {
|
||||||
|
self.pixel_format.clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl Send for Context {}
|
||||||
|
unsafe impl Sync for Context {}
|
||||||
|
|
||||||
|
unsafe fn create_context(extra: Option<(&gl::wgl_extra::Wgl, &BuilderAttribs<'static>)>,
|
||||||
|
_: winapi::HWND, hdc: winapi::HDC, share: Option<winapi::HGLRC>)
|
||||||
|
-> Result<ContextWrapper, CreationError>
|
||||||
|
{
|
||||||
|
let share = share.unwrap_or(ptr::null_mut());
|
||||||
|
|
||||||
|
let ctxt = if let Some((extra_functions, builder)) = extra {
|
||||||
|
if extra_functions.CreateContextAttribsARB.is_loaded() {
|
||||||
|
let mut attributes = Vec::new();
|
||||||
|
|
||||||
|
match builder.gl_version {
|
||||||
|
GlRequest::Latest => {},
|
||||||
|
GlRequest::Specific(Api::OpenGl, (major, minor)) => {
|
||||||
|
attributes.push(gl::wgl_extra::CONTEXT_MAJOR_VERSION_ARB as libc::c_int);
|
||||||
|
attributes.push(major as libc::c_int);
|
||||||
|
attributes.push(gl::wgl_extra::CONTEXT_MINOR_VERSION_ARB as libc::c_int);
|
||||||
|
attributes.push(minor as libc::c_int);
|
||||||
|
},
|
||||||
|
GlRequest::Specific(Api::OpenGlEs, (major, minor)) => {
|
||||||
|
if is_extension_supported(extra_functions, hdc,
|
||||||
|
"WGL_EXT_create_context_es2_profile")
|
||||||
|
{
|
||||||
|
attributes.push(gl::wgl_extra::CONTEXT_PROFILE_MASK_ARB as libc::c_int);
|
||||||
|
attributes.push(gl::wgl_extra::CONTEXT_ES2_PROFILE_BIT_EXT as libc::c_int);
|
||||||
|
} else {
|
||||||
|
return Err(CreationError::NotSupported);
|
||||||
|
}
|
||||||
|
|
||||||
|
attributes.push(gl::wgl_extra::CONTEXT_MAJOR_VERSION_ARB as libc::c_int);
|
||||||
|
attributes.push(major as libc::c_int);
|
||||||
|
attributes.push(gl::wgl_extra::CONTEXT_MINOR_VERSION_ARB as libc::c_int);
|
||||||
|
attributes.push(minor as libc::c_int);
|
||||||
|
},
|
||||||
|
GlRequest::Specific(_, _) => return Err(CreationError::NotSupported),
|
||||||
|
GlRequest::GlThenGles { opengl_version: (major, minor), .. } => {
|
||||||
|
attributes.push(gl::wgl_extra::CONTEXT_MAJOR_VERSION_ARB as libc::c_int);
|
||||||
|
attributes.push(major as libc::c_int);
|
||||||
|
attributes.push(gl::wgl_extra::CONTEXT_MINOR_VERSION_ARB as libc::c_int);
|
||||||
|
attributes.push(minor as libc::c_int);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(profile) = builder.gl_profile {
|
||||||
|
if is_extension_supported(extra_functions, hdc,
|
||||||
|
"WGL_ARB_create_context_profile")
|
||||||
|
{
|
||||||
|
let flag = match profile {
|
||||||
|
GlProfile::Compatibility =>
|
||||||
|
gl::wgl_extra::CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB,
|
||||||
|
GlProfile::Core =>
|
||||||
|
gl::wgl_extra::CONTEXT_CORE_PROFILE_BIT_ARB,
|
||||||
|
};
|
||||||
|
attributes.push(gl::wgl_extra::CONTEXT_PROFILE_MASK_ARB as libc::c_int);
|
||||||
|
attributes.push(flag as libc::c_int);
|
||||||
|
} else {
|
||||||
|
return Err(CreationError::NotSupported);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if builder.gl_debug {
|
||||||
|
attributes.push(gl::wgl_extra::CONTEXT_FLAGS_ARB as libc::c_int);
|
||||||
|
attributes.push(gl::wgl_extra::CONTEXT_DEBUG_BIT_ARB as libc::c_int);
|
||||||
|
}
|
||||||
|
|
||||||
|
attributes.push(0);
|
||||||
|
|
||||||
|
Some(extra_functions.CreateContextAttribsARB(hdc as *const libc::c_void,
|
||||||
|
share as *const libc::c_void,
|
||||||
|
attributes.as_ptr()))
|
||||||
|
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
let ctxt = match ctxt {
|
||||||
|
Some(ctxt) => ctxt,
|
||||||
|
None => {
|
||||||
|
let ctxt = gl::wgl::CreateContext(hdc as *const libc::c_void);
|
||||||
|
if !ctxt.is_null() && !share.is_null() {
|
||||||
|
gl::wgl::ShareLists(share as *const libc::c_void, ctxt);
|
||||||
|
};
|
||||||
|
ctxt
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if ctxt.is_null() {
|
||||||
|
return Err(CreationError::OsError(format!("OpenGL context creation failed: {}",
|
||||||
|
format!("{}", io::Error::last_os_error()))));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(ContextWrapper(ctxt as winapi::HGLRC))
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn enumerate_native_pixel_formats(hdc: winapi::HDC) -> Vec<(PixelFormat, libc::c_int)> {
|
||||||
|
let size_of_pxfmtdescr = mem::size_of::<winapi::PIXELFORMATDESCRIPTOR>() as u32;
|
||||||
|
let num = 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 = 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((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,
|
||||||
|
}, index));
|
||||||
|
}
|
||||||
|
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn enumerate_arb_pixel_formats(extra: &gl::wgl_extra::Wgl, hdc: winapi::HDC)
|
||||||
|
-> Vec<(PixelFormat, libc::c_int)>
|
||||||
|
{
|
||||||
|
let get_info = |index: u32, attrib: u32| {
|
||||||
|
let mut value = mem::uninitialized();
|
||||||
|
extra.GetPixelFormatAttribivARB(hdc as *const _, index as libc::c_int,
|
||||||
|
0, 1, [attrib as libc::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((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 is_extension_supported(extra, hdc, "WGL_ARB_multisample") {
|
||||||
|
match get_info(index, gl::wgl_extra::SAMPLES_ARB) {
|
||||||
|
0 => None,
|
||||||
|
a => Some(a as u16),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
},
|
||||||
|
srgb: if is_extension_supported(extra, hdc, "WGL_ARB_framebuffer_sRGB") {
|
||||||
|
get_info(index, gl::wgl_extra::FRAMEBUFFER_SRGB_CAPABLE_ARB) != 0
|
||||||
|
} else if is_extension_supported(extra, hdc, "WGL_EXT_framebuffer_sRGB") {
|
||||||
|
get_info(index, gl::wgl_extra::FRAMEBUFFER_SRGB_CAPABLE_EXT) != 0
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
},
|
||||||
|
}, index as libc::c_int));
|
||||||
|
}
|
||||||
|
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn set_pixel_format(hdc: winapi::HDC, id: libc::c_int) -> Result<(), CreationError> {
|
||||||
|
let mut output: winapi::PIXELFORMATDESCRIPTOR = mem::zeroed();
|
||||||
|
|
||||||
|
if gdi32::DescribePixelFormat(hdc, id, mem::size_of::<winapi::PIXELFORMATDESCRIPTOR>()
|
||||||
|
as winapi::UINT, &mut output) == 0
|
||||||
|
{
|
||||||
|
return Err(CreationError::OsError(format!("DescribePixelFormat function failed: {}",
|
||||||
|
format!("{}", io::Error::last_os_error()))));
|
||||||
|
}
|
||||||
|
|
||||||
|
if gdi32::SetPixelFormat(hdc, id, &output) == 0 {
|
||||||
|
return Err(CreationError::OsError(format!("SetPixelFormat function failed: {}",
|
||||||
|
format!("{}", io::Error::last_os_error()))));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn load_opengl32_dll() -> Result<winapi::HMODULE, CreationError> {
|
||||||
|
let name = OsStr::new("opengl32.dll").encode_wide().chain(Some(0).into_iter())
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
let lib = kernel32::LoadLibraryW(name.as_ptr());
|
||||||
|
|
||||||
|
if lib.is_null() {
|
||||||
|
return Err(CreationError::OsError(format!("LoadLibrary function failed: {}",
|
||||||
|
format!("{}", io::Error::last_os_error()))));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(lib)
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn is_extension_supported(extra: &gl::wgl_extra::Wgl, hdc: winapi::HDC,
|
||||||
|
extension: &str) -> bool
|
||||||
|
{
|
||||||
|
let extensions = if extra.GetExtensionsStringARB.is_loaded() {
|
||||||
|
let data = extra.GetExtensionsStringARB(hdc as *const _);
|
||||||
|
let data = CStr::from_ptr(data).to_bytes().to_vec();
|
||||||
|
String::from_utf8(data).unwrap()
|
||||||
|
|
||||||
|
} else if extra.GetExtensionsStringEXT.is_loaded() {
|
||||||
|
let data = extra.GetExtensionsStringEXT();
|
||||||
|
let data = CStr::from_ptr(data).to_bytes().to_vec();
|
||||||
|
String::from_utf8(data).unwrap()
|
||||||
|
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
extensions.split(" ").find(|&e| e == extension).is_some()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn choose_dummy_pixel_format<I>(iter: I) -> Result<libc::c_int, CreationError>
|
||||||
|
where I: Iterator<Item=(PixelFormat, libc::c_int)>
|
||||||
|
{
|
||||||
|
let mut backup_id = None;
|
||||||
|
|
||||||
|
for (format, id) in iter {
|
||||||
|
if backup_id.is_none() {
|
||||||
|
backup_id = Some(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if format.hardware_accelerated {
|
||||||
|
return Ok(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
backup_id.ok_or(CreationError::NotSupported)
|
||||||
|
}
|
|
@ -8,37 +8,32 @@ use std::thread;
|
||||||
use super::callback;
|
use super::callback;
|
||||||
use super::Window;
|
use super::Window;
|
||||||
use super::MonitorID;
|
use super::MonitorID;
|
||||||
use super::ContextWrapper;
|
|
||||||
use super::WindowWrapper;
|
use super::WindowWrapper;
|
||||||
use super::make_current_guard::CurrentContextGuard;
|
|
||||||
|
|
||||||
use Api;
|
|
||||||
use BuilderAttribs;
|
use BuilderAttribs;
|
||||||
use CreationError;
|
use CreationError;
|
||||||
use CreationError::OsError;
|
use CreationError::OsError;
|
||||||
use CursorState;
|
use CursorState;
|
||||||
use GlProfile;
|
|
||||||
use GlRequest;
|
|
||||||
use PixelFormat;
|
|
||||||
|
|
||||||
use std::ffi::{CStr, CString, OsStr};
|
use std::ffi::OsStr;
|
||||||
use std::os::windows::ffi::OsStrExt;
|
use std::os::windows::ffi::OsStrExt;
|
||||||
use std::sync::mpsc::channel;
|
use std::sync::mpsc::channel;
|
||||||
|
|
||||||
use libc;
|
|
||||||
use super::gl;
|
|
||||||
use winapi;
|
use winapi;
|
||||||
use kernel32;
|
use kernel32;
|
||||||
use user32;
|
use user32;
|
||||||
use gdi32;
|
|
||||||
|
use api::wgl::{self, Context};
|
||||||
|
|
||||||
/// Work-around the fact that HGLRC doesn't implement Send
|
/// Work-around the fact that HGLRC doesn't implement Send
|
||||||
pub struct ContextHack(pub winapi::HGLRC);
|
struct ContextHack(winapi::HGLRC);
|
||||||
unsafe impl Send for ContextHack {}
|
unsafe impl Send for ContextHack {}
|
||||||
|
|
||||||
pub fn new_window(builder: BuilderAttribs<'static>, builder_sharelists: Option<ContextHack>)
|
pub fn new_window(builder: BuilderAttribs<'static>, builder_sharelists: Option<winapi::HGLRC>)
|
||||||
-> Result<Window, CreationError>
|
-> Result<Window, CreationError>
|
||||||
{
|
{
|
||||||
|
let builder_sharelists = builder_sharelists.map(|s| ContextHack(s));
|
||||||
|
|
||||||
// initializing variables to be sent to the task
|
// initializing variables to be sent to the task
|
||||||
|
|
||||||
let title = OsStr::new(&builder.title).encode_wide().chain(Some(0).into_iter())
|
let title = OsStr::new(&builder.title).encode_wide().chain(Some(0).into_iter())
|
||||||
|
@ -110,57 +105,6 @@ unsafe fn init(title: Vec<u16>, builder: BuilderAttribs<'static>,
|
||||||
// adjusting the window coordinates using the style
|
// adjusting the window coordinates using the style
|
||||||
user32::AdjustWindowRectEx(&mut rect, style, 0, ex_style);
|
user32::AdjustWindowRectEx(&mut rect, style, 0, ex_style);
|
||||||
|
|
||||||
// the first step is to create a dummy window and a dummy context which we will use
|
|
||||||
// to load the pointers to some functions in the OpenGL driver in `extra_functions`
|
|
||||||
let extra_functions = {
|
|
||||||
// creating a dummy invisible window
|
|
||||||
let dummy_window = {
|
|
||||||
let handle = user32::CreateWindowExW(ex_style, class_name.as_ptr(),
|
|
||||||
title.as_ptr() as winapi::LPCWSTR,
|
|
||||||
style | winapi::WS_CLIPSIBLINGS | winapi::WS_CLIPCHILDREN,
|
|
||||||
winapi::CW_USEDEFAULT, winapi::CW_USEDEFAULT,
|
|
||||||
rect.right - rect.left, rect.bottom - rect.top,
|
|
||||||
ptr::null_mut(), ptr::null_mut(), kernel32::GetModuleHandleW(ptr::null()),
|
|
||||||
ptr::null_mut());
|
|
||||||
|
|
||||||
if handle.is_null() {
|
|
||||||
return Err(OsError(format!("CreateWindowEx function failed: {}",
|
|
||||||
format!("{}", io::Error::last_os_error()))));
|
|
||||||
}
|
|
||||||
|
|
||||||
let hdc = user32::GetDC(handle);
|
|
||||||
if hdc.is_null() {
|
|
||||||
let err = Err(OsError(format!("GetDC function failed: {}",
|
|
||||||
format!("{}", io::Error::last_os_error()))));
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
WindowWrapper(handle, hdc)
|
|
||||||
};
|
|
||||||
|
|
||||||
// getting the pixel format that we will use and setting it
|
|
||||||
{
|
|
||||||
let formats = enumerate_native_pixel_formats(&dummy_window);
|
|
||||||
let id = try!(choose_dummy_pixel_format(formats.into_iter()));
|
|
||||||
try!(set_pixel_format(&dummy_window, id));
|
|
||||||
}
|
|
||||||
|
|
||||||
// creating the dummy OpenGL context and making it current
|
|
||||||
let dummy_context = try!(create_context(None, &dummy_window, None));
|
|
||||||
let current_context = try!(CurrentContextGuard::make_current(&dummy_window,
|
|
||||||
&dummy_context));
|
|
||||||
|
|
||||||
// loading the extra WGL functions
|
|
||||||
gl::wgl_extra::Wgl::load_with(|addr| {
|
|
||||||
use libc;
|
|
||||||
|
|
||||||
let addr = CString::new(addr.as_bytes()).unwrap();
|
|
||||||
let addr = addr.as_ptr();
|
|
||||||
|
|
||||||
gl::wgl::GetProcAddress(addr) as *const libc::c_void
|
|
||||||
})
|
|
||||||
};
|
|
||||||
|
|
||||||
// creating the real window this time, by using the functions in `extra_functions`
|
// creating the real window this time, by using the functions in `extra_functions`
|
||||||
let real_window = {
|
let real_window = {
|
||||||
let (width, height) = if builder.monitor.is_some() || builder.dimensions.is_some() {
|
let (width, height) = if builder.monitor.is_some() || builder.dimensions.is_some() {
|
||||||
|
@ -203,27 +147,8 @@ unsafe fn init(title: Vec<u16>, builder: BuilderAttribs<'static>,
|
||||||
WindowWrapper(handle, hdc)
|
WindowWrapper(handle, hdc)
|
||||||
};
|
};
|
||||||
|
|
||||||
// calling SetPixelFormat
|
//
|
||||||
let pixel_format = {
|
let context = try!(wgl::Context::new(&builder, real_window.0, builder_sharelists));
|
||||||
let formats = if extra_functions.GetPixelFormatAttribivARB.is_loaded() {
|
|
||||||
let f = enumerate_arb_pixel_formats(&extra_functions, &real_window);
|
|
||||||
if f.is_empty() {
|
|
||||||
enumerate_native_pixel_formats(&real_window)
|
|
||||||
} else {
|
|
||||||
f
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
enumerate_native_pixel_formats(&real_window)
|
|
||||||
};
|
|
||||||
|
|
||||||
let (id, f) = try!(builder.choose_pixel_format(formats.into_iter().map(|(a, b)| (b, a))));
|
|
||||||
try!(set_pixel_format(&real_window, id));
|
|
||||||
f
|
|
||||||
};
|
|
||||||
|
|
||||||
// creating the OpenGL context
|
|
||||||
let context = try!(create_context(Some((&extra_functions, &builder)), &real_window,
|
|
||||||
builder_sharelists));
|
|
||||||
|
|
||||||
// calling SetForegroundWindow if fullscreen
|
// calling SetForegroundWindow if fullscreen
|
||||||
if builder.monitor.is_some() {
|
if builder.monitor.is_some() {
|
||||||
|
@ -248,29 +173,13 @@ unsafe fn init(title: Vec<u16>, builder: BuilderAttribs<'static>,
|
||||||
rx
|
rx
|
||||||
};
|
};
|
||||||
|
|
||||||
// loading the opengl32 module
|
|
||||||
let gl_library = try!(load_opengl32_dll());
|
|
||||||
|
|
||||||
// handling vsync
|
|
||||||
if builder.vsync {
|
|
||||||
if extra_functions.SwapIntervalEXT.is_loaded() {
|
|
||||||
let _guard = try!(CurrentContextGuard::make_current(&real_window, &context));
|
|
||||||
|
|
||||||
if extra_functions.SwapIntervalEXT(1) == 0 {
|
|
||||||
return Err(OsError(format!("wglSwapIntervalEXT failed")));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// building the struct
|
// building the struct
|
||||||
Ok(Window {
|
Ok(Window {
|
||||||
window: real_window,
|
window: real_window,
|
||||||
context: context,
|
context: context,
|
||||||
gl_library: gl_library,
|
|
||||||
events_receiver: events_receiver,
|
events_receiver: events_receiver,
|
||||||
is_closed: AtomicBool::new(false),
|
is_closed: AtomicBool::new(false),
|
||||||
cursor_state: cursor_state,
|
cursor_state: cursor_state,
|
||||||
pixel_format: pixel_format,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -332,276 +241,3 @@ unsafe fn switch_to_fullscreen(rect: &mut winapi::RECT, monitor: &MonitorID)
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn create_context(extra: Option<(&gl::wgl_extra::Wgl, &BuilderAttribs<'static>)>,
|
|
||||||
hdc: &WindowWrapper, share: Option<winapi::HGLRC>)
|
|
||||||
-> Result<ContextWrapper, CreationError>
|
|
||||||
{
|
|
||||||
let share = share.unwrap_or(ptr::null_mut());
|
|
||||||
|
|
||||||
let ctxt = if let Some((extra_functions, builder)) = extra {
|
|
||||||
if extra_functions.CreateContextAttribsARB.is_loaded() {
|
|
||||||
let mut attributes = Vec::new();
|
|
||||||
|
|
||||||
match builder.gl_version {
|
|
||||||
GlRequest::Latest => {},
|
|
||||||
GlRequest::Specific(Api::OpenGl, (major, minor)) => {
|
|
||||||
attributes.push(gl::wgl_extra::CONTEXT_MAJOR_VERSION_ARB as libc::c_int);
|
|
||||||
attributes.push(major as libc::c_int);
|
|
||||||
attributes.push(gl::wgl_extra::CONTEXT_MINOR_VERSION_ARB as libc::c_int);
|
|
||||||
attributes.push(minor as libc::c_int);
|
|
||||||
},
|
|
||||||
GlRequest::Specific(Api::OpenGlEs, (major, minor)) => {
|
|
||||||
if is_extension_supported(extra_functions, hdc,
|
|
||||||
"WGL_EXT_create_context_es2_profile")
|
|
||||||
{
|
|
||||||
attributes.push(gl::wgl_extra::CONTEXT_PROFILE_MASK_ARB as libc::c_int);
|
|
||||||
attributes.push(gl::wgl_extra::CONTEXT_ES2_PROFILE_BIT_EXT as libc::c_int);
|
|
||||||
} else {
|
|
||||||
return Err(CreationError::NotSupported);
|
|
||||||
}
|
|
||||||
|
|
||||||
attributes.push(gl::wgl_extra::CONTEXT_MAJOR_VERSION_ARB as libc::c_int);
|
|
||||||
attributes.push(major as libc::c_int);
|
|
||||||
attributes.push(gl::wgl_extra::CONTEXT_MINOR_VERSION_ARB as libc::c_int);
|
|
||||||
attributes.push(minor as libc::c_int);
|
|
||||||
},
|
|
||||||
GlRequest::Specific(_, _) => return Err(CreationError::NotSupported),
|
|
||||||
GlRequest::GlThenGles { opengl_version: (major, minor), .. } => {
|
|
||||||
attributes.push(gl::wgl_extra::CONTEXT_MAJOR_VERSION_ARB as libc::c_int);
|
|
||||||
attributes.push(major as libc::c_int);
|
|
||||||
attributes.push(gl::wgl_extra::CONTEXT_MINOR_VERSION_ARB as libc::c_int);
|
|
||||||
attributes.push(minor as libc::c_int);
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(profile) = builder.gl_profile {
|
|
||||||
if is_extension_supported(extra_functions, hdc,
|
|
||||||
"WGL_ARB_create_context_profile")
|
|
||||||
{
|
|
||||||
let flag = match profile {
|
|
||||||
GlProfile::Compatibility =>
|
|
||||||
gl::wgl_extra::CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB,
|
|
||||||
GlProfile::Core =>
|
|
||||||
gl::wgl_extra::CONTEXT_CORE_PROFILE_BIT_ARB,
|
|
||||||
};
|
|
||||||
attributes.push(gl::wgl_extra::CONTEXT_PROFILE_MASK_ARB as libc::c_int);
|
|
||||||
attributes.push(flag as libc::c_int);
|
|
||||||
} else {
|
|
||||||
return Err(CreationError::NotSupported);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if builder.gl_debug {
|
|
||||||
attributes.push(gl::wgl_extra::CONTEXT_FLAGS_ARB as libc::c_int);
|
|
||||||
attributes.push(gl::wgl_extra::CONTEXT_DEBUG_BIT_ARB as libc::c_int);
|
|
||||||
}
|
|
||||||
|
|
||||||
attributes.push(0);
|
|
||||||
|
|
||||||
Some(extra_functions.CreateContextAttribsARB(hdc.1 as *const libc::c_void,
|
|
||||||
share as *const libc::c_void,
|
|
||||||
attributes.as_ptr()))
|
|
||||||
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
let ctxt = match ctxt {
|
|
||||||
Some(ctxt) => ctxt,
|
|
||||||
None => {
|
|
||||||
let ctxt = gl::wgl::CreateContext(hdc.1 as *const libc::c_void);
|
|
||||||
if !ctxt.is_null() && !share.is_null() {
|
|
||||||
gl::wgl::ShareLists(share as *const libc::c_void, ctxt);
|
|
||||||
};
|
|
||||||
ctxt
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if ctxt.is_null() {
|
|
||||||
return Err(OsError(format!("OpenGL context creation failed: {}",
|
|
||||||
format!("{}", io::Error::last_os_error()))));
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(ContextWrapper(ctxt as winapi::HGLRC))
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe fn enumerate_native_pixel_formats(hdc: &WindowWrapper) -> Vec<(PixelFormat, libc::c_int)> {
|
|
||||||
let size_of_pxfmtdescr = mem::size_of::<winapi::PIXELFORMATDESCRIPTOR>() as u32;
|
|
||||||
let num = gdi32::DescribePixelFormat(hdc.1, 1, size_of_pxfmtdescr, ptr::null_mut());
|
|
||||||
|
|
||||||
let mut result = Vec::new();
|
|
||||||
|
|
||||||
for index in (0 .. num) {
|
|
||||||
let mut output: winapi::PIXELFORMATDESCRIPTOR = mem::zeroed();
|
|
||||||
|
|
||||||
if gdi32::DescribePixelFormat(hdc.1, 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((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,
|
|
||||||
}, index));
|
|
||||||
}
|
|
||||||
|
|
||||||
result
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe fn enumerate_arb_pixel_formats(extra: &gl::wgl_extra::Wgl, hdc: &WindowWrapper)
|
|
||||||
-> Vec<(PixelFormat, libc::c_int)>
|
|
||||||
{
|
|
||||||
let get_info = |index: u32, attrib: u32| {
|
|
||||||
let mut value = mem::uninitialized();
|
|
||||||
extra.GetPixelFormatAttribivARB(hdc.1 as *const libc::c_void, index as libc::c_int,
|
|
||||||
0, 1, [attrib as libc::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((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 is_extension_supported(extra, hdc, "WGL_ARB_multisample") {
|
|
||||||
match get_info(index, gl::wgl_extra::SAMPLES_ARB) {
|
|
||||||
0 => None,
|
|
||||||
a => Some(a as u16),
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
},
|
|
||||||
srgb: if is_extension_supported(extra, hdc, "WGL_ARB_framebuffer_sRGB") {
|
|
||||||
get_info(index, gl::wgl_extra::FRAMEBUFFER_SRGB_CAPABLE_ARB) != 0
|
|
||||||
} else if is_extension_supported(extra, hdc, "WGL_EXT_framebuffer_sRGB") {
|
|
||||||
get_info(index, gl::wgl_extra::FRAMEBUFFER_SRGB_CAPABLE_EXT) != 0
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
},
|
|
||||||
}, index as libc::c_int));
|
|
||||||
}
|
|
||||||
|
|
||||||
result
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe fn set_pixel_format(hdc: &WindowWrapper, id: libc::c_int) -> Result<(), CreationError> {
|
|
||||||
let mut output: winapi::PIXELFORMATDESCRIPTOR = mem::zeroed();
|
|
||||||
|
|
||||||
if gdi32::DescribePixelFormat(hdc.1, id, mem::size_of::<winapi::PIXELFORMATDESCRIPTOR>()
|
|
||||||
as winapi::UINT, &mut output) == 0
|
|
||||||
{
|
|
||||||
return Err(OsError(format!("DescribePixelFormat function failed: {}",
|
|
||||||
format!("{}", io::Error::last_os_error()))));
|
|
||||||
}
|
|
||||||
|
|
||||||
if gdi32::SetPixelFormat(hdc.1, id, &output) == 0 {
|
|
||||||
return Err(OsError(format!("SetPixelFormat function failed: {}",
|
|
||||||
format!("{}", io::Error::last_os_error()))));
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe fn load_opengl32_dll() -> Result<winapi::HMODULE, CreationError> {
|
|
||||||
let name = OsStr::new("opengl32.dll").encode_wide().chain(Some(0).into_iter())
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
let lib = kernel32::LoadLibraryW(name.as_ptr());
|
|
||||||
|
|
||||||
if lib.is_null() {
|
|
||||||
return Err(OsError(format!("LoadLibrary function failed: {}",
|
|
||||||
format!("{}", io::Error::last_os_error()))));
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(lib)
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe fn is_extension_supported(extra: &gl::wgl_extra::Wgl, hdc: &WindowWrapper,
|
|
||||||
extension: &str) -> bool
|
|
||||||
{
|
|
||||||
let extensions = if extra.GetExtensionsStringARB.is_loaded() {
|
|
||||||
let data = extra.GetExtensionsStringARB(hdc.1 as *const _);
|
|
||||||
let data = CStr::from_ptr(data).to_bytes().to_vec();
|
|
||||||
String::from_utf8(data).unwrap()
|
|
||||||
|
|
||||||
} else if extra.GetExtensionsStringEXT.is_loaded() {
|
|
||||||
let data = extra.GetExtensionsStringEXT();
|
|
||||||
let data = CStr::from_ptr(data).to_bytes().to_vec();
|
|
||||||
String::from_utf8(data).unwrap()
|
|
||||||
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
|
|
||||||
extensions.split(" ").find(|&e| e == extension).is_some()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn choose_dummy_pixel_format<I>(iter: I) -> Result<libc::c_int, CreationError>
|
|
||||||
where I: Iterator<Item=(PixelFormat, libc::c_int)>
|
|
||||||
{
|
|
||||||
let mut backup_id = None;
|
|
||||||
|
|
||||||
for (format, id) in iter {
|
|
||||||
if backup_id.is_none() {
|
|
||||||
backup_id = Some(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
if format.hardware_accelerated {
|
|
||||||
return Ok(id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
backup_id.ok_or(CreationError::NotSupported)
|
|
||||||
}
|
|
||||||
|
|
|
@ -3,7 +3,6 @@
|
||||||
use std::sync::atomic::AtomicBool;
|
use std::sync::atomic::AtomicBool;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
use std::ffi::CString;
|
|
||||||
use std::ffi::OsStr;
|
use std::ffi::OsStr;
|
||||||
use std::os::windows::ffi::OsStrExt;
|
use std::os::windows::ffi::OsStrExt;
|
||||||
use std::sync::{
|
use std::sync::{
|
||||||
|
@ -25,13 +24,12 @@ pub use self::monitor::{MonitorID, get_available_monitors, get_primary_monitor};
|
||||||
use winapi;
|
use winapi;
|
||||||
use user32;
|
use user32;
|
||||||
use kernel32;
|
use kernel32;
|
||||||
use gdi32;
|
|
||||||
|
use api::wgl;
|
||||||
|
|
||||||
mod callback;
|
mod callback;
|
||||||
mod event;
|
mod event;
|
||||||
mod gl;
|
|
||||||
mod init;
|
mod init;
|
||||||
mod make_current_guard;
|
|
||||||
mod monitor;
|
mod monitor;
|
||||||
|
|
||||||
/// The Win32 implementation of the main `Window` object.
|
/// The Win32 implementation of the main `Window` object.
|
||||||
|
@ -40,13 +38,7 @@ pub struct Window {
|
||||||
window: WindowWrapper,
|
window: WindowWrapper,
|
||||||
|
|
||||||
/// OpenGL context.
|
/// OpenGL context.
|
||||||
context: ContextWrapper,
|
context: wgl::Context,
|
||||||
|
|
||||||
/// Binded to `opengl32.dll`.
|
|
||||||
///
|
|
||||||
/// `wglGetProcAddress` returns null for GL 1.1 functions because they are
|
|
||||||
/// already defined by the system. This module contains them.
|
|
||||||
gl_library: winapi::HMODULE,
|
|
||||||
|
|
||||||
/// Receiver for the events dispatched by the window callback.
|
/// Receiver for the events dispatched by the window callback.
|
||||||
events_receiver: Receiver<Event>,
|
events_receiver: Receiver<Event>,
|
||||||
|
@ -56,27 +48,11 @@ pub struct Window {
|
||||||
|
|
||||||
/// The current cursor state.
|
/// The current cursor state.
|
||||||
cursor_state: Arc<Mutex<CursorState>>,
|
cursor_state: Arc<Mutex<CursorState>>,
|
||||||
|
|
||||||
/// The pixel format that has been used to create this window.
|
|
||||||
pixel_format: PixelFormat,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl Send for Window {}
|
unsafe impl Send for Window {}
|
||||||
unsafe impl Sync for Window {}
|
unsafe impl Sync for Window {}
|
||||||
|
|
||||||
/// A simple wrapper that destroys the context when it is destroyed.
|
|
||||||
// FIXME: remove `pub` (https://github.com/rust-lang/rust/issues/23585)
|
|
||||||
#[doc(hidden)]
|
|
||||||
pub struct ContextWrapper(pub winapi::HGLRC);
|
|
||||||
|
|
||||||
impl Drop for ContextWrapper {
|
|
||||||
fn drop(&mut self) {
|
|
||||||
unsafe {
|
|
||||||
gl::wgl::DeleteContext(self.0 as *const libc::c_void);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A simple wrapper that destroys the window when it is destroyed.
|
/// A simple wrapper that destroys the window when it is destroyed.
|
||||||
// FIXME: remove `pub` (https://github.com/rust-lang/rust/issues/23585)
|
// FIXME: remove `pub` (https://github.com/rust-lang/rust/issues/23585)
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
|
@ -103,7 +79,7 @@ impl Window {
|
||||||
/// See the docs in the crate root file.
|
/// See the docs in the crate root file.
|
||||||
pub fn new(builder: BuilderAttribs) -> Result<Window, CreationError> {
|
pub fn new(builder: BuilderAttribs) -> Result<Window, CreationError> {
|
||||||
let (builder, sharing) = builder.extract_non_static();
|
let (builder, sharing) = builder.extract_non_static();
|
||||||
let sharing = sharing.map(|w| init::ContextHack(w.context.0));
|
let sharing = sharing.map(|w| w.context.get_hglrc());
|
||||||
init::new_window(builder, sharing)
|
init::new_window(builder, sharing)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -326,38 +302,27 @@ impl Window {
|
||||||
|
|
||||||
impl GlContext for Window {
|
impl GlContext for Window {
|
||||||
unsafe fn make_current(&self) {
|
unsafe fn make_current(&self) {
|
||||||
// TODO: check return value
|
self.context.make_current()
|
||||||
gl::wgl::MakeCurrent(self.window.1 as *const libc::c_void,
|
|
||||||
self.context.0 as *const libc::c_void);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_current(&self) -> bool {
|
fn is_current(&self) -> bool {
|
||||||
unsafe { gl::wgl::GetCurrentContext() == self.context.0 as *const libc::c_void }
|
self.context.is_current()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_proc_address(&self, addr: &str) -> *const libc::c_void {
|
fn get_proc_address(&self, addr: &str) -> *const libc::c_void {
|
||||||
let addr = CString::new(addr.as_bytes()).unwrap();
|
self.context.get_proc_address(addr)
|
||||||
let addr = addr.as_ptr();
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
let p = gl::wgl::GetProcAddress(addr) as *const _;
|
|
||||||
if !p.is_null() { return p; }
|
|
||||||
kernel32::GetProcAddress(self.gl_library, addr) as *const _
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn swap_buffers(&self) {
|
fn swap_buffers(&self) {
|
||||||
unsafe {
|
self.context.swap_buffers()
|
||||||
gdi32::SwapBuffers(self.window.1);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_api(&self) -> Api {
|
fn get_api(&self) -> Api {
|
||||||
Api::OpenGl
|
self.context.get_api()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_pixel_format(&self) -> PixelFormat {
|
fn get_pixel_format(&self) -> PixelFormat {
|
||||||
self.pixel_format.clone()
|
self.context.get_pixel_format()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue