diff options
Diffstat (limited to 'src/api')
| -rw-r--r-- | src/api/egl/ffi.rs | 41 | ||||
| -rw-r--r-- | src/api/egl/mod.rs | 185 | ||||
| -rw-r--r-- | src/api/mod.rs | 1 | 
3 files changed, 227 insertions, 0 deletions
| diff --git a/src/api/egl/ffi.rs b/src/api/egl/ffi.rs new file mode 100644 index 0000000..e3cf32e --- /dev/null +++ b/src/api/egl/ffi.rs @@ -0,0 +1,41 @@ +use libc; + +#[cfg(target_os = "windows")] +extern crate winapi; +#[cfg(target_os = "linux")] +use api::x11::ffi; +#[cfg(target_os = "android")] +use api::android::ffi; + +pub mod egl { +    pub type khronos_utime_nanoseconds_t = super::khronos_utime_nanoseconds_t; +    pub type khronos_uint64_t = super::khronos_uint64_t; +    pub type khronos_ssize_t = super::khronos_ssize_t; +    pub type EGLNativeDisplayType = super::EGLNativeDisplayType; +    pub type EGLNativePixmapType = super::EGLNativePixmapType; +    pub type EGLNativeWindowType = super::EGLNativeWindowType; +    pub type EGLint = super::EGLint; +    pub type NativeDisplayType = super::EGLNativeDisplayType; +    pub type NativePixmapType = super::EGLNativePixmapType; +    pub type NativeWindowType = super::EGLNativeWindowType; + +    include!(concat!(env!("OUT_DIR"), "/egl_bindings.rs")); +} + +pub type khronos_utime_nanoseconds_t = khronos_uint64_t; +pub type khronos_uint64_t = libc::uint64_t; +pub type khronos_ssize_t = libc::c_long; +pub type EGLint = libc::int32_t; +pub type EGLNativeDisplayType = *const libc::c_void; +pub type EGLNativePixmapType = *const libc::c_void;     // FIXME: egl_native_pixmap_t instead + +#[cfg(target_os = "windows")] +pub type EGLNativeWindowType = winapi::HWND; +#[cfg(target_os = "linux")] +pub type EGLNativeWindowType = ffi::Window; +#[cfg(target_os = "android")] +pub type EGLNativeWindowType = *const ffi::ANativeWindow; + +#[cfg(not(target_os = "windows"))] +#[link(name = "EGL")] +extern {} diff --git a/src/api/egl/mod.rs b/src/api/egl/mod.rs new file mode 100644 index 0000000..d9ac313 --- /dev/null +++ b/src/api/egl/mod.rs @@ -0,0 +1,185 @@ +#![cfg(all(target_os = "windows", target_os = "linux"))]        // always false of the moment + +use BuilderAttribs; +use CreationError; +use GlRequest; +use Api; + +use libc; +use std::ffi::CString; +use std::{mem, ptr}; + +pub mod ffi; + +pub struct Context { +    egl: ffi::egl::Egl, +    display: ffi::egl::types::EGLDisplay, +    context: ffi::egl::types::EGLContext, +    surface: ffi::egl::types::EGLSurface, +} + +impl Context { +    pub fn new(egl: ffi::egl::Egl, builder: BuilderAttribs, +               native_display: Option<ffi::EGLNativeDisplayType>, +               native_window: ffi::EGLNativeWindowType) -> Result<Context, CreationError> +    { +        if builder.sharing.is_some() { +            unimplemented!() +        } + +        let display = unsafe { +            let display = egl.GetDisplay(native_display.unwrap_or(mem::transmute(ffi::egl::DEFAULT_DISPLAY))); +            if display.is_null() { +                return Err(CreationError::OsError("No EGL display connection available".to_string())); +            } +            display +        }; + +        let (_major, _minor) = unsafe { +            let mut major: ffi::egl::types::EGLint = mem::uninitialized(); +            let mut minor: ffi::egl::types::EGLint = mem::uninitialized(); + +            if egl.Initialize(display, &mut major, &mut minor) == 0 { +                return Err(CreationError::OsError(format!("eglInitialize failed"))) +            } + +            (major, minor) +        }; + +        let use_gles2 = match builder.gl_version { +            GlRequest::Specific(Api::OpenGlEs, (2, _)) => true, +            GlRequest::Specific(Api::OpenGlEs, _) => false, +            GlRequest::Specific(_, _) => return Err(CreationError::NotSupported), +            GlRequest::GlThenGles { opengles_version: (2, _), .. } => true, +            _ => false, +        }; + +        let mut attribute_list = vec!(); +        attribute_list.push(ffi::egl::RENDERABLE_TYPE as i32); +        attribute_list.push(ffi::egl::OPENGL_ES2_BIT as i32); + +        attribute_list.push(ffi::egl::CONFORMANT as i32); +        attribute_list.push(ffi::egl::OPENGL_ES2_BIT as i32); + +        attribute_list.push(ffi::egl::SURFACE_TYPE as i32); +        attribute_list.push(ffi::egl::WINDOW_BIT as i32); + +        { +            let (red, green, blue) = match builder.color_bits.unwrap_or(24) { +                24 => (8, 8, 8), +                16 => (6, 5, 6), +                _ => panic!("Bad color_bits"), +            }; + +            attribute_list.push(ffi::egl::RED_SIZE as i32); +            attribute_list.push(red); +            attribute_list.push(ffi::egl::GREEN_SIZE as i32); +            attribute_list.push(green); +            attribute_list.push(ffi::egl::BLUE_SIZE as i32); +            attribute_list.push(blue); +        } + +        attribute_list.push(ffi::egl::DEPTH_SIZE as i32); +        attribute_list.push(builder.depth_bits.unwrap_or(8) as i32); + +        attribute_list.push(ffi::egl::NONE as i32); + +        let config = unsafe { +            let mut num_config: ffi::egl::types::EGLint = mem::uninitialized(); +            let mut config: ffi::egl::types::EGLConfig = mem::uninitialized(); +            if egl.ChooseConfig(display, attribute_list.as_ptr(), &mut config, 1, +                                &mut num_config) == 0 +            { +                return Err(CreationError::OsError(format!("eglChooseConfig failed"))) +            } + +            if num_config <= 0 { +                return Err(CreationError::OsError(format!("eglChooseConfig returned no available config"))) +            } + +            config +        }; + +        let surface = unsafe { +            let surface = egl.CreateWindowSurface(display, config, native_window, ptr::null()); +            if surface.is_null() { +                return Err(CreationError::OsError(format!("eglCreateWindowSurface failed"))) +            } +            surface +        }; + +        let context = unsafe { +            let mut context_attributes = vec!(); +            context_attributes.push(ffi::egl::CONTEXT_CLIENT_VERSION as i32); +            context_attributes.push(2); +            context_attributes.push(ffi::egl::NONE as i32); + +            let context = egl.CreateContext(display, config, ptr::null(), +                                            context_attributes.as_ptr()); +            if context.is_null() { +                return Err(CreationError::OsError(format!("eglCreateContext failed"))) +            } +            context +        }; + +        Ok(Context { +            egl: egl, +            display: display, +            context: context, +            surface: surface, +        }) +    } + +    pub fn make_current(&self) { +        let ret = unsafe { +            self.egl.MakeCurrent(self.display, self.surface, self.surface, self.context) +        }; + +        if ret == 0 { +            panic!("eglMakeCurrent failed"); +        } +    } + +    pub fn is_current(&self) -> bool { +        unsafe { self.egl.GetCurrentContext() == self.context } +    } + +    pub fn get_proc_address(&self, addr: &str) -> *const () { +        let addr = CString::new(addr.as_bytes()).unwrap(); +        let addr = addr.as_ptr(); +        unsafe { +            self.egl.GetProcAddress(addr) as *const () +        } +    } + +    pub fn swap_buffers(&self) { +        let ret = unsafe { +            self.egl.SwapBuffers(self.display, self.surface) +        }; + +        if ret == 0 { +            panic!("eglSwapBuffers failed"); +        } +    } + +    pub fn get_api(&self) -> ::Api { +        ::Api::OpenGlEs +    } +} + +unsafe impl Send for Context {} +unsafe impl Sync for Context {} + +impl Drop for Context { +    fn drop(&mut self) { +        use std::ptr; + +        unsafe { +            // we don't call MakeCurrent(0, 0) because we are not sure that the context +            // is still the current one +            self.egl.DestroyContext(self.display, self.context); +            self.egl.DestroySurface(self.display, self.surface); +            self.egl.Terminate(self.display); +        } +    } +} diff --git a/src/api/mod.rs b/src/api/mod.rs index 472c716..b791880 100644 --- a/src/api/mod.rs +++ b/src/api/mod.rs @@ -1,4 +1,5 @@  pub mod android;  pub mod cocoa; +pub mod egl;  pub mod win32;  pub mod x11; | 
