From 10bb03c5f0c2ce39961b93e52c5a9200856d86f2 Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Tue, 23 Feb 2016 12:56:23 +0100 Subject: [PATCH] Remove most OpenGL stuff and make it compile on win32 --- Cargo.toml | 25 +- build.rs | 187 ------- examples/support/mod.rs | 109 ----- examples/window.rs | 16 +- src/api/egl/ffi.rs | 37 -- src/api/egl/mod.rs | 731 --------------------------- src/api/glx/mod.rs | 498 ------------------- src/api/mod.rs | 4 - src/api/osmesa/mod.rs | 140 ------ src/api/wgl/gl.rs | 12 - src/api/wgl/make_current_guard.rs | 47 -- src/api/wgl/mod.rs | 787 ------------------------------ src/api/win32/init.rs | 68 +-- src/api/win32/mod.rs | 84 +--- src/headless.rs | 156 ------ src/lib.rs | 332 ------------- src/os/windows.rs | 2 +- src/platform/windows/mod.rs | 130 +---- src/window.rs | 220 +-------- tests/headless.rs | 61 --- 20 files changed, 30 insertions(+), 3616 deletions(-) delete mode 100644 build.rs delete mode 100644 examples/support/mod.rs delete mode 100644 src/api/egl/ffi.rs delete mode 100644 src/api/egl/mod.rs delete mode 100644 src/api/glx/mod.rs delete mode 100644 src/api/osmesa/mod.rs delete mode 100644 src/api/wgl/gl.rs delete mode 100644 src/api/wgl/make_current_guard.rs delete mode 100644 src/api/wgl/mod.rs delete mode 100644 src/headless.rs delete mode 100644 tests/headless.rs diff --git a/Cargo.toml b/Cargo.toml index 3cce0ee6..b71af54f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,24 +1,19 @@ [package] -name = "glutin" +name = "winit" version = "0.4.8" -authors = ["The glutin contributors, Pierre Krieger "] -description = "Cross-platform OpenGL context provider." -keywords = ["windowing", "opengl"] +authors = ["The winit contributors, Pierre Krieger "] +description = "Cross-platform window creation library." +keywords = ["windowing"] license = "Apache-2.0" readme = "README.md" -repository = "https://github.com/tomaka/glutin" -documentation = "https://tomaka.github.io/glutin/" -build = "build.rs" +repository = "https://github.com/tomaka/winit" +documentation = "https://tomaka.github.io/winit/" [dependencies] lazy_static = "0.1.10" libc = "0.2" shared_library = "0.1.0" -[build-dependencies] -gl_generator = "0.4" -khronos_api = "1.0" - [target.arm-linux-androideabi.dependencies.android_glue] version = "0.1" @@ -77,56 +72,48 @@ kernel32-sys = "0.2" dwmapi-sys = "0.1" [target.i686-unknown-linux-gnu.dependencies] -osmesa-sys = "0.0.5" wayland-client = { version = "0.5.4", features = ["egl", "dlopen"] } wayland-kbd = "0.3.3" wayland-window = "0.2.2" x11-dl = "~2.3" [target.i586-unknown-linux-gnu.dependencies] -osmesa-sys = "0.0.5" wayland-client = { version = "0.5.4", features = ["egl", "dlopen"] } wayland-kbd = "0.3.3" wayland-window = "0.2.2" x11-dl = "~2.3" [target.x86_64-unknown-linux-gnu.dependencies] -osmesa-sys = "0.0.5" wayland-client = { version = "0.5.4", features = ["egl", "dlopen"] } wayland-kbd = "0.3.3" wayland-window = "0.2.2" x11-dl = "~2.3" [target.arm-unknown-linux-gnueabihf.dependencies] -osmesa-sys = "0.0.5" wayland-client = { version = "0.5.4", features = ["egl", "dlopen"] } wayland-kbd = "0.3.3" wayland-window = "0.2.2" x11-dl = "~2.3" [target.armv7-unknown-linux-gnueabihf.dependencies] -osmesa-sys = "0.0.5" wayland-client = { version = "0.5.4", features = ["egl", "dlopen"] } wayland-kbd = "0.3.3" wayland-window = "0.2.2" x11-dl = "~2.3" [target.aarch64-unknown-linux-gnu.dependencies] -osmesa-sys = "0.0.5" wayland-client = { version = "0.5.4", features = ["egl", "dlopen"] } wayland-kbd = "0.3.3" wayland-window = "0.2.2" x11-dl = "~2.3" [target.x86_64-unknown-dragonfly.dependencies] -osmesa-sys = "0.0.5" wayland-client = { version = "0.5.4", features = ["egl", "dlopen"] } wayland-kbd = "0.3.3" wayland-window = "0.2.2" x11-dl = "~2.3" [target.x86_64-unknown-freebsd.dependencies] -osmesa-sys = "0.0.5" wayland-client = { version = "0.5.4", features = ["egl", "dlopen"] } wayland-kbd = "0.3.3" wayland-window = "0.2.2" diff --git a/build.rs b/build.rs deleted file mode 100644 index bf25c959..00000000 --- a/build.rs +++ /dev/null @@ -1,187 +0,0 @@ -extern crate gl_generator; -extern crate khronos_api; - -use std::env; -use std::fs::File; -use std::path::PathBuf; - -fn main() { - let target = env::var("TARGET").unwrap(); - let dest = PathBuf::from(&env::var("OUT_DIR").unwrap()); - - println!("cargo:rerun-if-changed=build.rs"); - - if target.contains("windows") { - let mut file = File::create(&dest.join("wgl_bindings.rs")).unwrap(); - gl_generator::generate_bindings(gl_generator::StaticGenerator, - gl_generator::registry::Ns::Wgl, - gl_generator::Fallbacks::All, - khronos_api::WGL_XML, vec![], - "1.0", "core", &mut file).unwrap(); - - let mut file = File::create(&dest.join("wgl_extra_bindings.rs")).unwrap(); - gl_generator::generate_bindings(gl_generator::StructGenerator, - gl_generator::registry::Ns::Wgl, - gl_generator::Fallbacks::All, - khronos_api::WGL_XML, - vec![ - "WGL_ARB_create_context".to_string(), - "WGL_ARB_create_context_profile".to_string(), - "WGL_ARB_create_context_robustness".to_string(), - "WGL_ARB_context_flush_control".to_string(), - "WGL_ARB_extensions_string".to_string(), - "WGL_ARB_framebuffer_sRGB".to_string(), - "WGL_ARB_multisample".to_string(), - "WGL_ARB_pixel_format".to_string(), - "WGL_ARB_pixel_format_float".to_string(), - "WGL_EXT_create_context_es2_profile".to_string(), - "WGL_EXT_extensions_string".to_string(), - "WGL_EXT_framebuffer_sRGB".to_string(), - "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(), - "EGL_EXT_create_context_robustness".to_string(), - "EGL_KHR_create_context_no_error".to_string(), - "EGL_KHR_platform_x11".to_string(), - "EGL_KHR_platform_android".to_string(), - "EGL_KHR_platform_wayland".to_string(), - "EGL_KHR_platform_gbm".to_string(), - "EGL_EXT_platform_base".to_string(), - "EGL_EXT_platform_x11".to_string(), - "EGL_MESA_platform_gbm".to_string(), - "EGL_EXT_platform_wayland".to_string(), - "EGL_EXT_platform_device".to_string(), - ], - "1.5", "core", &mut file).unwrap(); - } - - if target.contains("linux") || target.contains("dragonfly") || target.contains("freebsd") { - let mut file = File::create(&dest.join("glx_bindings.rs")).unwrap(); - gl_generator::generate_bindings(gl_generator::StructGenerator, - gl_generator::registry::Ns::Glx, - gl_generator::Fallbacks::All, - khronos_api::GLX_XML, vec![], - "1.4", "core", &mut file).unwrap(); - - let mut file = File::create(&dest.join("glx_extra_bindings.rs")).unwrap(); - gl_generator::generate_bindings(gl_generator::StructGenerator, - gl_generator::registry::Ns::Glx, - gl_generator::Fallbacks::All, - khronos_api::GLX_XML, - vec![ - "GLX_ARB_create_context".to_string(), - "GLX_ARB_create_context_profile".to_string(), - "GLX_ARB_create_context_robustness".to_string(), - "GLX_ARB_context_flush_control".to_string(), - "GLX_ARB_fbconfig_float".to_string(), - "GLX_ARB_framebuffer_sRGB".to_string(), - "GLX_EXT_framebuffer_sRGB".to_string(), - "GLX_ARB_multisample".to_string(), - "GLX_EXT_swap_control".to_string(), - "GLX_SGI_swap_control".to_string() - ], - "1.4", "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(), - "EGL_EXT_create_context_robustness".to_string(), - "EGL_KHR_create_context_no_error".to_string(), - "EGL_KHR_platform_x11".to_string(), - "EGL_KHR_platform_android".to_string(), - "EGL_KHR_platform_wayland".to_string(), - "EGL_KHR_platform_gbm".to_string(), - "EGL_EXT_platform_base".to_string(), - "EGL_EXT_platform_x11".to_string(), - "EGL_MESA_platform_gbm".to_string(), - "EGL_EXT_platform_wayland".to_string(), - "EGL_EXT_platform_device".to_string(), - ], - "1.5", "core", &mut file).unwrap(); - } - - if target.contains("android") { - let mut file = File::create(&dest.join("egl_bindings.rs")).unwrap(); - gl_generator::generate_bindings(gl_generator::StaticStructGenerator, - gl_generator::registry::Ns::Egl, - gl_generator::Fallbacks::All, - khronos_api::EGL_XML, - vec![ - "EGL_KHR_create_context".to_string(), - "EGL_EXT_create_context_robustness".to_string(), - "EGL_KHR_create_context_no_error".to_string(), - "EGL_KHR_platform_x11".to_string(), - "EGL_KHR_platform_android".to_string(), - "EGL_KHR_platform_wayland".to_string(), - "EGL_KHR_platform_gbm".to_string(), - "EGL_EXT_platform_base".to_string(), - "EGL_EXT_platform_x11".to_string(), - "EGL_MESA_platform_gbm".to_string(), - "EGL_EXT_platform_wayland".to_string(), - "EGL_EXT_platform_device".to_string(), - ], - "1.5", "core", &mut file).unwrap(); - } - - if target.contains("ios") { - let mut file = File::create(&dest.join("egl_bindings.rs")).unwrap(); - gl_generator::generate_bindings(gl_generator::StaticStructGenerator, - gl_generator::registry::Ns::Egl, - gl_generator::Fallbacks::All, - khronos_api::EGL_XML, - vec![ - "EGL_KHR_create_context".to_string(), - "EGL_EXT_create_context_robustness".to_string(), - "EGL_KHR_create_context_no_error".to_string(), - "EGL_KHR_platform_x11".to_string(), - "EGL_KHR_platform_android".to_string(), - "EGL_KHR_platform_wayland".to_string(), - "EGL_KHR_platform_gbm".to_string(), - "EGL_EXT_platform_base".to_string(), - "EGL_EXT_platform_x11".to_string(), - "EGL_MESA_platform_gbm".to_string(), - "EGL_EXT_platform_wayland".to_string(), - "EGL_EXT_platform_device".to_string(), - ], - "1.5", "core", &mut file).unwrap(); - - let mut file = File::create(&dest.join("gles2_bindings.rs")).unwrap(); - gl_generator::generate_bindings(gl_generator::StaticStructGenerator, - gl_generator::registry::Ns::Gles2, - gl_generator::Fallbacks::None, - khronos_api::GL_XML, - vec![], - "2.0", "core", &mut file).unwrap(); - } - - if target.contains("darwin") { - let mut file = File::create(&dest.join("gl_bindings.rs")).unwrap(); - gl_generator::generate_bindings(gl_generator::GlobalGenerator, - gl_generator::registry::Ns::Gl, - gl_generator::Fallbacks::All, - khronos_api::GL_XML, - vec!["GL_EXT_framebuffer_object".to_string()], - "3.2", "core", &mut file).unwrap(); - } - - // TODO: only build the bindings below if we run tests/examples - - let mut file = File::create(&dest.join("test_gl_bindings.rs")).unwrap(); - gl_generator::generate_bindings(gl_generator::StructGenerator, - gl_generator::registry::Ns::Gles2, - gl_generator::Fallbacks::All, - khronos_api::GL_XML, vec![], - "3.0", "core", &mut file).unwrap(); -} diff --git a/examples/support/mod.rs b/examples/support/mod.rs deleted file mode 100644 index a51ca24c..00000000 --- a/examples/support/mod.rs +++ /dev/null @@ -1,109 +0,0 @@ -use std::ffi::CStr; -use std::mem; -use std::ptr; -use glutin; - -mod gl { - pub use self::Gles2 as Gl; - include!(concat!(env!("OUT_DIR"), "/test_gl_bindings.rs")); -} - -pub struct Context { - gl: gl::Gl -} - -pub fn load(window: &glutin::Window) -> Context { - let gl = gl::Gl::load_with(|ptr| window.get_proc_address(ptr) as *const _); - - let version = unsafe { - let data = CStr::from_ptr(gl.GetString(gl::VERSION) as *const _).to_bytes().to_vec(); - String::from_utf8(data).unwrap() - }; - - println!("OpenGL version {}", version); - - unsafe { - let vs = gl.CreateShader(gl::VERTEX_SHADER); - gl.ShaderSource(vs, 1, [VS_SRC.as_ptr() as *const _].as_ptr(), ptr::null()); - gl.CompileShader(vs); - - let fs = gl.CreateShader(gl::FRAGMENT_SHADER); - gl.ShaderSource(fs, 1, [FS_SRC.as_ptr() as *const _].as_ptr(), ptr::null()); - gl.CompileShader(fs); - - let program = gl.CreateProgram(); - gl.AttachShader(program, vs); - gl.AttachShader(program, fs); - gl.LinkProgram(program); - gl.UseProgram(program); - - let mut vb = mem::uninitialized(); - gl.GenBuffers(1, &mut vb); - gl.BindBuffer(gl::ARRAY_BUFFER, vb); - gl.BufferData(gl::ARRAY_BUFFER, - (VERTEX_DATA.len() * mem::size_of::()) as gl::types::GLsizeiptr, - VERTEX_DATA.as_ptr() as *const _, gl::STATIC_DRAW); - - if gl.BindVertexArray.is_loaded() { - let mut vao = mem::uninitialized(); - gl.GenVertexArrays(1, &mut vao); - gl.BindVertexArray(vao); - } - - let pos_attrib = gl.GetAttribLocation(program, b"position\0".as_ptr() as *const _); - let color_attrib = gl.GetAttribLocation(program, b"color\0".as_ptr() as *const _); - gl.VertexAttribPointer(pos_attrib as gl::types::GLuint, 2, gl::FLOAT, 0, - 5 * mem::size_of::() as gl::types::GLsizei, - ptr::null()); - gl.VertexAttribPointer(color_attrib as gl::types::GLuint, 3, gl::FLOAT, 0, - 5 * mem::size_of::() as gl::types::GLsizei, - (2 * mem::size_of::()) as *const () as *const _); - gl.EnableVertexAttribArray(pos_attrib as gl::types::GLuint); - gl.EnableVertexAttribArray(color_attrib as gl::types::GLuint); - } - - Context { gl: gl } -} - -impl Context { - pub fn draw_frame(&self, color: (f32, f32, f32, f32)) { - unsafe { - self.gl.ClearColor(color.0, color.1, color.2, color.3); - self.gl.Clear(gl::COLOR_BUFFER_BIT); - - self.gl.DrawArrays(gl::TRIANGLES, 0, 3); - } - } -} - -static VERTEX_DATA: [f32; 15] = [ - -0.5, -0.5, 1.0, 0.0, 0.0, - 0.0, 0.5, 0.0, 1.0, 0.0, - 0.5, -0.5, 0.0, 0.0, 1.0 -]; - -const VS_SRC: &'static [u8] = b" -#version 100 -precision mediump float; - -attribute vec2 position; -attribute vec3 color; - -varying vec3 v_color; - -void main() { - gl_Position = vec4(position, 0.0, 1.0); - v_color = color; -} -\0"; - -const FS_SRC: &'static [u8] = b" -#version 100 -precision mediump float; - -varying vec3 v_color; - -void main() { - gl_FragColor = vec4(v_color, 1.0); -} -\0"; diff --git a/examples/window.rs b/examples/window.rs index ddf98a98..ad7abda9 100644 --- a/examples/window.rs +++ b/examples/window.rs @@ -2,9 +2,7 @@ #[macro_use] extern crate android_glue; -extern crate glutin; - -mod support; +extern crate winit; #[cfg(target_os = "android")] android_start!(main); @@ -14,23 +12,15 @@ fn resize_callback(width: u32, height: u32) { } fn main() { - let mut window = glutin::WindowBuilder::new().build().unwrap(); + let mut window = winit::WindowBuilder::new().build().unwrap(); window.set_title("A fantastic window!"); window.set_window_resize_callback(Some(resize_callback as fn(u32, u32))); - let _ = unsafe { window.make_current() }; - - println!("Pixel format of the window: {:?}", window.get_pixel_format()); - - let context = support::load(&window); for event in window.wait_events() { - context.draw_frame((0.0, 1.0, 0.0, 1.0)); - let _ = window.swap_buffers(); - println!("{:?}", event); match event { - glutin::Event::Closed => break, + winit::Event::Closed => break, _ => () } } diff --git a/src/api/egl/ffi.rs b/src/api/egl/ffi.rs deleted file mode 100644 index ae02e308..00000000 --- a/src/api/egl/ffi.rs +++ /dev/null @@ -1,37 +0,0 @@ -#![allow(non_camel_case_types)] - -use libc; - -#[cfg(target_os = "windows")] -extern crate winapi; - -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 = *const libc::c_void; -#[cfg(target_os = "android")] -pub type EGLNativeWindowType = *const libc::c_void; -#[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] -pub type EGLNativeWindowType = *const libc::c_void; diff --git a/src/api/egl/mod.rs b/src/api/egl/mod.rs deleted file mode 100644 index ca3dc2aa..00000000 --- a/src/api/egl/mod.rs +++ /dev/null @@ -1,731 +0,0 @@ -#![cfg(any(target_os = "windows", target_os = "linux", target_os = "android", - target_os = "dragonfly", target_os = "freebsd"))] -#![allow(unused_variables)] - -use ContextError; -use CreationError; -use GlAttributes; -use GlContext; -use GlRequest; -use PixelFormat; -use PixelFormatRequirements; -use ReleaseBehavior; -use Robustness; -use Api; - -use std::ffi::{CStr, CString}; -use std::os::raw::{c_void, c_int}; -use std::{mem, ptr}; - -pub mod ffi; - -/// Specifies the type of display passed as `native_display`. -pub enum NativeDisplay { - /// `None` means `EGL_DEFAULT_DISPLAY`. - X11(Option), - /// `None` means `EGL_DEFAULT_DISPLAY`. - Gbm(Option), - /// `None` means `EGL_DEFAULT_DISPLAY`. - Wayland(Option), - /// `EGL_DEFAULT_DISPLAY` is mandatory for Android. - Android, - // TODO: should be `EGLDeviceEXT` - Device(ffi::EGLNativeDisplayType), - /// Don't specify any display type. Useful on windows. `None` means `EGL_DEFAULT_DISPLAY`. - Other(Option), -} - -pub struct Context { - egl: ffi::egl::Egl, - display: ffi::egl::types::EGLDisplay, - context: ffi::egl::types::EGLContext, - surface: ffi::egl::types::EGLSurface, - api: Api, - pixel_format: PixelFormat, -} - -#[cfg(target_os = "android")] -#[inline] -fn get_native_display(egl: &ffi::egl::Egl, - native_display: NativeDisplay) -> *const c_void { - unsafe { egl.GetDisplay(ffi::egl::DEFAULT_DISPLAY as *mut _) } -} - -#[cfg(not(target_os = "android"))] -fn get_native_display(egl: &ffi::egl::Egl, - native_display: NativeDisplay) -> *const c_void { - // the first step is to query the list of extensions without any display, if supported - let dp_extensions = unsafe { - let p = egl.QueryString(ffi::egl::NO_DISPLAY, ffi::egl::EXTENSIONS as i32); - - // this possibility is available only with EGL 1.5 or EGL_EXT_platform_base, otherwise - // `eglQueryString` returns an error - if p.is_null() { - vec![] - } else { - let p = CStr::from_ptr(p); - let list = String::from_utf8(p.to_bytes().to_vec()).unwrap_or_else(|_| format!("")); - list.split(' ').map(|e| e.to_string()).collect::>() - } - }; - - let has_dp_extension = |e: &str| dp_extensions.iter().find(|s| s == &e).is_some(); - - match native_display { - // Note: Some EGL implementations are missing the `eglGetPlatformDisplay(EXT)` symbol - // despite reporting `EGL_EXT_platform_base`. I'm pretty sure this is a bug. - // Therefore we detect whether the symbol is loaded in addition to checking for - // extensions. - NativeDisplay::X11(display) if has_dp_extension("EGL_KHR_platform_x11") && - egl.GetPlatformDisplay.is_loaded() => - { - let d = display.unwrap_or(ffi::egl::DEFAULT_DISPLAY as *const _); - // TODO: `PLATFORM_X11_SCREEN_KHR` - unsafe { egl.GetPlatformDisplay(ffi::egl::PLATFORM_X11_KHR, d as *mut _, - ptr::null()) } - }, - - NativeDisplay::X11(display) if has_dp_extension("EGL_EXT_platform_x11") && - egl.GetPlatformDisplayEXT.is_loaded() => - { - let d = display.unwrap_or(ffi::egl::DEFAULT_DISPLAY as *const _); - // TODO: `PLATFORM_X11_SCREEN_EXT` - unsafe { egl.GetPlatformDisplayEXT(ffi::egl::PLATFORM_X11_EXT, d as *mut _, - ptr::null()) } - }, - - NativeDisplay::Gbm(display) if has_dp_extension("EGL_KHR_platform_gbm") && - egl.GetPlatformDisplay.is_loaded() => - { - let d = display.unwrap_or(ffi::egl::DEFAULT_DISPLAY as *const _); - unsafe { egl.GetPlatformDisplay(ffi::egl::PLATFORM_GBM_KHR, d as *mut _, - ptr::null()) } - }, - - NativeDisplay::Gbm(display) if has_dp_extension("EGL_MESA_platform_gbm") && - egl.GetPlatformDisplayEXT.is_loaded() => - { - let d = display.unwrap_or(ffi::egl::DEFAULT_DISPLAY as *const _); - unsafe { egl.GetPlatformDisplayEXT(ffi::egl::PLATFORM_GBM_KHR, d as *mut _, - ptr::null()) } - }, - - NativeDisplay::Wayland(display) if has_dp_extension("EGL_KHR_platform_wayland") && - egl.GetPlatformDisplay.is_loaded() => - { - let d = display.unwrap_or(ffi::egl::DEFAULT_DISPLAY as *const _); - unsafe { egl.GetPlatformDisplay(ffi::egl::PLATFORM_WAYLAND_KHR, d as *mut _, - ptr::null()) } - }, - - NativeDisplay::Wayland(display) if has_dp_extension("EGL_EXT_platform_wayland") && - egl.GetPlatformDisplayEXT.is_loaded() => - { - let d = display.unwrap_or(ffi::egl::DEFAULT_DISPLAY as *const _); - unsafe { egl.GetPlatformDisplayEXT(ffi::egl::PLATFORM_WAYLAND_EXT, d as *mut _, - ptr::null()) } - }, - - // TODO: This will never be reached right now, as the android egl bindings - // use the static generator, so can't rely on GetPlatformDisplay(EXT). - NativeDisplay::Android if has_dp_extension("EGL_KHR_platform_android") && - egl.GetPlatformDisplay.is_loaded() => - { - unsafe { egl.GetPlatformDisplay(ffi::egl::PLATFORM_ANDROID_KHR, - ffi::egl::DEFAULT_DISPLAY as *mut _, ptr::null()) } - }, - - NativeDisplay::Device(display) if has_dp_extension("EGL_EXT_platform_device") && - egl.GetPlatformDisplay.is_loaded() => - { - unsafe { egl.GetPlatformDisplay(ffi::egl::PLATFORM_DEVICE_EXT, display as *mut _, - ptr::null()) } - }, - - NativeDisplay::X11(Some(display)) | NativeDisplay::Gbm(Some(display)) | - NativeDisplay::Wayland(Some(display)) | NativeDisplay::Device(display) | - NativeDisplay::Other(Some(display)) => { - unsafe { egl.GetDisplay(display as *mut _) } - } - - NativeDisplay::X11(None) | NativeDisplay::Gbm(None) | NativeDisplay::Wayland(None) | - NativeDisplay::Android | NativeDisplay::Other(None) => { - unsafe { egl.GetDisplay(ffi::egl::DEFAULT_DISPLAY as *mut _) } - }, - } -} - -impl Context { - /// Start building an EGL context. - /// - /// This function initializes some things and chooses the pixel format. - /// - /// To finish the process, you must call `.finish(window)` on the `ContextPrototype`. - pub fn new<'a>(egl: ffi::egl::Egl, pf_reqs: &PixelFormatRequirements, - opengl: &'a GlAttributes<&'a Context>, native_display: NativeDisplay) - -> Result, CreationError> - { - if opengl.sharing.is_some() { - unimplemented!() - } - - // calling `eglGetDisplay` or equivalent - let display = get_native_display(&egl, native_display); - - if display.is_null() { - return Err(CreationError::OsError("Could not create EGL display object".to_string())); - } - - let egl_version = 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) - }; - - // the list of extensions supported by the client once initialized is different from the - // list of extensions obtained earlier - let extensions = if egl_version >= (1, 2) { - let p = unsafe { CStr::from_ptr(egl.QueryString(display, ffi::egl::EXTENSIONS as i32)) }; - let list = String::from_utf8(p.to_bytes().to_vec()).unwrap_or_else(|_| format!("")); - list.split(' ').map(|e| e.to_string()).collect::>() - - } else { - vec![] - }; - - // binding the right API and choosing the version - let (version, api) = unsafe { - match opengl.version { - GlRequest::Latest => { - if egl_version >= (1, 4) { - if egl.BindAPI(ffi::egl::OPENGL_API) != 0 { - (None, Api::OpenGl) - } else if egl.BindAPI(ffi::egl::OPENGL_ES_API) != 0 { - (None, Api::OpenGlEs) - } else { - return Err(CreationError::OpenGlVersionNotSupported); - } - } else { - (None, Api::OpenGlEs) - } - }, - GlRequest::Specific(Api::OpenGlEs, version) => { - if egl_version >= (1, 2) { - if egl.BindAPI(ffi::egl::OPENGL_ES_API) == 0 { - return Err(CreationError::OpenGlVersionNotSupported); - } - } - (Some(version), Api::OpenGlEs) - }, - GlRequest::Specific(Api::OpenGl, version) => { - if egl_version < (1, 4) { - return Err(CreationError::OpenGlVersionNotSupported); - } - if egl.BindAPI(ffi::egl::OPENGL_API) == 0 { - return Err(CreationError::OpenGlVersionNotSupported); - } - (Some(version), Api::OpenGl) - }, - GlRequest::Specific(_, _) => return Err(CreationError::OpenGlVersionNotSupported), - GlRequest::GlThenGles { opengles_version, opengl_version } => { - if egl_version >= (1, 4) { - if egl.BindAPI(ffi::egl::OPENGL_API) != 0 { - (Some(opengl_version), Api::OpenGl) - } else if egl.BindAPI(ffi::egl::OPENGL_ES_API) != 0 { - (Some(opengles_version), Api::OpenGlEs) - } else { - return Err(CreationError::OpenGlVersionNotSupported); - } - } else { - (Some(opengles_version), Api::OpenGlEs) - } - }, - } - }; - - let (config_id, pixel_format) = unsafe { - try!(choose_fbconfig(&egl, display, &egl_version, api, version, pf_reqs)) - }; - - Ok(ContextPrototype { - opengl: opengl, - egl: egl, - display: display, - egl_version: egl_version, - extensions: extensions, - api: api, - version: version, - config_id: config_id, - pixel_format: pixel_format, - }) - } -} - -impl GlContext for Context { - unsafe fn make_current(&self) -> Result<(), ContextError> { - let ret = self.egl.MakeCurrent(self.display, self.surface, self.surface, self.context); - - if ret == 0 { - match self.egl.GetError() as u32 { - ffi::egl::CONTEXT_LOST => return Err(ContextError::ContextLost), - err => panic!("eglMakeCurrent failed (eglGetError returned 0x{:x})", err) - } - - } else { - Ok(()) - } - } - - #[inline] - fn is_current(&self) -> bool { - unsafe { self.egl.GetCurrentContext() == self.context } - } - - 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 _ - } - } - - #[inline] - fn swap_buffers(&self) -> Result<(), ContextError> { - let ret = unsafe { - self.egl.SwapBuffers(self.display, self.surface) - }; - - if ret == 0 { - match unsafe { self.egl.GetError() } as u32 { - ffi::egl::CONTEXT_LOST => return Err(ContextError::ContextLost), - err => panic!("eglSwapBuffers failed (eglGetError returned 0x{:x})", err) - } - - } else { - Ok(()) - } - } - - #[inline] - fn get_api(&self) -> Api { - self.api - } - - #[inline] - fn get_pixel_format(&self) -> PixelFormat { - self.pixel_format.clone() - } -} - -unsafe impl Send for Context {} -unsafe impl Sync for Context {} - -impl Drop for Context { - fn drop(&mut self) { - 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); - } - } -} - -pub struct ContextPrototype<'a> { - opengl: &'a GlAttributes<&'a Context>, - egl: ffi::egl::Egl, - display: ffi::egl::types::EGLDisplay, - egl_version: (ffi::egl::types::EGLint, ffi::egl::types::EGLint), - extensions: Vec, - api: Api, - version: Option<(u8, u8)>, - config_id: ffi::egl::types::EGLConfig, - pixel_format: PixelFormat, -} - -impl<'a> ContextPrototype<'a> { - pub fn get_native_visual_id(&self) -> ffi::egl::types::EGLint { - let mut value = unsafe { mem::uninitialized() }; - let ret = unsafe { self.egl.GetConfigAttrib(self.display, self.config_id, - ffi::egl::NATIVE_VISUAL_ID - as ffi::egl::types::EGLint, &mut value) }; - if ret == 0 { panic!("eglGetConfigAttrib failed") }; - value - } - - pub fn finish(self, native_window: ffi::EGLNativeWindowType) - -> Result - { - let surface = unsafe { - let surface = self.egl.CreateWindowSurface(self.display, self.config_id, native_window, - ptr::null()); - if surface.is_null() { - return Err(CreationError::OsError(format!("eglCreateWindowSurface failed"))) - } - surface - }; - - self.finish_impl(surface) - } - - pub fn finish_pbuffer(self, dimensions: (u32, u32)) -> Result { - let attrs = &[ - ffi::egl::WIDTH as c_int, dimensions.0 as c_int, - ffi::egl::HEIGHT as c_int, dimensions.1 as c_int, - ffi::egl::NONE as c_int, - ]; - - let surface = unsafe { - let surface = self.egl.CreatePbufferSurface(self.display, self.config_id, - attrs.as_ptr()); - if surface.is_null() { - return Err(CreationError::OsError(format!("eglCreatePbufferSurface failed"))) - } - surface - }; - - self.finish_impl(surface) - } - - fn finish_impl(self, surface: ffi::egl::types::EGLSurface) - -> Result - { - let context = unsafe { - if let Some(version) = self.version { - try!(create_context(&self.egl, self.display, &self.egl_version, - &self.extensions, self.api, version, self.config_id, - self.opengl.debug, self.opengl.robustness)) - - } else if self.api == Api::OpenGlEs { - if let Ok(ctxt) = create_context(&self.egl, self.display, &self.egl_version, - &self.extensions, self.api, (2, 0), self.config_id, - self.opengl.debug, self.opengl.robustness) - { - ctxt - } else if let Ok(ctxt) = create_context(&self.egl, self.display, &self.egl_version, - &self.extensions, self.api, (1, 0), - self.config_id, self.opengl.debug, - self.opengl.robustness) - { - ctxt - } else { - return Err(CreationError::OpenGlVersionNotSupported); - } - - } else { - if let Ok(ctxt) = create_context(&self.egl, self.display, &self.egl_version, - &self.extensions, self.api, (3, 2), self.config_id, - self.opengl.debug, self.opengl.robustness) - { - ctxt - } else if let Ok(ctxt) = create_context(&self.egl, self.display, &self.egl_version, - &self.extensions, self.api, (3, 1), - self.config_id, self.opengl.debug, - self.opengl.robustness) - { - ctxt - } else if let Ok(ctxt) = create_context(&self.egl, self.display, &self.egl_version, - &self.extensions, self.api, (1, 0), - self.config_id, self.opengl.debug, - self.opengl.robustness) - { - ctxt - } else { - return Err(CreationError::OpenGlVersionNotSupported); - } - } - }; - - Ok(Context { - egl: self.egl, - display: self.display, - context: context, - surface: surface, - api: self.api, - pixel_format: self.pixel_format, - }) - } -} - -unsafe fn choose_fbconfig(egl: &ffi::egl::Egl, display: ffi::egl::types::EGLDisplay, - egl_version: &(ffi::egl::types::EGLint, ffi::egl::types::EGLint), - api: Api, version: Option<(u8, u8)>, reqs: &PixelFormatRequirements) - -> Result<(ffi::egl::types::EGLConfig, PixelFormat), CreationError> -{ - let descriptor = { - let mut out: Vec = Vec::with_capacity(37); - - if egl_version >= &(1, 2) { - out.push(ffi::egl::COLOR_BUFFER_TYPE as c_int); - out.push(ffi::egl::RGB_BUFFER as c_int); - } - - out.push(ffi::egl::SURFACE_TYPE as c_int); - // TODO: Some versions of Mesa report a BAD_ATTRIBUTE error - // if we ask for PBUFFER_BIT as well as WINDOW_BIT - out.push((ffi::egl::WINDOW_BIT) as c_int); - - match (api, version) { - (Api::OpenGlEs, Some((3, _))) => { - if egl_version < &(1, 3) { return Err(CreationError::NoAvailablePixelFormat); } - out.push(ffi::egl::RENDERABLE_TYPE as c_int); - out.push(ffi::egl::OPENGL_ES3_BIT as c_int); - out.push(ffi::egl::CONFORMANT as c_int); - out.push(ffi::egl::OPENGL_ES3_BIT as c_int); - }, - (Api::OpenGlEs, Some((2, _))) => { - if egl_version < &(1, 3) { return Err(CreationError::NoAvailablePixelFormat); } - out.push(ffi::egl::RENDERABLE_TYPE as c_int); - out.push(ffi::egl::OPENGL_ES2_BIT as c_int); - out.push(ffi::egl::CONFORMANT as c_int); - out.push(ffi::egl::OPENGL_ES2_BIT as c_int); - }, - (Api::OpenGlEs, Some((1, _))) => { - if egl_version >= &(1, 3) { - out.push(ffi::egl::RENDERABLE_TYPE as c_int); - out.push(ffi::egl::OPENGL_ES_BIT as c_int); - out.push(ffi::egl::CONFORMANT as c_int); - out.push(ffi::egl::OPENGL_ES_BIT as c_int); - } - }, - (Api::OpenGlEs, _) => unimplemented!(), - (Api::OpenGl, _) => { - if egl_version < &(1, 3) { return Err(CreationError::NoAvailablePixelFormat); } - out.push(ffi::egl::RENDERABLE_TYPE as c_int); - out.push(ffi::egl::OPENGL_BIT as c_int); - out.push(ffi::egl::CONFORMANT as c_int); - out.push(ffi::egl::OPENGL_BIT as c_int); - }, - (_, _) => unimplemented!(), - }; - - if let Some(hardware_accelerated) = reqs.hardware_accelerated { - out.push(ffi::egl::CONFIG_CAVEAT as c_int); - out.push(if hardware_accelerated { - ffi::egl::NONE as c_int - } else { - ffi::egl::SLOW_CONFIG as c_int - }); - } - - if let Some(color) = reqs.color_bits { - out.push(ffi::egl::RED_SIZE as c_int); - out.push((color / 3) as c_int); - out.push(ffi::egl::GREEN_SIZE as c_int); - out.push((color / 3 + if color % 3 != 0 { 1 } else { 0 }) as c_int); - out.push(ffi::egl::BLUE_SIZE as c_int); - out.push((color / 3 + if color % 3 == 2 { 1 } else { 0 }) as c_int); - } - - if let Some(alpha) = reqs.alpha_bits { - out.push(ffi::egl::ALPHA_SIZE as c_int); - out.push(alpha as c_int); - } - - if let Some(depth) = reqs.depth_bits { - out.push(ffi::egl::DEPTH_SIZE as c_int); - out.push(depth as c_int); - } - - if let Some(stencil) = reqs.stencil_bits { - out.push(ffi::egl::STENCIL_SIZE as c_int); - out.push(stencil as c_int); - } - - if let Some(true) = reqs.double_buffer { - return Err(CreationError::NoAvailablePixelFormat); - } - - if let Some(multisampling) = reqs.multisampling { - out.push(ffi::egl::SAMPLES as c_int); - out.push(multisampling as c_int); - } - - if reqs.stereoscopy { - return Err(CreationError::NoAvailablePixelFormat); - } - - // FIXME: srgb is not taken into account - - match reqs.release_behavior { - ReleaseBehavior::Flush => (), - ReleaseBehavior::None => { - // TODO: with EGL you need to manually set the behavior - unimplemented!() - }, - } - - out.push(ffi::egl::NONE as c_int); - out - }; - - // calling `eglChooseConfig` - let mut config_id = mem::uninitialized(); - let mut num_configs = mem::uninitialized(); - if egl.ChooseConfig(display, descriptor.as_ptr(), &mut config_id, 1, &mut num_configs) == 0 { - return Err(CreationError::OsError(format!("eglChooseConfig failed"))); - } - if num_configs == 0 { - return Err(CreationError::NoAvailablePixelFormat); - } - - // analyzing each config - macro_rules! attrib { - ($egl:expr, $display:expr, $config:expr, $attr:expr) => ( - { - let mut value = mem::uninitialized(); - let res = $egl.GetConfigAttrib($display, $config, - $attr as ffi::egl::types::EGLint, &mut value); - if res == 0 { - return Err(CreationError::OsError(format!("eglGetConfigAttrib failed"))); - } - value - } - ) - }; - - let desc = PixelFormat { - hardware_accelerated: attrib!(egl, display, config_id, ffi::egl::CONFIG_CAVEAT) - != ffi::egl::SLOW_CONFIG as i32, - color_bits: attrib!(egl, display, config_id, ffi::egl::RED_SIZE) as u8 + - attrib!(egl, display, config_id, ffi::egl::BLUE_SIZE) as u8 + - attrib!(egl, display, config_id, ffi::egl::GREEN_SIZE) as u8, - alpha_bits: attrib!(egl, display, config_id, ffi::egl::ALPHA_SIZE) as u8, - depth_bits: attrib!(egl, display, config_id, ffi::egl::DEPTH_SIZE) as u8, - stencil_bits: attrib!(egl, display, config_id, ffi::egl::STENCIL_SIZE) as u8, - stereoscopy: false, - double_buffer: true, - multisampling: match attrib!(egl, display, config_id, ffi::egl::SAMPLES) { - 0 | 1 => None, - a => Some(a as u16), - }, - srgb: false, // TODO: use EGL_KHR_gl_colorspace to know that - }; - - Ok((config_id, desc)) -} - -unsafe fn create_context(egl: &ffi::egl::Egl, display: ffi::egl::types::EGLDisplay, - egl_version: &(ffi::egl::types::EGLint, ffi::egl::types::EGLint), - extensions: &[String], api: Api, version: (u8, u8), - config_id: ffi::egl::types::EGLConfig, gl_debug: bool, - gl_robustness: Robustness) - -> Result -{ - let mut context_attributes = Vec::with_capacity(10); - let mut flags = 0; - - if egl_version >= &(1, 5) || extensions.iter().find(|s| s == &"EGL_KHR_create_context") - .is_some() - { - context_attributes.push(ffi::egl::CONTEXT_MAJOR_VERSION as i32); - context_attributes.push(version.0 as i32); - context_attributes.push(ffi::egl::CONTEXT_MINOR_VERSION as i32); - context_attributes.push(version.1 as i32); - - // handling robustness - let supports_robustness = egl_version >= &(1, 5) || - extensions.iter() - .find(|s| s == &"EGL_EXT_create_context_robustness") - .is_some(); - - match gl_robustness { - Robustness::NotRobust => (), - - Robustness::NoError => { - if extensions.iter().find(|s| s == &"EGL_KHR_create_context_no_error").is_some() { - context_attributes.push(ffi::egl::CONTEXT_OPENGL_NO_ERROR_KHR as c_int); - context_attributes.push(1); - } - }, - - Robustness::RobustNoResetNotification => { - if supports_robustness { - context_attributes.push(ffi::egl::CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY - as c_int); - context_attributes.push(ffi::egl::NO_RESET_NOTIFICATION as c_int); - flags = flags | ffi::egl::CONTEXT_OPENGL_ROBUST_ACCESS as c_int; - } else { - return Err(CreationError::RobustnessNotSupported); - } - }, - - Robustness::TryRobustNoResetNotification => { - if supports_robustness { - context_attributes.push(ffi::egl::CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY - as c_int); - context_attributes.push(ffi::egl::NO_RESET_NOTIFICATION as c_int); - flags = flags | ffi::egl::CONTEXT_OPENGL_ROBUST_ACCESS as c_int; - } - }, - - Robustness::RobustLoseContextOnReset => { - if supports_robustness { - context_attributes.push(ffi::egl::CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY - as c_int); - context_attributes.push(ffi::egl::LOSE_CONTEXT_ON_RESET as c_int); - flags = flags | ffi::egl::CONTEXT_OPENGL_ROBUST_ACCESS as c_int; - } else { - return Err(CreationError::RobustnessNotSupported); - } - }, - - Robustness::TryRobustLoseContextOnReset => { - if supports_robustness { - context_attributes.push(ffi::egl::CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY - as c_int); - context_attributes.push(ffi::egl::LOSE_CONTEXT_ON_RESET as c_int); - flags = flags | ffi::egl::CONTEXT_OPENGL_ROBUST_ACCESS as c_int; - } - }, - } - - if gl_debug { - if egl_version >= &(1, 5) { - context_attributes.push(ffi::egl::CONTEXT_OPENGL_DEBUG as i32); - context_attributes.push(ffi::egl::TRUE as i32); - } - - // TODO: using this flag sometimes generates an error - // there was a change in the specs that added this flag, so it may not be - // supported everywhere ; however it is not possible to know whether it is - // supported or not - //flags = flags | ffi::egl::CONTEXT_OPENGL_DEBUG_BIT_KHR as i32; - } - - context_attributes.push(ffi::egl::CONTEXT_FLAGS_KHR as i32); - context_attributes.push(flags); - - } else if egl_version >= &(1, 3) && api == Api::OpenGlEs { - // robustness is not supported - match gl_robustness { - Robustness::RobustNoResetNotification | Robustness::RobustLoseContextOnReset => { - return Err(CreationError::RobustnessNotSupported); - }, - _ => () - } - - context_attributes.push(ffi::egl::CONTEXT_CLIENT_VERSION as i32); - context_attributes.push(version.0 as i32); - } - - context_attributes.push(ffi::egl::NONE as i32); - - let context = egl.CreateContext(display, config_id, ptr::null(), - context_attributes.as_ptr()); - - if context.is_null() { - match egl.GetError() as u32 { - ffi::egl::BAD_ATTRIBUTE => return Err(CreationError::OpenGlVersionNotSupported), - e => panic!("eglCreateContext failed: 0x{:x}", e), - } - } - - Ok(context) -} diff --git a/src/api/glx/mod.rs b/src/api/glx/mod.rs deleted file mode 100644 index 95b6f99e..00000000 --- a/src/api/glx/mod.rs +++ /dev/null @@ -1,498 +0,0 @@ -#![cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd"))] - -use ContextError; -use CreationError; -use GlAttributes; -use GlContext; -use GlProfile; -use GlRequest; -use Api; -use PixelFormat; -use PixelFormatRequirements; -use ReleaseBehavior; -use Robustness; - -use libc; -use libc::c_int; -use std::ffi::{CStr, CString}; -use std::{mem, ptr, slice}; - -use api::x11::ffi; - -use platform::Window as PlatformWindow; - -pub struct Context { - glx: ffi::glx::Glx, - display: *mut ffi::Display, - window: ffi::Window, - context: ffi::GLXContext, - pixel_format: PixelFormat, -} - -// TODO: remove me -fn with_c_str(s: &str, f: F) -> T where F: FnOnce(*const libc::c_char) -> T { - use std::ffi::CString; - let c_str = CString::new(s.as_bytes().to_vec()).unwrap(); - f(c_str.as_ptr()) -} - -impl Context { - pub fn new<'a>(glx: ffi::glx::Glx, xlib: &ffi::Xlib, pf_reqs: &PixelFormatRequirements, - opengl: &'a GlAttributes<&'a Context>, display: *mut ffi::Display, - screen_id: libc::c_int) -> Result, CreationError> - { - // This is completely ridiculous, but VirtualBox's OpenGL driver needs some call handled by - // *it* (i.e. not Mesa) to occur before anything else can happen. That is because - // VirtualBox's OpenGL driver is going to apply binary patches to Mesa in the DLL - // constructor and until it's loaded it won't have a chance to do that. - // - // The easiest way to do this is to just call `glXQueryVersion()` before doing anything - // else. See: https://www.virtualbox.org/ticket/8293 - let (mut major, mut minor) = (0, 0); - unsafe { - glx.QueryVersion(display as *mut _, &mut major, &mut minor); - } - - // loading the list of extensions - let extensions = unsafe { - let extensions = glx.QueryExtensionsString(display as *mut _, screen_id); - let extensions = CStr::from_ptr(extensions).to_bytes().to_vec(); - String::from_utf8(extensions).unwrap() - }; - - // finding the pixel format we want - let (fb_config, pixel_format) = unsafe { - try!(choose_fbconfig(&glx, &extensions, xlib, display, screen_id, pf_reqs) - .map_err(|_| CreationError::NoAvailablePixelFormat)) - }; - - // getting the visual infos - let visual_infos: ffi::glx::types::XVisualInfo = unsafe { - let vi = glx.GetVisualFromFBConfig(display as *mut _, fb_config); - if vi.is_null() { - return Err(CreationError::OsError(format!("glxGetVisualFromFBConfig failed"))); - } - let vi_copy = ptr::read(vi as *const _); - (xlib.XFree)(vi as *mut _); - vi_copy - }; - - Ok(ContextPrototype { - glx: glx, - extensions: extensions, - opengl: opengl, - display: display, - fb_config: fb_config, - visual_infos: unsafe { mem::transmute(visual_infos) }, - pixel_format: pixel_format, - }) - } -} - -impl GlContext for Context { - unsafe fn make_current(&self) -> Result<(), ContextError> { - // TODO: glutin needs some internal changes for proper error recovery - let res = self.glx.MakeCurrent(self.display as *mut _, self.window, self.context); - if res == 0 { - panic!("glx::MakeCurrent failed"); - } - Ok(()) - } - - #[inline] - fn is_current(&self) -> bool { - unsafe { self.glx.GetCurrentContext() == self.context } - } - - fn get_proc_address(&self, addr: &str) -> *const () { - let addr = CString::new(addr.as_bytes()).unwrap(); - let addr = addr.as_ptr(); - unsafe { - self.glx.GetProcAddress(addr as *const _) as *const _ - } - } - - #[inline] - fn swap_buffers(&self) -> Result<(), ContextError> { - // TODO: glutin needs some internal changes for proper error recovery - unsafe { self.glx.SwapBuffers(self.display as *mut _, self.window); } - Ok(()) - } - - #[inline] - fn get_api(&self) -> ::Api { - ::Api::OpenGl - } - - #[inline] - fn get_pixel_format(&self) -> PixelFormat { - self.pixel_format.clone() - } -} - -unsafe impl Send for Context {} -unsafe impl Sync for Context {} - -impl Drop for Context { - fn drop(&mut self) { - unsafe { - if self.is_current() { - self.glx.MakeCurrent(self.display as *mut _, 0, ptr::null_mut()); - } - - self.glx.DestroyContext(self.display as *mut _, self.context); - } - } -} - -pub struct ContextPrototype<'a> { - glx: ffi::glx::Glx, - extensions: String, - opengl: &'a GlAttributes<&'a Context>, - display: *mut ffi::Display, - fb_config: ffi::glx::types::GLXFBConfig, - visual_infos: ffi::XVisualInfo, - pixel_format: PixelFormat, -} - -impl<'a> ContextPrototype<'a> { - #[inline] - pub fn get_visual_infos(&self) -> &ffi::XVisualInfo { - &self.visual_infos - } - - pub fn finish(self, window: ffi::Window) -> Result { - let share = match self.opengl.sharing { - Some(ctxt) => ctxt.context, - None => ptr::null() - }; - - // loading the extra GLX functions - let extra_functions = ffi::glx_extra::Glx::load_with(|addr| { - with_c_str(addr, |s| { - unsafe { self.glx.GetProcAddress(s as *const u8) as *const _ } - }) - }); - - // creating GL context - let context = match self.opengl.version { - GlRequest::Latest => { - if let Ok(ctxt) = create_context(&self.glx, &extra_functions, &self.extensions, (3, 2), - self.opengl.profile, self.opengl.debug, - self.opengl.robustness, share, - self.display, self.fb_config, &self.visual_infos) - { - ctxt - } else if let Ok(ctxt) = create_context(&self.glx, &extra_functions, &self.extensions, - (3, 1), self.opengl.profile, - self.opengl.debug, - self.opengl.robustness, share, self.display, - self.fb_config, &self.visual_infos) - { - ctxt - - } else { - try!(create_context(&self.glx, &extra_functions, &self.extensions, (1, 0), - self.opengl.profile, self.opengl.debug, - self.opengl.robustness, - share, self.display, self.fb_config, &self.visual_infos)) - } - }, - GlRequest::Specific(Api::OpenGl, (major, minor)) => { - try!(create_context(&self.glx, &extra_functions, &self.extensions, (major, minor), - self.opengl.profile, self.opengl.debug, - self.opengl.robustness, share, self.display, self.fb_config, - &self.visual_infos)) - }, - GlRequest::Specific(_, _) => panic!("Only OpenGL is supported"), - GlRequest::GlThenGles { opengl_version: (major, minor), .. } => { - try!(create_context(&self.glx, &extra_functions, &self.extensions, (major, minor), - self.opengl.profile, self.opengl.debug, - self.opengl.robustness, share, self.display, self.fb_config, - &self.visual_infos)) - }, - }; - - // vsync - if self.opengl.vsync { - unsafe { self.glx.MakeCurrent(self.display as *mut _, window, context) }; - - if extra_functions.SwapIntervalEXT.is_loaded() { - // this should be the most common extension - unsafe { - extra_functions.SwapIntervalEXT(self.display as *mut _, window, 1); - } - - // checking that it worked - // TODO: handle this - /*if self.builder.strict { - let mut swap = unsafe { mem::uninitialized() }; - unsafe { - self.glx.QueryDrawable(self.display as *mut _, window, - ffi::glx_extra::SWAP_INTERVAL_EXT as i32, - &mut swap); - } - - if swap != 1 { - return Err(CreationError::OsError(format!("Couldn't setup vsync: expected \ - interval `1` but got `{}`", swap))); - } - }*/ - - // GLX_MESA_swap_control is not official - /*} else if extra_functions.SwapIntervalMESA.is_loaded() { - unsafe { - extra_functions.SwapIntervalMESA(1); - }*/ - - } else if extra_functions.SwapIntervalSGI.is_loaded() { - unsafe { - extra_functions.SwapIntervalSGI(1); - } - - }/* else if self.builder.strict { - // TODO: handle this - return Err(CreationError::OsError(format!("Couldn't find any available vsync extension"))); - }*/ - - unsafe { self.glx.MakeCurrent(self.display as *mut _, 0, ptr::null()) }; - } - - Ok(Context { - glx: self.glx, - display: self.display, - window: window, - context: context, - pixel_format: self.pixel_format, - }) - } -} - -fn create_context(glx: &ffi::glx::Glx, extra_functions: &ffi::glx_extra::Glx, extensions: &str, - version: (u8, u8), profile: Option, debug: bool, - robustness: Robustness, share: ffi::GLXContext, display: *mut ffi::Display, - fb_config: ffi::glx::types::GLXFBConfig, - visual_infos: &ffi::XVisualInfo) - -> Result -{ - unsafe { - let context = if extensions.split(' ').find(|&i| i == "GLX_ARB_create_context").is_some() { - let mut attributes = Vec::with_capacity(9); - - attributes.push(ffi::glx_extra::CONTEXT_MAJOR_VERSION_ARB as c_int); - attributes.push(version.0 as c_int); - attributes.push(ffi::glx_extra::CONTEXT_MINOR_VERSION_ARB as c_int); - attributes.push(version.1 as c_int); - - if let Some(profile) = profile { - let flag = match profile { - GlProfile::Compatibility => - ffi::glx_extra::CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB, - GlProfile::Core => - ffi::glx_extra::CONTEXT_CORE_PROFILE_BIT_ARB, - }; - - attributes.push(ffi::glx_extra::CONTEXT_PROFILE_MASK_ARB as c_int); - attributes.push(flag as c_int); - } - - let flags = { - let mut flags = 0; - - // robustness - if extensions.split(' ').find(|&i| i == "GLX_ARB_create_context_robustness").is_some() { - match robustness { - Robustness::RobustNoResetNotification | Robustness::TryRobustNoResetNotification => { - attributes.push(ffi::glx_extra::CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB as c_int); - attributes.push(ffi::glx_extra::NO_RESET_NOTIFICATION_ARB as c_int); - flags = flags | ffi::glx_extra::CONTEXT_ROBUST_ACCESS_BIT_ARB as c_int; - }, - Robustness::RobustLoseContextOnReset | Robustness::TryRobustLoseContextOnReset => { - attributes.push(ffi::glx_extra::CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB as c_int); - attributes.push(ffi::glx_extra::LOSE_CONTEXT_ON_RESET_ARB as c_int); - flags = flags | ffi::glx_extra::CONTEXT_ROBUST_ACCESS_BIT_ARB as c_int; - }, - Robustness::NotRobust => (), - Robustness::NoError => (), - } - } else { - match robustness { - Robustness::RobustNoResetNotification | Robustness::RobustLoseContextOnReset => { - return Err(CreationError::RobustnessNotSupported); - }, - _ => () - } - } - - if debug { - flags = flags | ffi::glx_extra::CONTEXT_DEBUG_BIT_ARB as c_int; - } - - flags - }; - - attributes.push(ffi::glx_extra::CONTEXT_FLAGS_ARB as c_int); - attributes.push(flags); - - attributes.push(0); - - extra_functions.CreateContextAttribsARB(display as *mut _, fb_config, share, 1, - attributes.as_ptr()) - - } else { - let visual_infos: *const ffi::XVisualInfo = visual_infos; - glx.CreateContext(display as *mut _, visual_infos as *mut _, share, 1) - }; - - if context.is_null() { - // TODO: check for errors and return `OpenGlVersionNotSupported` - return Err(CreationError::OsError(format!("GL context creation failed"))); - } - - Ok(context) - } -} - -/// Enumerates all available FBConfigs -unsafe fn choose_fbconfig(glx: &ffi::glx::Glx, extensions: &str, xlib: &ffi::Xlib, - display: *mut ffi::Display, screen_id: libc::c_int, - reqs: &PixelFormatRequirements) - -> Result<(ffi::glx::types::GLXFBConfig, PixelFormat), ()> -{ - let descriptor = { - let mut out: Vec = Vec::with_capacity(37); - - out.push(ffi::glx::X_RENDERABLE as c_int); - out.push(1); - - out.push(ffi::glx::X_VISUAL_TYPE as c_int); - out.push(ffi::glx::TRUE_COLOR as c_int); - - out.push(ffi::glx::DRAWABLE_TYPE as c_int); - out.push(ffi::glx::WINDOW_BIT as c_int); - - out.push(ffi::glx::RENDER_TYPE as c_int); - if reqs.float_color_buffer { - if extensions.split(' ').find(|&i| i == "GLX_ARB_fbconfig_float").is_some() { - out.push(ffi::glx_extra::RGBA_FLOAT_BIT_ARB as c_int); - } else { - return Err(()); - } - } else { - out.push(ffi::glx::RGBA_BIT as c_int); - } - - if let Some(hardware_accelerated) = reqs.hardware_accelerated { - out.push(ffi::glx::CONFIG_CAVEAT as c_int); - out.push(if hardware_accelerated { - ffi::glx::NONE as c_int - } else { - ffi::glx::SLOW_CONFIG as c_int - }); - } - - if let Some(color) = reqs.color_bits { - out.push(ffi::glx::RED_SIZE as c_int); - out.push((color / 3) as c_int); - out.push(ffi::glx::GREEN_SIZE as c_int); - out.push((color / 3 + if color % 3 != 0 { 1 } else { 0 }) as c_int); - out.push(ffi::glx::BLUE_SIZE as c_int); - out.push((color / 3 + if color % 3 == 2 { 1 } else { 0 }) as c_int); - } - - if let Some(alpha) = reqs.alpha_bits { - out.push(ffi::glx::ALPHA_SIZE as c_int); - out.push(alpha as c_int); - } - - if let Some(depth) = reqs.depth_bits { - out.push(ffi::glx::DEPTH_SIZE as c_int); - out.push(depth as c_int); - } - - if let Some(stencil) = reqs.stencil_bits { - out.push(ffi::glx::STENCIL_SIZE as c_int); - out.push(stencil as c_int); - } - - let double_buffer = reqs.double_buffer.unwrap_or(true); - out.push(ffi::glx::DOUBLEBUFFER as c_int); - out.push(if double_buffer { 1 } else { 0 }); - - if let Some(multisampling) = reqs.multisampling { - if extensions.split(' ').find(|&i| i == "GLX_ARB_multisample").is_some() { - out.push(ffi::glx_extra::SAMPLE_BUFFERS_ARB as c_int); - out.push(if multisampling == 0 { 0 } else { 1 }); - out.push(ffi::glx_extra::SAMPLES_ARB as c_int); - out.push(multisampling as c_int); - } else { - return Err(()); - } - } - - out.push(ffi::glx::STEREO as c_int); - out.push(if reqs.stereoscopy { 1 } else { 0 }); - - if reqs.srgb { - if extensions.split(' ').find(|&i| i == "GLX_ARB_framebuffer_sRGB").is_some() { - out.push(ffi::glx_extra::FRAMEBUFFER_SRGB_CAPABLE_ARB as c_int); - out.push(1); - } else { - return Err(()); - } - } - - match reqs.release_behavior { - ReleaseBehavior::Flush => (), - ReleaseBehavior::None => { - if extensions.split(' ').find(|&i| i == "GLX_ARB_context_flush_control").is_some() { - out.push(ffi::glx_extra::CONTEXT_RELEASE_BEHAVIOR_ARB as c_int); - out.push(ffi::glx_extra::CONTEXT_RELEASE_BEHAVIOR_NONE_ARB as c_int); - } - }, - } - - out.push(0); - out - }; - - // calling glXChooseFBConfig - let fb_config = { - let mut num_configs = 1; - let result = glx.ChooseFBConfig(display as *mut _, screen_id, descriptor.as_ptr(), - &mut num_configs); - if result.is_null() { return Err(()); } - if num_configs == 0 { return Err(()); } - let val = *result; - (xlib.XFree)(result as *mut _); - val - }; - - let get_attrib = |attrib: c_int| -> i32 { - let mut value = 0; - glx.GetFBConfigAttrib(display as *mut _, fb_config, attrib, &mut value); - // TODO: check return value - value - }; - - let pf_desc = PixelFormat { - hardware_accelerated: get_attrib(ffi::glx::CONFIG_CAVEAT as c_int) != - ffi::glx::SLOW_CONFIG as c_int, - color_bits: get_attrib(ffi::glx::RED_SIZE as c_int) as u8 + - get_attrib(ffi::glx::GREEN_SIZE as c_int) as u8 + - get_attrib(ffi::glx::BLUE_SIZE as c_int) as u8, - alpha_bits: get_attrib(ffi::glx::ALPHA_SIZE as c_int) as u8, - depth_bits: get_attrib(ffi::glx::DEPTH_SIZE as c_int) as u8, - stencil_bits: get_attrib(ffi::glx::STENCIL_SIZE as c_int) as u8, - stereoscopy: get_attrib(ffi::glx::STEREO as c_int) != 0, - double_buffer: get_attrib(ffi::glx::DOUBLEBUFFER as c_int) != 0, - multisampling: if get_attrib(ffi::glx::SAMPLE_BUFFERS as c_int) != 0 { - Some(get_attrib(ffi::glx::SAMPLES as c_int) as u16) - } else { - None - }, - srgb: get_attrib(ffi::glx_extra::FRAMEBUFFER_SRGB_CAPABLE_ARB as c_int) != 0, - }; - - Ok((fb_config, pf_desc)) -} diff --git a/src/api/mod.rs b/src/api/mod.rs index 3697255c..c7038463 100644 --- a/src/api/mod.rs +++ b/src/api/mod.rs @@ -2,12 +2,8 @@ pub mod android; pub mod caca; pub mod cocoa; pub mod dlopen; -pub mod egl; pub mod emscripten; -pub mod glx; -pub mod osmesa; pub mod wayland; -pub mod wgl; pub mod win32; pub mod x11; pub mod ios; diff --git a/src/api/osmesa/mod.rs b/src/api/osmesa/mod.rs deleted file mode 100644 index 7ef243a3..00000000 --- a/src/api/osmesa/mod.rs +++ /dev/null @@ -1,140 +0,0 @@ -#![cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd"))] - -extern crate osmesa_sys; - -use Api; -use ContextError; -use CreationError; -use GlAttributes; -use GlContext; -use PixelFormat; -use PixelFormatRequirements; -use Robustness; -use libc; -use std::{mem, ptr}; -use std::ffi::CString; - -pub struct OsMesaContext { - context: osmesa_sys::OSMesaContext, - buffer: Vec, - width: u32, - height: u32, -} - -pub enum OsMesaCreationError { - CreationError(CreationError), - NotSupported, -} - -impl From for OsMesaCreationError { - #[inline] - fn from(e: CreationError) -> OsMesaCreationError { - OsMesaCreationError::CreationError(e) - } -} - -impl OsMesaContext { - pub fn new(dimensions: (u32, u32), pf_reqs: &PixelFormatRequirements, - opengl: &GlAttributes<&OsMesaContext>) -> Result - { - if let Err(_) = osmesa_sys::OsMesa::try_loading() { - return Err(OsMesaCreationError::NotSupported); - } - - if opengl.sharing.is_some() { unimplemented!() } // TODO: proper error - - match opengl.robustness { - Robustness::RobustNoResetNotification | Robustness::RobustLoseContextOnReset => { - return Err(CreationError::RobustnessNotSupported.into()); - }, - _ => () - } - - // TODO: use `pf_reqs` for the format - // TODO: check OpenGL version and return `OpenGlVersionNotSupported` if necessary - - Ok(OsMesaContext { - width: dimensions.0, - height: dimensions.1, - buffer: ::std::iter::repeat(unsafe { mem::uninitialized() }) - .take((dimensions.0 * dimensions.1) as usize).collect(), - context: unsafe { - let ctxt = osmesa_sys::OSMesaCreateContext(0x1908, ptr::null_mut()); - if ctxt.is_null() { - return Err(CreationError::OsError("OSMesaCreateContext failed".to_string()).into()); - } - ctxt - } - }) - } - - #[inline] - pub fn get_framebuffer(&self) -> &[u32] { - &self.buffer - } - - #[inline] - pub fn get_dimensions(&self) -> (u32, u32) { - (self.width, self.height) - } - - #[allow(dead_code)] - // TODO: can we remove this without causing havoc? - #[inline] - pub fn set_window_resize_callback(&mut self, _: Option) { - } -} - -impl GlContext for OsMesaContext { - #[inline] - unsafe fn make_current(&self) -> Result<(), ContextError> { - let ret = osmesa_sys::OSMesaMakeCurrent(self.context, self.buffer.as_ptr() - as *mut _, 0x1401, self.width - as libc::c_int, self.height as libc::c_int); - - // an error can only happen in case of invalid parameter, which would indicate a bug - // in glutin - if ret == 0 { - panic!("OSMesaMakeCurrent failed"); - } - - Ok(()) - } - - #[inline] - fn is_current(&self) -> bool { - unsafe { osmesa_sys::OSMesaGetCurrentContext() == self.context } - } - - fn get_proc_address(&self, addr: &str) -> *const () { - unsafe { - let c_str = CString::new(addr.as_bytes().to_vec()).unwrap(); - mem::transmute(osmesa_sys::OSMesaGetProcAddress(mem::transmute(c_str.as_ptr()))) - } - } - - #[inline] - fn swap_buffers(&self) -> Result<(), ContextError> { - Ok(()) - } - - #[inline] - fn get_api(&self) -> Api { - Api::OpenGl - } - - #[inline] - fn get_pixel_format(&self) -> PixelFormat { - unimplemented!(); - } -} - -impl Drop for OsMesaContext { - #[inline] - fn drop(&mut self) { - unsafe { osmesa_sys::OSMesaDestroyContext(self.context) } - } -} - -unsafe impl Send for OsMesaContext {} -unsafe impl Sync for OsMesaContext {} diff --git a/src/api/wgl/gl.rs b/src/api/wgl/gl.rs deleted file mode 100644 index 1354d954..00000000 --- a/src/api/wgl/gl.rs +++ /dev/null @@ -1,12 +0,0 @@ -/// WGL bindings -pub mod wgl { - include!(concat!(env!("OUT_DIR"), "/wgl_bindings.rs")); -} - -/// Functions that are not necessarly always available -pub mod wgl_extra { - include!(concat!(env!("OUT_DIR"), "/wgl_extra_bindings.rs")); -} - -#[link(name = "opengl32")] -extern {} diff --git a/src/api/wgl/make_current_guard.rs b/src/api/wgl/make_current_guard.rs deleted file mode 100644 index 83e35b27..00000000 --- a/src/api/wgl/make_current_guard.rs +++ /dev/null @@ -1,47 +0,0 @@ -use std::marker::PhantomData; -use std::os::raw::c_void; -use std::io; - -use winapi; -use CreationError; - -use super::gl; -/// A guard for when you want to make the context current. Destroying the guard restores the -/// previously-current context. -pub struct CurrentContextGuard<'a, 'b> { - previous_hdc: winapi::HDC, - previous_hglrc: winapi::HGLRC, - marker1: PhantomData<&'a ()>, - marker2: PhantomData<&'b ()>, -} - -impl<'a, 'b> CurrentContextGuard<'a, 'b> { - pub unsafe fn make_current(hdc: winapi::HDC, context: winapi::HGLRC) - -> Result, CreationError> - { - let previous_hdc = gl::wgl::GetCurrentDC() as winapi::HDC; - let previous_hglrc = gl::wgl::GetCurrentContext() as winapi::HGLRC; - - let result = gl::wgl::MakeCurrent(hdc as *const _, context as *const _); - if result == 0 { - return Err(CreationError::OsError(format!("wglMakeCurrent function failed: {}", - format!("{}", io::Error::last_os_error())))); - } - - Ok(CurrentContextGuard { - previous_hdc: previous_hdc, - previous_hglrc: previous_hglrc, - marker1: PhantomData, - marker2: PhantomData, - }) - } -} - -impl<'a, 'b> Drop for CurrentContextGuard<'a, 'b> { - fn drop(&mut self) { - unsafe { - gl::wgl::MakeCurrent(self.previous_hdc as *const c_void, - self.previous_hglrc as *const c_void); - } - } -} diff --git a/src/api/wgl/mod.rs b/src/api/wgl/mod.rs deleted file mode 100644 index a0fce271..00000000 --- a/src/api/wgl/mod.rs +++ /dev/null @@ -1,787 +0,0 @@ -#![cfg(any(target_os = "windows"))] - -use ContextError; -use CreationError; -use GlAttributes; -use GlContext; -use GlRequest; -use GlProfile; -use PixelFormat; -use PixelFormatRequirements; -use ReleaseBehavior; -use Robustness; -use Api; - -use self::make_current_guard::CurrentContextGuard; - -use std::ffi::{CStr, CString, OsStr}; -use std::os::raw::{c_void, c_int}; -use std::os::windows::ffi::OsStrExt; -use std::{mem, ptr}; -use std::io; - -use winapi; -use kernel32; -use user32; -use gdi32; - -mod make_current_guard; -mod gl; - -/// A WGL context. -/// -/// Note: should be destroyed before its window. -pub struct Context { - context: ContextWrapper, - - hdc: winapi::HDC, - - /// Binded to `opengl32.dll`. - /// - /// `wglGetProcAddress` returns null for GL 1.1 functions because they are - /// already defined by the system. This module contains them. - gl_library: winapi::HMODULE, - - /// The pixel format that has been used to create this context. - pixel_format: PixelFormat, -} - -/// A simple wrapper that destroys the window when it is destroyed. -struct WindowWrapper(winapi::HWND, winapi::HDC); - -impl Drop for WindowWrapper { - #[inline] - fn drop(&mut self) { - unsafe { - user32::DestroyWindow(self.0); - } - } -} - -/// Wraps around a context so that it is destroyed when necessary. -struct ContextWrapper(winapi::HGLRC); - -impl Drop for ContextWrapper { - #[inline] - fn drop(&mut self) { - unsafe { - gl::wgl::DeleteContext(self.0 as *const _); - } - } -} - -impl Context { - /// Attempt to build a new WGL context on a window. - /// - /// The window must **not** have had `SetPixelFormat` called on it. - /// - /// # Unsafety - /// - /// The `window` must continue to exist as long as the resulting `Context` exists. - pub unsafe fn new(pf_reqs: &PixelFormatRequirements, opengl: &GlAttributes, - window: winapi::HWND) -> Result - { - let hdc = user32::GetDC(window); - if hdc.is_null() { - let err = Err(CreationError::OsError(format!("GetDC function failed: {}", - format!("{}", io::Error::last_os_error())))); - return err; - } - - // loading the functions that are not guaranteed to be supported - let extra_functions = try!(load_extra_functions(window)); - - // getting the list of the supported extensions - let extensions = if extra_functions.GetExtensionsStringARB.is_loaded() { - let data = extra_functions.GetExtensionsStringARB(hdc as *const _); - let data = CStr::from_ptr(data).to_bytes().to_vec(); - String::from_utf8(data).unwrap() - - } else if extra_functions.GetExtensionsStringEXT.is_loaded() { - let data = extra_functions.GetExtensionsStringEXT(); - let data = CStr::from_ptr(data).to_bytes().to_vec(); - String::from_utf8(data).unwrap() - - } else { - format!("") - }; - - // calling SetPixelFormat - let pixel_format = { - let (id, f) = if extensions.split(' ').find(|&i| i == "WGL_ARB_pixel_format") - .is_some() - { - try!(choose_arb_pixel_format(&extra_functions, &extensions, hdc, pf_reqs) - .map_err(|_| CreationError::NoAvailablePixelFormat)) - } else { - try!(choose_native_pixel_format(hdc, pf_reqs) - .map_err(|_| CreationError::NoAvailablePixelFormat)) - }; - - try!(set_pixel_format(hdc, id)); - f - }; - - // creating the OpenGL context - let context = try!(create_context(Some((&extra_functions, pf_reqs, opengl, &extensions)), - window, hdc)); - - // loading the opengl32 module - let gl_library = try!(load_opengl32_dll()); - - // handling vsync - if extensions.split(' ').find(|&i| i == "WGL_EXT_swap_control").is_some() { - let _guard = try!(CurrentContextGuard::make_current(hdc, context.0)); - - if extra_functions.SwapIntervalEXT(if opengl.vsync { 1 } else { 0 }) == 0 { - return Err(CreationError::OsError(format!("wglSwapIntervalEXT failed"))); - } - } - - Ok(Context { - context: context, - hdc: hdc, - gl_library: gl_library, - pixel_format: pixel_format, - }) - } - - /// Returns the raw HGLRC. - #[inline] - pub fn get_hglrc(&self) -> winapi::HGLRC { - self.context.0 - } -} - -impl GlContext for Context { - #[inline] - unsafe fn make_current(&self) -> Result<(), ContextError> { - if gl::wgl::MakeCurrent(self.hdc as *const _, self.context.0 as *const _) != 0 { - Ok(()) - } else { - Err(ContextError::IoError(io::Error::last_os_error())) - } - } - - #[inline] - fn is_current(&self) -> bool { - unsafe { gl::wgl::GetCurrentContext() == self.context.0 as *const c_void } - } - - fn get_proc_address(&self, addr: &str) -> *const () { - let addr = CString::new(addr.as_bytes()).unwrap(); - let addr = addr.as_ptr(); - - unsafe { - let p = gl::wgl::GetProcAddress(addr) as *const _; - if !p.is_null() { return p; } - kernel32::GetProcAddress(self.gl_library, addr) as *const _ - } - } - - #[inline] - fn swap_buffers(&self) -> Result<(), ContextError> { - // TODO: decide how to handle the error - /*if unsafe { gdi32::SwapBuffers(self.hdc) } != 0 { - Ok(()) - } else { - Err(ContextError::IoError(io::Error::last_os_error())) - }*/ - unsafe { gdi32::SwapBuffers(self.hdc) }; - Ok(()) - } - - #[inline] - fn get_api(&self) -> Api { - // FIXME: can be opengl es - Api::OpenGl - } - - #[inline] - fn get_pixel_format(&self) -> PixelFormat { - self.pixel_format.clone() - } -} - -unsafe impl Send for Context {} -unsafe impl Sync for Context {} - -/// Creates an OpenGL context. -/// -/// If `extra` is `Some`, this function will attempt to use the latest WGL functions to create the -/// context. -/// -/// Otherwise, only the basic API will be used and the chances of `CreationError::NotSupported` -/// being returned increase. -unsafe fn create_context(extra: Option<(&gl::wgl_extra::Wgl, &PixelFormatRequirements, - &GlAttributes, &str)>, - _: winapi::HWND, hdc: winapi::HDC) - -> Result -{ - let share; - - if let Some((extra_functions, pf_reqs, opengl, extensions)) = extra { - share = opengl.sharing.unwrap_or(ptr::null_mut()); - - if extensions.split(' ').find(|&i| i == "WGL_ARB_create_context").is_some() { - let mut attributes = Vec::new(); - - match opengl.version { - GlRequest::Latest => {}, - GlRequest::Specific(Api::OpenGl, (major, minor)) => { - attributes.push(gl::wgl_extra::CONTEXT_MAJOR_VERSION_ARB as c_int); - attributes.push(major as c_int); - attributes.push(gl::wgl_extra::CONTEXT_MINOR_VERSION_ARB as c_int); - attributes.push(minor as c_int); - }, - GlRequest::Specific(Api::OpenGlEs, (major, minor)) => { - if extensions.split(' ').find(|&i| i == "WGL_EXT_create_context_es2_profile") - .is_some() - { - attributes.push(gl::wgl_extra::CONTEXT_PROFILE_MASK_ARB as c_int); - attributes.push(gl::wgl_extra::CONTEXT_ES2_PROFILE_BIT_EXT as c_int); - } else { - return Err(CreationError::OpenGlVersionNotSupported); - } - - attributes.push(gl::wgl_extra::CONTEXT_MAJOR_VERSION_ARB as c_int); - attributes.push(major as c_int); - attributes.push(gl::wgl_extra::CONTEXT_MINOR_VERSION_ARB as c_int); - attributes.push(minor as c_int); - }, - GlRequest::Specific(_, _) => return Err(CreationError::OpenGlVersionNotSupported), - GlRequest::GlThenGles { opengl_version: (major, minor), .. } => { - attributes.push(gl::wgl_extra::CONTEXT_MAJOR_VERSION_ARB as c_int); - attributes.push(major as c_int); - attributes.push(gl::wgl_extra::CONTEXT_MINOR_VERSION_ARB as c_int); - attributes.push(minor as c_int); - }, - } - - if let Some(profile) = opengl.profile { - if extensions.split(' ').find(|&i| i == "WGL_ARB_create_context_profile").is_some() - { - let flag = match profile { - GlProfile::Compatibility => - gl::wgl_extra::CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB, - GlProfile::Core => - gl::wgl_extra::CONTEXT_CORE_PROFILE_BIT_ARB, - }; - attributes.push(gl::wgl_extra::CONTEXT_PROFILE_MASK_ARB as c_int); - attributes.push(flag as c_int); - } else { - return Err(CreationError::NotSupported); - } - } - - let flags = { - let mut flags = 0; - - // robustness - if extensions.split(' ').find(|&i| i == "WGL_ARB_create_context_robustness").is_some() { - match opengl.robustness { - Robustness::RobustNoResetNotification | Robustness::TryRobustNoResetNotification => { - attributes.push(gl::wgl_extra::CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB as c_int); - attributes.push(gl::wgl_extra::NO_RESET_NOTIFICATION_ARB as c_int); - flags = flags | gl::wgl_extra::CONTEXT_ROBUST_ACCESS_BIT_ARB as c_int; - }, - Robustness::RobustLoseContextOnReset | Robustness::TryRobustLoseContextOnReset => { - attributes.push(gl::wgl_extra::CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB as c_int); - attributes.push(gl::wgl_extra::LOSE_CONTEXT_ON_RESET_ARB as c_int); - flags = flags | gl::wgl_extra::CONTEXT_ROBUST_ACCESS_BIT_ARB as c_int; - }, - Robustness::NotRobust => (), - Robustness::NoError => (), - } - } else { - match opengl.robustness { - Robustness::RobustNoResetNotification | Robustness::RobustLoseContextOnReset => { - return Err(CreationError::RobustnessNotSupported); - }, - _ => () - } - } - - if opengl.debug { - flags = flags | gl::wgl_extra::CONTEXT_DEBUG_BIT_ARB as c_int; - } - - flags - }; - - attributes.push(gl::wgl_extra::CONTEXT_FLAGS_ARB as c_int); - attributes.push(flags); - - attributes.push(0); - - let ctxt = extra_functions.CreateContextAttribsARB(hdc as *const c_void, - share as *const c_void, - attributes.as_ptr()); - - if ctxt.is_null() { - return Err(CreationError::OsError(format!("wglCreateContextAttribsARB failed: {}", - format!("{}", io::Error::last_os_error())))); - } else { - return Ok(ContextWrapper(ctxt as winapi::HGLRC)); - } - } - - } else { - share = ptr::null_mut(); - } - - let ctxt = gl::wgl::CreateContext(hdc as *const c_void); - if ctxt.is_null() { - return Err(CreationError::OsError(format!("wglCreateContext failed: {}", - format!("{}", io::Error::last_os_error())))); - } - - if !share.is_null() { - if gl::wgl::ShareLists(share as *const c_void, ctxt) == 0 { - return Err(CreationError::OsError(format!("wglShareLists failed: {}", - format!("{}", io::Error::last_os_error())))); - } - }; - - Ok(ContextWrapper(ctxt as winapi::HGLRC)) -} - -/// Chooses a pixel formats without using WGL. -/// -/// Gives less precise results than `enumerate_arb_pixel_formats`. -unsafe fn choose_native_pixel_format(hdc: winapi::HDC, reqs: &PixelFormatRequirements) - -> Result<(c_int, PixelFormat), ()> -{ - // TODO: hardware acceleration is not handled - - // handling non-supported stuff - if reqs.float_color_buffer { - return Err(()); - } - - match reqs.multisampling { - Some(0) => (), - None => (), - Some(_) => return Err(()) - }; - - if reqs.stereoscopy { - return Err(()); - } - - if reqs.srgb { - return Err(()); - } - - if reqs.release_behavior != ReleaseBehavior::Flush { - return Err(()); - } - - // building the descriptor to pass to ChoosePixelFormat - let descriptor = winapi::PIXELFORMATDESCRIPTOR { - nSize: mem::size_of::() as u16, - nVersion: 1, - dwFlags: { - let f1 = match reqs.double_buffer { - None => winapi::PFD_DOUBLEBUFFER, // Should be PFD_DOUBLEBUFFER_DONTCARE after you can choose - Some(true) => winapi::PFD_DOUBLEBUFFER, - Some(false) => 0, - }; - - let f2 = if reqs.stereoscopy { - winapi::PFD_STEREO - } else { - 0 - }; - - winapi::PFD_DRAW_TO_WINDOW | winapi::PFD_SUPPORT_OPENGL | f1 | f2 - }, - iPixelType: winapi::PFD_TYPE_RGBA, - cColorBits: reqs.color_bits.unwrap_or(0), - cRedBits: 0, - cRedShift: 0, - cGreenBits: 0, - cGreenShift: 0, - cBlueBits: 0, - cBlueShift: 0, - cAlphaBits: reqs.alpha_bits.unwrap_or(0), - cAlphaShift: 0, - cAccumBits: 0, - cAccumRedBits: 0, - cAccumGreenBits: 0, - cAccumBlueBits: 0, - cAccumAlphaBits: 0, - cDepthBits: reqs.depth_bits.unwrap_or(0), - cStencilBits: reqs.stencil_bits.unwrap_or(0), - cAuxBuffers: 0, - iLayerType: winapi::PFD_MAIN_PLANE, - bReserved: 0, - dwLayerMask: 0, - dwVisibleMask: 0, - dwDamageMask: 0, - }; - - // now querying - let pf_id = gdi32::ChoosePixelFormat(hdc, &descriptor); - if pf_id == 0 { - return Err(()); - } - - // querying back the capabilities of what windows told us - let mut output: winapi::PIXELFORMATDESCRIPTOR = mem::zeroed(); - if gdi32::DescribePixelFormat(hdc, pf_id, mem::size_of::() as u32, - &mut output) == 0 - { - return Err(()); - } - - // windows may return us a non-conforming pixel format if none are supported, so we have to - // check this - if (output.dwFlags & winapi::PFD_DRAW_TO_WINDOW) == 0 { - return Err(()); - } - if (output.dwFlags & winapi::PFD_SUPPORT_OPENGL) == 0 { - return Err(()); - } - if output.iPixelType != winapi::PFD_TYPE_RGBA { - return Err(()); - } - - let pf_desc = PixelFormat { - hardware_accelerated: (output.dwFlags & winapi::PFD_GENERIC_FORMAT) == 0, - color_bits: output.cRedBits + output.cGreenBits + output.cBlueBits, - alpha_bits: output.cAlphaBits, - depth_bits: output.cDepthBits, - stencil_bits: output.cStencilBits, - stereoscopy: (output.dwFlags & winapi::PFD_STEREO) != 0, - double_buffer: (output.dwFlags & winapi::PFD_DOUBLEBUFFER) != 0, - multisampling: None, - srgb: false, - }; - - if pf_desc.alpha_bits < reqs.alpha_bits.unwrap_or(0) { - return Err(()); - } - if pf_desc.depth_bits < reqs.depth_bits.unwrap_or(0) { - return Err(()); - } - if pf_desc.stencil_bits < reqs.stencil_bits.unwrap_or(0) { - return Err(()); - } - if pf_desc.color_bits < reqs.color_bits.unwrap_or(0) { - return Err(()); - } - if let Some(req) = reqs.hardware_accelerated { - if pf_desc.hardware_accelerated != req { - return Err(()); - } - } - if let Some(req) = reqs.double_buffer { - if pf_desc.double_buffer != req { - return Err(()); - } - } - - Ok((pf_id, pf_desc)) -} - -/// Enumerates the list of pixel formats by using extra WGL functions. -/// -/// Gives more precise results than `enumerate_native_pixel_formats`. -unsafe fn choose_arb_pixel_format(extra: &gl::wgl_extra::Wgl, extensions: &str, - hdc: winapi::HDC, reqs: &PixelFormatRequirements) - -> Result<(c_int, PixelFormat), ()> -{ - let descriptor = { - let mut out: Vec = Vec::with_capacity(37); - - out.push(gl::wgl_extra::DRAW_TO_WINDOW_ARB as c_int); - out.push(1); - - out.push(gl::wgl_extra::SUPPORT_OPENGL_ARB as c_int); - out.push(1); - - out.push(gl::wgl_extra::PIXEL_TYPE_ARB as c_int); - if reqs.float_color_buffer { - if extensions.split(' ').find(|&i| i == "WGL_ARB_pixel_format_float").is_some() { - out.push(gl::wgl_extra::TYPE_RGBA_FLOAT_ARB as c_int); - } else { - return Err(()); - } - } else { - out.push(gl::wgl_extra::TYPE_RGBA_ARB as c_int); - } - - if let Some(hardware_accelerated) = reqs.hardware_accelerated { - out.push(gl::wgl_extra::ACCELERATION_ARB as c_int); - out.push(if hardware_accelerated { - gl::wgl_extra::FULL_ACCELERATION_ARB as c_int - } else { - gl::wgl_extra::NO_ACCELERATION_ARB as c_int - }); - } - - if let Some(color) = reqs.color_bits { - out.push(gl::wgl_extra::COLOR_BITS_ARB as c_int); - out.push(color as c_int); - } - - if let Some(alpha) = reqs.alpha_bits { - out.push(gl::wgl_extra::ALPHA_BITS_ARB as c_int); - out.push(alpha as c_int); - } - - if let Some(depth) = reqs.depth_bits { - out.push(gl::wgl_extra::DEPTH_BITS_ARB as c_int); - out.push(depth as c_int); - } - - if let Some(stencil) = reqs.stencil_bits { - out.push(gl::wgl_extra::STENCIL_BITS_ARB as c_int); - out.push(stencil as c_int); - } - - // Prefer double buffering if unspecified (probably shouldn't once you can choose) - let double_buffer = reqs.double_buffer.unwrap_or(true); - out.push(gl::wgl_extra::DOUBLE_BUFFER_ARB as c_int); - out.push(if double_buffer { 1 } else { 0 }); - - if let Some(multisampling) = reqs.multisampling { - if extensions.split(' ').find(|&i| i == "WGL_ARB_multisample").is_some() { - out.push(gl::wgl_extra::SAMPLE_BUFFERS_ARB as c_int); - out.push(if multisampling == 0 { 0 } else { 1 }); - out.push(gl::wgl_extra::SAMPLES_ARB as c_int); - out.push(multisampling as c_int); - } else { - return Err(()); - } - } - - out.push(gl::wgl_extra::STEREO_ARB as c_int); - out.push(if reqs.stereoscopy { 1 } else { 0 }); - - if reqs.srgb { - if extensions.split(' ').find(|&i| i == "WGL_ARB_framebuffer_sRGB").is_some() { - out.push(gl::wgl_extra::FRAMEBUFFER_SRGB_CAPABLE_ARB as c_int); - out.push(1); - } else if extensions.split(' ').find(|&i| i == "WGL_EXT_framebuffer_sRGB").is_some() { - out.push(gl::wgl_extra::FRAMEBUFFER_SRGB_CAPABLE_EXT as c_int); - out.push(1); - } else { - return Err(()); - } - } - - match reqs.release_behavior { - ReleaseBehavior::Flush => (), - ReleaseBehavior::None => { - if extensions.split(' ').find(|&i| i == "WGL_ARB_context_flush_control").is_some() { - out.push(gl::wgl_extra::CONTEXT_RELEASE_BEHAVIOR_ARB as c_int); - out.push(gl::wgl_extra::CONTEXT_RELEASE_BEHAVIOR_NONE_ARB as c_int); - } - }, - } - - out.push(0); - out - }; - - let mut format_id = mem::uninitialized(); - let mut num_formats = mem::uninitialized(); - if extra.ChoosePixelFormatARB(hdc as *const _, descriptor.as_ptr(), ptr::null(), 1, - &mut format_id, &mut num_formats) == 0 - { - return Err(()); - } - - if num_formats == 0 { - return Err(()); - } - - let get_info = |attrib: u32| { - let mut value = mem::uninitialized(); - extra.GetPixelFormatAttribivARB(hdc as *const _, format_id as c_int, - 0, 1, [attrib as c_int].as_ptr(), - &mut value); - value as u32 - }; - - let pf_desc = PixelFormat { - hardware_accelerated: get_info(gl::wgl_extra::ACCELERATION_ARB) != - gl::wgl_extra::NO_ACCELERATION_ARB, - color_bits: get_info(gl::wgl_extra::RED_BITS_ARB) as u8 + - get_info(gl::wgl_extra::GREEN_BITS_ARB) as u8 + - get_info(gl::wgl_extra::BLUE_BITS_ARB) as u8, - alpha_bits: get_info(gl::wgl_extra::ALPHA_BITS_ARB) as u8, - depth_bits: get_info(gl::wgl_extra::DEPTH_BITS_ARB) as u8, - stencil_bits: get_info(gl::wgl_extra::STENCIL_BITS_ARB) as u8, - stereoscopy: get_info(gl::wgl_extra::STEREO_ARB) != 0, - double_buffer: get_info(gl::wgl_extra::DOUBLE_BUFFER_ARB) != 0, - multisampling: { - if extensions.split(' ').find(|&i| i == "WGL_ARB_multisample").is_some() { - match get_info(gl::wgl_extra::SAMPLES_ARB) { - 0 => None, - a => Some(a as u16), - } - } else { - None - } - }, - srgb: if extensions.split(' ').find(|&i| i == "WGL_ARB_framebuffer_sRGB").is_some() { - get_info(gl::wgl_extra::FRAMEBUFFER_SRGB_CAPABLE_ARB) != 0 - } else if extensions.split(' ').find(|&i| i == "WGL_EXT_framebuffer_sRGB").is_some() { - get_info(gl::wgl_extra::FRAMEBUFFER_SRGB_CAPABLE_EXT) != 0 - } else { - false - }, - }; - - Ok((format_id, pf_desc)) -} - -/// Calls `SetPixelFormat` on a window. -unsafe fn set_pixel_format(hdc: winapi::HDC, id: c_int) -> Result<(), CreationError> { - let mut output: winapi::PIXELFORMATDESCRIPTOR = mem::zeroed(); - - if gdi32::DescribePixelFormat(hdc, id, mem::size_of::() - as winapi::UINT, &mut output) == 0 - { - return Err(CreationError::OsError(format!("DescribePixelFormat function failed: {}", - format!("{}", io::Error::last_os_error())))); - } - - if gdi32::SetPixelFormat(hdc, id, &output) == 0 { - return Err(CreationError::OsError(format!("SetPixelFormat function failed: {}", - format!("{}", io::Error::last_os_error())))); - } - - Ok(()) -} - -/// Loads the `opengl32.dll` library. -unsafe fn load_opengl32_dll() -> Result { - let name = OsStr::new("opengl32.dll").encode_wide().chain(Some(0).into_iter()) - .collect::>(); - - let lib = kernel32::LoadLibraryW(name.as_ptr()); - - if lib.is_null() { - return Err(CreationError::OsError(format!("LoadLibrary function failed: {}", - format!("{}", io::Error::last_os_error())))); - } - - Ok(lib) -} - -/// Loads the WGL functions that are not guaranteed to be supported. -/// -/// The `window` must be passed because the driver can vary depending on the window's -/// characteristics. -unsafe fn load_extra_functions(window: winapi::HWND) -> Result { - let (ex_style, style) = (winapi::WS_EX_APPWINDOW, winapi::WS_POPUP | - winapi::WS_CLIPSIBLINGS | winapi::WS_CLIPCHILDREN); - - // creating a dummy invisible window - let dummy_window = { - // getting the rect of the real window - let rect = { - let mut placement: winapi::WINDOWPLACEMENT = mem::zeroed(); - placement.length = mem::size_of::() as winapi::UINT; - if user32::GetWindowPlacement(window, &mut placement) == 0 { - panic!(); - } - placement.rcNormalPosition - }; - - // getting the class name of the real window - let mut class_name = [0u16; 128]; - if user32::GetClassNameW(window, class_name.as_mut_ptr(), 128) == 0 { - return Err(CreationError::OsError(format!("GetClassNameW function failed: {}", - format!("{}", io::Error::last_os_error())))); - } - - // this dummy window should match the real one enough to get the same OpenGL driver - let win = user32::CreateWindowExW(ex_style, class_name.as_ptr(), - b"dummy window\0".as_ptr() as *const _, style, - winapi::CW_USEDEFAULT, winapi::CW_USEDEFAULT, - rect.right - rect.left, - rect.bottom - rect.top, - ptr::null_mut(), ptr::null_mut(), - kernel32::GetModuleHandleW(ptr::null()), - ptr::null_mut()); - - if win.is_null() { - return Err(CreationError::OsError(format!("CreateWindowEx function failed: {}", - format!("{}", io::Error::last_os_error())))); - } - - let hdc = user32::GetDC(win); - if hdc.is_null() { - let err = Err(CreationError::OsError(format!("GetDC function failed: {}", - format!("{}", io::Error::last_os_error())))); - return err; - } - - WindowWrapper(win, hdc) - }; - - // getting the pixel format that we will use and setting it - { - let id = try!(choose_dummy_pixel_format(dummy_window.1)); - try!(set_pixel_format(dummy_window.1, id)); - } - - // creating the dummy OpenGL context and making it current - let dummy_context = try!(create_context(None, dummy_window.0, dummy_window.1)); - let _current_context = try!(CurrentContextGuard::make_current(dummy_window.1, - dummy_context.0)); - - // loading the extra WGL functions - Ok(gl::wgl_extra::Wgl::load_with(|addr| { - let addr = CString::new(addr.as_bytes()).unwrap(); - let addr = addr.as_ptr(); - gl::wgl::GetProcAddress(addr) as *const c_void - })) -} - -/// This function chooses a pixel format that is likely to be provided by -/// the main video driver of the system. -fn choose_dummy_pixel_format(hdc: winapi::HDC) -> Result { - // building the descriptor to pass to ChoosePixelFormat - let descriptor = winapi::PIXELFORMATDESCRIPTOR { - nSize: mem::size_of::() as u16, - nVersion: 1, - dwFlags: winapi::PFD_DRAW_TO_WINDOW | winapi::PFD_SUPPORT_OPENGL | winapi::PFD_DOUBLEBUFFER, - iPixelType: winapi::PFD_TYPE_RGBA, - cColorBits: 24, - cRedBits: 0, - cRedShift: 0, - cGreenBits: 0, - cGreenShift: 0, - cBlueBits: 0, - cBlueShift: 0, - cAlphaBits: 8, - cAlphaShift: 0, - cAccumBits: 0, - cAccumRedBits: 0, - cAccumGreenBits: 0, - cAccumBlueBits: 0, - cAccumAlphaBits: 0, - cDepthBits: 24, - cStencilBits: 8, - cAuxBuffers: 0, - iLayerType: winapi::PFD_MAIN_PLANE, - bReserved: 0, - dwLayerMask: 0, - dwVisibleMask: 0, - dwDamageMask: 0, - }; - - // now querying - let pf_id = unsafe { gdi32::ChoosePixelFormat(hdc, &descriptor) }; - if pf_id == 0 { - return Err(CreationError::OsError("No available pixel format".to_owned())); - } - - Ok(pf_id) -} diff --git a/src/api/win32/init.rs b/src/api/win32/init.rs index 394923d3..79482a3f 100644 --- a/src/api/win32/init.rs +++ b/src/api/win32/init.rs @@ -9,15 +9,10 @@ use super::WindowState; use super::Window; use super::MonitorId; use super::WindowWrapper; -use super::Context; -use Api; use CreationError; use CreationError::OsError; use CursorState; -use GlAttributes; -use GlRequest; -use PixelFormatRequirements; use WindowAttributes; use std::ffi::{OsStr}; @@ -29,28 +24,8 @@ use kernel32; use dwmapi; use user32; -use api::wgl::Context as WglContext; -use api::egl; -use api::egl::Context as EglContext; -use api::egl::ffi::egl::Egl; - -#[derive(Clone)] -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(window: &WindowAttributes, pf_reqs: &PixelFormatRequirements, - opengl: &GlAttributes, egl: Option<&Egl>) - -> Result -{ - let egl = egl.map(|e| e.clone()); +pub fn new_window(window: &WindowAttributes) -> Result { let window = window.clone(); - let pf_reqs = pf_reqs.clone(); - let opengl = opengl.clone(); // initializing variables to be sent to the task @@ -64,7 +39,7 @@ pub fn new_window(window: &WindowAttributes, pf_reqs: &PixelFormatRequirements, thread::spawn(move || { unsafe { // creating and sending the `Window` - match init(title, &window, &pf_reqs, &opengl, egl) { + match init(title, &window) { Ok(w) => tx.send(Ok(w)).ok(), Err(e) => { tx.send(Err(e)).ok(); @@ -90,17 +65,7 @@ pub fn new_window(window: &WindowAttributes, pf_reqs: &PixelFormatRequirements, rx.recv().unwrap() } -unsafe fn init(title: Vec, window: &WindowAttributes, pf_reqs: &PixelFormatRequirements, - opengl: &GlAttributes, egl: Option) - -> Result -{ - let opengl = opengl.clone().map_sharing(|sharelists| { - match sharelists { - RawContext::Wgl(c) => c, - _ => unimplemented!() - } - }); - +unsafe fn init(title: Vec, window: &WindowAttributes) -> Result { // registering the window class let class_name = register_window_class(); @@ -172,32 +137,6 @@ unsafe fn init(title: Vec, window: &WindowAttributes, pf_reqs: &PixelFormat WindowWrapper(handle, hdc) }; - // creating the OpenGL context - let context = match opengl.version { - GlRequest::Specific(Api::OpenGlEs, (_major, _minor)) => { - if let Some(egl) = egl { - if let Ok(c) = EglContext::new(egl, &pf_reqs, &opengl.clone().map_sharing(|_| unimplemented!()), - egl::NativeDisplay::Other(Some(ptr::null()))) - .and_then(|p| p.finish(real_window.0)) - { - Context::Egl(c) - - } else { - try!(WglContext::new(&pf_reqs, &opengl, real_window.0) - .map(Context::Wgl)) - } - - } else { - // falling back to WGL, which is always available - try!(WglContext::new(&pf_reqs, &opengl, real_window.0) - .map(Context::Wgl)) - } - }, - _ => { - try!(WglContext::new(&pf_reqs, &opengl, real_window.0).map(Context::Wgl)) - } - }; - // making the window transparent if window.transparent { let bb = winapi::DWM_BLURBEHIND { @@ -240,7 +179,6 @@ unsafe fn init(title: Vec, window: &WindowAttributes, pf_reqs: &PixelFormat // building the struct Ok(Window { window: real_window, - context: context, events_receiver: events_receiver, window_state: window_state, }) diff --git a/src/api/win32/mod.rs b/src/api/win32/mod.rs index cb7e1707..be9b776e 100644 --- a/src/api/win32/mod.rs +++ b/src/api/win32/mod.rs @@ -10,15 +10,9 @@ use std::sync::{ }; use std::sync::mpsc::Receiver; use libc; -use ContextError; use {CreationError, Event, MouseCursor}; use CursorState; -use GlAttributes; -use GlContext; -use Api; -use PixelFormat; -use PixelFormatRequirements; use WindowAttributes; pub use self::monitor::{MonitorId, get_available_monitors, get_primary_monitor}; @@ -27,12 +21,6 @@ use winapi; use user32; use kernel32; -use api::wgl::Context as WglContext; -use api::egl::Context as EglContext; -use api::egl::ffi::egl::Egl; - -use self::init::RawContext; - mod callback; mod event; mod init; @@ -58,9 +46,6 @@ pub struct Window { /// Main handle for the window. window: WindowWrapper, - /// OpenGL context. - context: Context, - /// Receiver for the events dispatched by the window callback. events_receiver: Receiver, @@ -71,11 +56,6 @@ 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)] @@ -109,18 +89,8 @@ impl WindowProxy { impl Window { /// See the docs in the crate root file. - pub fn new(window: &WindowAttributes, pf_reqs: &PixelFormatRequirements, - opengl: &GlAttributes<&Window>, egl: Option<&Egl>) - -> Result - { - let opengl = opengl.clone().map_sharing(|sharing| { - match sharing.context { - Context::Wgl(ref c) => RawContext::Wgl(c.get_hglrc()), - Context::Egl(_) => unimplemented!(), // FIXME: - } - }); - - init::new_window(window, pf_reqs, &opengl, egl) + pub fn new(window: &WindowAttributes) -> Result { + init::new_window(window) } /// See the docs in the crate root file. @@ -369,56 +339,6 @@ impl Window { } } -impl GlContext for Window { - #[inline] - unsafe fn make_current(&self) -> Result<(), ContextError> { - match self.context { - Context::Wgl(ref c) => c.make_current(), - Context::Egl(ref c) => c.make_current(), - } - } - - #[inline] - fn is_current(&self) -> bool { - match self.context { - Context::Wgl(ref c) => c.is_current(), - Context::Egl(ref c) => c.is_current(), - } - } - - #[inline] - fn get_proc_address(&self, addr: &str) -> *const () { - match self.context { - Context::Wgl(ref c) => c.get_proc_address(addr), - Context::Egl(ref c) => c.get_proc_address(addr), - } - } - - #[inline] - fn swap_buffers(&self) -> Result<(), ContextError> { - match self.context { - Context::Wgl(ref c) => c.swap_buffers(), - Context::Egl(ref c) => c.swap_buffers(), - } - } - - #[inline] - fn get_api(&self) -> Api { - match self.context { - Context::Wgl(ref c) => c.get_api(), - Context::Egl(ref c) => c.get_api(), - } - } - - #[inline] - fn get_pixel_format(&self) -> PixelFormat { - match self.context { - Context::Wgl(ref c) => c.get_pixel_format(), - Context::Egl(ref c) => c.get_pixel_format(), - } - } -} - pub struct PollEventsIterator<'a> { window: &'a Window, } diff --git a/src/headless.rs b/src/headless.rs deleted file mode 100644 index 8ea4141a..00000000 --- a/src/headless.rs +++ /dev/null @@ -1,156 +0,0 @@ -use Api; -use ContextError; -use CreationError; -use GlAttributes; -use GlRequest; -use GlContext; -use PixelFormat; -use PixelFormatRequirements; -use Robustness; - -use platform; - -/// Object that allows you to build headless contexts. -pub struct HeadlessRendererBuilder<'a> { - /// The dimensions to use. - pub dimensions: (u32, u32), - - /// The OpenGL attributes to build the context with. - pub opengl: GlAttributes<&'a platform::HeadlessContext>, - - // Should be made public once it's stabilized. - pf_reqs: PixelFormatRequirements, - - /// Platform-specific configuration. - platform_specific: platform::PlatformSpecificHeadlessBuilderAttributes, -} - -impl<'a> HeadlessRendererBuilder<'a> { - /// Initializes a new `HeadlessRendererBuilder` with default values. - #[inline] - pub fn new(width: u32, height: u32) -> HeadlessRendererBuilder<'a> { - HeadlessRendererBuilder { - dimensions: (width, height), - pf_reqs: Default::default(), - opengl: Default::default(), - platform_specific: Default::default(), - } - } - - /// Sets how the backend should choose the OpenGL API and version. - #[inline] - pub fn with_gl(mut self, request: GlRequest) -> HeadlessRendererBuilder<'a> { - self.opengl.version = request; - self - } - - /// Sets the *debug* flag for the OpenGL context. - /// - /// The default value for this flag is `cfg!(ndebug)`, which means that it's enabled - /// when you run `cargo build` and disabled when you run `cargo build --release`. - #[inline] - pub fn with_gl_debug_flag(mut self, flag: bool) -> HeadlessRendererBuilder<'a> { - self.opengl.debug = flag; - self - } - - /// Sets the robustness of the OpenGL context. See the docs of `Robustness`. - #[inline] - pub fn with_gl_robustness(mut self, robustness: Robustness) -> HeadlessRendererBuilder<'a> { - self.opengl.robustness = robustness; - self - } - - /// Builds the headless context. - /// - /// Error should be very rare and only occur in case of permission denied, incompatible system, - /// out of memory, etc. - #[inline] - pub fn build(self) -> Result { - platform::HeadlessContext::new(self.dimensions, &self.pf_reqs, &self.opengl, - &self.platform_specific) - .map(|w| HeadlessContext { context: w }) - } - - /// Builds the headless context. - /// - /// The context is build in a *strict* way. That means that if the backend couldn't give - /// you what you requested, an `Err` will be returned. - #[inline] - pub fn build_strict(self) -> Result { - self.build() - } -} - -/// Represents a headless OpenGL context. -pub struct HeadlessContext { - context: platform::HeadlessContext, -} - -impl HeadlessContext { - /// Creates a new OpenGL context - /// Sets the context as the current context. - #[inline] - pub unsafe fn make_current(&self) -> Result<(), ContextError> { - self.context.make_current() - } - - /// Returns true if this context is the current one in this thread. - #[inline] - pub fn is_current(&self) -> bool { - self.context.is_current() - } - - /// Returns the address of an OpenGL function. - /// - /// Contrary to `wglGetProcAddress`, all available OpenGL functions return an address. - #[inline] - pub fn get_proc_address(&self, addr: &str) -> *const () { - self.context.get_proc_address(addr) - } - - /// Returns the API that is currently provided by this window. - /// - /// See `Window::get_api` for more infos. - #[inline] - pub fn get_api(&self) -> Api { - self.context.get_api() - } - - #[inline] - pub fn set_window_resize_callback(&mut self, _: Option) { - } -} - -impl GlContext for HeadlessContext { - #[inline] - unsafe fn make_current(&self) -> Result<(), ContextError> { - self.context.make_current() - } - - #[inline] - fn is_current(&self) -> bool { - self.context.is_current() - } - - #[inline] - fn get_proc_address(&self, addr: &str) -> *const () { - self.context.get_proc_address(addr) - } - - #[inline] - fn swap_buffers(&self) -> Result<(), ContextError> { - self.context.swap_buffers() - } - - #[inline] - fn get_api(&self) -> Api { - self.context.get_api() - } - - #[inline] - fn get_pixel_format(&self) -> PixelFormat { - self.context.get_pixel_format() - } -} - diff --git a/src/lib.rs b/src/lib.rs index a27aa72d..e7ce2779 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -61,7 +61,6 @@ extern crate x11_dl; extern crate wayland_client; pub use events::*; -pub use headless::{HeadlessRendererBuilder, HeadlessContext}; pub use window::{WindowBuilder, WindowProxy, PollEventsIterator, WaitEventsIterator}; pub use window::{AvailableMonitorsIter, MonitorId, get_available_monitors, get_primary_monitor}; pub use native_monitor::NativeMonitorId; @@ -73,7 +72,6 @@ use std::cmp::Ordering; mod api; mod platform; mod events; -mod headless; mod window; pub mod os; @@ -105,44 +103,12 @@ pub struct Window { window: platform::Window, } -/// Trait that describes objects that have access to an OpenGL context. -pub trait GlContext { - /// Sets the context as the current context. - unsafe fn make_current(&self) -> Result<(), ContextError>; - - /// Returns true if this context is the current one in this thread. - fn is_current(&self) -> bool; - - /// Returns the address of an OpenGL function. - fn get_proc_address(&self, addr: &str) -> *const (); - - /// Swaps the buffers in case of double or triple buffering. - /// - /// You should call this function every time you have finished rendering, or the image - /// may not be displayed on the screen. - /// - /// **Warning**: if you enabled vsync, this function will block until the next time the screen - /// is refreshed. However drivers can choose to override your vsync settings, which means that - /// you can't know in advance whether `swap_buffers` will block or not. - fn swap_buffers(&self) -> Result<(), ContextError>; - - /// Returns the OpenGL API being used. - fn get_api(&self) -> Api; - - /// Returns the pixel format of the main framebuffer of the context. - fn get_pixel_format(&self) -> PixelFormat; -} - /// Error that can happen while creating a window or a headless renderer. #[derive(Debug)] pub enum CreationError { OsError(String), /// TODO: remove this error NotSupported, - NoBackendAvailable(Box), - RobustnessNotSupported, - OpenGlVersionNotSupported, - NoAvailablePixelFormat, } impl CreationError { @@ -150,13 +116,6 @@ impl CreationError { match *self { CreationError::OsError(ref text) => &text, CreationError::NotSupported => "Some of the requested attributes are not supported", - CreationError::NoBackendAvailable(_) => "No backend is available", - CreationError::RobustnessNotSupported => "You requested robustness, but it is \ - not supported.", - CreationError::OpenGlVersionNotSupported => "The requested OpenGL version is not \ - supported.", - CreationError::NoAvailablePixelFormat => "Couldn't find any pixel format that matches \ - the criterias.", } } } @@ -171,146 +130,6 @@ impl std::error::Error for CreationError { fn description(&self) -> &str { self.to_string() } - - fn cause(&self) -> Option<&std::error::Error> { - match *self { - CreationError::NoBackendAvailable(ref err) => Some(&**err), - _ => None - } - } -} - -/// Error that can happen when manipulating an OpenGL context. -#[derive(Debug)] -pub enum ContextError { - IoError(io::Error), - ContextLost, -} - -impl ContextError { - fn to_string(&self) -> &str { - use std::error::Error; - match *self { - ContextError::IoError(ref err) => err.description(), - ContextError::ContextLost => "Context lost" - } - } -} - -impl std::fmt::Display for ContextError { - fn fmt(&self, formatter: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { - formatter.write_str(self.to_string()) - } -} - -impl std::error::Error for ContextError { - fn description(&self) -> &str { - self.to_string() - } -} - -/// All APIs related to OpenGL that you can possibly get while using glutin. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum Api { - /// The classical OpenGL. Available on Windows, Linux, OS/X. - OpenGl, - /// OpenGL embedded system. Available on Linux, Android. - OpenGlEs, - /// OpenGL for the web. Very similar to OpenGL ES. - WebGl, -} - -/// Describes the requested OpenGL context profiles. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum GlProfile { - /// Include all the immediate more functions and definitions. - Compatibility, - /// Include all the future-compatible functions and definitions. - Core, -} - -/// Describes the OpenGL API and version that are being requested when a context is created. -#[derive(Debug, Copy, Clone)] -pub enum GlRequest { - /// Request the latest version of the "best" API of this platform. - /// - /// On desktop, will try OpenGL. - Latest, - - /// Request a specific version of a specific API. - /// - /// Example: `GlRequest::Specific(Api::OpenGl, (3, 3))`. - Specific(Api, (u8, u8)), - - /// If OpenGL is available, create an OpenGL context with the specified `opengl_version`. - /// Else if OpenGL ES or WebGL is available, create a context with the - /// specified `opengles_version`. - GlThenGles { - /// The version to use for OpenGL. - opengl_version: (u8, u8), - /// The version to use for OpenGL ES. - opengles_version: (u8, u8), - }, -} - -impl GlRequest { - /// Extract the desktop GL version, if any. - pub fn to_gl_version(&self) -> Option<(u8, u8)> { - match self { - &GlRequest::Specific(Api::OpenGl, version) => Some(version), - &GlRequest::GlThenGles { opengl_version: version, .. } => Some(version), - _ => None, - } - } -} - -/// The minimum core profile GL context. Useful for getting the minimum -/// required GL version while still running on OSX, which often forbids -/// the compatibility profile features. -pub static GL_CORE: GlRequest = GlRequest::Specific(Api::OpenGl, (3, 2)); - -/// Specifies the tolerance of the OpenGL context to faults. If you accept raw OpenGL commands -/// and/or raw shader code from an untrusted source, you should definitely care about this. -#[derive(Debug, Copy, Clone, PartialEq, Eq)] -pub enum Robustness { - /// Not everything is checked. Your application can crash if you do something wrong with your - /// shaders. - NotRobust, - - /// The driver doesn't check anything. This option is very dangerous. Please know what you're - /// doing before using it. See the `GL_KHR_no_error` extension. - /// - /// Since this option is purely an optimisation, no error will be returned if the backend - /// doesn't support it. Instead it will automatically fall back to `NotRobust`. - NoError, - - /// Everything is checked to avoid any crash. The driver will attempt to avoid any problem, - /// but if a problem occurs the behavior is implementation-defined. You are just guaranteed not - /// to get a crash. - RobustNoResetNotification, - - /// Same as `RobustNoResetNotification` but the context creation doesn't fail if it's not - /// supported. - TryRobustNoResetNotification, - - /// Everything is checked to avoid any crash. If a problem occurs, the context will enter a - /// "context lost" state. It must then be recreated. For the moment, glutin doesn't provide a - /// way to recreate a context with the same window :-/ - RobustLoseContextOnReset, - - /// Same as `RobustLoseContextOnReset` but the context creation doesn't fail if it's not - /// supported. - TryRobustLoseContextOnReset, -} - -/// The behavior of the driver when you change the current context. -#[derive(Debug, Copy, Clone, PartialEq, Eq)] -pub enum ReleaseBehavior { - /// Doesn't do anything. Most notably doesn't flush. - None, - - /// Flushes the context that was previously current as if `glFlush` was called. - Flush, } #[derive(Debug, Copy, Clone)] @@ -386,90 +205,6 @@ pub enum CursorState { Grab, } -/// Describes a possible format. Unused. -#[allow(missing_docs)] -#[derive(Debug, Clone)] -pub struct PixelFormat { - pub hardware_accelerated: bool, - pub color_bits: u8, - pub alpha_bits: u8, - pub depth_bits: u8, - pub stencil_bits: u8, - pub stereoscopy: bool, - pub double_buffer: bool, - pub multisampling: Option, - pub srgb: bool, -} - -/// Describes how the backend should choose a pixel format. -// TODO: swap method? (swap, copy) -#[derive(Clone, Debug)] -pub struct PixelFormatRequirements { - /// If true, only hardware-accelerated formats will be conisdered. If false, only software - /// renderers. `None` means "don't care". Default is `Some(true)`. - pub hardware_accelerated: Option, - - /// Minimum number of bits for the color buffer, excluding alpha. `None` means "don't care". - /// The default is `Some(24)`. - pub color_bits: Option, - - /// If true, the color buffer must be in a floating point format. Default is `false`. - /// - /// Using floating points allows you to write values outside of the `[0.0, 1.0]` range. - pub float_color_buffer: bool, - - /// Minimum number of bits for the alpha in the color buffer. `None` means "don't care". - /// The default is `Some(8)`. - pub alpha_bits: Option, - - /// Minimum number of bits for the depth buffer. `None` means "don't care". - /// The default value is `Some(24)`. - pub depth_bits: Option, - - /// Minimum number of bits for the depth buffer. `None` means "don't care". - /// The default value is `Some(8)`. - pub stencil_bits: Option, - - /// If true, only double-buffered formats will be considered. If false, only single-buffer - /// formats. `None` means "don't care". The default is `Some(true)`. - pub double_buffer: Option, - - /// Contains the minimum number of samples per pixel in the color, depth and stencil buffers. - /// `None` means "don't care". Default is `None`. - /// A value of `Some(0)` indicates that multisampling must not be enabled. - pub multisampling: Option, - - /// If true, only stereoscopic formats will be considered. If false, only non-stereoscopic - /// formats. The default is `false`. - pub stereoscopy: bool, - - /// If true, only sRGB-capable formats will be considered. If false, don't care. - /// The default is `false`. - pub srgb: bool, - - /// The behavior when changing the current context. Default is `Flush`. - pub release_behavior: ReleaseBehavior, -} - -impl Default for PixelFormatRequirements { - #[inline] - fn default() -> PixelFormatRequirements { - PixelFormatRequirements { - hardware_accelerated: Some(true), - color_bits: Some(24), - float_color_buffer: false, - alpha_bits: Some(8), - depth_bits: Some(24), - stencil_bits: Some(8), - double_buffer: None, - multisampling: None, - stereoscopy: false, - srgb: false, - release_behavior: ReleaseBehavior::Flush, - } - } -} - /// Attributes to use when creating a window. #[derive(Clone)] pub struct WindowAttributes { @@ -537,73 +272,6 @@ impl Default for WindowAttributes { } } -/// Attributes to use when creating an OpenGL context. -#[derive(Clone)] -pub struct GlAttributes { - /// An existing context to share the new the context with. - /// - /// The default is `None`. - pub sharing: Option, - - /// Version to try create. See `GlRequest` for more infos. - /// - /// The default is `Latest`. - pub version: GlRequest, - - /// OpenGL profile to use. - /// - /// The default is `None`. - pub profile: Option, - - /// Whether to enable the `debug` flag of the context. - /// - /// Debug contexts are usually slower but give better error reporting. - /// - /// The default is `true` in debug mode and `false` in release mode. - pub debug: bool, - - /// How the OpenGL context should detect errors. - /// - /// The default is `NotRobust` because this is what is typically expected when you create an - /// OpenGL context. However for safety you should consider `TryRobustLoseContextOnReset`. - pub robustness: Robustness, - - /// Whether to use vsync. If vsync is enabled, calling `swap_buffers` will block until the - /// screen refreshes. This is typically used to prevent screen tearing. - /// - /// The default is `false`. - pub vsync: bool, -} - -impl GlAttributes { - /// Turns the `sharing` parameter into another type by calling a closure. - #[inline] - pub fn map_sharing(self, f: F) -> GlAttributes where F: FnOnce(S) -> T { - GlAttributes { - sharing: self.sharing.map(f), - version: self.version, - profile: self.profile, - debug: self.debug, - robustness: self.robustness, - vsync: self.vsync, - } - } -} - -impl Default for GlAttributes { - #[inline] - fn default() -> GlAttributes { - GlAttributes { - sharing: None, - version: GlRequest::Latest, - profile: None, - debug: cfg!(debug_assertions), - robustness: Robustness::NotRobust, - vsync: false, - } - } -} - mod native_monitor { /// Native platform identifier for a monitor. Different platforms use fundamentally different types /// to represent a monitor ID. diff --git a/src/os/windows.rs b/src/os/windows.rs index 02a76e29..e37b4185 100644 --- a/src/os/windows.rs +++ b/src/os/windows.rs @@ -26,5 +26,5 @@ pub trait WindowBuilderExt { } -impl<'a> WindowBuilderExt for WindowBuilder<'a> { +impl WindowBuilderExt for WindowBuilder { } diff --git a/src/platform/windows/mod.rs b/src/platform/windows/mod.rs index 0c78322f..413a12f2 100644 --- a/src/platform/windows/mod.rs +++ b/src/platform/windows/mod.rs @@ -4,53 +4,13 @@ pub use api::win32; pub use api::win32::{MonitorId, get_available_monitors, get_primary_monitor}; pub use api::win32::{WindowProxy, PollEventsIterator, WaitEventsIterator}; -use Api; -use ContextError; use CreationError; -use PixelFormat; -use PixelFormatRequirements; -use GlAttributes; -use GlContext; use WindowAttributes; -use api::egl::ffi::egl::Egl; -use api::egl; -use api::egl::Context as EglContext; - use std::ffi::CString; use std::ops::{Deref, DerefMut}; use kernel32; -/// Stupid wrapper because `*const libc::c_void` doesn't implement `Sync`. -struct EglWrapper(Egl); -unsafe impl Sync for EglWrapper {} - -lazy_static! { - // An EGL implementation available on the system. - static ref EGL: Option = { - // the ATI drivers provide an EGL implementation in their DLLs - let dll_name = if cfg!(target_pointer_width = "64") { - b"atio6axx.dll\0" - } else { - b"atioglxx.dll\0" - }; - - let dll = unsafe { kernel32::LoadLibraryA(dll_name.as_ptr() as *const _) }; - - if !dll.is_null() { - let egl = Egl::load_with(|name| { - let name = CString::new(name).unwrap(); - unsafe { kernel32::GetProcAddress(dll, name.as_ptr()) as *const _ } - }); - - Some(EglWrapper(egl)) - - } else { - None - } - }; -} - #[derive(Default)] pub struct PlatformSpecificWindowBuilderAttributes; #[derive(Default)] @@ -62,12 +22,10 @@ pub struct Window(win32::Window); impl Window { /// See the docs in the crate root file. #[inline] - pub fn new(window: &WindowAttributes, pf_reqs: &PixelFormatRequirements, - opengl: &GlAttributes<&Window>, _: &PlatformSpecificWindowBuilderAttributes) + pub fn new(window: &WindowAttributes, _: &PlatformSpecificWindowBuilderAttributes) -> Result { - win32::Window::new(window, pf_reqs, &opengl.clone().map_sharing(|w| &w.0), - EGL.as_ref().map(|w| &w.0)).map(|w| Window(w)) + win32::Window::new(window).map(Window) } } @@ -86,87 +44,3 @@ impl DerefMut for Window { &mut self.0 } } - -/// -pub enum HeadlessContext { - /// A regular window, but invisible. - HiddenWindow(win32::Window), - /// An EGL pbuffer. - EglPbuffer(EglContext), -} - -impl HeadlessContext { - pub fn new(dimensions: (u32, u32), pf_reqs: &PixelFormatRequirements, - opengl: &GlAttributes<&HeadlessContext>, - _: &PlatformSpecificHeadlessBuilderAttributes) - -> Result - { - // if EGL is available, we try using EGL first - // if EGL returns an error, we try the hidden window method - if let &Some(ref egl) = &*EGL { - let context = EglContext::new(egl.0.clone(), pf_reqs, &opengl.clone().map_sharing(|_| unimplemented!()), // TODO: - egl::NativeDisplay::Other(None)) - .and_then(|prototype| prototype.finish_pbuffer(dimensions)) - .map(|ctxt| HeadlessContext::EglPbuffer(ctxt)); - - if let Ok(context) = context { - return Ok(context); - } - } - - let window = try!(win32::Window::new(&WindowAttributes { visible: false, .. Default::default() }, - pf_reqs, &opengl.clone().map_sharing(|_| unimplemented!()), //TODO: - EGL.as_ref().map(|w| &w.0))); - Ok(HeadlessContext::HiddenWindow(window)) - } -} - -impl GlContext for HeadlessContext { - #[inline] - unsafe fn make_current(&self) -> Result<(), ContextError> { - match self { - &HeadlessContext::HiddenWindow(ref ctxt) => ctxt.make_current(), - &HeadlessContext::EglPbuffer(ref ctxt) => ctxt.make_current(), - } - } - - #[inline] - fn is_current(&self) -> bool { - match self { - &HeadlessContext::HiddenWindow(ref ctxt) => ctxt.is_current(), - &HeadlessContext::EglPbuffer(ref ctxt) => ctxt.is_current(), - } - } - - #[inline] - fn get_proc_address(&self, addr: &str) -> *const () { - match self { - &HeadlessContext::HiddenWindow(ref ctxt) => ctxt.get_proc_address(addr), - &HeadlessContext::EglPbuffer(ref ctxt) => ctxt.get_proc_address(addr), - } - } - - #[inline] - fn swap_buffers(&self) -> Result<(), ContextError> { - match self { - &HeadlessContext::HiddenWindow(ref ctxt) => ctxt.swap_buffers(), - &HeadlessContext::EglPbuffer(ref ctxt) => ctxt.swap_buffers(), - } - } - - #[inline] - fn get_api(&self) -> Api { - match self { - &HeadlessContext::HiddenWindow(ref ctxt) => ctxt.get_api(), - &HeadlessContext::EglPbuffer(ref ctxt) => ctxt.get_api(), - } - } - - #[inline] - fn get_pixel_format(&self) -> PixelFormat { - match self { - &HeadlessContext::HiddenWindow(ref ctxt) => ctxt.get_pixel_format(), - &HeadlessContext::EglPbuffer(ref ctxt) => ctxt.get_pixel_format(), - } - } -} diff --git a/src/window.rs b/src/window.rs index 6d2f0d3b..4142aa4b 100644 --- a/src/window.rs +++ b/src/window.rs @@ -1,19 +1,10 @@ use std::collections::vec_deque::IntoIter as VecDequeIter; use std::default::Default; -use Api; -use ContextError; use CreationError; use CursorState; use Event; -use GlAttributes; -use GlContext; -use GlProfile; -use GlRequest; use MouseCursor; -use PixelFormat; -use PixelFormatRequirements; -use Robustness; use Window; use WindowAttributes; use native_monitor::NativeMonitorId; @@ -22,28 +13,20 @@ use libc; use platform; /// Object that allows you to build windows. -pub struct WindowBuilder<'a> { +pub struct WindowBuilder { /// The attributes to use to create the window. pub window: WindowAttributes, - /// The attributes to use to create the context. - pub opengl: GlAttributes<&'a platform::Window>, - - // Should be made public once it's stabilized. - pf_reqs: PixelFormatRequirements, - /// Platform-specific configuration. platform_specific: platform::PlatformSpecificWindowBuilderAttributes, } -impl<'a> WindowBuilder<'a> { +impl WindowBuilder { /// Initializes a new `WindowBuilder` with default values. #[inline] - pub fn new() -> WindowBuilder<'a> { + pub fn new() -> WindowBuilder { WindowBuilder { - pf_reqs: Default::default(), window: Default::default(), - opengl: Default::default(), platform_specific: Default::default(), } } @@ -52,7 +35,7 @@ impl<'a> WindowBuilder<'a> { /// /// Width and height are in pixels. #[inline] - pub fn with_dimensions(mut self, width: u32, height: u32) -> WindowBuilder<'a> { + pub fn with_dimensions(mut self, width: u32, height: u32) -> WindowBuilder { self.window.dimensions = Some((width, height)); self } @@ -61,7 +44,7 @@ impl<'a> WindowBuilder<'a> { /// /// Width and height are in pixels. #[inline] - pub fn with_min_dimensions(mut self, width: u32, height: u32) -> WindowBuilder<'a> { + pub fn with_min_dimensions(mut self, width: u32, height: u32) -> WindowBuilder { self.window.min_dimensions = Some((width, height)); self } @@ -70,14 +53,14 @@ impl<'a> WindowBuilder<'a> { /// /// Width and height are in pixels. #[inline] - pub fn with_max_dimensions(mut self, width: u32, height: u32) -> WindowBuilder<'a> { + pub fn with_max_dimensions(mut self, width: u32, height: u32) -> WindowBuilder { self.window.max_dimensions = Some((width, height)); self } /// Requests a specific title for the window. #[inline] - pub fn with_title(mut self, title: String) -> WindowBuilder<'a> { + pub fn with_title(mut self, title: String) -> WindowBuilder { self.window.title = title; self } @@ -86,131 +69,36 @@ impl<'a> WindowBuilder<'a> { /// /// If you don't specify dimensions for the window, it will match the monitor's. #[inline] - pub fn with_fullscreen(mut self, monitor: MonitorId) -> WindowBuilder<'a> { + pub fn with_fullscreen(mut self, monitor: MonitorId) -> WindowBuilder { let MonitorId(monitor) = monitor; self.window.monitor = Some(monitor); self } - /// The created window will share all its OpenGL objects with the window in the parameter. - /// - /// There are some exceptions, like FBOs or VAOs. See the OpenGL documentation. - #[inline] - pub fn with_shared_lists(mut self, other: &'a Window) -> WindowBuilder<'a> { - self.opengl.sharing = Some(&other.window); - self - } - - /// Sets how the backend should choose the OpenGL API and version. - #[inline] - pub fn with_gl(mut self, request: GlRequest) -> WindowBuilder<'a> { - self.opengl.version = request; - self - } - - /// Sets the desired OpenGL context profile. - #[inline] - pub fn with_gl_profile(mut self, profile: GlProfile) -> WindowBuilder<'a> { - self.opengl.profile = Some(profile); - self - } - - /// Sets the *debug* flag for the OpenGL context. - /// - /// The default value for this flag is `cfg!(debug_assertions)`, which means that it's enabled - /// when you run `cargo build` and disabled when you run `cargo build --release`. - #[inline] - pub fn with_gl_debug_flag(mut self, flag: bool) -> WindowBuilder<'a> { - self.opengl.debug = flag; - self - } - - /// Sets the robustness of the OpenGL context. See the docs of `Robustness`. - #[inline] - pub fn with_gl_robustness(mut self, robustness: Robustness) -> WindowBuilder<'a> { - self.opengl.robustness = robustness; - self - } - - /// Requests that the window has vsync enabled. - #[inline] - pub fn with_vsync(mut self) -> WindowBuilder<'a> { - self.opengl.vsync = true; - self - } - /// Sets whether the window will be initially hidden or visible. #[inline] - pub fn with_visibility(mut self, visible: bool) -> WindowBuilder<'a> { + pub fn with_visibility(mut self, visible: bool) -> WindowBuilder { self.window.visible = visible; self } - /// Sets the multisampling level to request. - /// - /// # Panic - /// - /// Will panic if `samples` is not a power of two. - #[inline] - pub fn with_multisampling(mut self, samples: u16) -> WindowBuilder<'a> { - assert!(samples.is_power_of_two()); - self.pf_reqs.multisampling = Some(samples); - self - } - - /// Sets the number of bits in the depth buffer. - #[inline] - pub fn with_depth_buffer(mut self, bits: u8) -> WindowBuilder<'a> { - self.pf_reqs.depth_bits = Some(bits); - self - } - - /// Sets the number of bits in the stencil buffer. - #[inline] - pub fn with_stencil_buffer(mut self, bits: u8) -> WindowBuilder<'a> { - self.pf_reqs.stencil_bits = Some(bits); - self - } - - /// Sets the number of bits in the color buffer. - #[inline] - pub fn with_pixel_format(mut self, color_bits: u8, alpha_bits: u8) -> WindowBuilder<'a> { - self.pf_reqs.color_bits = Some(color_bits); - self.pf_reqs.alpha_bits = Some(alpha_bits); - self - } - - /// Request the backend to be stereoscopic. - #[inline] - pub fn with_stereoscopy(mut self) -> WindowBuilder<'a> { - self.pf_reqs.stereoscopy = true; - self - } - - /// Sets whether sRGB should be enabled on the window. `None` means "I don't care". - #[inline] - pub fn with_srgb(mut self, srgb_enabled: Option) -> WindowBuilder<'a> { - self.pf_reqs.srgb = srgb_enabled.unwrap_or(false); - self - } - /// Sets whether the background of the window should be transparent. #[inline] - pub fn with_transparency(mut self, transparent: bool) -> WindowBuilder<'a> { + pub fn with_transparency(mut self, transparent: bool) -> WindowBuilder { self.window.transparent = transparent; self } /// Sets whether the window should have a border, a title bar, etc. #[inline] - pub fn with_decorations(mut self, decorations: bool) -> WindowBuilder<'a> { + pub fn with_decorations(mut self, decorations: bool) -> WindowBuilder { self.window.decorations = decorations; self } /// Enables multitouch #[inline] - pub fn with_multitouch(mut self) -> WindowBuilder<'a> { + pub fn with_multitouch(mut self) -> WindowBuilder { self.window.multitouch = true; self } @@ -231,8 +119,7 @@ impl<'a> WindowBuilder<'a> { } // building - platform::Window::new(&self.window, &self.pf_reqs, &self.opengl, &self.platform_specific) - .map(|w| Window { window: w }) + platform::Window::new(&self.window, &self.platform_specific).map(|w| Window { window: w }) } /// Builds the window. @@ -401,39 +288,6 @@ impl Window { WaitEventsIterator(self.window.wait_events()) } - /// Sets the context as the current context. - #[inline] - pub unsafe fn make_current(&self) -> Result<(), ContextError> { - self.window.make_current() - } - - /// Returns true if this context is the current one in this thread. - #[inline] - pub fn is_current(&self) -> bool { - self.window.is_current() - } - - /// Returns the address of an OpenGL function. - /// - /// Contrary to `wglGetProcAddress`, all available OpenGL functions return an address. - #[inline] - pub fn get_proc_address(&self, addr: &str) -> *const () { - self.window.get_proc_address(addr) - } - - /// Swaps the buffers in case of double or triple buffering. - /// - /// You should call this function every time you have finished rendering, or the image - /// may not be displayed on the screen. - /// - /// **Warning**: if you enabled vsync, this function will block until the next time the screen - /// is refreshed. However drivers can choose to override your vsync settings, which means that - /// you can't know in advance whether `swap_buffers` will block or not. - #[inline] - pub fn swap_buffers(&self) -> Result<(), ContextError> { - self.window.swap_buffers() - } - /// DEPRECATED. Gets the native platform specific display for this window. /// This is typically only required when integrating with /// other libraries that need this information. @@ -450,22 +304,6 @@ impl Window { self.window.platform_window() } - /// Returns the API that is currently provided by this window. - /// - /// - On Windows and OS/X, this always returns `OpenGl`. - /// - On Android, this always returns `OpenGlEs`. - /// - On Linux, it must be checked at runtime. - #[inline] - pub fn get_api(&self) -> Api { - self.window.get_api() - } - - /// Returns the pixel format of this window. - #[inline] - pub fn get_pixel_format(&self) -> PixelFormat { - self.window.get_pixel_format() - } - /// Create a window proxy for this window, that can be freely /// passed to different threads. #[inline] @@ -512,38 +350,6 @@ impl Window { } } -impl GlContext for Window { - #[inline] - unsafe fn make_current(&self) -> Result<(), ContextError> { - self.make_current() - } - - #[inline] - fn is_current(&self) -> bool { - self.is_current() - } - - #[inline] - fn get_proc_address(&self, addr: &str) -> *const () { - self.get_proc_address(addr) - } - - #[inline] - fn swap_buffers(&self) -> Result<(), ContextError> { - self.swap_buffers() - } - - #[inline] - fn get_api(&self) -> Api { - self.get_api() - } - - #[inline] - fn get_pixel_format(&self) -> PixelFormat { - self.get_pixel_format() - } -} - /// Represents a thread safe subset of operations that can be called /// on a window. This structure can be safely cloned and sent between /// threads. diff --git a/tests/headless.rs b/tests/headless.rs deleted file mode 100644 index c22be40e..00000000 --- a/tests/headless.rs +++ /dev/null @@ -1,61 +0,0 @@ -extern crate glutin; -extern crate libc; -use glutin::*; -use std::ptr; - -mod gl { - pub use self::Gles2 as Gl; - include!(concat!(env!("OUT_DIR"), "/test_gl_bindings.rs")); -} -use gl::types::*; - - -#[cfg(target_os = "macos")] -#[test] -fn test_headless() { - let width: i32 = 256; - let height: i32 = 256; - let window = glutin::HeadlessRendererBuilder::new(width as u32, height as u32).build().unwrap(); - - unsafe { window.make_current() }; - - let gl = gl::Gl::load_with(|symbol| window.get_proc_address(symbol) as *const _); - - unsafe { - let mut framebuffer = 0; - let mut texture = 0; - gl.GenFramebuffers(1, &mut framebuffer); - gl.BindFramebuffer(gl::FRAMEBUFFER, framebuffer); - gl.GenTextures(1, &mut texture); - gl.BindTexture(gl::TEXTURE_2D, texture); - gl.TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, gl::LINEAR as i32); - gl.TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, gl::LINEAR as i32); - gl.TexImage2D(gl::TEXTURE_2D, 0, gl::RGBA as i32, width, height, - 0, gl::RGBA, gl::UNSIGNED_BYTE, ptr::null()); - gl.FramebufferTexture2D(gl::FRAMEBUFFER, gl::COLOR_ATTACHMENT0, gl::TEXTURE_2D, texture, 0); - let status = gl.CheckFramebufferStatus(gl::FRAMEBUFFER); - if status != gl::FRAMEBUFFER_COMPLETE { - panic!("Error while creating the framebuffer"); - } - - gl.ClearColor(0.0, 1.0, 0.0, 1.0); - gl.Clear(gl::COLOR_BUFFER_BIT); - gl.Enable(gl::SCISSOR_TEST); - gl.Scissor(1, 0, 1, 1); - gl.ClearColor(1.0, 0.0, 0.0, 1.0); - gl.Clear(gl::COLOR_BUFFER_BIT); - - let mut values: Vec = vec![0;(width*height*4) as usize]; - gl.ReadPixels(0, 0, width, height, gl::RGBA, gl::UNSIGNED_BYTE, values.as_mut_ptr() as *mut GLvoid); - - assert_eq!(values[0], 0); - assert_eq!(values[1], 255); - assert_eq!(values[2], 0); - assert_eq!(values[3], 255); - - assert_eq!(values[4], 255); - assert_eq!(values[5], 0); - assert_eq!(values[6], 0); - assert_eq!(values[7], 255); - } -}