jay-compositor 1.15.0

The Jay compositor
use crate::format::Format;
use crate::gfx_api::AsyncShmGfxTexture;
use crate::gfx_api::AsyncShmGfxTextureCallback;
use crate::gfx_api::GfxError;
use crate::gfx_api::GfxStagingBuffer;
use crate::gfx_api::GfxTexture;
use crate::gfx_api::PendingShmTransfer;
use crate::gfx_api::ShmGfxTexture;
use crate::gfx_api::ShmMemory;
use crate::gfx_apis::gl::RenderError;
use crate::gfx_apis::gl::gl::texture::GlTexture;
use crate::gfx_apis::gl::renderer::context::GlRenderContext;
use crate::gfx_apis::gl::sys::GL_CLAMP_TO_EDGE;
use crate::gfx_apis::gl::sys::GL_TEXTURE_2D;
use crate::gfx_apis::gl::sys::GL_TEXTURE_WRAP_S;
use crate::gfx_apis::gl::sys::GL_TEXTURE_WRAP_T;
use crate::gfx_apis::gl::sys::GL_UNPACK_ROW_LENGTH_EXT;
use crate::gfx_apis::gl::sys::GLint;
use crate::rect::Region;
use crate::video::dmabuf::DmaBuf;
use std::cell::Cell;
use std::fmt::Debug;
use std::fmt::Formatter;
use std::rc::Rc;

pub struct Texture {
    pub(in crate::gfx_apis::gl) ctx: Rc<GlRenderContext>,
    pub(in crate::gfx_apis::gl) gl: GlTexture,
    pub(in crate::gfx_apis::gl) format: &'static Format,
}

impl Debug for Texture {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("Texture").finish_non_exhaustive()
    }
}

impl Texture {
    fn width(&self) -> i32 {
        self.gl.width
    }

    fn height(&self) -> i32 {
        self.gl.height
    }
}

impl GfxTexture for Texture {
    fn size(&self) -> (i32, i32) {
        (self.width(), self.height())
    }

    fn dmabuf(&self) -> Option<&Rc<DmaBuf>> {
        self.gl.img.as_ref().map(|i| &i.dmabuf)
    }

    fn format(&self) -> &'static Format {
        self.format
    }
}

impl ShmGfxTexture for Texture {}

impl AsyncShmGfxTexture for Texture {
    fn async_upload(
        self: Rc<Self>,
        _staging: &Rc<dyn GfxStagingBuffer>,
        _callback: Rc<dyn AsyncShmGfxTextureCallback>,
        mem: Rc<dyn ShmMemory>,
        _damage: Region,
    ) -> Result<Option<PendingShmTransfer>, GfxError> {
        let mut res = Ok(());
        mem.access(&mut |data| {
            res = self.clone().sync_upload(data, Region::default());
        })
        .map_err(RenderError::AccessFailed)?;
        res.map(|_| None)
    }

    fn sync_upload(self: Rc<Self>, data: &[Cell<u8>], _damage: Region) -> Result<(), GfxError> {
        let shm_info = self.format.shm_info.as_ref().unwrap();
        if (self.gl.stride * self.gl.height) as usize > data.len() {
            return Err(RenderError::SmallImageBuffer.into());
        }
        let gles = self.ctx.ctx.dpy.gles;
        self.ctx.ctx.with_current(|| unsafe {
            (gles.glBindTexture)(GL_TEXTURE_2D, self.gl.tex);
            (gles.glTexParameteri)(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
            (gles.glTexParameteri)(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
            (gles.glPixelStorei)(
                GL_UNPACK_ROW_LENGTH_EXT,
                self.gl.stride / self.format.bpp as GLint,
            );
            (gles.glTexImage2D)(
                GL_TEXTURE_2D,
                0,
                shm_info.gl_format,
                self.gl.width,
                self.gl.height,
                0,
                shm_info.gl_format as _,
                shm_info.gl_type as _,
                data.as_ptr() as _,
            );
            (gles.glPixelStorei)(GL_UNPACK_ROW_LENGTH_EXT, 0);
            (gles.glBindTexture)(GL_TEXTURE_2D, 0);
            Ok(())
        })?;
        self.gl.contents_valid.set(true);
        Ok(())
    }

    fn compatible_with(
        &self,
        format: &'static Format,
        width: i32,
        height: i32,
        stride: i32,
    ) -> bool {
        format == self.gl.format
            && width == self.gl.width
            && height == self.gl.height
            && stride == self.gl.stride
    }
}