Merge pull request #486 from tomaka/context-error

Handle errors from MakeCurrent and SwapBuffers
This commit is contained in:
tomaka 2015-06-17 07:36:00 +02:00
commit 90b28c2052
20 changed files with 123 additions and 62 deletions

View file

@ -15,6 +15,7 @@ use std::collections::VecDeque;
use Api; use Api;
use BuilderAttribs; use BuilderAttribs;
use ContextError;
use CursorState; use CursorState;
use GlContext; use GlContext;
use GlRequest; use GlRequest;
@ -213,7 +214,7 @@ unsafe impl Send for Window {}
unsafe impl Sync for Window {} unsafe impl Sync for Window {}
impl GlContext for Window { impl GlContext for Window {
unsafe fn make_current(&self) { unsafe fn make_current(&self) -> Result<(), ContextError> {
self.context.make_current() self.context.make_current()
} }
@ -225,7 +226,7 @@ impl GlContext for Window {
self.context.get_proc_address(addr) self.context.get_proc_address(addr)
} }
fn swap_buffers(&self) { fn swap_buffers(&self) -> Result<(), ContextError> {
self.context.swap_buffers() self.context.swap_buffers()
} }

View file

@ -6,6 +6,7 @@ use api::osmesa::{OsMesaContext, OsMesaCreationError};
use Api; use Api;
use BuilderAttribs; use BuilderAttribs;
use ContextError;
use CreationError; use CreationError;
use Event; use Event;
use GlContext; use GlContext;
@ -209,7 +210,7 @@ impl Window {
} }
impl GlContext for Window { impl GlContext for Window {
unsafe fn make_current(&self) { unsafe fn make_current(&self) -> Result<(), ContextError> {
self.opengl.make_current() self.opengl.make_current()
} }
@ -221,7 +222,7 @@ impl GlContext for Window {
self.opengl.get_proc_address(addr) self.opengl.get_proc_address(addr)
} }
fn swap_buffers(&self) { fn swap_buffers(&self) -> Result<(), ContextError> {
unsafe { unsafe {
let canvas = (self.libcaca.caca_get_canvas)(self.display); let canvas = (self.libcaca.caca_get_canvas)(self.display);
let width = (self.libcaca.caca_get_canvas_width)(canvas); let width = (self.libcaca.caca_get_canvas_width)(canvas);
@ -235,6 +236,8 @@ impl GlContext for Window {
buffer.as_ptr() as *const _); buffer.as_ptr() as *const _);
(self.libcaca.caca_refresh_display)(self.display); (self.libcaca.caca_refresh_display)(self.display);
}; };
Ok(())
} }
fn get_api(&self) -> Api { fn get_api(&self) -> Api {

View file

@ -1,3 +1,4 @@
use ContextError;
use CreationError; use CreationError;
use CreationError::OsError; use CreationError::OsError;
use BuilderAttribs; use BuilderAttribs;
@ -61,7 +62,7 @@ impl HeadlessContext {
} }
impl GlContext for HeadlessContext { impl GlContext for HeadlessContext {
unsafe fn make_current(&self) { unsafe fn make_current(&self) -> Result<(), ContextError> {
self.context.makeCurrentContext(); self.context.makeCurrentContext();
gl::GenFramebuffersEXT(1, &mut framebuffer); gl::GenFramebuffersEXT(1, &mut framebuffer);
@ -78,6 +79,8 @@ impl GlContext for HeadlessContext {
if status != gl::FRAMEBUFFER_COMPLETE_EXT { if status != gl::FRAMEBUFFER_COMPLETE_EXT {
panic!("Error while creating the framebuffer"); panic!("Error while creating the framebuffer");
} }
Ok(())
} }
fn is_current(&self) -> bool { fn is_current(&self) -> bool {
@ -96,7 +99,8 @@ impl GlContext for HeadlessContext {
symbol as *const libc::c_void symbol as *const libc::c_void
} }
fn swap_buffers(&self) { fn swap_buffers(&self) -> Result<(), ContextError> {
Ok(())
} }
fn get_api(&self) -> ::Api { fn get_api(&self) -> ::Api {

View file

@ -8,6 +8,7 @@ use libc;
use Api; use Api;
use BuilderAttribs; use BuilderAttribs;
use ContextError;
use GlContext; use GlContext;
use GlProfile; use GlProfile;
use GlRequest; use GlRequest;
@ -781,9 +782,10 @@ impl Window {
} }
impl GlContext for Window { impl GlContext for Window {
unsafe fn make_current(&self) { unsafe fn make_current(&self) -> Result<(), ContextError> {
let _: () = msg_send![*self.context, update]; let _: () = msg_send![*self.context, update];
self.context.makeCurrentContext(); self.context.makeCurrentContext();
Ok(())
} }
fn is_current(&self) -> bool { fn is_current(&self) -> bool {
@ -810,8 +812,9 @@ impl GlContext for Window {
symbol as *const _ symbol as *const _
} }
fn swap_buffers(&self) { fn swap_buffers(&self) -> Result<(), ContextError> {
unsafe { self.context.flushBuffer(); } unsafe { self.context.flushBuffer(); }
Ok(())
} }
fn get_api(&self) -> ::Api { fn get_api(&self) -> ::Api {

View file

@ -2,6 +2,7 @@
#![allow(unused_variables)] #![allow(unused_variables)]
use BuilderAttribs; use BuilderAttribs;
use ContextError;
use CreationError; use CreationError;
use GlContext; use GlContext;
use GlRequest; use GlRequest;
@ -161,12 +162,19 @@ impl Context {
} }
impl GlContext for Context { impl GlContext for Context {
unsafe fn make_current(&self) { unsafe fn make_current(&self) -> Result<(), ContextError> {
let ret = self.egl.MakeCurrent(self.display, self.surface, self.surface, self.context); let ret = self.egl.MakeCurrent(self.display, self.surface, self.surface, self.context);
if ret == 0 { if ret == 0 {
if self.egl.GetError() as u32 == ffi::egl::CONTEXT_LOST {
return Err(ContextError::ContextLost);
} else {
panic!("eglMakeCurrent failed"); panic!("eglMakeCurrent failed");
} }
} else {
Ok(())
}
} }
fn is_current(&self) -> bool { fn is_current(&self) -> bool {
@ -181,14 +189,21 @@ impl GlContext for Context {
} }
} }
fn swap_buffers(&self) { fn swap_buffers(&self) -> Result<(), ContextError> {
let ret = unsafe { let ret = unsafe {
self.egl.SwapBuffers(self.display, self.surface) self.egl.SwapBuffers(self.display, self.surface)
}; };
if ret == 0 { if ret == 0 {
if unsafe { self.egl.GetError() } as u32 == ffi::egl::CONTEXT_LOST {
return Err(ContextError::ContextLost);
} else {
panic!("eglSwapBuffers failed"); panic!("eglSwapBuffers failed");
} }
} else {
Ok(())
}
} }
fn get_api(&self) -> Api { fn get_api(&self) -> Api {

View file

@ -5,6 +5,7 @@ use libc;
use {Event, BuilderAttribs, CreationError, MouseCursor}; use {Event, BuilderAttribs, CreationError, MouseCursor};
use Api; use Api;
use PixelFormat; use PixelFormat;
use ContextError;
use GlContext; use GlContext;
use std::collections::VecDeque; use std::collections::VecDeque;
@ -191,9 +192,10 @@ impl Window {
} }
impl GlContext for Window { impl GlContext for Window {
unsafe fn make_current(&self) { unsafe fn make_current(&self) -> Result<(), ContextError> {
// TOOD: check if == EMSCRIPTEN_RESULT // TOOD: check if == EMSCRIPTEN_RESULT
ffi::emscripten_webgl_make_context_current(self.context); ffi::emscripten_webgl_make_context_current(self.context);
Ok(())
} }
fn is_current(&self) -> bool { fn is_current(&self) -> bool {
@ -209,10 +211,9 @@ impl GlContext for Window {
} }
} }
fn swap_buffers(&self) { fn swap_buffers(&self) -> Result<(), ContextError> {
unsafe { unsafe { ffi::emscripten_sleep(1); } // FIXME:
ffi::emscripten_sleep(1); // FIXME: Ok(())
}
} }
fn get_api(&self) -> Api { fn get_api(&self) -> Api {

View file

@ -1,6 +1,7 @@
#![cfg(all(target_os = "linux", feature = "window"))] #![cfg(all(target_os = "linux", feature = "window"))]
use BuilderAttribs; use BuilderAttribs;
use ContextError;
use CreationError; use CreationError;
use GlContext; use GlContext;
use GlProfile; use GlProfile;
@ -139,11 +140,13 @@ impl Context {
} }
impl GlContext for Context { impl GlContext for Context {
unsafe fn make_current(&self) { 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); let res = self.glx.MakeCurrent(self.display as *mut _, self.window, self.context);
if res == 0 { if res == 0 {
panic!("glx::MakeCurrent failed"); panic!("glx::MakeCurrent failed");
} }
Ok(())
} }
fn is_current(&self) -> bool { fn is_current(&self) -> bool {
@ -158,10 +161,10 @@ impl GlContext for Context {
} }
} }
fn swap_buffers(&self) { fn swap_buffers(&self) -> Result<(), ContextError> {
unsafe { // TODO: glutin needs some internal changes for proper error recovery
self.glx.SwapBuffers(self.display as *mut _, self.window) unsafe { self.glx.SwapBuffers(self.display as *mut _, self.window); }
} Ok(())
} }
fn get_api(&self) -> ::Api { fn get_api(&self) -> ::Api {

View file

@ -4,6 +4,7 @@ extern crate osmesa_sys;
use Api; use Api;
use BuilderAttribs; use BuilderAttribs;
use ContextError;
use CreationError; use CreationError;
use GlContext; use GlContext;
use PixelFormat; use PixelFormat;
@ -67,14 +68,18 @@ impl OsMesaContext {
} }
impl GlContext for OsMesaContext { impl GlContext for OsMesaContext {
unsafe fn make_current(&self) { unsafe fn make_current(&self) -> Result<(), ContextError> {
let ret = osmesa_sys::OSMesaMakeCurrent(self.context, let ret = osmesa_sys::OSMesaMakeCurrent(self.context, self.buffer.as_ptr()
self.buffer.as_ptr() as *mut libc::c_void, as *mut libc::c_void, 0x1401, self.width
0x1401, self.width as libc::c_int, self.height as libc::c_int); 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 { if ret == 0 {
panic!("OSMesaMakeCurrent failed") panic!("OSMesaMakeCurrent failed");
} }
Ok(())
} }
fn is_current(&self) -> bool { fn is_current(&self) -> bool {
@ -88,7 +93,8 @@ impl GlContext for OsMesaContext {
} }
} }
fn swap_buffers(&self) { fn swap_buffers(&self) -> Result<(), ContextError> {
Ok(())
} }
fn get_api(&self) -> Api { fn get_api(&self) -> Api {

View file

@ -9,6 +9,7 @@ use api::dlopen;
use api::egl::Context as EglContext; use api::egl::Context as EglContext;
use BuilderAttribs; use BuilderAttribs;
use ContextError;
use CreationError; use CreationError;
use Event; use Event;
use PixelFormat; use PixelFormat;
@ -282,8 +283,7 @@ impl Window {
} }
impl GlContext for Window { impl GlContext for Window {
unsafe fn make_current(&self) -> Result<(), ContextError> {
unsafe fn make_current(&self) {
self.context.make_current() self.context.make_current()
} }
@ -295,7 +295,7 @@ impl GlContext for Window {
self.context.get_proc_address(addr) self.context.get_proc_address(addr)
} }
fn swap_buffers(&self) { fn swap_buffers(&self) -> Result<(), ContextError> {
self.context.swap_buffers() self.context.swap_buffers()
} }

View file

@ -1,6 +1,7 @@
#![cfg(any(target_os = "windows"))] #![cfg(any(target_os = "windows"))]
use BuilderAttribs; use BuilderAttribs;
use ContextError;
use CreationError; use CreationError;
use GlContext; use GlContext;
use GlRequest; use GlRequest;
@ -156,9 +157,12 @@ impl Context {
} }
impl GlContext for Context { impl GlContext for Context {
unsafe fn make_current(&self) { unsafe fn make_current(&self) -> Result<(), ContextError> {
// TODO: check return value if gl::wgl::MakeCurrent(self.hdc as *const _, self.context.0 as *const _) != 0 {
gl::wgl::MakeCurrent(self.hdc as *const _, self.context.0 as *const _); Ok(())
} else {
Err(ContextError::IoError(io::Error::last_os_error()))
}
} }
fn is_current(&self) -> bool { fn is_current(&self) -> bool {
@ -176,9 +180,11 @@ impl GlContext for Context {
} }
} }
fn swap_buffers(&self) { fn swap_buffers(&self) -> Result<(), ContextError> {
unsafe { if unsafe { gdi32::SwapBuffers(self.hdc) } != 0 {
gdi32::SwapBuffers(self.hdc); Ok(())
} else {
Err(ContextError::IoError(io::Error::last_os_error()))
} }
} }

View file

@ -11,6 +11,7 @@ use std::sync::{
}; };
use std::sync::mpsc::Receiver; use std::sync::mpsc::Receiver;
use libc; use libc;
use ContextError;
use {CreationError, Event, MouseCursor}; use {CreationError, Event, MouseCursor};
use CursorState; use CursorState;
use GlContext; use GlContext;
@ -315,7 +316,7 @@ impl Window {
} }
impl GlContext for Window { impl GlContext for Window {
unsafe fn make_current(&self) { unsafe fn make_current(&self) -> Result<(), ContextError> {
match self.context { match self.context {
Context::Wgl(ref c) => c.make_current(), Context::Wgl(ref c) => c.make_current(),
Context::Egl(ref c) => c.make_current(), Context::Egl(ref c) => c.make_current(),
@ -336,7 +337,7 @@ impl GlContext for Window {
} }
} }
fn swap_buffers(&self) { fn swap_buffers(&self) -> Result<(), ContextError> {
match self.context { match self.context {
Context::Wgl(ref c) => c.swap_buffers(), Context::Wgl(ref c) => c.swap_buffers(),
Context::Egl(ref c) => c.swap_buffers(), Context::Egl(ref c) => c.swap_buffers(),

View file

@ -9,6 +9,7 @@ use std::collections::VecDeque;
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
use Api; use Api;
use ContextError;
use CursorState; use CursorState;
use GlContext; use GlContext;
use GlRequest; use GlRequest;
@ -800,11 +801,11 @@ impl Window {
} }
impl GlContext for Window { impl GlContext for Window {
unsafe fn make_current(&self) { unsafe fn make_current(&self) -> Result<(), ContextError> {
match self.x.context { match self.x.context {
Context::Glx(ref ctxt) => ctxt.make_current(), Context::Glx(ref ctxt) => ctxt.make_current(),
Context::Egl(ref ctxt) => ctxt.make_current(), Context::Egl(ref ctxt) => ctxt.make_current(),
Context::None => {} Context::None => Ok(())
} }
} }
@ -824,11 +825,11 @@ impl GlContext for Window {
} }
} }
fn swap_buffers(&self) { fn swap_buffers(&self) -> Result<(), ContextError> {
match self.x.context { match self.x.context {
Context::Glx(ref ctxt) => ctxt.swap_buffers(), Context::Glx(ref ctxt) => ctxt.swap_buffers(),
Context::Egl(ref ctxt) => ctxt.swap_buffers(), Context::Egl(ref ctxt) => ctxt.swap_buffers(),
Context::None => {} Context::None => Ok(())
} }
} }

View file

@ -1,5 +1,6 @@
use Api; use Api;
use BuilderAttribs; use BuilderAttribs;
use ContextError;
use CreationError; use CreationError;
use GlRequest; use GlRequest;
use GlContext; use GlContext;
@ -69,7 +70,7 @@ impl HeadlessContext {
/// Creates a new OpenGL context /// Creates a new OpenGL context
/// Sets the context as the current context. /// Sets the context as the current context.
#[inline] #[inline]
pub unsafe fn make_current(&self) { pub unsafe fn make_current(&self) -> Result<(), ContextError> {
self.context.make_current() self.context.make_current()
} }
@ -105,7 +106,7 @@ impl gl_common::GlFunctionsSource for HeadlessContext {
} }
impl GlContext for HeadlessContext { impl GlContext for HeadlessContext {
unsafe fn make_current(&self) { unsafe fn make_current(&self) -> Result<(), ContextError> {
self.context.make_current() self.context.make_current()
} }
@ -117,7 +118,7 @@ impl GlContext for HeadlessContext {
self.context.get_proc_address(addr) self.context.get_proc_address(addr)
} }
fn swap_buffers(&self) { fn swap_buffers(&self) -> Result<(), ContextError> {
self.context.swap_buffers() self.context.swap_buffers()
} }

View file

@ -65,6 +65,8 @@ pub use window::{AvailableMonitorsIter, MonitorID, get_available_monitors, get_p
#[cfg(feature = "window")] #[cfg(feature = "window")]
pub use native_monitor::NativeMonitorId; pub use native_monitor::NativeMonitorId;
use std::io;
mod api; mod api;
mod platform; mod platform;
mod events; mod events;
@ -75,7 +77,7 @@ mod window;
/// Trait that describes objects that have access to an OpenGL context. /// Trait that describes objects that have access to an OpenGL context.
pub trait GlContext { pub trait GlContext {
/// Sets the context as the current context. /// Sets the context as the current context.
unsafe fn make_current(&self); unsafe fn make_current(&self) -> Result<(), ContextError>;
/// Returns true if this context is the current one in this thread. /// Returns true if this context is the current one in this thread.
fn is_current(&self) -> bool; fn is_current(&self) -> bool;
@ -91,7 +93,7 @@ pub trait GlContext {
/// **Warning**: if you enabled vsync, this function will block until the next time 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 /// 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. /// you can't know in advance whether `swap_buffers` will block or not.
fn swap_buffers(&self); fn swap_buffers(&self) -> Result<(), ContextError>;
/// Returns the OpenGL API being used. /// Returns the OpenGL API being used.
fn get_api(&self) -> Api; fn get_api(&self) -> Api;
@ -128,6 +130,13 @@ impl std::error::Error for CreationError {
} }
} }
/// Error that can happen when manipulating an OpenGL context.
#[derive(Debug)]
pub enum ContextError {
IoError(io::Error),
ContextLost,
}
/// All APIs related to OpenGL that you can possibly get while using glutin. /// All APIs related to OpenGL that you can possibly get while using glutin.
#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Api { pub enum Api {

View file

@ -2,6 +2,8 @@
pub use api::android::*; pub use api::android::*;
use ContextError;
pub struct HeadlessContext(i32); pub struct HeadlessContext(i32);
impl HeadlessContext { impl HeadlessContext {
@ -11,7 +13,7 @@ impl HeadlessContext {
} }
/// See the docs in the crate root file. /// See the docs in the crate root file.
pub unsafe fn make_current(&self) { pub unsafe fn make_current(&self) -> Result<(), ContextError> {
unimplemented!() unimplemented!()
} }

View file

@ -1,5 +1,6 @@
#![cfg(target_os = "emscripten")] #![cfg(target_os = "emscripten")]
use ContextError;
use GlContext; use GlContext;
pub use api::emscripten::{Window, WindowProxy, MonitorID, get_available_monitors}; pub use api::emscripten::{Window, WindowProxy, MonitorID, get_available_monitors};
@ -15,7 +16,7 @@ impl HeadlessContext {
} }
impl GlContext for HeadlessContext { impl GlContext for HeadlessContext {
unsafe fn make_current(&self) { unsafe fn make_current(&self) -> Result<(), ContextError> {
self.0.make_current() self.0.make_current()
} }
@ -27,7 +28,7 @@ impl GlContext for HeadlessContext {
self.0.get_proc_address(addr) self.0.get_proc_address(addr)
} }
fn swap_buffers(&self) { fn swap_buffers(&self) -> Result<(), ContextError> {
self.0.swap_buffers() self.0.swap_buffers()
} }

View file

@ -7,6 +7,7 @@ use std::collections::VecDeque;
use std::sync::Arc; use std::sync::Arc;
use BuilderAttribs; use BuilderAttribs;
use ContextError;
use CreationError; use CreationError;
use CursorState; use CursorState;
use Event; use Event;
@ -289,7 +290,7 @@ impl Window {
} }
impl GlContext for Window { impl GlContext for Window {
unsafe fn make_current(&self) { unsafe fn make_current(&self) -> Result<(), ContextError> {
match self { match self {
&Window::X(ref w) => w.make_current(), &Window::X(ref w) => w.make_current(),
&Window::Wayland(ref w) => w.make_current() &Window::Wayland(ref w) => w.make_current()
@ -310,7 +311,7 @@ impl GlContext for Window {
} }
} }
fn swap_buffers(&self) { fn swap_buffers(&self) -> Result<(), ContextError> {
match self { match self {
&Window::X(ref w) => w.swap_buffers(), &Window::X(ref w) => w.swap_buffers(),
&Window::Wayland(ref w) => w.swap_buffers() &Window::Wayland(ref w) => w.swap_buffers()

View file

@ -2,6 +2,7 @@
use Api; use Api;
use BuilderAttribs; use BuilderAttribs;
use ContextError;
use CreationError; use CreationError;
use GlContext; use GlContext;
use PixelFormat; use PixelFormat;
@ -37,7 +38,7 @@ impl HeadlessContext {
impl GlContext for HeadlessContext { impl GlContext for HeadlessContext {
#[inline] #[inline]
unsafe fn make_current(&self) { unsafe fn make_current(&self) -> Result<(), ContextError> {
self.0.make_current() self.0.make_current()
} }
@ -52,7 +53,7 @@ impl GlContext for HeadlessContext {
} }
#[inline] #[inline]
fn swap_buffers(&self) { fn swap_buffers(&self) -> Result<(), ContextError> {
self.0.swap_buffers() self.0.swap_buffers()
} }

View file

@ -6,6 +6,7 @@ use libc;
use Api; use Api;
use BuilderAttribs; use BuilderAttribs;
use ContextError;
use CreationError; use CreationError;
use PixelFormat; use PixelFormat;
use GlContext; use GlContext;
@ -21,7 +22,7 @@ impl HeadlessContext {
} }
impl GlContext for HeadlessContext { impl GlContext for HeadlessContext {
unsafe fn make_current(&self) { unsafe fn make_current(&self) -> Result<(), ContextError> {
self.0.make_current() self.0.make_current()
} }
@ -33,7 +34,7 @@ impl GlContext for HeadlessContext {
self.0.get_proc_address(addr) self.0.get_proc_address(addr)
} }
fn swap_buffers(&self) { fn swap_buffers(&self) -> Result<(), ContextError> {
self.0.swap_buffers() self.0.swap_buffers()
} }

View file

@ -3,6 +3,7 @@ use std::default::Default;
use Api; use Api;
use BuilderAttribs; use BuilderAttribs;
use ContextError;
use CreationError; use CreationError;
use CursorState; use CursorState;
use Event; use Event;
@ -339,7 +340,7 @@ impl Window {
/// Sets the context as the current context. /// Sets the context as the current context.
#[inline] #[inline]
pub unsafe fn make_current(&self) { pub unsafe fn make_current(&self) -> Result<(), ContextError> {
self.window.make_current() self.window.make_current()
} }
@ -366,7 +367,7 @@ impl Window {
/// is refreshed. However drivers can choose to override your vsync settings, which means that /// 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. /// you can't know in advance whether `swap_buffers` will block or not.
#[inline] #[inline]
pub fn swap_buffers(&self) { pub fn swap_buffers(&self) -> Result<(), ContextError> {
self.window.swap_buffers() self.window.swap_buffers()
} }
@ -449,7 +450,7 @@ impl gl_common::GlFunctionsSource for Window {
} }
impl GlContext for Window { impl GlContext for Window {
unsafe fn make_current(&self) { unsafe fn make_current(&self) -> Result<(), ContextError> {
self.make_current() self.make_current()
} }
@ -461,7 +462,7 @@ impl GlContext for Window {
self.get_proc_address(addr) self.get_proc_address(addr)
} }
fn swap_buffers(&self) { fn swap_buffers(&self) -> Result<(), ContextError> {
self.swap_buffers() self.swap_buffers()
} }