native/desktop-linux/src/linux/rendering_egl.rs (86 lines of code) (raw):
use anyhow::Context;
use khronos_egl as egl;
use log::{debug, info};
use smithay_client_toolkit::reexports::client::{
Proxy as _,
protocol::{wl_display::WlDisplay, wl_surface::WlSurface},
};
use wayland_egl::WlEglSurface;
use crate::linux::{application_state::EglInstance, events::SoftwareDrawData, geometry::PhysicalSize};
#[derive(Debug)]
pub struct EglRendering<'a> {
egl: &'a EglInstance,
wl_egl_surface: WlEglSurface,
egl_display: egl::Display,
egl_window_surface: khronos_egl::Surface,
egl_context: egl::Context,
}
impl Drop for EglRendering<'_> {
fn drop(&mut self) {
debug!("EglRendering::drop");
self.egl.destroy_context(self.egl_display, self.egl_context).unwrap();
self.egl.destroy_surface(self.egl_display, self.egl_window_surface).unwrap();
}
}
impl<'a> EglRendering<'a> {
pub fn new(egl: &'a EglInstance, display: &WlDisplay, surface: &WlSurface, size: PhysicalSize) -> anyhow::Result<Self> {
info!("Trying to use EGL rendering for {}", surface.id());
let wl_egl_surface = WlEglSurface::new(surface.id(), size.width.0, size.height.0)
.with_context(|| format!("WlEglSurface::new (surface.id() = {})", surface.id()))?;
let wayland_display_ptr = display.id().as_ptr();
let egl_display = unsafe { egl.get_display(wayland_display_ptr.cast()) }.context("egl.get_display")?;
egl.initialize(egl_display).context("egl.initialize")?;
let egl_attributes = [
egl::RED_SIZE,
8,
egl::GREEN_SIZE,
8,
egl::BLUE_SIZE,
8,
egl::ALPHA_SIZE,
8,
egl::NONE,
];
let egl_config = egl
.choose_first_config(egl_display, &egl_attributes)?
.context("unable to find an appropriate ELG configuration")?;
let egl_context_attributes = [egl::CONTEXT_MAJOR_VERSION, 3, egl::CONTEXT_MINOR_VERSION, 0, egl::NONE];
let egl_context = egl
.create_context(egl_display, egl_config, None, &egl_context_attributes)
.context("egl.create_context")?;
let egl_window_surface = unsafe { egl.create_window_surface(egl_display, egl_config, wl_egl_surface.ptr().cast_mut(), None) }
.with_context(|| format!("egl.create_window_surface, surface.id()={}", surface.id()))?;
egl.make_current(egl_display, Some(egl_window_surface), Some(egl_window_surface), Some(egl_context))
.context("egl.make_current")?;
Ok(Self {
egl,
wl_egl_surface,
egl_display,
egl_window_surface,
egl_context,
})
}
pub fn resize(&self, size: PhysicalSize) {
self.wl_egl_surface.resize(size.width.0, size.height.0, 0, 0);
}
pub fn draw<F>(&self, surface: &WlSurface, do_draw: F)
where
F: FnOnce(SoftwareDrawData) -> bool,
{
self.egl
.make_current(
self.egl_display,
Some(self.egl_window_surface),
Some(self.egl_window_surface),
Some(self.egl_context),
)
.context("egl.make_current")
.unwrap();
if do_draw(SoftwareDrawData::default()) {
self.egl
.swap_buffers(self.egl_display, self.egl_window_surface)
.context(surface.id())
.unwrap();
}
}
}