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(), +        }      }  } | 
