Created
April 6, 2019 23:35
-
-
Save goddessfreya/20398fb571ca5f73e08c00338ffb669a to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/CHANGELOG.md b/CHANGELOG.md | |
index 0b4978b..3f0243c 100644 | |
--- a/CHANGELOG.md | |
+++ b/CHANGELOG.md | |
@@ -5,10 +5,10 @@ | |
- Added headless example. | |
- Removed internal code relating to libcaca. | |
- Implemented `Debug` on all public facing types. | |
- - Dropping contexts on platforms using egl and/or glx no longer resets the | |
+ - Dropping contexts on platforms using egl and/or glx no longer resets the | |
current context, if the context dropped wasn't the current context. | |
- Added context sharing support to MacOS. | |
- - **Breaking**: Split `ContextTrait` into `ContextTrait` and `PossiblyCurrentContextTrait`. | |
+ - **Breaking**: Removed `ContextTrait`. | |
- **Breaking**: Renamed `OsMesaContextExt` to `HeadlessContextExt`. Added functions | |
for using egl-surfaceless. | |
- **Breaking**: Changed `WindowedContext` and `RawContext` into typedefs of | |
@@ -16,10 +16,9 @@ | |
- **Breaking**: Removed `new_windowed` and `new_headless` from `WindowedContext` | |
and `Context`, respectively. | |
- **Breaking**: Added two new types, `NotCurrentContext` and `PossiblyCurrentContext`, | |
- which `RawContext`, `WindowedContext`, `ContextBuilder` and `Context` are now | |
+ which `RawContext`, `WindowedContext`, `ContextBuilder` and `Context` are now | |
generic over. | |
- - Added `make_not_current` function into `ContextTrait`. | |
- - Added `treat_as_not_current` function into `ContextTrait`. | |
+ - Added `{make,treat_as}_not_current` function to `{Raw,Windowed,}Context`. | |
- We now load `libGL.so` instead of `libGLX.so`. | |
- **Breaking**: Added `DisplayLost` variant to `ContextError`. | |
- Fixed bug where we drop the hidden window belonging to a headless context on | |
diff --git a/README.md b/README.md | |
index bf1380e..a1c1338 100644 | |
--- a/README.md | |
+++ b/README.md | |
@@ -43,7 +43,6 @@ gl = "*" | |
```rust | |
use glutin::dpi::*; | |
-use glutin::ContextTrait; | |
fn main() { | |
let mut el = glutin::EventsLoop::new(); | |
diff --git a/glutin/src/api/android/mod.rs b/glutin/src/api/android/mod.rs | |
index bf825f3..a8a9f43 100644 | |
--- a/glutin/src/api/android/mod.rs | |
+++ b/glutin/src/api/android/mod.rs | |
@@ -59,7 +59,7 @@ impl Context { | |
let gl_attr = gl_attr.clone().map_sharing(|c| &c.0.egl_context); | |
let nwin = unsafe { android_glue::get_native_window() }; | |
if nwin.is_null() { | |
- return Err(OsError(format!("Android's native window is null"))); | |
+ return Err(OsError("Android's native window is null".to_string())); | |
} | |
let native_display = NativeDisplay::Android; | |
let egl_context = | |
diff --git a/glutin/src/api/egl/mod.rs b/glutin/src/api/egl/mod.rs | |
index bc21383..8c4374a 100644 | |
--- a/glutin/src/api/egl/mod.rs | |
+++ b/glutin/src/api/egl/mod.rs | |
@@ -330,9 +330,9 @@ impl Context { | |
let mut minor: ffi::egl::types::EGLint = std::mem::uninitialized(); | |
if egl.Initialize(display, &mut major, &mut minor) == 0 { | |
- return Err(CreationError::OsError(format!( | |
- "eglInitialize failed" | |
- ))); | |
+ return Err(CreationError::OsError( | |
+ "eglInitialize failed".to_string(), | |
+ )); | |
} | |
(major, minor) | |
@@ -768,9 +768,9 @@ impl<'a> ContextPrototype<'a> { | |
std::ptr::null(), | |
); | |
if surface.is_null() { | |
- return Err(CreationError::OsError(format!( | |
- "eglCreateWindowSurface failed" | |
- ))); | |
+ return Err(CreationError::OsError( | |
+ "eglCreateWindowSurface failed".to_string(), | |
+ )); | |
} | |
surface | |
}; | |
@@ -794,9 +794,9 @@ impl<'a> ContextPrototype<'a> { | |
.find(|s| s == &"EGL_KHR_surfaceless_context") | |
.is_none() | |
{ | |
- Err(CreationError::OsError(format!( | |
- "EGL surfaceless not supported." | |
- ))) | |
+ Err(CreationError::NotSupported( | |
+ "EGL surfaceless not supported".to_string(), | |
+ )) | |
} else { | |
self.finish_impl(None) | |
} | |
@@ -838,9 +838,9 @@ impl<'a> ContextPrototype<'a> { | |
attrs.as_ptr(), | |
); | |
if surface.is_null() || surface == ffi::egl::NO_SURFACE { | |
- return Err(CreationError::OsError(format!( | |
- "eglCreatePbufferSurface failed" | |
- ))); | |
+ return Err(CreationError::OsError( | |
+ "eglCreatePbufferSurface failed".to_string(), | |
+ )); | |
} | |
surface | |
}; | |
@@ -1100,7 +1100,9 @@ unsafe fn choose_fbconfig( | |
&mut num_configs, | |
) == 0 | |
{ | |
- return Err(CreationError::OsError(format!("eglChooseConfig failed"))); | |
+ return Err(CreationError::OsError( | |
+ "eglChooseConfig failed".to_string(), | |
+ )); | |
} | |
if num_configs == 0 { | |
return Err(CreationError::NoAvailablePixelFormat); | |
@@ -1117,9 +1119,9 @@ unsafe fn choose_fbconfig( | |
&mut value, | |
); | |
if res == 0 { | |
- return Err(CreationError::OsError(format!( | |
- "eglGetConfigAttrib failed" | |
- ))); | |
+ return Err(CreationError::OsError( | |
+ "eglGetConfigAttrib failed".to_string(), | |
+ )); | |
} | |
value | |
}}; | |
diff --git a/glutin/src/api/glx/mod.rs b/glutin/src/api/glx/mod.rs | |
index e71abd5..6d586b8 100644 | |
--- a/glutin/src/api/glx/mod.rs | |
+++ b/glutin/src/api/glx/mod.rs | |
@@ -103,9 +103,10 @@ impl Context { | |
let extensions = | |
glx.QueryExtensionsString(xconn.display as *mut _, screen_id); | |
if extensions.is_null() { | |
- return Err(CreationError::OsError(format!( | |
+ return Err(CreationError::OsError( | |
"`glXQueryExtensionsString` found no glX extensions" | |
- ))); | |
+ .to_string(), | |
+ )); | |
} | |
let extensions = CStr::from_ptr(extensions).to_bytes().to_vec(); | |
String::from_utf8(extensions).unwrap() | |
@@ -129,9 +130,10 @@ impl Context { | |
let vi = | |
glx.GetVisualFromFBConfig(xconn.display as *mut _, fb_config); | |
if vi.is_null() { | |
- return Err(CreationError::OsError(format!( | |
+ return Err(CreationError::OsError( | |
"`glXGetVisualFromFBConfig` failed: invalid `GLXFBConfig`" | |
- ))); | |
+ .to_string(), | |
+ )); | |
} | |
let vi_copy = std::ptr::read(vi as *const _); | |
(xconn.xlib.XFree)(vi as *mut _); | |
@@ -471,9 +473,9 @@ impl<'a> ContextPrototype<'a> { | |
extra_functions.SwapIntervalSGI(1); | |
} | |
} else { | |
- return Err(CreationError::OsError(format!( | |
- "Couldn't find any available vsync extension" | |
- ))); | |
+ return Err(CreationError::OsError( | |
+ "Couldn't find any available vsync extension".to_string(), | |
+ )); | |
} | |
} | |
@@ -614,9 +616,9 @@ fn create_context( | |
if context.is_null() { | |
// TODO: check for errors and return `OpenGlVersionNotSupported` | |
- return Err(CreationError::OsError(format!( | |
- "GL context creation failed" | |
- ))); | |
+ return Err(CreationError::OsError( | |
+ "GL context creation failed".to_string(), | |
+ )); | |
} | |
Ok(context) | |
diff --git a/glutin/src/api/ios/mod.rs b/glutin/src/api/ios/mod.rs | |
index 9ba831f..88581a3 100644 | |
--- a/glutin/src/api/ios/mod.rs | |
+++ b/glutin/src/api/ios/mod.rs | |
@@ -239,9 +239,10 @@ impl Context { | |
version -= 1; | |
} | |
if valid_context == ffi::nil { | |
- Err(CreationError::OsError(format!( | |
+ Err(CreationError::OsError( | |
"Failed to create an OpenGL ES context with any version" | |
- ))) | |
+ .to_string(), | |
+ )) | |
} else { | |
Ok(eagl_context) | |
} | |
diff --git a/glutin/src/api/wgl/make_current_guard.rs b/glutin/src/api/wgl/make_current_guard.rs | |
index d355d89..2a05561 100644 | |
--- a/glutin/src/api/wgl/make_current_guard.rs | |
+++ b/glutin/src/api/wgl/make_current_guard.rs | |
@@ -29,7 +29,7 @@ impl<'a, 'b> CurrentContextGuard<'a, 'b> { | |
if result == 0 { | |
return Err(CreationError::OsError(format!( | |
"wglMakeCurrent function failed: {}", | |
- format!("{}", io::Error::last_os_error()) | |
+ io::Error::last_os_error() | |
))); | |
} | |
diff --git a/glutin/src/api/wgl/mod.rs b/glutin/src/api/wgl/mod.rs | |
index 91b33ee..93d22eb 100644 | |
--- a/glutin/src/api/wgl/mod.rs | |
+++ b/glutin/src/api/wgl/mod.rs | |
@@ -84,7 +84,7 @@ impl Context { | |
if hdc.is_null() { | |
let err = Err(CreationError::OsError(format!( | |
"GetDC function failed: {}", | |
- format!("{}", std::io::Error::last_os_error()) | |
+ std::io::Error::last_os_error() | |
))); | |
return err; | |
} | |
@@ -164,9 +164,9 @@ impl Context { | |
if extra_functions.SwapIntervalEXT(if opengl.vsync { 1 } else { 0 }) | |
== 0 | |
{ | |
- return Err(CreationError::OsError(format!( | |
- "wglSwapIntervalEXT failed" | |
- ))); | |
+ return Err(CreationError::OsError( | |
+ "wglSwapIntervalEXT failed".to_string(), | |
+ )); | |
} | |
} | |
@@ -361,7 +361,7 @@ unsafe fn create_context( | |
attributes.push(flag as raw::c_int); | |
} else { | |
return Err(CreationError::NotSupported( | |
- "required extension \"WGL_ARB_create_context_profile\" not found", | |
+ "required extension \"WGL_ARB_create_context_profile\" not found".to_string(), | |
)); | |
} | |
} | |
@@ -437,7 +437,7 @@ unsafe fn create_context( | |
if ctx.is_null() { | |
return Err(CreationError::OsError(format!( | |
"wglCreateContextAttribsARB failed: {}", | |
- format!("{}", std::io::Error::last_os_error()) | |
+ std::io::Error::last_os_error() | |
))); | |
} else { | |
return Ok(ContextWrapper(ctx as HGLRC)); | |
@@ -451,7 +451,7 @@ unsafe fn create_context( | |
if ctx.is_null() { | |
return Err(CreationError::OsError(format!( | |
"wglCreateContext failed: {}", | |
- format!("{}", std::io::Error::last_os_error()) | |
+ std::io::Error::last_os_error() | |
))); | |
} | |
@@ -459,7 +459,7 @@ unsafe fn create_context( | |
if gl::wgl::ShareLists(share as *const raw::c_void, ctx) == 0 { | |
return Err(CreationError::OsError(format!( | |
"wglShareLists failed: {}", | |
- format!("{}", std::io::Error::last_os_error()) | |
+ std::io::Error::last_os_error() | |
))); | |
} | |
}; | |
@@ -850,14 +850,14 @@ unsafe fn set_pixel_format( | |
{ | |
return Err(CreationError::OsError(format!( | |
"DescribePixelFormat function failed: {}", | |
- format!("{}", std::io::Error::last_os_error()) | |
+ std::io::Error::last_os_error() | |
))); | |
} | |
if SetPixelFormat(hdc, id, &output) == 0 { | |
return Err(CreationError::OsError(format!( | |
"SetPixelFormat function failed: {}", | |
- format!("{}", std::io::Error::last_os_error()) | |
+ std::io::Error::last_os_error() | |
))); | |
} | |
@@ -876,7 +876,7 @@ unsafe fn load_opengl32_dll() -> Result<HMODULE, CreationError> { | |
if lib.is_null() { | |
return Err(CreationError::OsError(format!( | |
"LoadLibrary function failed: {}", | |
- format!("{}", std::io::Error::last_os_error()) | |
+ std::io::Error::last_os_error() | |
))); | |
} | |
@@ -912,7 +912,7 @@ unsafe fn load_extra_functions( | |
if GetClassNameW(win, class_name.as_mut_ptr(), 128) == 0 { | |
return Err(CreationError::OsError(format!( | |
"GetClassNameW function failed: {}", | |
- format!("{}", std::io::Error::last_os_error()) | |
+ std::io::Error::last_os_error() | |
))); | |
} | |
@@ -923,7 +923,7 @@ unsafe fn load_extra_functions( | |
if GetClassInfoExW(instance, class_name.as_ptr(), &mut class) == 0 { | |
return Err(CreationError::OsError(format!( | |
"GetClassInfoExW function failed: {}", | |
- format!("{}", std::io::Error::last_os_error()) | |
+ std::io::Error::last_os_error() | |
))); | |
} | |
@@ -968,7 +968,7 @@ unsafe fn load_extra_functions( | |
if win.is_null() { | |
return Err(CreationError::OsError(format!( | |
"CreateWindowEx function failed: {}", | |
- format!("{}", std::io::Error::last_os_error()) | |
+ std::io::Error::last_os_error() | |
))); | |
} | |
@@ -976,7 +976,7 @@ unsafe fn load_extra_functions( | |
if hdc.is_null() { | |
let err = Err(CreationError::OsError(format!( | |
"GetDC function failed: {}", | |
- format!("{}", std::io::Error::last_os_error()) | |
+ std::io::Error::last_os_error() | |
))); | |
return err; | |
} | |
diff --git a/glutin/src/context.rs b/glutin/src/context.rs | |
index 8fa6a69..680cbb1 100644 | |
--- a/glutin/src/context.rs | |
+++ b/glutin/src/context.rs | |
@@ -10,7 +10,6 @@ use std::marker::PhantomData; | |
/// # Example | |
/// | |
/// ```no_run | |
-/// # use glutin::ContextTrait; | |
/// # fn main() { | |
/// # let el = glutin::EventsLoop::new(); | |
/// # let wb = glutin::WindowBuilder::new(); | |
@@ -29,56 +28,14 @@ pub struct Context<T: ContextCurrentState> { | |
pub(crate) phantom: PhantomData<T>, | |
} | |
-/// A trait for types associated with a GL context. | |
-pub trait ContextTrait | |
-where | |
- Self: Sized, | |
-{ | |
- type PossiblyCurrentContext: PossiblyCurrentContextTrait | |
- + ContextTrait< | |
- PossiblyCurrentContext = Self::PossiblyCurrentContext, | |
- NotCurrentContext = Self::NotCurrentContext, | |
- >; | |
- type NotCurrentContext: ContextTrait< | |
- PossiblyCurrentContext = Self::PossiblyCurrentContext, | |
- NotCurrentContext = Self::NotCurrentContext, | |
- >; | |
- | |
- /// Sets the context as the current context. The previously current context | |
- /// (if any) is no longer current. | |
- unsafe fn make_current( | |
- self, | |
- ) -> Result<Self::PossiblyCurrentContext, (Self, ContextError)>; | |
- | |
- /// If this context is current, makes the context not current. | |
- unsafe fn make_not_current( | |
- self, | |
- ) -> Result<Self::NotCurrentContext, (Self, ContextError)>; | |
- | |
- /// Treats the context as not current, even if it is current. We do no | |
- /// checks to confirm that this is the case. Prefer to use | |
- /// `make_not_current` which will do nothing if this context is not current. | |
- unsafe fn treat_as_not_current(self) -> Self::NotCurrentContext; | |
- | |
- /// Returns true if this context is the current one in this thread. | |
- fn is_current(&self) -> bool; | |
- | |
- /// Returns the OpenGL API being used. | |
- fn get_api(&self) -> Api; | |
-} | |
- | |
-pub trait PossiblyCurrentContextTrait { | |
- /// Returns the address of an OpenGL function. | |
- fn get_proc_address(&self, addr: &str) -> *const (); | |
-} | |
- | |
-impl<T: ContextCurrentState> ContextTrait for Context<T> { | |
- type PossiblyCurrentContext = Context<PossiblyCurrentContext>; | |
- type NotCurrentContext = Context<NotCurrentContext>; | |
- | |
- unsafe fn make_current( | |
+impl<T: ContextCurrentState> Context<T> { | |
+ /// See [`ContextWrapper::make_current`]. | |
+ /// | |
+ /// [`ContextWrapper::make_current`]: | |
+ /// struct.ContextWrapper.html#method.make_current | |
+ pub unsafe fn make_current( | |
self, | |
- ) -> Result<Self::PossiblyCurrentContext, (Self, ContextError)> { | |
+ ) -> Result<Context<PossiblyCurrentContext>, (Self, ContextError)> { | |
match self.context.make_current() { | |
Ok(()) => Ok(Context { | |
context: self.context, | |
@@ -94,9 +51,13 @@ impl<T: ContextCurrentState> ContextTrait for Context<T> { | |
} | |
} | |
- unsafe fn make_not_current( | |
+ /// See [`ContextWrapper::make_not_current`]. | |
+ /// | |
+ /// [`ContextWrapper::make_not_current`]: | |
+ /// struct.ContextWrapper.html#method.make_not_current | |
+ pub unsafe fn make_not_current( | |
self, | |
- ) -> Result<Self::NotCurrentContext, (Self, ContextError)> { | |
+ ) -> Result<Context<NotCurrentContext>, (Self, ContextError)> { | |
match self.context.make_not_current() { | |
Ok(()) => Ok(Context { | |
context: self.context, | |
@@ -112,24 +73,39 @@ impl<T: ContextCurrentState> ContextTrait for Context<T> { | |
} | |
} | |
- unsafe fn treat_as_not_current(self) -> Self::NotCurrentContext { | |
+ /// See [`ContextWrapper::treat_as_not_current`]. | |
+ /// | |
+ /// [`ContextWrapper::treat_as_not_current`]: | |
+ /// struct.ContextWrapper.html#method.treat_as_not_current | |
+ pub unsafe fn treat_as_not_current(self) -> Context<NotCurrentContext> { | |
Context { | |
context: self.context, | |
phantom: PhantomData, | |
} | |
} | |
- fn is_current(&self) -> bool { | |
+ /// See [`ContextWrapper::is_current`]. | |
+ /// | |
+ /// [`ContextWrapper::is_current`]: | |
+ /// struct.ContextWrapper.html#method.is_current | |
+ pub fn is_current(&self) -> bool { | |
self.context.is_current() | |
} | |
- fn get_api(&self) -> Api { | |
+ /// See [`ContextWrapper::get_api`]. | |
+ /// | |
+ /// [`ContextWrapper::get_api`]: struct.ContextWrapper.html#method.get_api | |
+ pub fn get_api(&self) -> Api { | |
self.context.get_api() | |
} | |
} | |
-impl PossiblyCurrentContextTrait for Context<PossiblyCurrentContext> { | |
- fn get_proc_address(&self, addr: &str) -> *const () { | |
+impl Context<PossiblyCurrentContext> { | |
+ /// See [`ContextWrapper::get_proc_address`]. | |
+ /// | |
+ /// [`ContextWrapper::get_proc_address`]: | |
+ /// struct.ContextWrapper.html#method.get_proc_address | |
+ pub fn get_proc_address(&self, addr: &str) -> *const () { | |
self.context.get_proc_address(addr) | |
} | |
} | |
@@ -140,11 +116,43 @@ impl<'a, T: ContextCurrentState> ContextBuilder<'a, T> { | |
/// One notable limitation of the Wayland backend when it comes to shared | |
/// contexts is that both contexts must use the same events loop. | |
/// | |
+ /// When on linux, prefer [`build_surfaceless`]. If both | |
+ /// [`build_surfaceless`] and `build_headless` fail, try using a hidden | |
+ /// window, or [`build_osmesa`]. Please note that if you choose to use a | |
+ /// hidden window, you must still handle the events it generates on the | |
+ /// events loop. | |
+ /// | |
/// Errors can occur in two scenarios: | |
/// - If the window could not be created (via permission denied, | |
/// incompatible system, out of memory, etc.). This should be very rare. | |
/// - If the OpenGL context could not be created. This generally happens | |
/// because the underlying platform doesn't support a requested feature. | |
+ #[cfg_attr( | |
+ not(any( | |
+ target_os = "linux", | |
+ target_os = "dragonfly", | |
+ target_os = "freebsd", | |
+ target_os = "netbsd", | |
+ target_os = "openbsd", | |
+ )), | |
+ doc = "\ | |
+ [`build_surfaceless`]: os/index.html | |
+ [`build_osmesa`]: os/index.html | |
+ " | |
+ )] | |
+ #[cfg_attr( | |
+ any( | |
+ target_os = "linux", | |
+ target_os = "dragonfly", | |
+ target_os = "freebsd", | |
+ target_os = "netbsd", | |
+ target_os = "openbsd", | |
+ ), | |
+ doc = "\ | |
+ [`build_surfaceless`]: os/unix/trait.HeadlessContextExt.html#tymethod.build_surfaceless | |
+ [`build_osmesa`]: os/unix/trait.HeadlessContextExt.html#tymethod.build_osmesa | |
+ " | |
+ )] | |
pub fn build_headless( | |
self, | |
el: &EventsLoop, | |
@@ -167,14 +175,33 @@ impl<'a, T: ContextCurrentState> ContextBuilder<'a, T> { | |
// | |
// Instead we add a phantom type to PossiblyCurrentContext | |
-#[derive(Debug, Clone)] | |
+/// A type that contexts which might possibly be currently current on some | |
+/// thread take as a generic. | |
+/// | |
+/// See [`ContextWrapper::make_current`] for more details. | |
+/// | |
+/// [`ContextWrapper::make_current`]: | |
+/// struct.ContextWrapper.html#method.make_current | |
+#[derive(Debug, Clone, Copy)] | |
pub struct PossiblyCurrentContext { | |
phantom: PhantomData<*mut ()>, | |
} | |
-#[derive(Debug, Clone)] | |
+/// A type that contexts which are not currently current on any thread take as | |
+/// a generic. | |
+/// | |
+/// See [`ContextWrapper::make_current`] for more details. | |
+/// | |
+/// [`ContextWrapper::make_current`]: | |
+/// struct.ContextWrapper.html#method.make_current | |
+#[derive(Debug, Clone, Copy)] | |
pub enum NotCurrentContext {} | |
+/// A trait implemented on both [`NotCurrentContext`] and | |
+/// [`PossiblyCurrentContext`]. | |
+/// | |
+/// [`NotCurrentContext`]: enum.NotCurrentContext.html | |
+/// [`PossiblyCurrentContext`]: struct.PossiblyCurrentContext.html | |
pub trait ContextCurrentState: std::fmt::Debug + Clone {} | |
impl ContextCurrentState for PossiblyCurrentContext {} | |
diff --git a/glutin/src/lib.rs b/glutin/src/lib.rs | |
index 32f42c0..1d8625c 100644 | |
--- a/glutin/src/lib.rs | |
+++ b/glutin/src/lib.rs | |
@@ -43,6 +43,8 @@ | |
missing_debug_implementations, | |
//missing_docs, | |
)] | |
+// Docs for subcrates are borked. | |
+#![allow(intra_doc_link_resolution_failure)] | |
#[cfg(any( | |
target_os = "windows", | |
@@ -76,8 +78,7 @@ mod platform; | |
mod windowed; | |
pub use crate::context::{ | |
- Context, ContextCurrentState, ContextTrait, NotCurrentContext, | |
- PossiblyCurrentContext, PossiblyCurrentContextTrait, | |
+ Context, ContextCurrentState, NotCurrentContext, PossiblyCurrentContext, | |
}; | |
pub use crate::windowed::{ContextWrapper, RawContext, WindowedContext}; | |
@@ -264,20 +265,19 @@ impl<'a, T: ContextCurrentState> ContextBuilder<'a, T> { | |
#[derive(Debug)] | |
pub enum CreationError { | |
OsError(String), | |
- /// TODO: remove this error | |
- NotSupported(&'static str), | |
+ NotSupported(String), | |
NoBackendAvailable(Box<std::error::Error + Send + Sync>), | |
RobustnessNotSupported, | |
OpenGlVersionNotSupported, | |
NoAvailablePixelFormat, | |
PlatformSpecific(String), | |
Window(WindowCreationError), | |
- /// We received two errors, instead of one. | |
+ /// We received multiple errors, instead of one. | |
CreationErrors(Vec<Box<CreationError>>), | |
} | |
impl CreationError { | |
- pub fn append(self, err: CreationError) -> Self { | |
+ pub(crate) fn append(self, err: CreationError) -> Self { | |
match self { | |
CreationError::CreationErrors(mut errs) => { | |
errs.push(Box::new(err)); | |
@@ -292,8 +292,8 @@ impl CreationError { | |
fn to_string(&self) -> &str { | |
match *self { | |
- CreationError::OsError(ref text) => &text, | |
- CreationError::NotSupported(text) => &text, | |
+ CreationError::OsError(ref text) | |
+ | CreationError::NotSupported(ref text) => &text, | |
CreationError::NoBackendAvailable(_) => "No backend is available", | |
CreationError::RobustnessNotSupported => { | |
"You requested robustness, but it is not supported." | |
@@ -327,9 +327,6 @@ impl std::fmt::Display for CreationError { | |
write!(formatter, "`")?; | |
} | |
- if let &CreationError::NotSupported(msg) = self { | |
- write!(formatter, ": {}", msg)?; | |
- } | |
if let Some(err) = std::error::Error::source(self) { | |
write!(formatter, ": {}", err)?; | |
} | |
@@ -508,17 +505,20 @@ pub enum ReleaseBehavior { | |
Flush, | |
} | |
-/// Describes a possible format. Unused. | |
+/// Describes a possible format. | |
#[allow(missing_docs)] | |
#[derive(Debug, Clone)] | |
pub struct PixelFormat { | |
pub hardware_accelerated: bool, | |
+ /// The number of color bits. Does not include alpha bits. | |
pub color_bits: u8, | |
pub alpha_bits: u8, | |
pub depth_bits: u8, | |
pub stencil_bits: u8, | |
pub stereoscopy: bool, | |
pub double_buffer: bool, | |
+ /// `None` if multisampling is disabled, otherwise `Some(N)` where `N` is | |
+ /// the multisampling level. | |
pub multisampling: Option<u16>, | |
pub srgb: bool, | |
} | |
@@ -551,7 +551,7 @@ pub struct PixelFormatRequirements { | |
/// The default value is `Some(24)`. | |
pub depth_bits: Option<u8>, | |
- /// Minimum number of bits for the depth buffer. `None` means "don't care". | |
+ /// Minimum number of stencil bits. `None` means "don't care". | |
/// The default value is `Some(8)`. | |
pub stencil_bits: Option<u8>, | |
diff --git a/glutin/src/os/mod.rs b/glutin/src/os/mod.rs | |
index 4ef0c07..b73a465 100644 | |
--- a/glutin/src/os/mod.rs | |
+++ b/glutin/src/os/mod.rs | |
@@ -9,11 +9,17 @@ | |
//! - `windows` | |
//! | |
+/// Platform specific methods for android. | |
pub mod android; | |
+/// Platform specific methods for blank backend. | |
pub mod blank; | |
+/// Platform specific methods for iOS. | |
pub mod ios; | |
+/// Platform specific methods for macOS. | |
pub mod macos; | |
+/// Platform specific methods for unix. | |
pub mod unix; | |
+/// Platform specific methods for Windows. | |
pub mod windows; | |
use std::os::raw; | |
diff --git a/glutin/src/platform/linux/mod.rs b/glutin/src/platform/linux/mod.rs | |
index 2e16790..1f99f8e 100644 | |
--- a/glutin/src/platform/linux/mod.rs | |
+++ b/glutin/src/platform/linux/mod.rs | |
@@ -26,7 +26,9 @@ use std::sync::Arc; | |
/// Context handles available on Unix-like platforms. | |
#[derive(Clone, Debug)] | |
pub enum RawHandle { | |
+ /// Context handles for glx contexts. | |
Glx(glutin_glx_sys::GLXContext), | |
+ /// Context handles for egl contexts. | |
Egl(glutin_egl_sys::EGLContext), | |
} | |
@@ -240,7 +242,16 @@ impl Context { | |
} | |
} | |
+/// A linux-specific extension to the [`ContextBuilder`] which allows building | |
+/// linux specific headless contexts. | |
+/// | |
+/// [`ContextBuilder`]: struct.ContextBuilder.html | |
pub trait HeadlessContextExt { | |
+ /// Builds the given OsMesa context. | |
+ /// | |
+ /// Errors can occur if the OpenGL context could not be created. This | |
+ /// generally happens because the underlying platform doesn't support a | |
+ /// requested feature. | |
fn build_osmesa( | |
self, | |
size: dpi::PhysicalSize, | |
@@ -248,6 +259,11 @@ pub trait HeadlessContextExt { | |
where | |
Self: Sized; | |
+ /// Builds an EGL-surfaceless context. | |
+ /// | |
+ /// Errors can occur if the OpenGL context could not be created. This | |
+ /// generally happens because the underlying platform doesn't support a | |
+ /// requested feature. | |
fn build_surfaceless( | |
self, | |
el: &winit::EventsLoop, | |
@@ -259,11 +275,6 @@ pub trait HeadlessContextExt { | |
impl<'a, T: ContextCurrentState> HeadlessContextExt | |
for crate::ContextBuilder<'a, T> | |
{ | |
- /// Builds the given OsMesa context. | |
- /// | |
- /// Errors can occur if the OpenGL context could not be created. This | |
- /// generally happens because the underlying platform doesn't support a | |
- /// requested feature. | |
#[inline] | |
fn build_osmesa( | |
self, | |
@@ -287,11 +298,6 @@ impl<'a, T: ContextCurrentState> HeadlessContextExt | |
}) | |
} | |
- /// Builds an egl-surfaceless context. | |
- /// | |
- /// Errors can occur if the OpenGL context could not be created. This | |
- /// generally happens because the underlying platform doesn't support a | |
- /// requested feature. | |
#[inline] | |
fn build_surfaceless( | |
self, | |
@@ -311,6 +317,11 @@ impl<'a, T: ContextCurrentState> HeadlessContextExt | |
} | |
} | |
+/// A linux-specific for the [`ContextBuilder`] which allows assembling | |
+/// [`RawContext<T>`]s. | |
+/// | |
+/// [`RawContext<T>`]: type.RawContext.html | |
+/// [`ContextBuilder`]: struct.ContextBuilder.html | |
pub trait RawContextExt { | |
/// Creates a raw context on the provided surface. | |
/// | |
diff --git a/glutin/src/platform/linux/wayland.rs b/glutin/src/platform/linux/wayland.rs | |
index 6e8b332..8c97f90 100644 | |
--- a/glutin/src/platform/linux/wayland.rs | |
+++ b/glutin/src/platform/linux/wayland.rs | |
@@ -95,7 +95,9 @@ impl Context { | |
let surface = match surface { | |
Some(s) => s, | |
None => { | |
- return Err(CreationError::NotSupported("Wayland not found")); | |
+ return Err(CreationError::NotSupported( | |
+ "Wayland not found".to_string(), | |
+ )); | |
} | |
}; | |
diff --git a/glutin/src/platform/linux/x11.rs b/glutin/src/platform/linux/x11.rs | |
index f838e1a..dbda206 100644 | |
--- a/glutin/src/platform/linux/x11.rs | |
+++ b/glutin/src/platform/linux/x11.rs | |
@@ -298,7 +298,7 @@ impl Context { | |
} | |
return Err(CreationError::NotSupported( | |
- "both libGL and libEGL are not present", | |
+ "both libGL and libEGL are not present".to_string(), | |
)); | |
} else { | |
match (&*GLX, &*EGL, prefer_egl) { | |
@@ -308,7 +308,7 @@ impl Context { | |
} | |
return Err(CreationError::NotSupported( | |
- "lacking either libGL or libEGL so could not fallback to other", | |
+ "lacking either libGL or libEGL so could not fallback to other".to_string(), | |
)); | |
} | |
} | |
@@ -328,13 +328,13 @@ impl Context { | |
)?) | |
} else { | |
return Err(CreationError::NotSupported( | |
- "libEGL not present", | |
+ "libEGL not present".to_string(), | |
)); | |
} | |
} | |
GlRequest::Specific(_, _) => { | |
return Err(CreationError::NotSupported( | |
- "requested specific without gl or gles", | |
+ "requested specific without gl or gles".to_string(), | |
)); | |
} | |
}) | |
diff --git a/glutin/src/platform/macos/mod.rs b/glutin/src/platform/macos/mod.rs | |
index cd58f32..6aeea50 100644 | |
--- a/glutin/src/platform/macos/mod.rs | |
+++ b/glutin/src/platform/macos/mod.rs | |
@@ -90,7 +90,7 @@ impl Context { | |
Some(gl_context) => gl_context, | |
None => { | |
return Err(CreationError::NotSupported( | |
- "could not open gl context", | |
+ "could not open gl context".to_string(), | |
)); | |
} | |
}; | |
@@ -175,16 +175,16 @@ impl Context { | |
let pixelformat = NSOpenGLPixelFormat::alloc(nil) | |
.initWithAttributes_(&attributes); | |
if pixelformat == nil { | |
- return Err(CreationError::OsError(format!( | |
- "Could not create the pixel format" | |
- ))); | |
+ return Err(CreationError::OsError( | |
+ "Could not create the pixel format".to_string(), | |
+ )); | |
} | |
let context = NSOpenGLContext::alloc(nil) | |
.initWithFormat_shareContext_(pixelformat, nil); | |
if context == nil { | |
- return Err(CreationError::OsError(format!( | |
- "Could not create the rendering context" | |
- ))); | |
+ return Err(CreationError::OsError( | |
+ "Could not create the rendering context".to_string(), | |
+ )); | |
} | |
IdRef::new(context) | |
diff --git a/glutin/src/windowed.rs b/glutin/src/windowed.rs | |
index 5c4e51e..5bb254c 100644 | |
--- a/glutin/src/windowed.rs | |
+++ b/glutin/src/windowed.rs | |
@@ -4,10 +4,11 @@ use std::marker::PhantomData; | |
/// Represents an OpenGL context and the `Window` with which it is associated. | |
/// | |
+/// Please see [`ContextWrapper<T, Window>`]. | |
+/// | |
/// # Example | |
/// | |
/// ```no_run | |
-/// # use glutin::ContextTrait; | |
/// # fn main() { | |
/// let mut el = glutin::EventsLoop::new(); | |
/// let wb = glutin::WindowBuilder::new(); | |
@@ -32,11 +33,69 @@ use std::marker::PhantomData; | |
/// } | |
/// # } | |
/// ``` | |
+/// | |
+/// [`ContextWrapper<T, Window>`]: struct.ContextWrapper.html | |
pub type WindowedContext<T> = ContextWrapper<T, Window>; | |
-/// Represents a raw OpenGL context. | |
+/// Represents am OpenGL context which has an underlying window that is | |
+/// stored separately. | |
+/// | |
+/// This type can only be created via one of three ways: | |
+/// | |
+/// * [`os::unix::RawContextExt`] | |
+/// * [`os::windows::RawContextExt`] | |
+/// * [`WindowedContext<T>::split`] | |
+/// | |
+/// Please see [`ContextWrapper<T, ()>`]. | |
+/// | |
+/// [`ContextWrapper<T, ()>`]: struct.ContextWrapper.html | |
+/// [`WindowedContext<T>::split`]: type.WindowedContext.html#method.split | |
+#[cfg_attr( | |
+ target_os = "windows", | |
+ doc = "\ | |
+[`os::windows::RawContextExt`]: os/windows/enum.RawHandle.html | |
+" | |
+)] | |
+#[cfg_attr( | |
+ not(target_os = "windows",), | |
+ doc = "\ | |
+[`os::windows::RawContextExt`]: os/index.html | |
+" | |
+)] | |
+#[cfg_attr( | |
+ not(any( | |
+ target_os = "linux", | |
+ target_os = "dragonfly", | |
+ target_os = "freebsd", | |
+ target_os = "netbsd", | |
+ target_os = "openbsd", | |
+ )), | |
+ doc = "\ | |
+[`os::unix::RawContextExt`]: os/index.html | |
+" | |
+)] | |
+#[cfg_attr( | |
+ any( | |
+ target_os = "linux", | |
+ target_os = "dragonfly", | |
+ target_os = "freebsd", | |
+ target_os = "netbsd", | |
+ target_os = "openbsd", | |
+ ), | |
+ doc = "\ | |
+[`os::unix::RawContextExt`]: os/unix/enum.RawHandle.html | |
+" | |
+)] | |
pub type RawContext<T> = ContextWrapper<T, ()>; | |
+/// A context which has an underlying window, which may or may not be stored | |
+/// separately. | |
+/// | |
+/// If the window is stored separately, it is a [`RawContext<T>`]. Otherwise, | |
+/// it is a [`WindowedContext<T>`]. | |
+/// | |
+/// [`WindowedContext<T>`]: type.WindowedContext.html | |
+/// [`RawContext<T>`]: type.RawContext.html | |
#[derive(Debug)] | |
pub struct ContextWrapper<T: ContextCurrentState, W> { | |
pub(crate) context: Context<T>, | |
@@ -65,13 +124,6 @@ impl<T: ContextCurrentState> WindowedContext<T> { | |
} | |
} | |
-impl<T: ContextCurrentState, W> ContextWrapper<T, W> { | |
- /// Borrow the inner GL `Context`. | |
- pub fn context(&self) -> &Context<T> { | |
- &self.context | |
- } | |
-} | |
- | |
impl<W> ContextWrapper<PossiblyCurrentContext, W> { | |
/// Swaps the buffers in case of double or triple buffering. | |
/// | |
@@ -105,13 +157,70 @@ impl<W> ContextWrapper<PossiblyCurrentContext, W> { | |
} | |
} | |
-impl<T: ContextCurrentState, W> ContextTrait for ContextWrapper<T, W> { | |
- type PossiblyCurrentContext = ContextWrapper<PossiblyCurrentContext, W>; | |
- type NotCurrentContext = ContextWrapper<NotCurrentContext, W>; | |
+impl<T: ContextCurrentState, W> ContextWrapper<T, W> { | |
+ /// Borrow the inner GL `Context`. | |
+ pub fn context(&self) -> &Context<T> { | |
+ &self.context | |
+ } | |
- unsafe fn make_current( | |
+ /// Sets this context as the current context. The previously current context | |
+ /// (if any) is no longer current. | |
+ /// | |
+ /// A failed call to `make_current` might make this, or no context | |
+ /// current. It could also keep the previous context current. What happens | |
+ /// varies by platform and error. | |
+ /// | |
+ /// To attempt to recover and get back into a know state, either: | |
+ /// | |
+ /// * attempt to use [`is_current`] to find the new current context; or | |
+ /// * call [`make_not_current`] on both the previously | |
+ /// current context and this context. | |
+ /// | |
+ /// # An higher level overview. | |
+ /// | |
+ /// In OpenGl, only a single context can be current in a thread at a time. | |
+ /// Making a new context current will make the old one not current. | |
+ /// Contexts can only be sent to different threads if they are not current. | |
+ /// | |
+ /// If you call `make_current` on some context, you should call | |
+ /// [`treat_as_not_current`] as soon as possible on the previously current | |
+ /// context. | |
+ /// | |
+ /// If you wish to move a currently current context to a different thread, | |
+ /// you should do one of two options: | |
+ /// | |
+ /// * Call `make_current` on an other context, then call | |
+ /// [`treat_as_not_current`] on this context. | |
+ /// * Call [`make_current`] on this context. | |
+ /// | |
+ /// If you are aware of what context you intend to make current next, it is | |
+ /// preferable for performance reasons to call `make_current` on that | |
+ /// context, then [`treat_as_not_current`] on this context. | |
+ /// | |
+ /// If you are not aware of what context you intend to make current next, | |
+ /// consider waiting until you do. If you need this context not current | |
+ /// immediately (e.g. to transfer it to an other thread), then call | |
+ /// [`make_not_current`] on this context. | |
+ /// | |
+ /// Please avoid calling [`make_not_current`] on one context only to call | |
+ /// [`make_current`] on an other context before and/or after. This hurts | |
+ /// performance by requiring glutin to: | |
+ /// | |
+ /// * Check if this context is current; then | |
+ /// * If it is, change the current context from this context to none; then | |
+ /// * Change the current context from none to the new context. | |
+ /// | |
+ /// Instead prefer the method we mentioned above with `make_current` and | |
+ /// [`treat_as_not_current`]. | |
+ /// | |
+ /// [`make_not_current`]: struct.ContextWrapper.html#method.make_not_current | |
+ /// [`treat_as_not_current`]: | |
+ /// struct.ContextWrapper.html#method.treat_as_not_current | |
+ /// [`is_current`]: struct.ContextWrapper.html#method.is_current | |
+ pub unsafe fn make_current( | |
self, | |
- ) -> Result<Self::PossiblyCurrentContext, (Self, ContextError)> { | |
+ ) -> Result<ContextWrapper<PossiblyCurrentContext, W>, (Self, ContextError)> | |
+ { | |
let window = self.window; | |
match self.context.make_current() { | |
Ok(context) => Ok(ContextWrapper { window, context }), | |
@@ -121,9 +230,16 @@ impl<T: ContextCurrentState, W> ContextTrait for ContextWrapper<T, W> { | |
} | |
} | |
- unsafe fn make_not_current( | |
+ /// If this context is current, makes this context not current. If this | |
+ /// context is not current however, this function does nothing. | |
+ /// | |
+ /// Please see [`make_current`]. | |
+ /// | |
+ /// [`make_current`]: struct.ContextWrapper.html#method.make_current | |
+ pub unsafe fn make_not_current( | |
self, | |
- ) -> Result<Self::NotCurrentContext, (Self, ContextError)> { | |
+ ) -> Result<ContextWrapper<NotCurrentContext, W>, (Self, ContextError)> | |
+ { | |
let window = self.window; | |
match self.context.make_not_current() { | |
Ok(context) => Ok(ContextWrapper { window, context }), | |
@@ -133,26 +249,40 @@ impl<T: ContextCurrentState, W> ContextTrait for ContextWrapper<T, W> { | |
} | |
} | |
- unsafe fn treat_as_not_current(self) -> Self::NotCurrentContext { | |
+ /// Treats this context as not current, even if it is current. We do no | |
+ /// checks to confirm that this is actually case. | |
+ /// | |
+ /// If unsure whether or not this context is current, please use | |
+ /// [`make_not_current`] which will do nothing if this context is not | |
+ /// current. | |
+ /// | |
+ /// Please see [`make_current`]. | |
+ /// | |
+ /// [`make_not_current`]: struct.ContextWrapper.html#method.make_not_current | |
+ /// [`make_current`]: struct.ContextWrapper.html#method.make_current | |
+ pub unsafe fn treat_as_not_current( | |
+ self, | |
+ ) -> ContextWrapper<NotCurrentContext, W> { | |
ContextWrapper { | |
context: self.context.treat_as_not_current(), | |
window: self.window, | |
} | |
} | |
- fn is_current(&self) -> bool { | |
+ /// Returns true if this context is the current one in this thread. | |
+ pub fn is_current(&self) -> bool { | |
self.context.is_current() | |
} | |
- fn get_api(&self) -> Api { | |
+ /// Returns the OpenGL API being used. | |
+ pub fn get_api(&self) -> Api { | |
self.context.get_api() | |
} | |
} | |
-impl<W> PossiblyCurrentContextTrait | |
- for ContextWrapper<PossiblyCurrentContext, W> | |
-{ | |
- fn get_proc_address(&self, addr: &str) -> *const () { | |
+impl<W> ContextWrapper<PossiblyCurrentContext, W> { | |
+ /// Returns the address of an OpenGL function. | |
+ pub fn get_proc_address(&self, addr: &str) -> *const () { | |
self.context.get_proc_address(addr) | |
} | |
} | |
diff --git a/glutin_examples/examples/fullscreen.rs b/glutin_examples/examples/fullscreen.rs | |
index 2e7baf0..628fec0 100644 | |
--- a/glutin_examples/examples/fullscreen.rs | |
+++ b/glutin_examples/examples/fullscreen.rs | |
@@ -1,6 +1,5 @@ | |
mod support; | |
-use glutin::ContextTrait; | |
use std::io::{self, Write}; | |
fn main() { | |
diff --git a/glutin_examples/examples/headless.rs b/glutin_examples/examples/headless.rs | |
index beba6c5..50abf67 100644 | |
--- a/glutin_examples/examples/headless.rs | |
+++ b/glutin_examples/examples/headless.rs | |
@@ -1,7 +1,6 @@ | |
mod support; | |
use glutin::dpi::PhysicalSize; | |
-use glutin::ContextTrait; | |
use std::path::Path; | |
use support::gl; | |
diff --git a/glutin_examples/examples/multiwindow.rs b/glutin_examples/examples/multiwindow.rs | |
index e4ac4ec..9ce8b06 100644 | |
--- a/glutin_examples/examples/multiwindow.rs | |
+++ b/glutin_examples/examples/multiwindow.rs | |
@@ -1,7 +1,5 @@ | |
mod support; | |
-use glutin::ContextTrait; | |
- | |
use support::{ContextCurrentWrapper, ContextTracker, ContextWrapper}; | |
fn main() { | |
diff --git a/glutin_examples/examples/raw_context.rs b/glutin_examples/examples/raw_context.rs | |
index 5fac0ce..a47c584 100644 | |
--- a/glutin_examples/examples/raw_context.rs | |
+++ b/glutin_examples/examples/raw_context.rs | |
@@ -11,7 +11,6 @@ fn main() { | |
#[cfg(any(target_os = "linux", target_os = "windows"))] | |
mod this_example { | |
use super::support; | |
- use glutin::ContextTrait; | |
pub fn main() { | |
let (raw_context, mut el, win) = { | |
diff --git a/glutin_examples/examples/support/mod.rs b/glutin_examples/examples/support/mod.rs | |
index d7a31c4..008cfb4 100644 | |
--- a/glutin_examples/examples/support/mod.rs | |
+++ b/glutin_examples/examples/support/mod.rs | |
@@ -1,4 +1,4 @@ | |
-use glutin::{self, PossiblyCurrentContext, PossiblyCurrentContextTrait}; | |
+use glutin::{self, PossiblyCurrentContext}; | |
use std::ffi::CStr; | |
@@ -168,8 +168,8 @@ pub use self::context_tracker::{ | |
#[allow(dead_code)] // Not used by all examples | |
mod context_tracker { | |
use glutin::{ | |
- self, Context, ContextCurrentState, ContextError, ContextTrait, | |
- NotCurrentContext, PossiblyCurrentContext, WindowedContext, | |
+ self, Context, ContextCurrentState, ContextError, NotCurrentContext, | |
+ PossiblyCurrentContext, WindowedContext, | |
}; | |
use takeable_option::Takeable; | |
@@ -370,6 +370,17 @@ mod context_tracker { | |
} | |
} | |
+ if let Err(err2) = self.modify(id, |ctx| { | |
+ ctx.map_possibly(|ctx| { | |
+ ctx.map( | |
+ |ctx| ctx.make_not_current(), | |
+ |ctx| ctx.make_not_current(), | |
+ ) | |
+ }) | |
+ }) { | |
+ panic!("Could not `make_current` nor `make_not_current`, {:?}, {:?}", err, err2); | |
+ } | |
+ | |
return Err(err); | |
} | |
diff --git a/glutin_examples/examples/transparent.rs b/glutin_examples/examples/transparent.rs | |
index 6480472..3ff7429 100644 | |
--- a/glutin_examples/examples/transparent.rs | |
+++ b/glutin_examples/examples/transparent.rs | |
@@ -1,7 +1,5 @@ | |
mod support; | |
-use glutin::ContextTrait; | |
- | |
fn main() { | |
let mut el = glutin::EventsLoop::new(); | |
let wb = glutin::WindowBuilder::new() | |
diff --git a/glutin_examples/examples/window.rs b/glutin_examples/examples/window.rs | |
index 92cedb7..6e23485 100644 | |
--- a/glutin_examples/examples/window.rs | |
+++ b/glutin_examples/examples/window.rs | |
@@ -1,7 +1,5 @@ | |
mod support; | |
-use glutin::ContextTrait; | |
- | |
fn main() { | |
let mut el = glutin::EventsLoop::new(); | |
let wb = glutin::WindowBuilder::new().with_title("A fantastic window!"); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment