use memmap2

This commit is contained in:
stickynotememo
2025-11-20 08:52:44 +11:00
parent 6c8fc2b35f
commit 3867e9a571
4 changed files with 79 additions and 24 deletions
Generated
+10
View File
@@ -96,6 +96,15 @@ dependencies = [
"libc", "libc",
] ]
[[package]]
name = "memmap2"
version = "0.9.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "744133e4a0e0a658e1374cf3bf8e415c4052a15a111acd372764c55b4177d490"
dependencies = [
"libc",
]
[[package]] [[package]]
name = "memoffset" name = "memoffset"
version = "0.6.5" version = "0.6.5"
@@ -381,6 +390,7 @@ version = "0.1.0"
dependencies = [ dependencies = [
"libc", "libc",
"memfile", "memfile",
"memmap2",
"shared_memory", "shared_memory",
"wayland-client", "wayland-client",
"wayland-protocols", "wayland-protocols",
+1
View File
@@ -6,6 +6,7 @@ edition = "2024"
[dependencies] [dependencies]
libc = "0.2.177" libc = "0.2.177"
memfile = "0.3.2" memfile = "0.3.2"
memmap2 = "0.9.9"
shared_memory = "0.12.4" shared_memory = "0.12.4"
wayland-client = "0.31" wayland-client = "0.31"
wayland-protocols = { version = "0.32.9", features = ["client"] } wayland-protocols = { version = "0.32.9", features = ["client"] }
+3
View File
@@ -0,0 +1,3 @@
## Wolfenstein-3d like renderer
This renderer generates
+65 -24
View File
@@ -1,8 +1,11 @@
#![feature(more_qualified_paths)] #![feature(more_qualified_paths)]
use std::fs::File;
use std::time::Duration; use std::time::Duration;
use std::{ffi::CString, thread::sleep}; use std::{ffi::CString, thread::sleep};
use std::os::fd::BorrowedFd; use std::os::fd::BorrowedFd;
use memmap2::{MmapMut, MmapOptions};
use wayland_client::{ use wayland_client::{
Connection, Dispatch, EventQueue, Proxy, backend::ObjectId, delegate_noop, protocol::{ Connection, Dispatch, EventQueue, Proxy, backend::ObjectId, delegate_noop, protocol::{
wl_buffer::{self, WlBuffer}, wl_buffer::{self, WlBuffer},
@@ -31,7 +34,7 @@ const HEIGHT: i32 = 540;
#[derive(Debug)] #[derive(Debug)]
struct State { struct State {
exit: bool, exit: bool,
ready: bool, _ready: bool,
compositor: Option<WlCompositor>, compositor: Option<WlCompositor>,
surface: Option<WlSurface>, surface: Option<WlSurface>,
shm: Option<WlShm>, shm: Option<WlShm>,
@@ -41,6 +44,7 @@ struct State {
xdg_surface: Option<XdgSurface>, xdg_surface: Option<XdgSurface>,
toplevel_surface: Option<XdgToplevel>, toplevel_surface: Option<XdgToplevel>,
pool: Option<WlShmPool>, pool: Option<WlShmPool>,
memory_map: Option<MmapMut>,
} }
impl Dispatch<wl_registry::WlRegistry, ()> for State { impl Dispatch<wl_registry::WlRegistry, ()> for State {
@@ -120,6 +124,8 @@ impl Dispatch<WlShm, ()> for State {
// Data races should not be possible as the compositor will // Data races should not be possible as the compositor will
// not modify the buffer. (Non owners do not have write // not modify the buffer. (Non owners do not have write
// permissions) // permissions)
//
// TODO: Use shared_memory and implement FD return
let fildes = shm_open(name.as_ptr(), O_RDWR | O_CREAT, S_IRWXU | S_IROTH); let fildes = shm_open(name.as_ptr(), O_RDWR | O_CREAT, S_IRWXU | S_IROTH);
if fildes <= 0 { if fildes <= 0 {
@@ -129,6 +135,22 @@ impl Dispatch<WlShm, ()> for State {
BorrowedFd::borrow_raw(fildes) BorrowedFd::borrow_raw(fildes)
}; };
let mut shm_file = File::from(shm_fd.try_clone_to_owned().unwrap()); // Converts borrowed
// to owned. Are there problems with this?
let mut mmap = unsafe {
// SAFETY: This effectively creates a memory map from a raw
// pointer. As above, as long as the compositor does not
// mutate the underlying shared memory pool, mutations
// should be safe and not cause data races [undefined.race]
// https://doc.rust-lang.org/reference/behavior-considered-undefined.html#r-undefined.alias
MmapOptions::new()
.len(size as usize)
.map_mut(&shm_file)
.unwrap()
};
state.memory_map = Some(mmap);
let shm_pool = proxy.create_pool(shm_fd, size.try_into().unwrap(), qhandle, *data); let shm_pool = proxy.create_pool(shm_fd, size.try_into().unwrap(), qhandle, *data);
// TODO: Move drawing logic to event loop (double flush) // TODO: Move drawing logic to event loop (double flush)
state.pool = Some(shm_pool); state.pool = Some(shm_pool);
@@ -228,16 +250,17 @@ fn main() {
let mut state = State { let mut state = State {
exit: false, exit: false,
ready: false, _ready: false,
formats: vec![],
compositor: None, compositor: None,
surface: None, surface: None,
shm: None, shm: None,
formats: vec![],
buffer: None, buffer: None,
wm_base: None, wm_base: None,
xdg_surface: None, xdg_surface: None,
toplevel_surface: None, toplevel_surface: None,
pool: None, pool: None,
memory_map: None
}; };
let mut event_queue: EventQueue<State> = conn.new_event_queue(); let mut event_queue: EventQueue<State> = conn.new_event_queue();
@@ -266,33 +289,29 @@ fn main() {
surface.commit(); surface.commit();
}; };
} }
state.ready = if let (Some(_), Some(_), Some(_), Some(_), Some(_)) = (
&state.compositor,
&state.surface,
&state.shm,
&state.buffer,
&state.wm_base,
) {
true
} else {
false
};
if let Some(shm_pool) = &state.pool { if let Some(shm_pool) = &state.pool {
let channels: i32 = if state.formats.contains(&Format::Xrgb8888) { let format = if state.formats.contains(&Format::Xrgb8888) {
4 Format::Xrgb8888
} else { } else {
4 Format::Argb8888
}; // we know that the supported formats are only the two above, so we can safely assume that any format which is not Xrgb8888 is Argb8888, requiring 4 channels. };
let channel_count = match format {
Format::Xrgb8888 => 4,
Format::Argb8888 => 4,
_ => unimplemented!("Other formats not supported")
};
// FIX: 3 channels won't work, even with Xrgb8888 for some reason // FIX: 3 channels won't work, even with Xrgb8888 for some reason
// TODO: Update for more channels // TODO: Update for more channels
let size: i32 = (WIDTH * HEIGHT * channels * 2).try_into().unwrap(); let size: i32 = (WIDTH * HEIGHT * channel_count * 2).try_into().unwrap();
let buffer = shm_pool.create_buffer( let buffer = shm_pool.create_buffer(
0, 0,
WIDTH.try_into().unwrap(), WIDTH.try_into().unwrap(),
HEIGHT.try_into().unwrap(), HEIGHT.try_into().unwrap(),
(WIDTH * channels).try_into().unwrap(), (WIDTH * channel_count).try_into().unwrap(),
if state.formats.contains(&Format::Xrgb8888) { if state.formats.contains(&Format::Xrgb8888) {
Format::Xrgb8888 Format::Xrgb8888
} else { } else {
@@ -304,10 +323,32 @@ fn main() {
state.buffer = Some(buffer.clone()); state.buffer = Some(buffer.clone());
} }
if state.ready { state._ready = if let (Some(_), Some(_), Some(_), Some(_), Some(_), Some(mmap)) = (
dbg!("ready"); &state.compositor,
sleep(Duration::from_secs(2)); &state.surface,
return; &state.shm,
&state.buffer,
&state.wm_base,
&mut state.memory_map,
) {
draw(mmap);
true
} else {
false
}; };
} }
} }
fn draw(memory_map: &mut MmapMut) { // TODO: WlCallback on frame
let mut pixel: u64 = 0;
for byte in &mut **memory_map {
let pixel_offset = (pixel % 4) as u8;
pixel += 1;
*byte = match pixel_offset {
1 => 0,
_ => 255
};
};
}