From 3867e9a57141b1c5ac05ae11d0cc521bc1b6f14b Mon Sep 17 00:00:00 2001 From: stickynotememo Date: Thu, 20 Nov 2025 08:52:44 +1100 Subject: [PATCH] use memmap2 --- Cargo.lock | 10 ++++++ Cargo.toml | 1 + README.md | 3 ++ src/main.rs | 89 ++++++++++++++++++++++++++++++++++++++--------------- 4 files changed, 79 insertions(+), 24 deletions(-) create mode 100644 README.md diff --git a/Cargo.lock b/Cargo.lock index afb64d7..3493452 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -96,6 +96,15 @@ dependencies = [ "libc", ] +[[package]] +name = "memmap2" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "744133e4a0e0a658e1374cf3bf8e415c4052a15a111acd372764c55b4177d490" +dependencies = [ + "libc", +] + [[package]] name = "memoffset" version = "0.6.5" @@ -381,6 +390,7 @@ version = "0.1.0" dependencies = [ "libc", "memfile", + "memmap2", "shared_memory", "wayland-client", "wayland-protocols", diff --git a/Cargo.toml b/Cargo.toml index d8ae379..8264814 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,6 +6,7 @@ edition = "2024" [dependencies] libc = "0.2.177" memfile = "0.3.2" +memmap2 = "0.9.9" shared_memory = "0.12.4" wayland-client = "0.31" wayland-protocols = { version = "0.32.9", features = ["client"] } diff --git a/README.md b/README.md new file mode 100644 index 0000000..6a4edfd --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +## Wolfenstein-3d like renderer +This renderer generates + diff --git a/src/main.rs b/src/main.rs index af02485..44b0360 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,8 +1,11 @@ #![feature(more_qualified_paths)] +use std::fs::File; use std::time::Duration; use std::{ffi::CString, thread::sleep}; use std::os::fd::BorrowedFd; +use memmap2::{MmapMut, MmapOptions}; + use wayland_client::{ Connection, Dispatch, EventQueue, Proxy, backend::ObjectId, delegate_noop, protocol::{ wl_buffer::{self, WlBuffer}, @@ -31,7 +34,7 @@ const HEIGHT: i32 = 540; #[derive(Debug)] struct State { exit: bool, - ready: bool, + _ready: bool, compositor: Option, surface: Option, shm: Option, @@ -41,6 +44,7 @@ struct State { xdg_surface: Option, toplevel_surface: Option, pool: Option, + memory_map: Option, } impl Dispatch for State { @@ -120,6 +124,8 @@ impl Dispatch for State { // Data races should not be possible as the compositor will // not modify the buffer. (Non owners do not have write // permissions) + // + // TODO: Use shared_memory and implement FD return let fildes = shm_open(name.as_ptr(), O_RDWR | O_CREAT, S_IRWXU | S_IROTH); if fildes <= 0 { @@ -129,6 +135,22 @@ impl Dispatch for State { 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); // TODO: Move drawing logic to event loop (double flush) state.pool = Some(shm_pool); @@ -228,16 +250,17 @@ fn main() { let mut state = State { exit: false, - ready: false, + _ready: false, + formats: vec![], compositor: None, surface: None, shm: None, - formats: vec![], buffer: None, wm_base: None, xdg_surface: None, toplevel_surface: None, pool: None, + memory_map: None }; let mut event_queue: EventQueue = conn.new_event_queue(); @@ -266,33 +289,29 @@ fn main() { 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 { - let channels: i32 = if state.formats.contains(&Format::Xrgb8888) { - 4 + let format = if state.formats.contains(&Format::Xrgb8888) { + Format::Xrgb8888 } else { - 4 - }; // 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. + Format::Argb8888 + }; + + 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 // 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( 0, WIDTH.try_into().unwrap(), HEIGHT.try_into().unwrap(), - (WIDTH * channels).try_into().unwrap(), + (WIDTH * channel_count).try_into().unwrap(), if state.formats.contains(&Format::Xrgb8888) { Format::Xrgb8888 } else { @@ -304,10 +323,32 @@ fn main() { state.buffer = Some(buffer.clone()); } - if state.ready { - dbg!("ready"); - sleep(Duration::from_secs(2)); - return; + state._ready = if let (Some(_), Some(_), Some(_), Some(_), Some(_), Some(mmap)) = ( + &state.compositor, + &state.surface, + &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 + }; + }; +}