diff options
author | Pierre Krieger <pierre.krieger1708@gmail.com> | 2015-05-21 18:59:30 +0200 |
---|---|---|
committer | Pierre Krieger <pierre.krieger1708@gmail.com> | 2015-05-21 18:59:30 +0200 |
commit | 01ecd24fe2dff3c81bfa57e76ebab9a05048e246 (patch) | |
tree | e15a00f7e7e15d016f052ec2f3dd47a3ae40ba92 /src/api/win32 | |
parent | e606281862dfd016051e2ee66e67eddb71c6d0ac (diff) | |
download | glutin-01ecd24fe2dff3c81bfa57e76ebab9a05048e246.tar.gz glutin-01ecd24fe2dff3c81bfa57e76ebab9a05048e246.zip |
Allow creating EGL contexts on win32 with the AMD DLLs
Diffstat (limited to 'src/api/win32')
-rw-r--r-- | src/api/win32/init.rs | 90 | ||||
-rw-r--r-- | src/api/win32/mod.rs | 48 |
2 files changed, 117 insertions, 21 deletions
diff --git a/src/api/win32/init.rs b/src/api/win32/init.rs index 9223105..fb4e181 100644 --- a/src/api/win32/init.rs +++ b/src/api/win32/init.rs @@ -4,18 +4,22 @@ use std::io; use std::ptr; use std::mem; use std::thread; +use libc; use super::callback; use super::Window; use super::MonitorID; use super::WindowWrapper; +use super::Context; +use Api; use BuilderAttribs; use CreationError; use CreationError::OsError; use CursorState; +use GlRequest; -use std::ffi::OsStr; +use std::ffi::{CString, OsStr}; use std::os::windows::ffi::OsStrExt; use std::sync::mpsc::channel; @@ -23,17 +27,22 @@ use winapi; use kernel32; use user32; -use api::wgl::{self, Context}; +use api::wgl; +use api::wgl::Context as WglContext; +use api::egl; +use api::egl::Context as EglContext; -/// Work-around the fact that HGLRC doesn't implement Send -struct ContextHack(winapi::HGLRC); -unsafe impl Send for ContextHack {} +pub enum RawContext { + Egl(egl::ffi::egl::types::EGLContext), + Wgl(winapi::HGLRC), +} + +unsafe impl Send for RawContext {} +unsafe impl Sync for RawContext {} -pub fn new_window(builder: BuilderAttribs<'static>, builder_sharelists: Option<winapi::HGLRC>) +pub fn new_window(builder: BuilderAttribs<'static>, builder_sharelists: Option<RawContext>) -> Result<Window, CreationError> { - let builder_sharelists = builder_sharelists.map(|s| ContextHack(s)); - // initializing variables to be sent to the task let title = OsStr::new(&builder.title).encode_wide().chain(Some(0).into_iter()) @@ -73,10 +82,8 @@ pub fn new_window(builder: BuilderAttribs<'static>, builder_sharelists: Option<w } unsafe fn init(title: Vec<u16>, builder: BuilderAttribs<'static>, - builder_sharelists: Option<ContextHack>) -> Result<Window, CreationError> + builder_sharelists: Option<RawContext>) -> Result<Window, CreationError> { - let builder_sharelists = builder_sharelists.map(|s| s.0); - // registering the window class let class_name = register_window_class(); @@ -147,8 +154,65 @@ unsafe fn init(title: Vec<u16>, builder: BuilderAttribs<'static>, WindowWrapper(handle, hdc) }; - // - let context = try!(wgl::Context::new(&builder, real_window.0, builder_sharelists)); + // creating the OpenGL context + let context = match builder.gl_version { + GlRequest::Specific(Api::OpenGlEs, (major, minor)) => { + // trying to load EGL from the ATI drivers + + // TODO: use LoadLibraryA instead + let dll_name = if cfg!(target_pointer_width = "64") { + "atio6axx.dll" + } else { + "atioglxx.dll" + }; + let dll_name = OsStr::new(dll_name).encode_wide().chain(Some(0).into_iter()) + .collect::<Vec<_>>(); + let dll = unsafe { kernel32::LoadLibraryW(dll_name.as_ptr()) }; + + if !dll.is_null() { + let egl = ::api::egl::ffi::egl::Egl::load_with(|name| { + let name = CString::new(name).unwrap(); + unsafe { kernel32::GetProcAddress(dll, name.as_ptr()) as *const libc::c_void } + }); + + if let Ok(c) = EglContext::new(egl, &builder, Some(ptr::null()), + real_window.0) + { + Context::Egl(c) + + } else { + let builder_sharelists = match builder_sharelists { + None => None, + Some(RawContext::Wgl(c)) => Some(c), + _ => unimplemented!() + }; + + try!(WglContext::new(&builder, real_window.0, builder_sharelists) + .map(Context::Wgl)) + } + + } else { + // falling back to WGL, which is always available + let builder_sharelists = match builder_sharelists { + None => None, + Some(RawContext::Wgl(c)) => Some(c), + _ => unimplemented!() + }; + + try!(WglContext::new(&builder, real_window.0, builder_sharelists) + .map(Context::Wgl)) + } + }, + _ => { + let builder_sharelists = match builder_sharelists { + None => None, + Some(RawContext::Wgl(c)) => Some(c), + _ => unimplemented!() + }; + + try!(WglContext::new(&builder, real_window.0, builder_sharelists).map(Context::Wgl)) + } + }; // calling SetForegroundWindow if fullscreen if builder.monitor.is_some() { diff --git a/src/api/win32/mod.rs b/src/api/win32/mod.rs index ff42408..af339c5 100644 --- a/src/api/win32/mod.rs +++ b/src/api/win32/mod.rs @@ -26,6 +26,10 @@ use user32; use kernel32; use api::wgl; +use api::wgl::Context as WglContext; +use api::egl::Context as EglContext; + +use self::init::RawContext; mod callback; mod event; @@ -38,7 +42,7 @@ pub struct Window { window: WindowWrapper, /// OpenGL context. - context: wgl::Context, + context: Context, /// Receiver for the events dispatched by the window callback. events_receiver: Receiver<Event>, @@ -53,6 +57,11 @@ pub struct Window { unsafe impl Send for Window {} unsafe impl Sync for Window {} +enum Context { + Egl(EglContext), + Wgl(WglContext), +} + /// A simple wrapper that destroys the window when it is destroyed. // FIXME: remove `pub` (https://github.com/rust-lang/rust/issues/23585) #[doc(hidden)] @@ -79,7 +88,12 @@ impl Window { /// See the docs in the crate root file. pub fn new(builder: BuilderAttribs) -> Result<Window, CreationError> { let (builder, sharing) = builder.extract_non_static(); - let sharing = sharing.map(|w| w.context.get_hglrc()); + + let sharing = sharing.map(|w| match w.context { + Context::Wgl(ref c) => RawContext::Wgl(c.get_hglrc()), + Context::Egl(_) => unimplemented!(), // FIXME: + }); + init::new_window(builder, sharing) } @@ -302,27 +316,45 @@ impl Window { impl GlContext for Window { unsafe fn make_current(&self) { - self.context.make_current() + match self.context { + Context::Wgl(ref c) => c.make_current(), + Context::Egl(ref c) => c.make_current(), + } } fn is_current(&self) -> bool { - self.context.is_current() + match self.context { + Context::Wgl(ref c) => c.is_current(), + Context::Egl(ref c) => c.is_current(), + } } fn get_proc_address(&self, addr: &str) -> *const libc::c_void { - self.context.get_proc_address(addr) + match self.context { + Context::Wgl(ref c) => c.get_proc_address(addr), + Context::Egl(ref c) => c.get_proc_address(addr), + } } fn swap_buffers(&self) { - self.context.swap_buffers() + match self.context { + Context::Wgl(ref c) => c.swap_buffers(), + Context::Egl(ref c) => c.swap_buffers(), + } } fn get_api(&self) -> Api { - self.context.get_api() + match self.context { + Context::Wgl(ref c) => c.get_api(), + Context::Egl(ref c) => c.get_api(), + } } fn get_pixel_format(&self) -> PixelFormat { - self.context.get_pixel_format() + match self.context { + Context::Wgl(ref c) => c.get_pixel_format(), + Context::Egl(ref c) => c.get_pixel_format(), + } } } |