From 81eb01170da4334dce88bd0d9e815d6d28e3c796 Mon Sep 17 00:00:00 2001 From: HampusM Date: Sun, 31 May 2026 23:43:23 +0200 Subject: refactor(engine): replace windowing app message channels with queues --- engine/Cargo.toml | 2 +- engine/src/windowing.rs | 131 ++++++++++++++++++++++-------------------------- 2 files changed, 60 insertions(+), 73 deletions(-) (limited to 'engine') diff --git a/engine/Cargo.toml b/engine/Cargo.toml index 260bb56..1e10d42 100644 --- a/engine/Cargo.toml +++ b/engine/Cargo.toml @@ -12,9 +12,9 @@ tracing = "0.1.39" seq-macro = "0.3.5" paste = "1.0.14" parking_lot = "0.12.3" -crossbeam-channel = "0.5.15" safer-ffi = "0.1.13" nu-ansi-term = "0.46.0" +crossbeam-queue = "0.3.12" engine-ecs = { workspace = true } util-macros = { workspace = true } opengl-bindings = { workspace = true } diff --git a/engine/src/windowing.rs b/engine/src/windowing.rs index 096a23f..fac1c62 100644 --- a/engine/src/windowing.rs +++ b/engine/src/windowing.rs @@ -1,14 +1,9 @@ use std::hint::cold_path; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::{Arc, Weak}; -use std::thread::{Builder as ThreadBuilder, JoinHandle as ThreadJoinHandle}; +use std::thread::Builder as ThreadBuilder; -use crossbeam_channel::{ - bounded as bounded_channel, - Receiver as ChannelReceiver, - Sender as ChannelSender, - TrySendError, -}; +use crossbeam_queue::ArrayQueue; use raw_window_handle::{DisplayHandle, HandleError, HasDisplayHandle, WindowHandle}; use winit::application::ApplicationHandler; use winit::dpi::PhysicalPosition; @@ -55,9 +50,9 @@ pub mod keyboard; pub mod mouse; pub mod window; -const MESSAGE_FROM_APP_CHANNEL_CAP: usize = 512; +const MESSAGE_FROM_APP_QUEUE_SIZE: usize = 512; -const MESSAGE_TO_APP_CHANNEL_CAP: usize = 16; // Increase if more messages are added +const MESSAGE_TO_APP_QUEUE_SIZE: usize = 16; // Increase if more messages are added declare_entity!( pub PHASE, @@ -144,13 +139,13 @@ fn update_stuff( .into(); let Context { - ref message_from_app_receiver, + ref message_from_app_queue, ref mut display_handle, ref mut windows, .. } = *context; - for message in message_from_app_receiver.try_iter() { + for message in iter_array_queue(message_from_app_queue) { tracing::trace!(message=?message, "Received message from app"); match message { @@ -304,9 +299,8 @@ fn handle_window_removed( #[derive(Debug, Sole)] pub struct Context { - _thread: ThreadJoinHandle<()>, - message_from_app_receiver: ChannelReceiver, - message_to_app_sender: ChannelSender, + message_from_app_queue: Arc>, + message_to_app_queue: Arc>, shared_state: Arc, display_handle: Option, windows: MapVec, Uid)>, @@ -350,15 +344,10 @@ impl Context fn try_send_message_to_app(&self, message: MessageToApp) { - if let Err(err) = self.message_to_app_sender.try_send(message) { - let error = match &err { - TrySendError::Full(_) => TrySendError::Full(()), - TrySendError::Disconnected(_) => TrySendError::Disconnected(()), - }; - - let message = err.into_inner(); - - tracing::error!("Failed to send message {error}: {message:?}"); + if self.message_to_app_queue.push(message).is_err() { + tracing::error!( + "Failed to send message. Queue for messages to windowing app is full" + ); } } } @@ -367,46 +356,49 @@ impl Default for Context { fn default() -> Self { - let (message_from_app_sender, message_from_app_receiver) = - bounded_channel::(MESSAGE_FROM_APP_CHANNEL_CAP); + let message_from_app_queue = Arc::new(ArrayQueue::::new( + MESSAGE_FROM_APP_QUEUE_SIZE, + )); - let message_from_app_receiver_b = message_from_app_receiver.clone(); + let message_from_app_queue_b = message_from_app_queue.clone(); - let (message_to_app_sender, message_to_app_receiver) = - bounded_channel::(MESSAGE_TO_APP_CHANNEL_CAP); + let message_to_app_queue = + Arc::new(ArrayQueue::::new(MESSAGE_TO_APP_QUEUE_SIZE)); + + let message_to_app_queue_b = message_to_app_queue.clone(); let shared_state = Arc::new(SharedState::default()); let shared_state_b = shared_state.clone(); - Self { - _thread: ThreadBuilder::new() - .name("windowing".to_string()) - .spawn(move || { - let mut app = App { - message_from_app_sender, - message_from_app_receiver: message_from_app_receiver_b, - message_to_app_receiver, - shared_state: shared_state_b, - windows: MapVec::default(), - }; + ThreadBuilder::new() + .name("windowing app".to_string()) + .spawn(move || { + let mut app = App { + message_from_app_queue: message_from_app_queue_b, + message_to_app_queue: message_to_app_queue_b, + shared_state: shared_state_b, + windows: MapVec::default(), + }; - let event_loop = match create_event_loop() { - Ok(event_loop) => event_loop, - Err(err) => { - tracing::error!("Failed to create event loop: {err}"); - return; - } - }; + let event_loop = match create_event_loop() { + Ok(event_loop) => event_loop, + Err(err) => { + tracing::error!("Failed to create event loop: {err}"); + return; + } + }; - event_loop.set_control_flow(EventLoopControlFlow::Poll); + event_loop.set_control_flow(EventLoopControlFlow::Poll); - if let Err(err) = event_loop.run_app(&mut app) { - tracing::error!("Event loop error occurred: {err}"); - } - }) - .expect("Failed to create windowing thread"), - message_from_app_receiver, - message_to_app_sender, + if let Err(err) = event_loop.run_app(&mut app) { + tracing::error!("Event loop error occurred: {err}"); + } + }) + .expect("Failed to create windowing thread"); + + Self { + message_from_app_queue, + message_to_app_queue, shared_state, display_handle: None, windows: MapVec::default(), @@ -486,9 +478,8 @@ impl Default for SharedState #[derive(Debug)] struct App { - message_from_app_sender: ChannelSender, - message_from_app_receiver: ChannelReceiver, - message_to_app_receiver: ChannelReceiver, + message_from_app_queue: Arc>, + message_to_app_queue: Arc>, shared_state: Arc, windows: MapVec, WindowSettings)>, } @@ -498,7 +489,7 @@ impl App #[tracing::instrument(skip_all)] fn handle_received_messages(&mut self, event_loop: &ActiveEventLoop) { - for message in self.message_to_app_receiver.try_iter() { + for message in iter_array_queue(&self.message_to_app_queue) { match message { MessageToApp::CreateWindow(window_ent_id, window_creation_attrs) => { tracing::info!( @@ -549,24 +540,13 @@ impl App #[tracing::instrument(skip_all)] fn send_message(&self, message: MessageFromApp) { - if self.message_from_app_sender.is_full() { + if self.message_from_app_queue.is_full() { tracing::warn!( - "Message channel is full! Dropping oldest message from channel" + "Queue for messages to windowing app is full! Dropping oldest message" ); - - self.message_from_app_receiver.try_recv().ok(); } - if let Err(err) = self.message_from_app_sender.try_send(message) { - let error = match &err { - TrySendError::Full(_) => TrySendError::Full(()), - TrySendError::Disconnected(_) => TrySendError::Disconnected(()), - }; - - let message = err.into_inner(); - - tracing::error!("Failed to send message {error}: {message:?}"); - } + self.message_from_app_queue.force_push(message); } } @@ -749,3 +729,10 @@ struct WindowSettings { cursor_grab_mode: CursorGrabMode, } + +fn iter_array_queue( + queue: &ArrayQueue, +) -> impl Iterator + use<'_, Item> +{ + (0..queue.len()).into_iter().filter_map(|_| queue.pop()) +} -- cgit v1.2.3-18-g5258