use super::super::context::{egl_ext, Egl, GlContext};
use super::super::dma_import::DmaImportAttrs;
use super::super::EglDisplayKind;
use super::GlPlatform;
use edgefirst_tensor::{PixelFormat, Tensor};
use khronos_egl as egl;
use std::rc::Rc;
pub(in crate::opengl_headless) struct EglImage {
pub(in crate::opengl_headless) egl_image: egl::Image,
pub(in crate::opengl_headless) egl: Rc<Egl>,
pub(in crate::opengl_headless) display: egl::Display,
}
impl Drop for EglImage {
fn drop(&mut self) {
if self.egl_image.as_ptr() == egl::NO_IMAGE {
return;
}
let _ = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
let _image_guard = super::super::context::image_lifecycle_guard();
let e =
GlContext::egl_destroy_image_with_fallback(&self.egl, self.display, self.egl_image);
if let Err(e) = e {
log::error!("Could not destroy EGL image: {e:?}");
}
}));
}
}
pub(crate) struct LinuxEgl;
impl GlPlatform for LinuxEgl {
type Display = GlContext;
type Import = EglImage;
type ImportHandle = egl::Image;
const PERSISTENT_TEX_BINDINGS: bool = true;
const EXTERNAL_OES: bool = true;
fn init_display(kind: Option<EglDisplayKind>) -> crate::Result<GlContext> {
GlContext::new(kind)
}
fn load_gl_once(display: &GlContext) {
static GL_LOADED: std::sync::OnceLock<()> = std::sync::OnceLock::new();
GL_LOADED.get_or_init(|| {
gls::load_with(|s| {
display
.egl
.get_proc_address(s)
.map_or(std::ptr::null(), |p| p as *const _)
});
});
}
fn import_handle(import: &EglImage) -> egl::Image {
import.egl_image
}
unsafe fn attach_tex_image_2d(_display: &GlContext, handle: egl::Image) -> crate::Result<()> {
gls::gl::EGLImageTargetTexture2DOES(gls::gl::TEXTURE_2D, handle.as_ptr());
Ok(())
}
unsafe fn attach_tex_image_external(
_display: &GlContext,
handle: egl::Image,
) -> crate::Result<()> {
gls::egl_image_target_texture_2d_oes(gls::gl::TEXTURE_EXTERNAL_OES, handle.as_ptr());
Ok(())
}
unsafe fn attach_renderbuffer_storage(
_display: &GlContext,
handle: egl::Image,
) -> crate::Result<()> {
gls::gl::EGLImageTargetRenderbufferStorageOES(gls::gl::RENDERBUFFER, handle.as_ptr());
Ok(())
}
fn end_gpu_pass(_display: &GlContext) {
}
fn import_buffer_packed<T>(
display: &GlContext,
img: &Tensor<T>,
width: usize,
height: usize,
fmt: super::PackedImportFormat,
) -> crate::Result<EglImage>
where
T: num_traits::Num + Clone + std::fmt::Debug + Send + Sync,
{
use std::os::fd::AsRawFd;
let drm_format = match fmt {
super::PackedImportFormat::Rgba8888 => drm_fourcc::DrmFourcc::Abgr8888,
super::PackedImportFormat::Rgba16161616F => drm_fourcc::DrmFourcc::Abgr16161616f,
};
let bpp = fmt.bytes_per_pixel();
let dma = img.as_dma().ok_or_else(|| {
crate::Error::NotImplemented("import_buffer_packed requires DMA tensor".to_string())
})?;
let fd = dma.fd.as_raw_fd();
let pitch = img.effective_row_stride().unwrap_or(width * bpp);
let offset = img.plane_offset().unwrap_or(0);
let egl_img_attr = [
egl_ext::LINUX_DRM_FOURCC as egl::Attrib,
drm_format as u32 as egl::Attrib,
khronos_egl::WIDTH as egl::Attrib,
width as egl::Attrib,
khronos_egl::HEIGHT as egl::Attrib,
height as egl::Attrib,
egl_ext::DMA_BUF_PLANE0_PITCH as egl::Attrib,
pitch as egl::Attrib,
egl_ext::DMA_BUF_PLANE0_OFFSET as egl::Attrib,
offset as egl::Attrib,
egl_ext::DMA_BUF_PLANE0_FD as egl::Attrib,
fd as egl::Attrib,
egl::IMAGE_PRESERVED as egl::Attrib,
egl::TRUE as egl::Attrib,
khronos_egl::NONE as egl::Attrib,
];
new_egl_image_owned(display, egl_ext::LINUX_DMA_BUF, &egl_img_attr)
}
fn import_buffer(
display: &GlContext,
img: &Tensor<u8>,
fmt: PixelFormat,
for_dst: bool,
) -> crate::Result<EglImage> {
let attrs = DmaImportAttrs::from_tensor(img, fmt, for_dst)?;
new_egl_image_owned(display, egl_ext::LINUX_DMA_BUF, &attrs.to_egl_attribs())
}
fn import_buffer_nv_r8(
display: &GlContext,
img: &Tensor<u8>,
fmt: PixelFormat,
) -> crate::Result<EglImage> {
let attrs = DmaImportAttrs::from_tensor_nv_r8(img, fmt)?;
new_egl_image_owned(display, egl_ext::LINUX_DMA_BUF, &attrs.to_egl_attribs())
}
}
pub(in crate::opengl_headless) fn new_egl_image_owned(
display: &GlContext,
target: egl::Enum,
attrib_list: &[egl::Attrib],
) -> crate::Result<EglImage> {
let _span = tracing::trace_span!("image.convert.gl.egl_import", target).entered();
let _image_guard = super::super::context::image_lifecycle_guard();
let image = GlContext::egl_create_image_with_fallback(
&display.egl,
display.display,
unsafe { egl::Context::from_ptr(egl::NO_CONTEXT) },
target,
unsafe { egl::ClientBuffer::from_ptr(std::ptr::null_mut()) },
attrib_list,
)?;
Ok(EglImage {
egl_image: image,
display: display.display,
egl: Rc::clone(&display.egl),
})
}