diff --git a/Cargo.lock b/Cargo.lock index 76982098..3c7c813b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -322,6 +322,12 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + [[package]] name = "errno" version = "0.3.5" @@ -386,6 +392,12 @@ version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0" +[[package]] +name = "hashbrown" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f93e7192158dbcda357bdec5fb5788eebf8bbac027f3f33e719d29135ae84156" + [[package]] name = "heck" version = "0.4.1" @@ -421,6 +433,16 @@ dependencies = [ "cc", ] +[[package]] +name = "indexmap" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" +dependencies = [ + "equivalent", + "hashbrown", +] + [[package]] name = "isnt" version = "0.1.0" @@ -447,6 +469,7 @@ dependencies = [ "dirs", "futures-util", "humantime", + "indexmap", "isnt", "jay-config", "libloading", diff --git a/Cargo.toml b/Cargo.toml index 484b2ef7..c2f2e8d2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -42,6 +42,7 @@ backtrace = "0.3.64" chrono = "0.4.19" parking_lot = "0.12.1" arrayvec = "0.7.4" +indexmap = "2.1.0" [build-dependencies] repc = "0.1.1" diff --git a/src/drm_feedback.rs b/src/drm_feedback.rs index 4f54a608..7eb8bdb3 100644 --- a/src/drm_feedback.rs +++ b/src/drm_feedback.rs @@ -42,7 +42,7 @@ impl DrmFeedback { fn create_fd_data(ctx: &dyn GfxContext) -> Vec { let mut vec = vec![]; for (format, info) in &*ctx.formats() { - for modifier in info.modifiers.keys() { + for modifier in &info.modifiers { vec.write_u32::(*format).unwrap(); vec.write_u32::(0).unwrap(); vec.write_u64::(*modifier).unwrap(); diff --git a/src/gfx_api.rs b/src/gfx_api.rs index ef25cad3..2de46e62 100644 --- a/src/gfx_api.rs +++ b/src/gfx_api.rs @@ -9,9 +9,10 @@ use { state::State, theme::Color, tree::Node, - video::{dmabuf::DmaBuf, gbm::GbmDevice}, + video::{dmabuf::DmaBuf, gbm::GbmDevice, Modifier}, }, ahash::AHashMap, + indexmap::IndexSet, std::{ any::Any, cell::Cell, @@ -277,8 +278,6 @@ pub trait GfxTexture: Debug { pub trait GfxContext: Debug { fn reset_status(&self) -> Option; - fn supports_external_texture(&self) -> bool; - fn render_node(&self) -> Rc; fn formats(&self) -> Rc>; @@ -302,14 +301,7 @@ pub trait GfxContext: Debug { #[derive(Debug)] pub struct GfxFormat { pub format: &'static Format, - pub implicit_external_only: bool, - pub modifiers: AHashMap, -} - -#[derive(Debug)] -pub struct GfxModifier { - pub modifier: u64, - pub external_only: bool, + pub modifiers: IndexSet, } #[derive(Error)] diff --git a/src/gfx_apis/gl.rs b/src/gfx_apis/gl.rs index df57d8fc..3e80a101 100644 --- a/src/gfx_apis/gl.rs +++ b/src/gfx_apis/gl.rs @@ -126,6 +126,8 @@ enum RenderError { ExternalOnly, #[error("OpenGL context does not support external textures")] ExternalUnsupported, + #[error("OpenGL context does not support any formats")] + NoSupportedFormats, } #[derive(Default)] diff --git a/src/gfx_apis/gl/egl/context.rs b/src/gfx_apis/gl/egl/context.rs index c71f7176..8a90ef91 100644 --- a/src/gfx_apis/gl/egl/context.rs +++ b/src/gfx_apis/gl/egl/context.rs @@ -1,6 +1,6 @@ use { crate::{ - gfx_api::ResetStatus, + gfx_api::{GfxFormat, ResetStatus}, gfx_apis::gl::{ egl::{ display::EglDisplay, @@ -17,6 +17,7 @@ use { RenderError, }, }, + ahash::AHashMap, std::rc::Rc, }; @@ -25,6 +26,7 @@ pub struct EglContext { pub dpy: Rc, pub ext: GlExt, pub ctx: EGLContext, + pub formats: Rc>, } impl Drop for EglContext { diff --git a/src/gfx_apis/gl/egl/display.rs b/src/gfx_apis/gl/egl/display.rs index 95681b63..04d01ced 100644 --- a/src/gfx_apis/gl/egl/display.rs +++ b/src/gfx_apis/gl/egl/display.rs @@ -1,7 +1,7 @@ use { crate::{ format::{formats, Format}, - gfx_api::{GfxFormat, GfxModifier}, + gfx_api::GfxFormat, gfx_apis::gl::{ egl::{ context::EglContext, @@ -30,16 +30,30 @@ use { }, RenderError, }, - video::{dmabuf::DmaBuf, drm::Drm, gbm::GbmDevice, INVALID_MODIFIER}, + video::{dmabuf::DmaBuf, drm::Drm, gbm::GbmDevice, Modifier, INVALID_MODIFIER}, }, ahash::AHashMap, + indexmap::{IndexMap, IndexSet}, std::{ptr, rc::Rc}, }; +#[derive(Debug)] +pub struct EglFormat { + pub format: &'static Format, + pub implicit_external_only: bool, + pub modifiers: IndexMap, +} + +#[derive(Debug)] +pub struct EglModifier { + pub modifier: u64, + pub external_only: bool, +} + #[derive(Debug)] pub struct EglDisplay { pub exts: DisplayExt, - pub formats: Rc>, + pub formats: AHashMap, pub gbm: Rc, pub dpy: EGLDisplay, } @@ -61,7 +75,7 @@ impl EglDisplay { } let mut dpy = EglDisplay { exts: DisplayExt::empty(), - formats: Rc::new(AHashMap::new()), + formats: AHashMap::new(), gbm: Rc::new(gbm), dpy, }; @@ -89,7 +103,7 @@ impl EglDisplay { if !dpy.exts.intersects(DisplayExt::KHR_SURFACELESS_CONTEXT) { return Err(RenderError::SurfacelessContext); } - dpy.formats = Rc::new(query_formats(dpy.dpy)?); + dpy.formats = query_formats(dpy.dpy)?; Ok(Rc::new(dpy)) } @@ -109,27 +123,57 @@ impl EglDisplay { log::warn!("EGL display does not support gpu reset notifications"); } attrib.push(EGL_NONE); - unsafe { - let ctx = eglCreateContext( + let ctx = unsafe { + eglCreateContext( self.dpy, EGLConfig::none(), EGLContext::none(), attrib.as_ptr(), - ); - if ctx.is_none() { - return Err(RenderError::CreateContext); - } - let mut ctx = EglContext { - dpy: self.clone(), - ext: GlExt::empty(), - ctx, - }; - ctx.ext = ctx.with_current(|| Ok(get_gl_ext()))?; - if !ctx.ext.contains(GlExt::GL_OES_EGL_IMAGE) { - return Err(RenderError::OesEglImage); - } - Ok(Rc::new(ctx)) + ) + }; + if ctx.is_none() { + return Err(RenderError::CreateContext); } + let mut ctx = EglContext { + dpy: self.clone(), + ext: GlExt::empty(), + ctx, + formats: Default::default(), + }; + ctx.ext = ctx.with_current(|| Ok(get_gl_ext()))?; + if !ctx.ext.contains(GlExt::GL_OES_EGL_IMAGE) { + return Err(RenderError::OesEglImage); + } + ctx.formats = { + let mut formats = AHashMap::new(); + let supports_external_only = ctx.ext.contains(GlExt::GL_OES_EGL_IMAGE_EXTERNAL); + for (&drm, format) in &self.formats { + if format.implicit_external_only && !supports_external_only { + continue; + } + let mut modifiers = IndexSet::new(); + for modifier in format.modifiers.values() { + if modifier.external_only && !supports_external_only { + continue; + } + modifiers.insert(modifier.modifier); + } + if !modifiers.is_empty() { + formats.insert( + drm, + GfxFormat { + format: format.format, + modifiers, + }, + ); + } + } + Rc::new(formats) + }; + if ctx.formats.is_empty() { + return Err(RenderError::NoSupportedFormats); + } + Ok(Rc::new(ctx)) } pub(in crate::gfx_apis::gl) fn import_dmabuf( @@ -228,7 +272,7 @@ impl Drop for EglDisplay { } } -unsafe fn query_formats(dpy: EGLDisplay) -> Result, RenderError> { +unsafe fn query_formats(dpy: EGLDisplay) -> Result, RenderError> { let mut vec = vec![]; let mut num = 0; let res = PROCS.eglQueryDmaBufFormatsEXT(dpy, num, ptr::null_mut(), &mut num); @@ -248,7 +292,7 @@ unsafe fn query_formats(dpy: EGLDisplay) -> Result, Ren let (modifiers, external_only) = query_modifiers(dpy, fmt, format)?; res.insert( format.drm, - GfxFormat { + EglFormat { format, implicit_external_only: external_only, modifiers, @@ -263,7 +307,7 @@ unsafe fn query_modifiers( dpy: EGLDisplay, gl_format: EGLint, format: &'static Format, -) -> Result<(AHashMap, bool), RenderError> { +) -> Result<(IndexMap, bool), RenderError> { let mut mods = vec![]; let mut ext_only = vec![]; let mut num = 0; @@ -293,11 +337,11 @@ unsafe fn query_modifiers( } mods.set_len(num as usize); ext_only.set_len(num as usize); - let mut res = AHashMap::new(); + let mut res = IndexMap::new(); for (modifier, ext_only) in mods.iter().copied().zip(ext_only.iter().copied()) { res.insert( modifier as _, - GfxModifier { + EglModifier { modifier: modifier as _, external_only: ext_only == EGL_TRUE, }, @@ -309,7 +353,7 @@ unsafe fn query_modifiers( } res.insert( INVALID_MODIFIER, - GfxModifier { + EglModifier { modifier: INVALID_MODIFIER, external_only, }, diff --git a/src/gfx_apis/gl/renderer/context.rs b/src/gfx_apis/gl/renderer/context.rs index 46ed57dd..103ffc82 100644 --- a/src/gfx_apis/gl/renderer/context.rs +++ b/src/gfx_apis/gl/renderer/context.rs @@ -81,10 +81,6 @@ impl GlRenderContext { self.ctx.reset_status() } - pub fn supports_external_texture(&self) -> bool { - self.ctx.ext.contains(GlExt::GL_OES_EGL_IMAGE_EXTERNAL) - } - pub(in crate::gfx_apis::gl) fn from_drm_device(drm: &Drm) -> Result { let nodes = drm.get_nodes()?; let node = match nodes @@ -160,7 +156,7 @@ impl GlRenderContext { } pub fn formats(&self) -> Rc> { - self.ctx.dpy.formats.clone() + self.ctx.formats.clone() } fn dmabuf_fb(self: &Rc, buf: &DmaBuf) -> Result, RenderError> { @@ -206,10 +202,6 @@ impl GfxContext for GlRenderContext { self.reset_status() } - fn supports_external_texture(&self) -> bool { - self.supports_external_texture() - } - fn render_node(&self) -> Rc { self.render_node() } diff --git a/src/ifs/zwp_linux_buffer_params_v1.rs b/src/ifs/zwp_linux_buffer_params_v1.rs index 9120e553..35aecf09 100644 --- a/src/ifs/zwp_linux_buffer_params_v1.rs +++ b/src/ifs/zwp_linux_buffer_params_v1.rs @@ -110,7 +110,7 @@ impl ZwpLinuxBufferParamsV1 { Some(m) => m, _ => return Err(ZwpLinuxBufferParamsV1Error::NoPlanes), }; - if !format.modifiers.contains_key(&modifier) { + if !format.modifiers.contains(&modifier) { return Err(ZwpLinuxBufferParamsV1Error::InvalidModifier(modifier)); } let mut dmabuf = DmaBuf { diff --git a/src/ifs/zwp_linux_dmabuf_v1.rs b/src/ifs/zwp_linux_dmabuf_v1.rs index 3b506cf0..f76d4954 100644 --- a/src/ifs/zwp_linux_dmabuf_v1.rs +++ b/src/ifs/zwp_linux_dmabuf_v1.rs @@ -42,16 +42,10 @@ impl ZwpLinuxDmabufV1Global { if let Some(ctx) = client.state.render_ctx.get() { let formats = ctx.formats(); for format in formats.values() { - if format.implicit_external_only && !ctx.supports_external_texture() { - continue; - } obj.send_format(format.format.drm); if version >= MODIFIERS_SINCE_VERSION { - for modifier in format.modifiers.values() { - if modifier.external_only && !ctx.supports_external_texture() { - continue; - } - obj.send_modifier(format.format.drm, modifier.modifier); + for &modifier in &format.modifiers { + obj.send_modifier(format.format.drm, modifier); } } }