From 01ecd24fe2dff3c81bfa57e76ebab9a05048e246 Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Thu, 21 May 2015 18:59:30 +0200 Subject: [PATCH] Allow creating EGL contexts on win32 with the AMD DLLs --- build.rs | 10 +++++ src/api/android/mod.rs | 2 +- src/api/egl/mod.rs | 4 +- src/api/wayland/mod.rs | 2 +- src/api/win32/init.rs | 90 ++++++++++++++++++++++++++++++++++++------ src/api/win32/mod.rs | 48 ++++++++++++++++++---- src/api/x11/window.rs | 4 +- 7 files changed, 133 insertions(+), 27 deletions(-) diff --git a/build.rs b/build.rs index a4f744d0..c21f4f6a 100644 --- a/build.rs +++ b/build.rs @@ -35,6 +35,16 @@ fn main() { "WGL_EXT_swap_control".to_string(), ], "1.0", "core", &mut file).unwrap(); + + let mut file = File::create(&dest.join("egl_bindings.rs")).unwrap(); + gl_generator::generate_bindings(gl_generator::StructGenerator, + gl_generator::registry::Ns::Egl, + gl_generator::Fallbacks::All, + khronos_api::EGL_XML, + vec![ + "EGL_KHR_create_context".to_string() + ], + "1.5", "core", &mut file).unwrap(); } if target.contains("linux") { diff --git a/src/api/android/mod.rs b/src/api/android/mod.rs index 9a983226..d1281e3d 100644 --- a/src/api/android/mod.rs +++ b/src/api/android/mod.rs @@ -110,7 +110,7 @@ impl Window { return Err(OsError(format!("Android's native window is null"))); } - let context = try!(EglContext::new(egl::ffi::egl::Egl, builder, None, + let context = try!(EglContext::new(egl::ffi::egl::Egl, &builder, None, native_window as *const _)); let (tx, rx) = channel(); diff --git a/src/api/egl/mod.rs b/src/api/egl/mod.rs index a97ef624..3335de05 100644 --- a/src/api/egl/mod.rs +++ b/src/api/egl/mod.rs @@ -1,4 +1,4 @@ -#![cfg(any(target_os = "linux", target_os = "android"))] +#![cfg(any(target_os = "windows", target_os = "linux", target_os = "android"))] #![allow(unused_variables)] use BuilderAttribs; @@ -24,7 +24,7 @@ pub struct Context { } impl Context { - pub fn new(egl: ffi::egl::Egl, builder: BuilderAttribs, + pub fn new(egl: ffi::egl::Egl, builder: &BuilderAttribs, native_display: Option, native_window: ffi::EGLNativeWindowType) -> Result { diff --git a/src/api/wayland/mod.rs b/src/api/wayland/mod.rs index 8a4b5cc2..b9bfa18e 100644 --- a/src/api/wayland/mod.rs +++ b/src/api/wayland/mod.rs @@ -165,7 +165,7 @@ impl Window { }); try!(EglContext::new( egl, - builder, + &builder, Some(wayland_context.display.ptr() as *const _), (*shell_surface).ptr() as *const _ )) diff --git a/src/api/win32/init.rs b/src/api/win32/init.rs index 92231050..fb4e1812 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), +} -pub fn new_window(builder: BuilderAttribs<'static>, builder_sharelists: Option) +unsafe impl Send for RawContext {} +unsafe impl Sync for RawContext {} + +pub fn new_window(builder: BuilderAttribs<'static>, builder_sharelists: Option) -> Result { - 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, builder: BuilderAttribs<'static>, - builder_sharelists: Option) -> Result + builder_sharelists: Option) -> Result { - 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, 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::>(); + 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 ff42408d..af339c55 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, @@ -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 { 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(), + } } } diff --git a/src/api/x11/window.rs b/src/api/x11/window.rs index f5f3f2fe..4582c3ed 100644 --- a/src/api/x11/window.rs +++ b/src/api/x11/window.rs @@ -523,14 +523,14 @@ impl Window { Context::Glx(try!(GlxContext::new(glx.clone(), builder, display.display, window, fb_config, visual_infos))) } else if let Some(ref egl) = display.egl { - Context::Egl(try!(EglContext::new(egl.clone(), builder, Some(display.display as *const _), window as *const _))) + Context::Egl(try!(EglContext::new(egl.clone(), &builder, Some(display.display as *const _), window as *const _))) } else { return Err(CreationError::NotSupported); } }, GlRequest::Specific(Api::OpenGlEs, _) => { if let Some(ref egl) = display.egl { - Context::Egl(try!(EglContext::new(egl.clone(), builder, Some(display.display as *const _), window as *const _))) + Context::Egl(try!(EglContext::new(egl.clone(), &builder, Some(display.display as *const _), window as *const _))) } else { return Err(CreationError::NotSupported); }