Merge pull request #459 from tomaka/win32-egl-2

Allow creating EGL contexts on win32 with the AMD DLLs
This commit is contained in:
tomaka 2015-05-21 19:37:10 +02:00
commit 4824333453
7 changed files with 133 additions and 27 deletions

View file

@ -35,6 +35,16 @@ fn main() {
"WGL_EXT_swap_control".to_string(), "WGL_EXT_swap_control".to_string(),
], ],
"1.0", "core", &mut file).unwrap(); "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") { if target.contains("linux") {

View file

@ -110,7 +110,7 @@ impl Window {
return Err(OsError(format!("Android's native window is null"))); 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 _)); native_window as *const _));
let (tx, rx) = channel(); let (tx, rx) = channel();

View file

@ -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)] #![allow(unused_variables)]
use BuilderAttribs; use BuilderAttribs;
@ -24,7 +24,7 @@ pub struct Context {
} }
impl Context { impl Context {
pub fn new(egl: ffi::egl::Egl, builder: BuilderAttribs, pub fn new(egl: ffi::egl::Egl, builder: &BuilderAttribs,
native_display: Option<ffi::EGLNativeDisplayType>, native_display: Option<ffi::EGLNativeDisplayType>,
native_window: ffi::EGLNativeWindowType) -> Result<Context, CreationError> native_window: ffi::EGLNativeWindowType) -> Result<Context, CreationError>
{ {

View file

@ -165,7 +165,7 @@ impl Window {
}); });
try!(EglContext::new( try!(EglContext::new(
egl, egl,
builder, &builder,
Some(wayland_context.display.ptr() as *const _), Some(wayland_context.display.ptr() as *const _),
(*shell_surface).ptr() as *const _ (*shell_surface).ptr() as *const _
)) ))

View file

@ -4,18 +4,22 @@ use std::io;
use std::ptr; use std::ptr;
use std::mem; use std::mem;
use std::thread; use std::thread;
use libc;
use super::callback; use super::callback;
use super::Window; use super::Window;
use super::MonitorID; use super::MonitorID;
use super::WindowWrapper; use super::WindowWrapper;
use super::Context;
use Api;
use BuilderAttribs; use BuilderAttribs;
use CreationError; use CreationError;
use CreationError::OsError; use CreationError::OsError;
use CursorState; use CursorState;
use GlRequest;
use std::ffi::OsStr; use std::ffi::{CString, OsStr};
use std::os::windows::ffi::OsStrExt; use std::os::windows::ffi::OsStrExt;
use std::sync::mpsc::channel; use std::sync::mpsc::channel;
@ -23,17 +27,22 @@ use winapi;
use kernel32; use kernel32;
use user32; 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 pub enum RawContext {
struct ContextHack(winapi::HGLRC); Egl(egl::ffi::egl::types::EGLContext),
unsafe impl Send for ContextHack {} Wgl(winapi::HGLRC),
}
pub fn new_window(builder: BuilderAttribs<'static>, builder_sharelists: Option<winapi::HGLRC>) unsafe impl Send for RawContext {}
unsafe impl Sync for RawContext {}
pub fn new_window(builder: BuilderAttribs<'static>, builder_sharelists: Option<RawContext>)
-> 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())
@ -73,10 +82,8 @@ pub fn new_window(builder: BuilderAttribs<'static>, builder_sharelists: Option<w
} }
unsafe fn init(title: Vec<u16>, builder: BuilderAttribs<'static>, 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 // registering the window class
let class_name = register_window_class(); let class_name = register_window_class();
@ -147,8 +154,65 @@ unsafe fn init(title: Vec<u16>, builder: BuilderAttribs<'static>,
WindowWrapper(handle, hdc) WindowWrapper(handle, hdc)
}; };
// // creating the OpenGL context
let context = try!(wgl::Context::new(&builder, real_window.0, builder_sharelists)); 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 // calling SetForegroundWindow if fullscreen
if builder.monitor.is_some() { if builder.monitor.is_some() {

View file

@ -26,6 +26,10 @@ use user32;
use kernel32; use kernel32;
use api::wgl; use api::wgl;
use api::wgl::Context as WglContext;
use api::egl::Context as EglContext;
use self::init::RawContext;
mod callback; mod callback;
mod event; mod event;
@ -38,7 +42,7 @@ pub struct Window {
window: WindowWrapper, window: WindowWrapper,
/// OpenGL context. /// OpenGL context.
context: wgl::Context, context: Context,
/// 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>,
@ -53,6 +57,11 @@ pub struct Window {
unsafe impl Send for Window {} unsafe impl Send for Window {}
unsafe impl Sync for Window {} unsafe impl Sync for Window {}
enum Context {
Egl(EglContext),
Wgl(WglContext),
}
/// 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)]
@ -79,7 +88,12 @@ 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| 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) init::new_window(builder, sharing)
} }
@ -302,27 +316,45 @@ impl Window {
impl GlContext for Window { impl GlContext for Window {
unsafe fn make_current(&self) { 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 { 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 { 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) { 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 { 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 { 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(),
}
} }
} }

View file

@ -523,14 +523,14 @@ impl Window {
Context::Glx(try!(GlxContext::new(glx.clone(), builder, display.display, window, Context::Glx(try!(GlxContext::new(glx.clone(), builder, display.display, window,
fb_config, visual_infos))) fb_config, visual_infos)))
} else if let Some(ref egl) = display.egl { } 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 { } else {
return Err(CreationError::NotSupported); return Err(CreationError::NotSupported);
} }
}, },
GlRequest::Specific(Api::OpenGlEs, _) => { GlRequest::Specific(Api::OpenGlEs, _) => {
if let Some(ref egl) = display.egl { 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 { } else {
return Err(CreationError::NotSupported); return Err(CreationError::NotSupported);
} }