Merge pull request #155 from YaLTeR/fix-dimensions

anvil: retrieve buffer dimensions on commit
This commit is contained in:
Victor Berger 2020-02-03 14:53:35 +01:00 committed by GitHub
commit 7fa7fe03be
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 131 additions and 12 deletions

59
anvil/src/buffer_utils.rs Normal file
View File

@ -0,0 +1,59 @@
use std::{cell::RefCell, rc::Rc};
use slog::Logger;
#[cfg(feature = "egl")]
use smithay::backend::egl::{BufferAccessError, EGLDisplay};
use smithay::{
reexports::wayland_server::protocol::wl_buffer::WlBuffer,
wayland::shm::with_buffer_contents as shm_buffer_contents,
};
/// Utilities for working with `WlBuffer`s.
#[derive(Clone)]
pub struct BufferUtils {
#[cfg(feature = "egl")]
egl_display: Rc<RefCell<Option<EGLDisplay>>>,
log: Logger,
}
impl BufferUtils {
/// Creates a new `BufferUtils`.
#[cfg(feature = "egl")]
pub fn new(egl_display: Rc<RefCell<Option<EGLDisplay>>>, log: Logger) -> Self {
Self { egl_display, log }
}
/// Creates a new `BufferUtils`.
#[cfg(not(feature = "egl"))]
pub fn new(log: Logger) -> Self {
Self { log }
}
/// Returns the dimensions of an image stored in the buffer.
#[cfg(feature = "egl")]
pub fn dimensions(&self, buffer: &WlBuffer) -> Option<(i32, i32)> {
// Try to retrieve the EGL dimensions of this buffer, and, if that fails, the shm dimensions.
self.egl_display
.borrow()
.as_ref()
.and_then(|display| display.egl_buffer_dimensions(buffer))
.or_else(|| self.shm_buffer_dimensions(buffer))
}
/// Returns the dimensions of an image stored in the buffer.
#[cfg(not(feature = "egl"))]
pub fn dimensions(&self, buffer: &WlBuffer) -> Option<(i32, i32)> {
self.shm_buffer_dimensions(buffer)
}
/// Returns the dimensions of an image stored in the shm buffer.
fn shm_buffer_dimensions(&self, buffer: &WlBuffer) -> Option<(i32, i32)> {
shm_buffer_contents(buffer, |_, data| (data.width, data.height))
.map_err(|err| {
warn!(self.log, "Unable to load buffer contents"; "err" => format!("{:?}", err));
err
})
.ok()
}
}

View File

@ -12,6 +12,7 @@ use smithay::reexports::{calloop::EventLoop, wayland_server::Display};
#[macro_use] #[macro_use]
mod shaders; mod shaders;
mod buffer_utils;
mod glium_drawer; mod glium_drawer;
mod input_handler; mod input_handler;
mod shell; mod shell;

View File

@ -29,7 +29,10 @@ use smithay::{
}, },
}; };
use crate::window_map::{Kind as SurfaceKind, WindowMap}; use crate::{
buffer_utils::BufferUtils,
window_map::{Kind as SurfaceKind, WindowMap},
};
define_roles!(Roles => define_roles!(Roles =>
[ XdgSurface, XdgSurfaceRole ] [ XdgSurface, XdgSurfaceRole ]
@ -98,6 +101,7 @@ impl PointerGrab for MoveSurfaceGrab {
pub fn init_shell( pub fn init_shell(
display: &mut Display, display: &mut Display,
buffer_utils: BufferUtils,
log: ::slog::Logger, log: ::slog::Logger,
) -> ( ) -> (
CompositorToken<Roles>, CompositorToken<Roles>,
@ -109,7 +113,7 @@ pub fn init_shell(
let (compositor_token, _, _) = compositor_init( let (compositor_token, _, _) = compositor_init(
display, display,
move |request, surface, ctoken| match request { move |request, surface, ctoken| match request {
SurfaceEvent::Commit => surface_commit(&surface, ctoken), SurfaceEvent::Commit => surface_commit(&surface, ctoken, &buffer_utils),
SurfaceEvent::Frame { callback } => callback SurfaceEvent::Frame { callback } => callback
.implement_closure(|_, _| unreachable!(), None::<fn(_)>, ()) .implement_closure(|_, _| unreachable!(), None::<fn(_)>, ())
.done(0), .done(0),
@ -273,10 +277,15 @@ pub fn init_shell(
pub struct SurfaceData { pub struct SurfaceData {
pub buffer: Option<wl_buffer::WlBuffer>, pub buffer: Option<wl_buffer::WlBuffer>,
pub texture: Option<crate::glium_drawer::TextureMetadata>, pub texture: Option<crate::glium_drawer::TextureMetadata>,
pub dimensions: Option<(i32, i32)>,
pub input_region: Option<RegionAttributes>, pub input_region: Option<RegionAttributes>,
} }
fn surface_commit(surface: &wl_surface::WlSurface, token: CompositorToken<Roles>) { fn surface_commit(
surface: &wl_surface::WlSurface,
token: CompositorToken<Roles>,
buffer_utils: &BufferUtils,
) {
token.with_surface_data(surface, |attributes| { token.with_surface_data(surface, |attributes| {
attributes.user_data.insert_if_missing(SurfaceData::default); attributes.user_data.insert_if_missing(SurfaceData::default);
let data = attributes.user_data.get_mut::<SurfaceData>().unwrap(); let data = attributes.user_data.get_mut::<SurfaceData>().unwrap();
@ -292,6 +301,8 @@ fn surface_commit(surface: &wl_surface::WlSurface, token: CompositorToken<Roles>
old_buffer.release(); old_buffer.release();
} }
data.texture = None; data.texture = None;
// If this fails, the buffer will be discarded later by the drawing code.
data.dimensions = buffer_utils.dimensions(data.buffer.as_ref().unwrap());
} }
Some(None) => { Some(None) => {
// erase the contents // erase the contents
@ -299,6 +310,7 @@ fn surface_commit(surface: &wl_surface::WlSurface, token: CompositorToken<Roles>
old_buffer.release(); old_buffer.release();
} }
data.texture = None; data.texture = None;
data.dimensions = None;
} }
None => {} None => {}
} }
@ -306,12 +318,10 @@ fn surface_commit(surface: &wl_surface::WlSurface, token: CompositorToken<Roles>
} }
fn get_size(attrs: &SurfaceAttributes) -> Option<(i32, i32)> { fn get_size(attrs: &SurfaceAttributes) -> Option<(i32, i32)> {
attrs.user_data.get::<SurfaceData>().and_then(|data| { attrs
data.texture .user_data
.as_ref() .get::<SurfaceData>()
.map(|ref meta| meta.dimensions) .and_then(|data| data.dimensions)
.map(|(x, y)| (x as i32, y as i32))
})
} }
fn contains_point(attrs: &SurfaceAttributes, point: (f64, f64)) -> bool { fn contains_point(attrs: &SurfaceAttributes, point: (f64, f64)) -> bool {

View File

@ -61,6 +61,7 @@ use smithay::{
}, },
}; };
use crate::buffer_utils::BufferUtils;
use crate::glium_drawer::GliumDrawer; use crate::glium_drawer::GliumDrawer;
use crate::input_handler::AnvilInputHandler; use crate::input_handler::AnvilInputHandler;
use crate::shell::{init_shell, MyWindowMap, Roles}; use crate::shell::{init_shell, MyWindowMap, Roles};
@ -85,6 +86,11 @@ pub fn run_udev(mut display: Display, mut event_loop: EventLoop<()>, log: Logger
#[cfg(feature = "egl")] #[cfg(feature = "egl")]
let active_egl_context = Rc::new(RefCell::new(None)); let active_egl_context = Rc::new(RefCell::new(None));
#[cfg(feature = "egl")]
let buffer_utils = BufferUtils::new(active_egl_context.clone(), log.clone());
#[cfg(not(feature = "egl"))]
let buffer_utils = BufferUtils::new(log.clone());
let display = Rc::new(RefCell::new(display)); let display = Rc::new(RefCell::new(display));
/* /*
@ -92,7 +98,8 @@ pub fn run_udev(mut display: Display, mut event_loop: EventLoop<()>, log: Logger
*/ */
init_shm_global(&mut display.borrow_mut(), vec![], log.clone()); init_shm_global(&mut display.borrow_mut(), vec![], log.clone());
let (compositor_token, _, _, window_map) = init_shell(&mut display.borrow_mut(), log.clone()); let (compositor_token, _, _, window_map) =
init_shell(&mut display.borrow_mut(), buffer_utils, log.clone());
/* /*
* Initialize session * Initialize session

View File

@ -23,6 +23,7 @@ use smithay::{
use slog::Logger; use slog::Logger;
use crate::buffer_utils::BufferUtils;
use crate::glium_drawer::GliumDrawer; use crate::glium_drawer::GliumDrawer;
use crate::input_handler::AnvilInputHandler; use crate::input_handler::AnvilInputHandler;
use crate::shell::init_shell; use crate::shell::init_shell;
@ -42,10 +43,15 @@ pub fn run_winit(display: &mut Display, event_loop: &mut EventLoop<()>, log: Log
let (w, h) = renderer.get_framebuffer_dimensions(); let (w, h) = renderer.get_framebuffer_dimensions();
#[cfg(feature = "egl")] #[cfg(feature = "egl")]
let drawer = GliumDrawer::init(renderer, egl_display, log.clone()); let drawer = GliumDrawer::init(renderer, egl_display.clone(), log.clone());
#[cfg(not(feature = "egl"))] #[cfg(not(feature = "egl"))]
let drawer = GliumDrawer::init(renderer, log.clone()); let drawer = GliumDrawer::init(renderer, log.clone());
#[cfg(feature = "egl")]
let buffer_utils = BufferUtils::new(egl_display, log.clone());
#[cfg(not(feature = "egl"))]
let buffer_utils = BufferUtils::new(log.clone());
let name = display.add_socket_auto().unwrap().into_string().unwrap(); let name = display.add_socket_auto().unwrap().into_string().unwrap();
info!(log, "Listening on wayland socket"; "name" => name.clone()); info!(log, "Listening on wayland socket"; "name" => name.clone());
::std::env::set_var("WAYLAND_DISPLAY", name); ::std::env::set_var("WAYLAND_DISPLAY", name);
@ -58,7 +64,7 @@ pub fn run_winit(display: &mut Display, event_loop: &mut EventLoop<()>, log: Log
init_shm_global(display, vec![], log.clone()); init_shm_global(display, vec![], log.clone());
let (compositor_token, _, _, window_map) = init_shell(display, log.clone()); let (compositor_token, _, _, window_map) = init_shell(display, buffer_utils, log.clone());
let dnd_icon = Arc::new(Mutex::new(None)); let dnd_icon = Arc::new(Mutex::new(None));

View File

@ -472,6 +472,42 @@ impl EGLDisplay {
Err(BufferAccessError::ContextLost) Err(BufferAccessError::ContextLost)
} }
} }
/// Try to receive the dimensions of a given [`WlBuffer`].
///
/// In case the buffer is not managed by EGL (but e.g. the [`wayland::shm` module](::wayland::shm)) or the
/// context has been lost, `None` is returned.
pub fn egl_buffer_dimensions(&self, buffer: &WlBuffer) -> Option<(i32, i32)> {
if let Some(display) = self.egl.upgrade() {
let mut width: i32 = 0;
if unsafe {
ffi::egl::QueryWaylandBufferWL(
*display,
buffer.as_ref().c_ptr() as *mut _,
ffi::egl::WIDTH as i32,
&mut width as *mut _,
) == 0
} {
return None;
}
let mut height: i32 = 0;
if unsafe {
ffi::egl::QueryWaylandBufferWL(
*display,
buffer.as_ref().c_ptr() as *mut _,
ffi::egl::HEIGHT as i32,
&mut height as *mut _,
) == 0
} {
return None;
}
Some((width, height))
} else {
None
}
}
} }
#[cfg(feature = "native_lib")] #[cfg(feature = "native_lib")]