From 8d410d74580501c6ea05519f929fbf85640e51e7 Mon Sep 17 00:00:00 2001 From: CheerfulPianissimo Date: Sat, 27 Jul 2024 18:09:23 +0530 Subject: [PATCH] [feat] get waymirror-egl dmabuf MVP demo working --- Cargo.lock | 7 +- libwayshot/examples/waymirror-egl/Cargo.toml | 5 +- libwayshot/examples/waymirror-egl/src/main.rs | 7 +- .../waymirror-egl/src/shaders/frag.glsl | 5 +- .../waymirror-egl/src/shaders/vert.glsl | 12 +- .../examples/waymirror-egl/src/state.rs | 257 ++++++++++++------ libwayshot/src/lib.rs | 2 +- 7 files changed, 201 insertions(+), 94 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index cbc3c475..ffd3fda3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -567,7 +567,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6aae1df220ece3c0ada96b8153459b67eebe9ae9212258bb0134ae60416fdf76" dependencies = [ "libc", - "pkg-config", + "libloading", ] [[package]] @@ -590,9 +590,9 @@ checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" [[package]] name = "libloading" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c2a198fb6b0eada2a8df47933734e6d35d350665a33a3593d7164fa52c75c19" +checksum = "e310b3a6b5907f99202fcdb4960ff45b93735d7c7d96b760fcff8db2dc0e103d" dependencies = [ "cfg-if", "windows-targets", @@ -1187,6 +1187,7 @@ dependencies = [ "gl", "gl_loader", "khronos-egl", + "libloading", "libwayshot", "thiserror", "tracing", diff --git a/libwayshot/examples/waymirror-egl/Cargo.toml b/libwayshot/examples/waymirror-egl/Cargo.toml index 9dd6fd39..4653f73d 100644 --- a/libwayshot/examples/waymirror-egl/Cargo.toml +++ b/libwayshot/examples/waymirror-egl/Cargo.toml @@ -6,7 +6,7 @@ edition = "2021" [dependencies] gl = "0.14.0" gl_loader = "0.1.2" -khronos-egl = { version = "6.0.0", features = ["static"] } +khronos-egl = { version = "6.0.0",features = ["dynamic"] } thiserror = "1.0.58" tracing = "0.1.40" tracing-subscriber = "0.3.18" @@ -14,4 +14,5 @@ wayland-backend = { version = "0.3.3", features = ["client_system"] } wayland-client = { version = "0.31.2" } wayland-egl = { version = "0.32.0" } wayland-protocols = { version = "0.31.2", features = ["client"] } -libwayshot={path="../.."} \ No newline at end of file +libwayshot={path="../.."} +libloading="0.8.4" \ No newline at end of file diff --git a/libwayshot/examples/waymirror-egl/src/main.rs b/libwayshot/examples/waymirror-egl/src/main.rs index 34aed15b..63e04efb 100644 --- a/libwayshot/examples/waymirror-egl/src/main.rs +++ b/libwayshot/examples/waymirror-egl/src/main.rs @@ -9,7 +9,7 @@ use std::str::FromStr; pub fn main() -> Result<(), Box> { tracing_subscriber::fmt() - .with_max_level(tracing::Level::from_str("trace")?) + .with_max_level(tracing::Level::from_str("error")?) .with_writer(std::io::stderr) .init(); @@ -52,13 +52,14 @@ pub fn main() -> Result<(), Box> { state.init_egl()?; while state.running { event_queue.dispatch_pending(&mut state)?; - + // event_queue.blocking_dispatch(&mut state)?; + // state.dmabuf_to_egl() state.draw(); state .egl .swap_buffers(state.egl_display.unwrap(), state.egl_surface.unwrap())?; - tracing::event!(tracing::Level::DEBUG, "eglSwapBuffers called"); + //tracing::event!(tracing::Level::DEBUG, "eglSwapBuffers called"); } state.deinit()?; diff --git a/libwayshot/examples/waymirror-egl/src/shaders/frag.glsl b/libwayshot/examples/waymirror-egl/src/shaders/frag.glsl index 165f300a..8212a377 100644 --- a/libwayshot/examples/waymirror-egl/src/shaders/frag.glsl +++ b/libwayshot/examples/waymirror-egl/src/shaders/frag.glsl @@ -2,7 +2,10 @@ precision mediump float; out vec4 FragColor; +uniform sampler2D uTexture; +in vec2 vTexCoord; void main() { - FragColor = vec4 ( 1.0, 0.2, 0.0, 1.0 ); + vec4 color = texture(uTexture, vTexCoord); + FragColor = vec4 ( 1.0-color.r,1.0-color.g,1.0-color.b, 1.0 ); } diff --git a/libwayshot/examples/waymirror-egl/src/shaders/vert.glsl b/libwayshot/examples/waymirror-egl/src/shaders/vert.glsl index 7523d9c2..9b27c568 100644 --- a/libwayshot/examples/waymirror-egl/src/shaders/vert.glsl +++ b/libwayshot/examples/waymirror-egl/src/shaders/vert.glsl @@ -1,7 +1,11 @@ #version 300 es +layout (location = 0) in vec3 aPos; +layout (location = 1) in vec2 aTexCoord; -layout(location = 0) in vec3 aPos; +out vec2 vTexCoord; -void main() { - gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0); -} +void main() +{ + gl_Position = vec4(aPos, 1.0); + vTexCoord = vec2(aTexCoord.x, aTexCoord.y); +} \ No newline at end of file diff --git a/libwayshot/examples/waymirror-egl/src/state.rs b/libwayshot/examples/waymirror-egl/src/state.rs index 460109b9..c73b0790 100644 --- a/libwayshot/examples/waymirror-egl/src/state.rs +++ b/libwayshot/examples/waymirror-egl/src/state.rs @@ -3,9 +3,9 @@ use crate::utils::load_shader; use libwayshot::WayshotConnection; -use gl::types::GLuint; -use khronos_egl::{self as egl, Attrib}; -use std::os::fd::AsRawFd; +use gl::types::{GLeglImageOES, GLuint}; +use khronos_egl::{self as egl, Attrib, DynamicInstance, EGLClientBuffer}; +use std::os::fd::{AsRawFd, IntoRawFd}; use std::{ffi::c_void, rc::Rc}; use wayland_client::{ protocol::{wl_compositor, wl_display::WlDisplay, wl_surface::WlSurface}, @@ -25,7 +25,7 @@ pub struct WaylandEGLState { pub wl_display: WlDisplay, pub wl_surface: Option, - pub egl: egl::Instance, + pub egl: egl::DynamicInstance, pub egl_window: Option>, pub egl_display: Option, pub egl_surface: Option, @@ -33,6 +33,7 @@ pub struct WaylandEGLState { pub egl_image: Option, pub gl_program: GLuint, + pub gl_texture: GLuint, pub xdg_wm_base: Option, pub xdg_surface: Option, @@ -46,9 +47,16 @@ impl WaylandEGLState { #[tracing::instrument] pub fn new() -> Result { let server_connection = Connection::connect_to_env()?; + let lib = + unsafe { libloading::Library::new("libEGL.so.1").expect("unable to find libEGL.so.1") }; + let egl = unsafe { + egl::DynamicInstance::::load_required_from(lib) + .expect("unable to load libEGL.so.1") + }; + Ok(Self { - width: 320, - height: 240, + width: 1920, + height: 1080, running: true, title: "Nya".into(), @@ -56,13 +64,14 @@ impl WaylandEGLState { wl_display: server_connection.display(), wl_surface: None, - egl: egl::Instance::new(egl::Static), + egl: egl, egl_window: None, egl_display: None, egl_surface: None, egl_context: None, egl_image: None, gl_program: 0, + gl_texture: 0, xdg_wm_base: None, xdg_surface: None, @@ -120,8 +129,6 @@ impl WaylandEGLState { 8, egl::BLUE_SIZE, 8, - egl::ALPHA_SIZE, - 8, egl::NONE, ]; @@ -129,7 +136,7 @@ impl WaylandEGLState { .egl .choose_first_config(self.egl_display.unwrap(), &attributes)? .expect("unable to find an appropriate EGL configuration"); - + dbg!(config); self.egl_surface = Some(unsafe { self.egl.create_window_surface( self.egl_display.unwrap(), @@ -139,7 +146,7 @@ impl WaylandEGLState { )? }); - let context_attributes = [egl::CONTEXT_CLIENT_VERSION, 2, egl::NONE, egl::NONE]; + let context_attributes = [egl::CONTEXT_CLIENT_VERSION, 2, egl::NONE]; self.egl_context = Some(self.egl.create_context( self.egl_display.unwrap(), config, @@ -155,64 +162,6 @@ impl WaylandEGLState { )?; self.init_program()?; - let (frame_format, _guard, bo) = self - .wayshot - .capture_output_frame_dmabuf(true, &self.wayshot.get_all_outputs()[0].wl_output, None) - .unwrap(); - let modifier: u64 = dbg!(bo.modifier().unwrap().into()); - dbg!(bo.plane_count().unwrap()); - let image_attribs = [ - egl::WIDTH as Attrib, - frame_format.size.width as Attrib, - egl::HEIGHT as Attrib, - frame_format.size.height as Attrib, - 0x3271, //EGL_LINUX_DRM_FOURCC_EXT - bo.format().unwrap() as Attrib, - 0x3272, //EGL_DMA_BUF_PLANE0_FD_EXT - dbg!(bo.fd_for_plane(0).unwrap().as_raw_fd()) as Attrib, - 0x3273, - bo.offset(0).unwrap() as Attrib, - 0x3274, //EGL_DMA_BUF_PLANE0_PITCH_EXT - bo.stride_for_plane(0).unwrap() as Attrib, - 0x3443, //EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT - (modifier as u32) as Attrib, - 0x3444, //EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT - (modifier >> 32) as Attrib, - egl::ATTRIB_NONE, - ]; - dbg!(image_attribs, image_attribs.len()); - unsafe { - let egl_create_image_khr: fn( - display: khronos_egl::EGLDisplay, - ctx: khronos_egl::EGLContext, - target: khronos_egl::Enum, - buffer: khronos_egl::EGLClientBuffer, - attrib_list: *const Attrib, - ) -> khronos_egl::EGLImage = std::mem::transmute(dbg!(self - .egl - .get_proc_address("eglCreateImageKHR") - .unwrap())); - let image = egl_create_image_khr( - self.egl_display.unwrap().as_ptr(), - egl::NO_CONTEXT as *mut c_void, - 0x3270, - std::ptr::null_mut(), - image_attribs.as_ptr(), - ); - dbg!(image, self.egl.get_error().unwrap()); - assert_ne!(image, 0 as *mut c_void); - } - // self.egl_image = Some(unsafe { - // self.egl - // .create_image( - // self.egl_display.unwrap(), - // khronos_egl::Context::from_ptr(egl::NO_CONTEXT), - // 0x3270, // EGL_LINUX_DMA_BUF_EXT - // ClientBuffer::from_ptr(std::ptr::null_mut()), //NULL - // &image_attribs, - // ) - // .unwrap() - // }); Ok(()) } @@ -254,11 +203,13 @@ impl WaylandEGLState { } else { return Err(WaylandEGLStateError::GLLinkProgramFailed); } - let vertices: [gl::types::GLfloat; 12] = [ - 0.9, 0.9, 0.0, // top right - 0.9, -0.9, 0.0, // bottom right - -0.9, -0.9, 0.0, // bottom left - -0.9, 0.9, 0.0, // top left + + let vertices: [gl::types::GLfloat; 20] = [ + // positions // texture coords + 1.0, 1.0, 0.0, 1.0, 0.0, // top right + 1.0, -1.0, 0.0, 1.0, 1.0, // bottom right + -1.0, -1.0, 0.0, 0.0, 1.0, // bottom left + -1.0, 1.0, 0.0, 0.0, 0.0, // top left ]; let indices: [gl::types::GLint; 6] = [ 0, 1, 3, // first Triangle @@ -267,7 +218,12 @@ impl WaylandEGLState { let mut vbo: GLuint = 0; let mut vao: GLuint = 0; let mut ebo: GLuint = 0; + unsafe { + gl::GenTextures(1, &mut self.gl_texture); + + self.dmabuf_to_egl(); + gl::GenVertexArrays(1, &mut vao as *mut u32); gl::GenBuffers(1, &mut vbo as *mut u32); gl::GenBuffers(1, &mut ebo as *mut u32); @@ -297,30 +253,171 @@ impl WaylandEGLState { 3, gl::FLOAT, gl::FALSE, - 3 * std::mem::size_of::() as gl::types::GLint, + 5 * std::mem::size_of::() as gl::types::GLint, 0 as *const c_void, ); gl::EnableVertexAttribArray(0); - gl::BindBuffer(gl::ARRAY_BUFFER, 0); + gl::VertexAttribPointer( + 1, + 2, + gl::FLOAT, + gl::FALSE, + 5 * std::mem::size_of::() as gl::types::GLint, + (3 * std::mem::size_of::()) as *const c_void, + ); + gl::EnableVertexAttribArray(1); + gl::BindBuffer(gl::ARRAY_BUFFER, 0); //gl::BindVertexArray(0); } Ok(()) } - pub fn draw(&self) { + pub fn draw(&mut self) { unsafe { gl::ClearColor(1.0, 1.0, 0.0, 1.0); gl::Clear(gl::COLOR_BUFFER_BIT); - + gl::DeleteTextures(1, &mut self.gl_texture); + self.dmabuf_to_egl(); gl::UseProgram(self.gl_program); - + //gl::BindTexture(gl::TEXTURE_2D, self.gl_texture); //gl::BindVertexArray(1); gl::DrawElements(gl::TRIANGLES, 6, gl::UNSIGNED_INT, 0 as *const c_void); - dbg!(gl::GetError()); } } + pub fn dmabuf_to_egl(&self) { + type Attrib = egl::Attrib; + let (frame_format, guard, bo) = self + .wayshot + .capture_output_frame_dmabuf(true, &self.wayshot.get_all_outputs()[0].wl_output, None) + .unwrap(); + self.egl_window.as_ref().unwrap().resize( + frame_format.size.width as i32, + frame_format.size.height as i32, + 0, + 0, + ); + unsafe { + gl::Viewport( + 0, + 0, + frame_format.size.width as i32, + frame_format.size.height as i32, + ) + }; + // let modifier: u64 = dbg!(bo.modifier().unwrap().into()); + // dbg!(bo.plane_count().unwrap()); + let image_attribs = [ + egl::WIDTH as Attrib, + frame_format.size.width as Attrib, + egl::HEIGHT as Attrib, + frame_format.size.height as Attrib, + 0x3271, //EGL_LINUX_DRM_FOURCC_EXT + bo.format().unwrap() as Attrib, + 0x3272, //EGL_DMA_BUF_PLANE0_FD_EXT + bo.fd_for_plane(0).unwrap().into_raw_fd() as Attrib, + 0x3273, //EGL_DMA_BUF_PLANE0_OFFSET_EXT + bo.offset(0).unwrap() as Attrib, + 0x3274, //EGL_DMA_BUF_PLANE0_PITCH_EXT + bo.stride_for_plane(0).unwrap() as Attrib, + // 0x3443, //EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT + // (modifier as u32) as Attrib, + // 0x3444, //EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT + // (modifier >> 32) as Attrib, + egl::ATTRIB_NONE as Attrib, + ]; + + // self.wl_surface + // .as_ref() + // .unwrap() + // .attach(Some(&guard.buffer), 0, 0); + // self.wl_surface.as_ref().unwrap().commit(); + // let wlbuf = guard.buffer.id().as_ptr(); + // dbg!(image_attribs, image_attribs.len()); + unsafe { + // let egl_create_image_khr: unsafe extern "system" fn( + // display: khronos_egl::EGLDisplay, + // ctx: khronos_egl::EGLContext, + // target: khronos_egl::Enum, + // buffer: khronos_egl::EGLClientBuffer, + // attrib_list: *const Attrib, + // ) + // -> khronos_egl::EGLImage = + // std::mem::transmute(dbg!(self.egl.get_proc_address("eglCreateImage").unwrap())); + // let image = egl_create_image_khr( + // self.egl_display.unwrap().as_ptr(), + // egl::NO_CONTEXT, + // 0x3270, + // std::ptr::null_mut() as EGLClientBuffer, + // image_attribs.as_ptr(), + // ); + let image = self + .egl + .create_image( + self.egl_display.unwrap(), + khronos_egl::Context::from_ptr(egl::NO_CONTEXT), + 0x3270, // EGL_LINUX_DMA_BUF_EXT + khronos_egl::ClientBuffer::from_ptr(std::ptr::null_mut()), //NULL + &image_attribs, + ) + .unwrap(); + //dbg!(image, self.egl.get_error()); + let gl_egl_image_texture_target_2d_oes: unsafe extern "system" fn( + target: gl::types::GLenum, + image: GLeglImageOES, + ) -> () = std::mem::transmute( + self.egl + .get_proc_address("glEGLImageTargetTexture2DOES") + .unwrap(), + ); + + gl::BindTexture(gl::TEXTURE_2D, self.gl_texture); + gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, gl::LINEAR as i32); + gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, gl::LINEAR as i32); + + gl_egl_image_texture_target_2d_oes(gl::TEXTURE_2D, image.as_ptr()); + self.egl + .destroy_image(self.egl_display.unwrap(), image) + .unwrap(); + + // let image_wl_attribs = [ + // 0x31D6 as Attrib, //EGL_WAYLAND_PLANE_WL + // 0 as Attrib, + // egl::ATTRIB_NONE as Attrib, + // ]; + // let image = egl_create_image_khr( + // self.egl_display.unwrap().as_ptr(), + // egl::NO_CONTEXT as *mut c_void, + // 0x31D5, //EGL_WAYLAND_BUFFER_WL, + // wlbuf as *mut c_void, + // image_wl_attribs.as_ptr(), + // ); + // dbg!(image, self.egl.get_error()); + //assert_ne!(image, 0 as *mut c_void); + // self.egl + // .create_image( + // self.egl_display.unwrap(), + // khronos_egl::Context::from_ptr(egl::NO_CONTEXT), + // 0x31D5, //EGL_WAYLAND_BUFFER_WL, + // khronos_egl::ClientBuffer::from_ptr(wlbuf.display_ptr() as *mut c_void), //NULL + // &image_wl_attribs, + // ) + // .unwrap(); + } + // self.egl_image = Some(unsafe { + // self.egl + // .create_image( + // self.egl_display.unwrap(), + // khronos_egl::Context::from_ptr(egl::NO_CONTEXT), + // 0x3270, // EGL_LINUX_DMA_BUF_EXT + // ClientBuffer::from_ptr(std::ptr::null_mut()), //NULL + // &image_attribs, + // ) + // .unwrap() + // }); + } + pub fn validate_globals(&self) -> Result<()> { if self.xdg_wm_base.is_none() { return Err(WaylandEGLStateError::XdgWmBaseMissing); diff --git a/libwayshot/src/lib.rs b/libwayshot/src/lib.rs index 2797fb6b..9fc6c86d 100644 --- a/libwayshot/src/lib.rs +++ b/libwayshot/src/lib.rs @@ -280,7 +280,7 @@ impl WayshotConnection { frame_format, stride, modifier, - bo.fd()?, + bo.fd_for_plane(0)?, )?; Ok((frame_format, frame_guard, bo))