buffer: switch to memmap2, destroy shm pools, never underflow refcounts
memmap 0.7 is unmaintained (RUSTSEC-2020-0077); memmap2 is a drop-in replacement. Drop the unused shlex dependency. Each resize created a new wl_shm_pool that was never destroyed; keep the pool on the buffer and destroy it with it. A wl_buffer.release for a buffer we didn't consider acquired used to underflow refcnt and wedge rendering. Fix the lifetime-elision warnings while here. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5.1
parent
c033335912
commit
6af81b587c
Generated
+1
-18
@@ -462,16 +462,6 @@ version = "2.7.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149"
|
checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "memmap"
|
|
||||||
version = "0.7.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "6585fd95e7bb50d6cc31e20d4cf9afb4e2ba16c5846fc76793f11218da9c475b"
|
|
||||||
dependencies = [
|
|
||||||
"libc",
|
|
||||||
"winapi",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "memmap2"
|
name = "memmap2"
|
||||||
version = "0.9.5"
|
version = "0.9.5"
|
||||||
@@ -809,12 +799,6 @@ dependencies = [
|
|||||||
"digest",
|
"digest",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "shlex"
|
|
||||||
version = "1.3.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "simd-json"
|
name = "simd-json"
|
||||||
version = "0.13.8"
|
version = "0.13.8"
|
||||||
@@ -1289,13 +1273,12 @@ dependencies = [
|
|||||||
"fontconfig",
|
"fontconfig",
|
||||||
"fuzzy-matcher",
|
"fuzzy-matcher",
|
||||||
"libpulse-binding",
|
"libpulse-binding",
|
||||||
"memmap",
|
"memmap2",
|
||||||
"nix 0.26.4",
|
"nix 0.26.4",
|
||||||
"rcalc_lib",
|
"rcalc_lib",
|
||||||
"rusttype",
|
"rusttype",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_yaml",
|
"serde_yaml",
|
||||||
"shlex",
|
|
||||||
"simd-json",
|
"simd-json",
|
||||||
"unicode-segmentation",
|
"unicode-segmentation",
|
||||||
"walkdir",
|
"walkdir",
|
||||||
|
|||||||
+1
-2
@@ -16,7 +16,7 @@ wayland-client = { version = "0.30", features = ["calloop", "log"] }
|
|||||||
wayland-protocols = { version = "0.30", features = ["client", "unstable", "staging"] }
|
wayland-protocols = { version = "0.30", features = ["client", "unstable", "staging"] }
|
||||||
wayland-protocols-wlr = { version = "0.1", features = ["client"] }
|
wayland-protocols-wlr = { version = "0.1", features = ["client"] }
|
||||||
nix = "0.26" # 0.27 is breaking
|
nix = "0.26" # 0.27 is breaking
|
||||||
memmap = "0.7"
|
memmap2 = "0.9"
|
||||||
fontconfig = { version = "0.8.0", optional = true }
|
fontconfig = { version = "0.8.0", optional = true }
|
||||||
rusttype = "0.9"
|
rusttype = "0.9"
|
||||||
# fontdue = "0.7"
|
# fontdue = "0.7"
|
||||||
@@ -27,7 +27,6 @@ walkdir = "2.4"
|
|||||||
|
|
||||||
unicode-segmentation = "1.10"
|
unicode-segmentation = "1.10"
|
||||||
fuzzy-matcher = "0.3"
|
fuzzy-matcher = "0.3"
|
||||||
shlex = "1.3"
|
|
||||||
|
|
||||||
xkbcommon = { version = "0.8", features = ["wayland"] }
|
xkbcommon = { version = "0.8", features = ["wayland"] }
|
||||||
|
|
||||||
|
|||||||
+16
-17
@@ -16,7 +16,7 @@ use nix::{
|
|||||||
unistd,
|
unistd,
|
||||||
};
|
};
|
||||||
|
|
||||||
use memmap::MmapMut;
|
use memmap2::MmapMut;
|
||||||
|
|
||||||
use wayland_client::{
|
use wayland_client::{
|
||||||
protocol::{wl_buffer, wl_shm, wl_shm_pool},
|
protocol::{wl_buffer, wl_shm, wl_shm_pool},
|
||||||
@@ -78,11 +78,13 @@ fn create_shm_fd() -> io::Result<RawFd> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct ShmBuffer {
|
pub struct ShmBuffer {
|
||||||
|
// Keeps the memfd alive for as long as the mapping and pool exist.
|
||||||
|
#[allow(dead_code)]
|
||||||
pub file: File,
|
pub file: File,
|
||||||
pub mmap: MmapMut,
|
pub mmap: MmapMut,
|
||||||
|
pub pool: wl_shm_pool::WlShmPool,
|
||||||
pub buffer: wl_buffer::WlBuffer,
|
pub buffer: wl_buffer::WlBuffer,
|
||||||
pub refcnt: u32,
|
pub refcnt: u32,
|
||||||
pub id: u32,
|
|
||||||
pub last_damage: Vec<Geometry>,
|
pub last_damage: Vec<Geometry>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -94,7 +96,6 @@ impl ShmBuffer {
|
|||||||
height: i32,
|
height: i32,
|
||||||
stride: i32,
|
stride: i32,
|
||||||
format: wl_shm::Format,
|
format: wl_shm::Format,
|
||||||
id: u32,
|
|
||||||
) -> io::Result<ShmBuffer>
|
) -> io::Result<ShmBuffer>
|
||||||
where
|
where
|
||||||
D: Dispatch<wl_shm_pool::WlShmPool, ()> + Dispatch<wl_buffer::WlBuffer, ()> + 'static,
|
D: Dispatch<wl_shm_pool::WlShmPool, ()> + Dispatch<wl_buffer::WlBuffer, ()> + 'static,
|
||||||
@@ -103,15 +104,15 @@ impl ShmBuffer {
|
|||||||
let file = unsafe { File::from_raw_fd(mem_fd) };
|
let file = unsafe { File::from_raw_fd(mem_fd) };
|
||||||
file.set_len((height * stride) as u64)?;
|
file.set_len((height * stride) as u64)?;
|
||||||
let pool = shm.create_pool(mem_fd, height * stride, &qh, ());
|
let pool = shm.create_pool(mem_fd, height * stride, &qh, ());
|
||||||
let mmap = unsafe { MmapMut::map_mut(&file).unwrap() };
|
let mmap = unsafe { MmapMut::map_mut(&file)? };
|
||||||
let buffer = pool.create_buffer(0, width, height, stride, format, &qh, ());
|
let buffer = pool.create_buffer(0, width, height, stride, format, &qh, ());
|
||||||
|
|
||||||
Ok(ShmBuffer {
|
Ok(ShmBuffer {
|
||||||
refcnt: 0,
|
refcnt: 0,
|
||||||
file,
|
file,
|
||||||
mmap,
|
mmap,
|
||||||
|
pool,
|
||||||
buffer,
|
buffer,
|
||||||
id,
|
|
||||||
last_damage: Vec::new(),
|
last_damage: Vec::new(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -121,26 +122,27 @@ impl ShmBuffer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn release(&mut self) {
|
pub fn release(&mut self) {
|
||||||
self.refcnt -= 1;
|
// A compositor may release a buffer we never considered acquired
|
||||||
|
// (e.g. after a resize); never underflow and wedge the buffer.
|
||||||
|
self.refcnt = self.refcnt.saturating_sub(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct BufferManager {
|
pub struct BufferManager {
|
||||||
pub buffers: Vec<ShmBuffer>,
|
pub buffers: Vec<ShmBuffer>,
|
||||||
pub next_id: u32,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BufferManager {
|
impl BufferManager {
|
||||||
pub fn new() -> BufferManager {
|
pub fn new() -> BufferManager {
|
||||||
BufferManager {
|
BufferManager {
|
||||||
buffers: Vec::new(),
|
buffers: Vec::new(),
|
||||||
next_id: 0,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn clear_buffers(&mut self) {
|
pub fn clear_buffers(&mut self) {
|
||||||
for buf in self.buffers.iter_mut() {
|
for buf in self.buffers.iter_mut() {
|
||||||
buf.buffer.destroy()
|
buf.buffer.destroy();
|
||||||
|
buf.pool.destroy();
|
||||||
}
|
}
|
||||||
self.buffers.clear()
|
self.buffers.clear()
|
||||||
}
|
}
|
||||||
@@ -162,18 +164,15 @@ impl BufferManager {
|
|||||||
) where
|
) where
|
||||||
D: Dispatch<wl_shm_pool::WlShmPool, ()> + Dispatch<wl_buffer::WlBuffer, ()> + 'static,
|
D: Dispatch<wl_shm_pool::WlShmPool, ()> + Dispatch<wl_buffer::WlBuffer, ()> + 'static,
|
||||||
{
|
{
|
||||||
let mut buf = ShmBuffer::new(
|
let buf = ShmBuffer::new(
|
||||||
wl_shm,
|
wl_shm,
|
||||||
qh,
|
qh,
|
||||||
dimensions.0,
|
dimensions.0,
|
||||||
dimensions.1,
|
dimensions.1,
|
||||||
dimensions.0 * 4,
|
dimensions.0 * 4,
|
||||||
wl_shm::Format::Argb8888,
|
wl_shm::Format::Argb8888,
|
||||||
self.next_id,
|
|
||||||
)
|
)
|
||||||
.expect("unable to add buffer");
|
.expect("unable to add buffer");
|
||||||
self.next_id += 1;
|
|
||||||
BufferView::new(&mut buf.mmap, (dimensions.0 as u32, dimensions.1 as u32));
|
|
||||||
self.buffers.push(buf);
|
self.buffers.push(buf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -185,7 +184,7 @@ pub struct BufferView<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> BufferView<'a> {
|
impl<'a> BufferView<'a> {
|
||||||
pub fn new(buf: &'a mut MmapMut, dimensions: (u32, u32)) -> BufferView {
|
pub fn new(buf: &'a mut MmapMut, dimensions: (u32, u32)) -> BufferView<'a> {
|
||||||
let view = unsafe {
|
let view = unsafe {
|
||||||
std::slice::from_raw_parts_mut(
|
std::slice::from_raw_parts_mut(
|
||||||
buf.as_mut_ptr() as *mut u32,
|
buf.as_mut_ptr() as *mut u32,
|
||||||
@@ -208,7 +207,7 @@ impl<'a> BufferView<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn subdimensions(&mut self, subdimensions: (u32, u32, u32, u32)) -> BufferView {
|
pub fn subdimensions(&mut self, subdimensions: (u32, u32, u32, u32)) -> BufferView<'_> {
|
||||||
let bounds = self.get_bounds();
|
let bounds = self.get_bounds();
|
||||||
if cfg!(debug_assertions)
|
if cfg!(debug_assertions)
|
||||||
&& (subdimensions.0 + subdimensions.2 > bounds.2
|
&& (subdimensions.0 + subdimensions.2 > bounds.2
|
||||||
@@ -232,11 +231,11 @@ impl<'a> BufferView<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn subgeometry(&mut self, geo: Geometry) -> BufferView {
|
pub fn subgeometry(&mut self, geo: Geometry) -> BufferView<'_> {
|
||||||
self.subdimensions((geo.x, geo.y, geo.width, geo.height))
|
self.subdimensions((geo.x, geo.y, geo.width, geo.height))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn offset(&mut self, offset: (u32, u32)) -> BufferView {
|
pub fn offset(&mut self, offset: (u32, u32)) -> BufferView<'_> {
|
||||||
let bounds = self.get_bounds();
|
let bounds = self.get_bounds();
|
||||||
if cfg!(debug_assertions) && (offset.0 > bounds.2 || offset.1 > bounds.3) {
|
if cfg!(debug_assertions) && (offset.0 > bounds.2 || offset.1 > bounds.3) {
|
||||||
panic!(
|
panic!(
|
||||||
|
|||||||
Reference in New Issue
Block a user