From 0a0caf38007c6a30653c7356020974785998fdcd Mon Sep 17 00:00:00 2001 From: Julian Orth Date: Sat, 7 Sep 2024 21:35:21 +0200 Subject: [PATCH] opengl: implement AsyncShmGfxTexture --- src/gfx_api.rs | 3 +- src/gfx_apis/gl.rs | 7 +++ src/gfx_apis/gl/gl/texture.rs | 6 +++ src/gfx_apis/gl/renderer/context.rs | 29 +++++++++-- src/gfx_apis/gl/renderer/texture.rs | 74 ++++++++++++++++++++++++++++- 5 files changed, 111 insertions(+), 8 deletions(-) diff --git a/src/gfx_api.rs b/src/gfx_api.rs index e0c4c28e..a3556206 100644 --- a/src/gfx_api.rs +++ b/src/gfx_api.rs @@ -537,8 +537,8 @@ pub trait ShmGfxTexture: GfxTexture { fn into_texture(self: Rc) -> Rc; } -#[expect(dead_code)] pub trait AsyncShmGfxTextureCallback { + #[expect(dead_code)] fn completed(self: Rc, res: Result<(), GfxError>); } @@ -560,7 +560,6 @@ pub trait AsyncShmGfxTexture: GfxTexture { damage: Region, ) -> Result, GfxError>; - #[expect(dead_code)] fn sync_upload(self: Rc, shm: &[Cell], damage: Region) -> Result<(), GfxError>; #[expect(dead_code)] diff --git a/src/gfx_apis/gl.rs b/src/gfx_apis/gl.rs index d8b96c05..22d2a511 100644 --- a/src/gfx_apis/gl.rs +++ b/src/gfx_apis/gl.rs @@ -67,6 +67,7 @@ macro_rules! dynload { use { crate::{ + clientmem::ClientMemError, gfx_api::{ AcquireSync, CopyTexture, FillRect, GfxApiOpt, GfxContext, GfxError, GfxTexture, ReleaseSync, SyncFile, @@ -196,6 +197,8 @@ enum RenderError { WaitSync, #[error("Buffer format {0} is not supported for shm buffers in OpenGL context")] UnsupportedShmFormat(&'static str), + #[error("Could not access the client memory")] + AccessFailed(#[source] ClientMemError), } #[derive(Default)] @@ -318,6 +321,10 @@ fn fill_boxes3(ctx: &GlRenderContext, boxes: &[[f32; 2]], color: &Color) { fn render_texture(ctx: &GlRenderContext, tex: &CopyTexture) { let texture = tex.tex.as_gl(); + if !texture.gl.contents_valid.get() { + log::error!("Ignoring texture with invalid contents"); + return; + } assert!(rc_eq(&ctx.ctx, &texture.ctx.ctx)); let gles = ctx.ctx.dpy.gles; unsafe { diff --git a/src/gfx_apis/gl/gl/texture.rs b/src/gfx_apis/gl/gl/texture.rs index c1c5e943..d6ab3e02 100644 --- a/src/gfx_apis/gl/gl/texture.rs +++ b/src/gfx_apis/gl/gl/texture.rs @@ -21,8 +21,10 @@ pub struct GlTexture { pub tex: GLuint, pub width: i32, pub height: i32, + pub stride: i32, pub external_only: bool, pub format: &'static Format, + pub contents_valid: Cell, } pub fn image_target(external_only: bool) -> GLenum { @@ -60,8 +62,10 @@ impl GlTexture { tex, width: img.dmabuf.width, height: img.dmabuf.height, + stride: 0, external_only: img.external_only, format: img.dmabuf.format, + contents_valid: Cell::new(true), }) } @@ -108,8 +112,10 @@ impl GlTexture { tex, width, height, + stride, external_only: false, format, + contents_valid: Cell::new(true), }) } } diff --git a/src/gfx_apis/gl/renderer/context.rs b/src/gfx_apis/gl/renderer/context.rs index 8ff76a27..f242800c 100644 --- a/src/gfx_apis/gl/renderer/context.rs +++ b/src/gfx_apis/gl/renderer/context.rs @@ -282,13 +282,32 @@ impl GfxContext for GlRenderContext { fn async_shmem_texture( self: Rc, - _format: &'static Format, - _width: i32, - _height: i32, - _stride: i32, + format: &'static Format, + width: i32, + height: i32, + stride: i32, _cpu_worker: &Rc, ) -> Result, GfxError> { - todo!() + let tex = self.ctx.with_current(|| unsafe { + let mut tex = 0; + (self.ctx.dpy.gles.glGenTextures)(1, &mut tex); + Ok(tex) + })?; + Ok(Rc::new(Texture { + gl: GlTexture { + ctx: self.ctx.clone(), + img: None, + tex, + width, + height, + stride, + external_only: false, + format, + contents_valid: Cell::new(false), + }, + ctx: self, + format, + })) } fn allocator(&self) -> Rc { diff --git a/src/gfx_apis/gl/renderer/texture.rs b/src/gfx_apis/gl/renderer/texture.rs index e4a97575..efa45b84 100644 --- a/src/gfx_apis/gl/renderer/texture.rs +++ b/src/gfx_apis/gl/renderer/texture.rs @@ -1,12 +1,21 @@ use { crate::{ + clientmem::ClientMemOffset, format::Format, - gfx_api::{GfxError, GfxTexture, ShmGfxTexture}, + gfx_api::{ + AsyncShmGfxTexture, AsyncShmGfxTextureCallback, GfxError, GfxTexture, PendingShmUpload, + ShmGfxTexture, + }, gfx_apis::gl::{ gl::texture::GlTexture, renderer::{context::GlRenderContext, framebuffer::Framebuffer}, + sys::{ + GLint, GL_CLAMP_TO_EDGE, GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_TEXTURE_WRAP_T, + GL_UNPACK_ROW_LENGTH_EXT, + }, RenderError, }, + rect::Region, video::dmabuf::DmaBuf, }, std::{ @@ -88,3 +97,66 @@ impl ShmGfxTexture for Texture { self } } + +impl AsyncShmGfxTexture for Texture { + fn async_upload( + self: Rc, + _callback: Rc, + mem: &Rc, + damage: Region, + ) -> Result, GfxError> { + mem.access(|data| self.clone().sync_upload(data, damage)) + .map_err(RenderError::AccessFailed)??; + Ok(None) + } + + fn sync_upload(self: Rc, data: &[Cell], _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 / shm_info.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 + } + + fn into_texture(self: Rc) -> Rc { + self + } +}