Merge pull request #155 from YaLTeR/fix-dimensions
anvil: retrieve buffer dimensions on commit
This commit is contained in:
commit
7fa7fe03be
|
@ -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()
|
||||
}
|
||||
}
|
|
@ -12,6 +12,7 @@ use smithay::reexports::{calloop::EventLoop, wayland_server::Display};
|
|||
|
||||
#[macro_use]
|
||||
mod shaders;
|
||||
mod buffer_utils;
|
||||
mod glium_drawer;
|
||||
mod input_handler;
|
||||
mod shell;
|
||||
|
|
|
@ -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 =>
|
||||
[ XdgSurface, XdgSurfaceRole ]
|
||||
|
@ -98,6 +101,7 @@ impl PointerGrab for MoveSurfaceGrab {
|
|||
|
||||
pub fn init_shell(
|
||||
display: &mut Display,
|
||||
buffer_utils: BufferUtils,
|
||||
log: ::slog::Logger,
|
||||
) -> (
|
||||
CompositorToken<Roles>,
|
||||
|
@ -109,7 +113,7 @@ pub fn init_shell(
|
|||
let (compositor_token, _, _) = compositor_init(
|
||||
display,
|
||||
move |request, surface, ctoken| match request {
|
||||
SurfaceEvent::Commit => surface_commit(&surface, ctoken),
|
||||
SurfaceEvent::Commit => surface_commit(&surface, ctoken, &buffer_utils),
|
||||
SurfaceEvent::Frame { callback } => callback
|
||||
.implement_closure(|_, _| unreachable!(), None::<fn(_)>, ())
|
||||
.done(0),
|
||||
|
@ -273,10 +277,15 @@ pub fn init_shell(
|
|||
pub struct SurfaceData {
|
||||
pub buffer: Option<wl_buffer::WlBuffer>,
|
||||
pub texture: Option<crate::glium_drawer::TextureMetadata>,
|
||||
pub dimensions: Option<(i32, i32)>,
|
||||
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| {
|
||||
attributes.user_data.insert_if_missing(SurfaceData::default);
|
||||
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();
|
||||
}
|
||||
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) => {
|
||||
// erase the contents
|
||||
|
@ -299,6 +310,7 @@ fn surface_commit(surface: &wl_surface::WlSurface, token: CompositorToken<Roles>
|
|||
old_buffer.release();
|
||||
}
|
||||
data.texture = None;
|
||||
data.dimensions = None;
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
|
@ -306,12 +318,10 @@ fn surface_commit(surface: &wl_surface::WlSurface, token: CompositorToken<Roles>
|
|||
}
|
||||
|
||||
fn get_size(attrs: &SurfaceAttributes) -> Option<(i32, i32)> {
|
||||
attrs.user_data.get::<SurfaceData>().and_then(|data| {
|
||||
data.texture
|
||||
.as_ref()
|
||||
.map(|ref meta| meta.dimensions)
|
||||
.map(|(x, y)| (x as i32, y as i32))
|
||||
})
|
||||
attrs
|
||||
.user_data
|
||||
.get::<SurfaceData>()
|
||||
.and_then(|data| data.dimensions)
|
||||
}
|
||||
|
||||
fn contains_point(attrs: &SurfaceAttributes, point: (f64, f64)) -> bool {
|
||||
|
|
|
@ -61,6 +61,7 @@ use smithay::{
|
|||
},
|
||||
};
|
||||
|
||||
use crate::buffer_utils::BufferUtils;
|
||||
use crate::glium_drawer::GliumDrawer;
|
||||
use crate::input_handler::AnvilInputHandler;
|
||||
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")]
|
||||
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));
|
||||
|
||||
/*
|
||||
|
@ -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());
|
||||
|
||||
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
|
||||
|
|
|
@ -23,6 +23,7 @@ use smithay::{
|
|||
|
||||
use slog::Logger;
|
||||
|
||||
use crate::buffer_utils::BufferUtils;
|
||||
use crate::glium_drawer::GliumDrawer;
|
||||
use crate::input_handler::AnvilInputHandler;
|
||||
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();
|
||||
#[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"))]
|
||||
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();
|
||||
info!(log, "Listening on wayland socket"; "name" => name.clone());
|
||||
::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());
|
||||
|
||||
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));
|
||||
|
||||
|
|
|
@ -472,6 +472,42 @@ impl EGLDisplay {
|
|||
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")]
|
||||
|
|
Loading…
Reference in New Issue