use anyhow::{Context, Result};
use std::ffi::c_void;
pub struct EglGlContext {
pub egl: khronos_egl::DynamicInstance<khronos_egl::EGL1_5>,
pub display: khronos_egl::Display,
pub context: khronos_egl::Context,
pub surface: khronos_egl::Surface,
pub config: khronos_egl::Config,
}
impl EglGlContext {
pub unsafe fn new(native_display: *mut c_void, native_window: *mut c_void) -> Result<Self> {
let egl_lib =
unsafe { libloading::Library::new("libEGL.so.1") }.context("loading libEGL.so.1")?;
let egl = unsafe {
khronos_egl::DynamicInstance::<khronos_egl::EGL1_5>::load_required_from(egl_lib)
}
.context("initializing EGL dynamic instance")?;
let display = unsafe { egl.get_display(native_display) }
.ok_or_else(|| anyhow::anyhow!("eglGetDisplay returned no display"))?;
egl.initialize(display).context("eglInitialize")?;
egl.bind_api(khronos_egl::OPENGL_ES_API)
.context("eglBindAPI(EGL_OPENGL_ES_API)")?;
let config_attributes = [
khronos_egl::SURFACE_TYPE,
khronos_egl::WINDOW_BIT,
khronos_egl::RED_SIZE,
8,
khronos_egl::GREEN_SIZE,
8,
khronos_egl::BLUE_SIZE,
8,
khronos_egl::ALPHA_SIZE,
8,
khronos_egl::RENDERABLE_TYPE,
khronos_egl::OPENGL_ES2_BIT,
khronos_egl::NONE,
];
let config = egl
.choose_first_config(display, &config_attributes)
.context("eglChooseConfig")?
.ok_or_else(|| anyhow::anyhow!("no suitable EGL config found"))?;
let context_attributes = [khronos_egl::CONTEXT_CLIENT_VERSION, 2, khronos_egl::NONE];
let context = egl
.create_context(display, config, None, &context_attributes)
.context("eglCreateContext")?;
let surface = unsafe { egl.create_window_surface(display, config, native_window, None) }
.context("eglCreateWindowSurface")?;
egl.make_current(display, Some(surface), Some(surface), Some(context))
.context("eglMakeCurrent")?;
Ok(Self {
egl,
display,
context,
surface,
config,
})
}
pub fn swap_buffers(&self) -> Result<()> {
self.egl
.swap_buffers(self.display, self.surface)
.context("eglSwapBuffers")
}
}
impl Drop for EglGlContext {
fn drop(&mut self) {
let _ = self.egl.make_current(self.display, None, None, None);
let _ = self.egl.destroy_surface(self.display, self.surface);
let _ = self.egl.destroy_context(self.display, self.context);
let _ = self.egl.terminate(self.display);
}
}