use { crate::render::{ egl::{ display::EglDisplay, sys::{eglDestroyContext, eglMakeCurrent, EGLContext, EGLSurface, EGL_FALSE, EGL_TRUE}, PROCS, }, ext::{DisplayExt, GlExt}, sys::{ GL_GUILTY_CONTEXT_RESET_ARB, GL_INNOCENT_CONTEXT_RESET_ARB, GL_UNKNOWN_CONTEXT_RESET_ARB, }, RenderError, ResetStatus, }, std::rc::Rc, }; #[derive(Debug, Clone)] pub struct EglContext { pub dpy: Rc, pub ext: GlExt, pub ctx: EGLContext, } impl Drop for EglContext { fn drop(&mut self) { unsafe { if eglDestroyContext(self.dpy.dpy, self.ctx) != EGL_TRUE { log::warn!("`eglDestroyContext` failed"); } } } } #[thread_local] static mut CURRENT: EGLContext = EGLContext::none(); impl EglContext { pub fn reset_status(&self) -> Option { if !self .dpy .exts .contains(DisplayExt::EXT_CREATE_CONTEXT_ROBUSTNESS) { return None; } let status = self.with_current(|| unsafe { let status = match PROCS.glGetGraphicsResetStatusKHR() { 0 => return Ok(None), GL_GUILTY_CONTEXT_RESET_ARB => ResetStatus::Guilty, GL_INNOCENT_CONTEXT_RESET_ARB => ResetStatus::Innocent, GL_UNKNOWN_CONTEXT_RESET_ARB => ResetStatus::Unknown, n => ResetStatus::Other(n), }; Ok(Some(status)) }); status.unwrap_or_default() } #[inline] pub fn with_current Result>( &self, f: F, ) -> Result { unsafe { if CURRENT == self.ctx { return f(); } self.with_current_slow(f) } } #[cold] unsafe fn with_current_slow Result>( &self, f: F, ) -> Result { if eglMakeCurrent( self.dpy.dpy, EGLSurface::none(), EGLSurface::none(), self.ctx, ) == EGL_FALSE { return Err(RenderError::MakeCurrent); } let prev = CURRENT; CURRENT = self.ctx; let res = f(); if eglMakeCurrent(self.dpy.dpy, EGLSurface::none(), EGLSurface::none(), prev) == EGL_FALSE { panic!("Could not restore EGLContext"); } CURRENT = prev; res } }