2023-01-11 00:28:54 +01:00
|
|
|
use std::{
|
|
|
|
|
ffi::CStr,
|
|
|
|
|
fs::File,
|
|
|
|
|
io,
|
|
|
|
|
os::unix::io::{FromRawFd, RawFd},
|
|
|
|
|
time::SystemTime,
|
|
|
|
|
time::UNIX_EPOCH,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
#[cfg(target_os = "linux")]
|
|
|
|
|
use nix::sys::memfd;
|
|
|
|
|
use nix::{
|
|
|
|
|
errno::Errno,
|
|
|
|
|
fcntl,
|
|
|
|
|
sys::{mman, stat},
|
|
|
|
|
unistd,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
use memmap::MmapMut;
|
|
|
|
|
|
|
|
|
|
use wayland_client::{
|
|
|
|
|
protocol::{wl_buffer, wl_shm, wl_shm_pool},
|
|
|
|
|
Dispatch, QueueHandle,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
use crate::color::Color;
|
|
|
|
|
use crate::widgets::Geometry;
|
|
|
|
|
|
|
|
|
|
fn create_shm_fd() -> io::Result<RawFd> {
|
|
|
|
|
// Only try memfd on linux
|
|
|
|
|
#[cfg(target_os = "linux")]
|
|
|
|
|
loop {
|
|
|
|
|
match memfd::memfd_create(
|
|
|
|
|
CStr::from_bytes_with_nul(b"wldash\0").unwrap(),
|
|
|
|
|
memfd::MemFdCreateFlag::MFD_CLOEXEC,
|
|
|
|
|
) {
|
|
|
|
|
Ok(fd) => return Ok(fd),
|
|
|
|
|
Err(Errno::EINTR) => continue,
|
|
|
|
|
Err(Errno::ENOSYS) => break,
|
|
|
|
|
Err(errno) => return Err(io::Error::from(errno)),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Fallback to using shm_open
|
|
|
|
|
let sys_time = SystemTime::now();
|
|
|
|
|
let mut mem_file_handle = format!(
|
|
|
|
|
"/wldash-{}",
|
|
|
|
|
sys_time.duration_since(UNIX_EPOCH).unwrap().subsec_nanos()
|
|
|
|
|
);
|
|
|
|
|
loop {
|
|
|
|
|
match mman::shm_open(
|
|
|
|
|
mem_file_handle.as_str(),
|
|
|
|
|
fcntl::OFlag::O_CREAT
|
|
|
|
|
| fcntl::OFlag::O_EXCL
|
|
|
|
|
| fcntl::OFlag::O_RDWR
|
|
|
|
|
| fcntl::OFlag::O_CLOEXEC,
|
|
|
|
|
stat::Mode::S_IRUSR | stat::Mode::S_IWUSR,
|
|
|
|
|
) {
|
|
|
|
|
Ok(fd) => match mman::shm_unlink(mem_file_handle.as_str()) {
|
|
|
|
|
Ok(_) => return Ok(fd),
|
|
|
|
|
Err(errno) => match unistd::close(fd) {
|
|
|
|
|
Ok(_) => return Err(io::Error::from(errno)),
|
|
|
|
|
Err(errno) => return Err(io::Error::from(errno)),
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
Err(Errno::EEXIST) => {
|
|
|
|
|
// If a file with that handle exists then change the handle
|
|
|
|
|
mem_file_handle = format!(
|
|
|
|
|
"/wldash-{}",
|
|
|
|
|
sys_time.duration_since(UNIX_EPOCH).unwrap().subsec_nanos()
|
|
|
|
|
);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
Err(Errno::EINTR) => continue,
|
|
|
|
|
Err(errno) => return Err(io::Error::from(errno)),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub struct ShmBuffer {
|
|
|
|
|
pub file: File,
|
|
|
|
|
pub mmap: MmapMut,
|
|
|
|
|
pub buffer: wl_buffer::WlBuffer,
|
|
|
|
|
pub refcnt: u32,
|
2025-01-12 22:50:00 +01:00
|
|
|
pub id: u32,
|
2025-02-27 15:10:07 +01:00
|
|
|
pub last_damage: Vec<Geometry>,
|
2023-01-11 00:28:54 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl ShmBuffer {
|
2025-01-12 22:50:00 +01:00
|
|
|
fn new<D>(
|
2023-01-11 00:28:54 +01:00
|
|
|
shm: &wl_shm::WlShm,
|
|
|
|
|
qh: &QueueHandle<D>,
|
|
|
|
|
width: i32,
|
|
|
|
|
height: i32,
|
|
|
|
|
stride: i32,
|
|
|
|
|
format: wl_shm::Format,
|
2025-01-12 22:50:00 +01:00
|
|
|
id: u32,
|
2023-01-11 00:28:54 +01:00
|
|
|
) -> io::Result<ShmBuffer>
|
|
|
|
|
where
|
|
|
|
|
D: Dispatch<wl_shm_pool::WlShmPool, ()> + Dispatch<wl_buffer::WlBuffer, ()> + 'static,
|
|
|
|
|
{
|
|
|
|
|
let mem_fd = create_shm_fd()?;
|
|
|
|
|
let file = unsafe { File::from_raw_fd(mem_fd) };
|
|
|
|
|
file.set_len((height * stride) as u64)?;
|
|
|
|
|
let pool = shm.create_pool(mem_fd, height * stride, &qh, ());
|
|
|
|
|
let mmap = unsafe { MmapMut::map_mut(&file).unwrap() };
|
|
|
|
|
let buffer = pool.create_buffer(0, width, height, stride, format, &qh, ());
|
|
|
|
|
|
|
|
|
|
Ok(ShmBuffer {
|
|
|
|
|
refcnt: 0,
|
|
|
|
|
file,
|
|
|
|
|
mmap,
|
|
|
|
|
buffer,
|
2025-01-12 22:50:00 +01:00
|
|
|
id,
|
2025-02-27 15:10:07 +01:00
|
|
|
last_damage: Vec::new(),
|
2023-01-11 00:28:54 +01:00
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn acquire(&mut self) {
|
|
|
|
|
self.refcnt += 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn release(&mut self) {
|
|
|
|
|
self.refcnt -= 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub struct BufferManager {
|
|
|
|
|
pub buffers: Vec<ShmBuffer>,
|
2025-01-12 22:50:00 +01:00
|
|
|
pub next_id: u32,
|
2023-01-11 00:28:54 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl BufferManager {
|
2023-01-16 00:25:34 +01:00
|
|
|
pub fn new() -> BufferManager {
|
|
|
|
|
BufferManager {
|
|
|
|
|
buffers: Vec::new(),
|
2025-01-12 22:50:00 +01:00
|
|
|
next_id: 0,
|
2023-01-16 00:25:34 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-11 00:28:54 +01:00
|
|
|
pub fn clear_buffers(&mut self) {
|
|
|
|
|
for buf in self.buffers.iter_mut() {
|
|
|
|
|
buf.buffer.destroy()
|
|
|
|
|
}
|
|
|
|
|
self.buffers.clear()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn next_buffer(&mut self) -> Option<&mut ShmBuffer> {
|
|
|
|
|
for buf in self.buffers.iter_mut() {
|
|
|
|
|
if buf.refcnt == 0 {
|
|
|
|
|
return Some(buf);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
None
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn add_buffer<D>(
|
|
|
|
|
&mut self,
|
|
|
|
|
wl_shm: &wl_shm::WlShm,
|
|
|
|
|
dimensions: (i32, i32),
|
|
|
|
|
qh: &QueueHandle<D>,
|
|
|
|
|
) where
|
|
|
|
|
D: Dispatch<wl_shm_pool::WlShmPool, ()> + Dispatch<wl_buffer::WlBuffer, ()> + 'static,
|
|
|
|
|
{
|
|
|
|
|
let mut buf = ShmBuffer::new(
|
|
|
|
|
wl_shm,
|
|
|
|
|
qh,
|
|
|
|
|
dimensions.0,
|
|
|
|
|
dimensions.1,
|
|
|
|
|
dimensions.0 * 4,
|
|
|
|
|
wl_shm::Format::Argb8888,
|
2025-01-12 22:50:00 +01:00
|
|
|
self.next_id,
|
2023-01-11 00:28:54 +01:00
|
|
|
)
|
|
|
|
|
.expect("unable to add buffer");
|
2025-01-12 22:50:00 +01:00
|
|
|
self.next_id += 1;
|
2023-01-11 00:28:54 +01:00
|
|
|
BufferView::new(&mut buf.mmap, (dimensions.0 as u32, dimensions.1 as u32));
|
|
|
|
|
self.buffers.push(buf);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub struct BufferView<'a> {
|
2023-02-02 23:52:59 +01:00
|
|
|
view: &'a mut [u32],
|
2023-01-11 00:28:54 +01:00
|
|
|
dimensions: (u32, u32),
|
|
|
|
|
subdimensions: Option<(u32, u32, u32, u32)>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<'a> BufferView<'a> {
|
|
|
|
|
pub fn new(buf: &'a mut MmapMut, dimensions: (u32, u32)) -> BufferView {
|
2023-02-02 23:52:59 +01:00
|
|
|
let view = unsafe {
|
|
|
|
|
std::slice::from_raw_parts_mut(
|
|
|
|
|
buf.as_mut_ptr() as *mut u32,
|
|
|
|
|
(dimensions.0 * dimensions.1) as usize,
|
|
|
|
|
)
|
|
|
|
|
};
|
2023-01-11 00:28:54 +01:00
|
|
|
BufferView {
|
2023-02-02 23:52:59 +01:00
|
|
|
view,
|
2023-01-11 00:28:54 +01:00
|
|
|
dimensions,
|
|
|
|
|
subdimensions: None,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-02 23:52:59 +01:00
|
|
|
#[inline]
|
2023-01-11 00:28:54 +01:00
|
|
|
pub fn get_bounds(&self) -> (u32, u32, u32, u32) {
|
|
|
|
|
if let Some(subdim) = self.subdimensions {
|
|
|
|
|
subdim
|
|
|
|
|
} else {
|
|
|
|
|
(0, 0, self.dimensions.0, self.dimensions.1)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-08 22:53:41 +01:00
|
|
|
pub fn subdimensions(&mut self, subdimensions: (u32, u32, u32, u32)) -> BufferView {
|
2023-01-11 00:28:54 +01:00
|
|
|
let bounds = self.get_bounds();
|
2023-02-08 22:53:41 +01:00
|
|
|
if cfg!(debug_assertions)
|
|
|
|
|
&& (subdimensions.0 + subdimensions.2 > bounds.2
|
|
|
|
|
|| subdimensions.1 + subdimensions.3 > bounds.3)
|
2023-01-11 00:28:54 +01:00
|
|
|
{
|
2023-02-08 22:53:41 +01:00
|
|
|
panic!(
|
|
|
|
|
"cannot create subdimensions larger than buffer: {:?} > {:?}",
|
|
|
|
|
subdimensions, bounds
|
|
|
|
|
);
|
2023-01-11 00:28:54 +01:00
|
|
|
}
|
|
|
|
|
|
2023-02-02 23:52:59 +01:00
|
|
|
BufferView {
|
|
|
|
|
view: self.view,
|
2023-01-11 00:28:54 +01:00
|
|
|
dimensions: self.dimensions,
|
|
|
|
|
subdimensions: Some((
|
|
|
|
|
subdimensions.0 + bounds.0,
|
|
|
|
|
subdimensions.1 + bounds.1,
|
|
|
|
|
subdimensions.2,
|
|
|
|
|
subdimensions.3,
|
|
|
|
|
)),
|
2023-02-02 23:52:59 +01:00
|
|
|
}
|
2023-01-11 00:28:54 +01:00
|
|
|
}
|
|
|
|
|
|
2023-02-02 23:52:59 +01:00
|
|
|
pub fn subgeometry(&mut self, geo: Geometry) -> BufferView {
|
2023-01-11 00:28:54 +01:00
|
|
|
self.subdimensions((geo.x, geo.y, geo.width, geo.height))
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-02 23:52:59 +01:00
|
|
|
pub fn offset(&mut self, offset: (u32, u32)) -> BufferView {
|
2023-01-11 00:28:54 +01:00
|
|
|
let bounds = self.get_bounds();
|
2023-02-02 23:52:59 +01:00
|
|
|
if cfg!(debug_assertions) && (offset.0 > bounds.2 || offset.1 > bounds.3) {
|
2023-02-08 22:53:41 +01:00
|
|
|
panic!(
|
|
|
|
|
"cannot create offset outside buffer: {:?} > {:?}",
|
|
|
|
|
offset, bounds
|
|
|
|
|
);
|
2023-01-11 00:28:54 +01:00
|
|
|
}
|
|
|
|
|
|
2023-02-02 23:52:59 +01:00
|
|
|
BufferView {
|
|
|
|
|
view: self.view,
|
2023-01-11 00:28:54 +01:00
|
|
|
dimensions: self.dimensions,
|
|
|
|
|
subdimensions: Some((
|
|
|
|
|
offset.0 + bounds.0,
|
|
|
|
|
offset.1 + bounds.1,
|
|
|
|
|
bounds.2 - offset.0,
|
|
|
|
|
bounds.3 - offset.1,
|
|
|
|
|
)),
|
2023-02-02 23:52:59 +01:00
|
|
|
}
|
2023-01-11 00:28:54 +01:00
|
|
|
}
|
|
|
|
|
|
2023-02-02 23:52:59 +01:00
|
|
|
pub fn memset(&mut self, c: Color) {
|
2023-01-11 00:28:54 +01:00
|
|
|
if let Some(subdim) = self.subdimensions {
|
2023-02-02 23:52:59 +01:00
|
|
|
for y in subdim.1..(subdim.1 + subdim.3) {
|
2023-02-06 18:34:07 +01:00
|
|
|
let start = (subdim.0 + y * self.dimensions.0) as usize;
|
|
|
|
|
let end = start + subdim.2 as usize;
|
|
|
|
|
self.view[start..end].fill(c.0);
|
2023-01-11 00:28:54 +01:00
|
|
|
}
|
|
|
|
|
} else {
|
2023-02-02 23:52:59 +01:00
|
|
|
self.view.fill(c.0);
|
2023-01-11 00:28:54 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-06 18:34:07 +01:00
|
|
|
pub fn clear(&mut self) {
|
|
|
|
|
if let Some(subdim) = self.subdimensions {
|
|
|
|
|
for y in subdim.1..(subdim.1 + subdim.3) {
|
|
|
|
|
let start = (subdim.0 + y * self.dimensions.0) as usize;
|
|
|
|
|
let end = start + subdim.2 as usize;
|
|
|
|
|
self.view[start..end].fill(0x0);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
self.view.fill(0x0);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-08 22:53:41 +01:00
|
|
|
#[inline]
|
|
|
|
|
pub fn put_raw(&mut self, pos: (u32, u32), c: Color) {
|
|
|
|
|
self.view[(pos.0 + pos.1 * self.dimensions.0) as usize] = c.0
|
|
|
|
|
}
|
2023-01-11 00:28:54 +01:00
|
|
|
|
2023-02-08 22:53:41 +01:00
|
|
|
#[inline]
|
|
|
|
|
pub fn put_line_raw(&mut self, pos: (u32, u32), len: u32, c: Color) {
|
|
|
|
|
let start = (pos.0 + (pos.1 * self.dimensions.0)) as usize;
|
|
|
|
|
let len = len as usize;
|
|
|
|
|
self.view[start..start + len].fill(c.0);
|
2023-01-11 00:28:54 +01:00
|
|
|
}
|
|
|
|
|
}
|