pub mod headless;
use crate::egl_ext as ext;
use crate::glerr;
use dma_boom::DmaBuf;
use ext::{KhrImageBaseInstance, OesImageInstance};
use gbm::Format;
use gl::types::GLuint;
pub use khronos_egl;
use khronos_egl as egl;
use std::os::fd::{AsRawFd, AsFd, BorrowedFd, OwnedFd};
use std::ptr;
use thiserror::Error;
#[derive(Copy, Clone, Debug)]
pub struct TextureId(GLuint);
impl TextureId {
pub fn as_gl_id(&self) -> GLuint {
self.0
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct Dimensions {
pub width: u32,
pub height: u32,
}
#[derive(Debug)]
pub struct Texture {
id: TextureId,
dimensions: Dimensions,
format: Format,
}
impl Texture {
pub fn id(&self) ->TextureId {
self.id
}
pub fn dimensions(&self) -> Dimensions {
self.dimensions
}
pub fn format(&self) -> Format {
self.format
}
}
#[derive(Debug)]
pub struct DmabufImage {
texture: TextureId,
image: egl::Image,
dimensions: Dimensions,
format: Format,
}
#[derive(Debug)]
pub struct DmabufTexture {
texture: glium::Texture2d,
image: egl::Image,
dimensions: Dimensions,
format: Format,
}
unsafe impl Send for DmabufImage{}
impl DmabufImage {
pub fn get_texture(&self) ->Texture {
Texture {
id: self.texture,
dimensions: self.dimensions,
format: self.format,
}
}
}
pub type DmabufImageRef = DmabufImage;
#[derive(Debug)]
pub struct OwnedDmabufImage {
dmafd: DmaBuf,
image: DmabufImageRef,
}
impl OwnedDmabufImage {
pub fn get_texture(&self) -> &DmabufImageRef {
&self.image
}
pub fn dmabuf(&self) -> &DmaBuf {
&self.dmafd
}
pub fn fd(&self) -> BorrowedFd {
self.dmafd.as_fd()
}
}
fn format_bpp(fourcc: Format) -> Option<usize> {
match fourcc {
Format::Argb8888 => Some(4),
Format::R8 => Some(1),
Format::R16 => Some(2),
Format::Rg88 => Some(2),
Format::Gr88 => Some(2),
_ => None,
}
}
#[derive(Debug, Error)]
pub enum DmabufImportError {
#[error("This format is TODO")]
UnsupportedPixelFormat,
#[error("EGL call failed")]
EglError(egl::Error),
#[error("OpenGL call failed")]
GlError(crate::glerr::Error),
}
pub unsafe fn import_dmabuf_display(
display: egl::Display,
fd: &DmaBuf,
(width, height): (u32, u32),
fourcc: Format,
) -> Result<DmabufImage, DmabufImportError> {
let egl_calls = egl::Instance::new(egl::Static);
let bytes_per_pixel = format_bpp(fourcc).ok_or(DmabufImportError::UnsupportedPixelFormat)?;
let image = unsafe {
use ext::image_dma_buf_import as ext;
egl_calls.create_image_khr(
display,
egl::Context::from_ptr(egl::NO_CONTEXT),
ext::LINUX_DMA_BUF_EXT,
egl::ClientBuffer::from_ptr(ptr::null_mut()),
&[
egl::WIDTH as _, width as _,
egl::HEIGHT as _, height as _,
ext::LINUX_DRM_FOURCC_EXT, fourcc as _,
ext::DMA_BUF_PLANE0_FD_EXT, fd.as_raw_fd() as _,
ext::DMA_BUF_PLANE0_OFFSET_EXT, 0,
ext::DMA_BUF_PLANE0_PITCH_EXT, (width as egl::Int) * (bytes_per_pixel as egl::Int),
egl::NONE,
],
)
}.map_err(DmabufImportError::EglError)?;
gl::load_with(|s| egl_calls.get_proc_address(s).unwrap() as _);
let texture = {
let mut texture = 0;
glerr::check(unsafe {
gl::GenTextures(1, &mut texture);
texture
})
}.map_err(DmabufImportError::GlError)?;
attach_image_current(DmabufImage {
texture: TextureId(texture),
image,
dimensions: Dimensions { width, height },
format: fourcc,
})
}
unsafe fn attach_image_current(buf: DmabufImage) -> Result<DmabufImage, DmabufImportError> {
let egl_calls = egl::Instance::new(egl::Static);
gl::load_with(|s| egl_calls.get_proc_address(s).unwrap() as _);
glerr::check(unsafe {
gl::BindTexture(gl::TEXTURE_2D, buf.texture.0)
}).map_err(DmabufImportError::GlError)?;
unsafe {
egl_calls.image_target_texture_2d_oes(gl::TEXTURE_2D, buf.image)
}.map_err(DmabufImportError::EglError)?;
Ok(buf)
}