Skip to content

Commit

Permalink
use locking when drawing
Browse files Browse the repository at this point in the history
all renderers will obtain a draw guard to ensure only one is rendering at a time. impl some todo's within input now that multiple windows exist. simplify multi window renderer following the draw guard change.
  • Loading branch information
AustinJ235 committed Mar 10, 2024
1 parent 86cd155 commit af8a63b
Show file tree
Hide file tree
Showing 7 changed files with 71 additions and 102 deletions.
4 changes: 2 additions & 2 deletions src/input/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,8 +130,8 @@ impl<'a> InputHookBuilder<'a> {
});

match &self.target {
InputHookTarget::Window(_) => {
// TODO:
InputHookTarget::Window(window) => {
window.attach_input_hook(id);
},
InputHookTarget::Bin(bin) => {
bin.attach_input_hook(id);
Expand Down
8 changes: 6 additions & 2 deletions src/input/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -290,9 +290,13 @@ impl Input {
/// Manually set the `Bin` that is focused.
///
/// Useful for dialogs/forms that require text input.
///
/// ***Note:**: If the bin doesn't have an associated window, this does nothing.
pub fn set_bin_focused(&self, bin: &Arc<Bin>) {
// TODO: get window from Bin
let win = WindowID::invalid();
let win = match bin.associated_window() {
Some(some) => some.id(),
None => return,
};

self.event_send
.send(LoopEvent::FocusBin {
Expand Down
4 changes: 4 additions & 0 deletions src/interface/bin/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,10 @@ impl Bin {
*associated_window = Some(Arc::downgrade(window));
}

pub fn associated_window(&self) -> Option<Arc<Window>> {
self.associated_window.lock().clone().and_then(|weak| weak.upgrade())
}

pub fn ancestors(&self) -> Vec<Arc<Bin>> {
let mut out = Vec::new();
let mut check_wk_op = self.hrchy.load_full().parent.clone();
Expand Down
128 changes: 37 additions & 91 deletions src/renderer/amwr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,14 @@ use std::sync::Arc;
use std::thread;
use std::thread::JoinHandle;

use flume::TryRecvError;

use crate::renderer::Renderer;
use crate::window::{WMHookID, Window, WindowID};
use crate::Basalt;

pub struct AutoMultiWindowRenderer {
basalt: Arc<Basalt>,
wm_hook_ids: Vec<WMHookID>,
window_states: HashMap<WindowID, WindowState>,
}

struct WindowState {
window: Arc<Window>,
worker_handle: Option<JoinHandle<Result<(), String>>>,
hook_ids: Vec<WMHookID>,
join_handles: HashMap<WindowID, JoinHandle<Result<(), String>>>,
}

enum AMWREvent {
Expand All @@ -29,115 +22,68 @@ impl AutoMultiWindowRenderer {
pub fn new(basalt: Arc<Basalt>) -> Self {
Self {
basalt,
wm_hook_ids: Vec::new(),
window_states: HashMap::new(),
hook_ids: Vec::new(),
join_handles: HashMap::new(),
}
}

fn add_window(&mut self, window: Arc<Window>) {
let window_cp = window.clone();

let join_handle = thread::spawn(move || Renderer::new(window)?.run_interface_only());

self.window_states.insert(
window_cp.id(),
WindowState {
window: window_cp,
worker_handle: Some(join_handle),
},
);
}

fn remove_window(&mut self, window_id: WindowID) {
self.window_states.remove(&window_id);
}

pub fn run(mut self, exit_when_all_windows_closed: bool) -> Result<(), String> {
let (event_send, event_recv) = flume::unbounded();

for window in self.basalt.window_manager_ref().windows() {
self.add_window(window);
event_send.send(AMWREvent::Open(window)).unwrap();
}

let (event_send, event_recv) = flume::unbounded();
let on_open_event_send = event_send.clone();
let on_close_event_send = event_send;

self.wm_hook_ids
self.hook_ids
.push(self.basalt.window_manager_ref().on_open(move |window| {
on_open_event_send.send(AMWREvent::Open(window)).unwrap();
}));

self.wm_hook_ids
self.hook_ids
.push(self.basalt.window_manager_ref().on_close(move |window_id| {
on_close_event_send
.send(AMWREvent::Close(window_id))
.unwrap();
}));

let mut event_recv_block = self.window_states.is_empty();

'main_loop: loop {
if event_recv_block && exit_when_all_windows_closed {
break;
}

loop {
let event = match event_recv_block {
true => {
match event_recv.recv() {
Ok(ok) => ok,
Err(_) => break 'main_loop,
}
},
false => {
match event_recv.try_recv() {
Ok(ok) => ok,
Err(TryRecvError::Empty) => break,
Err(TryRecvError::Disconnected) => break 'main_loop,
}
},
};

match event {
AMWREvent::Open(window) => {
self.add_window(window);
},
AMWREvent::Close(_window_id) => (),
}
}

self.window_states.retain(|window_id, window_state| {
if window_state.worker_handle.as_ref().unwrap().is_finished() {
match window_state.worker_handle.take().unwrap().join() {
Ok(worker_result) => {
if let Err(e) = worker_result {
while let Ok(event) = event_recv.recv() {
match event {
AMWREvent::Open(window) => {
if !self.join_handles.contains_key(&window.id()) {
self.join_handles.insert(
window.id(),
thread::spawn(move || Renderer::new(window)?.run_interface_only()),
);
}
},
AMWREvent::Close(window_id) => {
if let Some(join_handle) = self.join_handles.remove(&window_id) {
match join_handle.join() {
Ok(Ok(_)) => (),
Ok(Err(e)) => {
println!(
"[Basalt][AMWR]: Window with ID of {:?} had its renderer exit \
with an error of: {}",
"[Basalt][AMWR]: {:?} had its renderer exit with an error: {}",
window_id, e
);
}
},
Err(_) => {
println!(
"[Basalt][AMWR]: Window with ID of {:?} had its renderer panic!",
window_id
);
},
},
Err(_) => {
println!("[Basalt][AMWR]: {:?} had its renderer panic!", window_id);
},
}
}

return false;
}

// TODO: Trigger render

true
});

event_recv_block = self.window_states.is_empty();
if exit_when_all_windows_closed && self.join_handles.is_empty() {
break;
}
},
}
}

for wm_hook_id in self.wm_hook_ids.drain(..) {
self.basalt.window_manager_ref().remove_hook(wm_hook_id);
for hook_id in self.hook_ids.drain(..) {
self.basalt.window_manager_ref().remove_hook(hook_id);
}

Ok(())
Expand Down
3 changes: 3 additions & 0 deletions src/renderer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -435,6 +435,7 @@ impl Renderer {
depth_range: 0.0..=1.0,
};

let window_manager = self.window.window_manager();
let mut swapchain_op: Option<Arc<Swapchain>> = None;
let mut swapchain_views_op = None;
let mut buffer_op = None;
Expand Down Expand Up @@ -642,6 +643,8 @@ impl Renderer {
release_exclusive_fullscreen = false;
}

let _draw_guard = window_manager.request_draw();

let (image_num, suboptimal, acquire_future) = match swapchain::acquire_next_image(
swapchain_op.as_ref().unwrap().clone(),
Some(Duration::from_millis(1000)),
Expand Down
14 changes: 13 additions & 1 deletion src/window/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use std::thread;

use flume::{Receiver, Sender};
pub use monitor::{FullScreenBehavior, FullScreenError, Monitor, MonitorMode};
use parking_lot::{Condvar, Mutex};
use parking_lot::{Condvar, FairMutex, FairMutexGuard, Mutex};
pub use window::Window;
use winit::dpi::PhysicalSize;
use winit::event::{
Expand Down Expand Up @@ -215,6 +215,11 @@ pub struct WindowManager {
event_proxy: EventLoopProxy<WMEvent>,
next_hook_id: AtomicU64,
windows: Mutex<HashMap<WindowID, Arc<Window>>>,
draw_lock: FairMutex<()>,
}

pub(crate) struct DrawGuard<'a> {
inner: FairMutexGuard<'a, ()>,
}

impl WindowManager {
Expand Down Expand Up @@ -344,6 +349,12 @@ impl WindowManager {
result_guard.take().unwrap()
}

pub(crate) fn request_draw(&self) -> DrawGuard {
DrawGuard {
inner: self.draw_lock.lock(),
}
}

pub(crate) fn add_binary_font(&self, binary_font: Arc<dyn AsRef<[u8]> + Sync + Send>) {
self.send_event(WMEvent::AddBinaryFont(binary_font));
}
Expand Down Expand Up @@ -377,6 +388,7 @@ impl WindowManager {
event_proxy,
next_hook_id: AtomicU64::new(1),
windows: Mutex::new(HashMap::new()),
draw_lock: FairMutex::new(()),
});

let wm_closure = wm.clone();
Expand Down
12 changes: 6 additions & 6 deletions src/window/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ struct State {
msaa: MSAA,
vsync: VSync,
associated_bins: HashMap<BinID, Weak<Bin>>,
associated_hooks: Vec<InputHookID>,
attached_input_hooks: Vec<InputHookID>,
keep_alive_objects: Vec<Box<dyn Any + Send + Sync + 'static>>,
}

Expand Down Expand Up @@ -110,7 +110,7 @@ impl Window {
vsync: options.default_vsync,
interface_scale: basalt.options_ref().scale,
associated_bins: HashMap::new(),
associated_hooks: Vec::new(),
attached_input_hooks: Vec::new(),
keep_alive_objects: Vec::new(),
};

Expand Down Expand Up @@ -678,13 +678,13 @@ impl Window {
.unwrap_or_else(|| self.inner_dimensions())
}

/// Associate an input hook to this window. When the window closes, this hook will be
/// Attach an input hook to this window. When the window closes, this hook will be
/// automatically removed from `Input`.
///
/// ***Note**: If a hook's target is a window this behavior already occurs without needing to
/// call this method.*
pub fn associate_hook(&self, hook: InputHookID) {
self.state.lock().associated_hooks.push(hook);
pub fn attach_input_hook(&self, hook: InputHookID) {
self.state.lock().attached_input_hooks.push(hook);
}

pub fn on_press<C: KeyCombo, F>(self: &Arc<Self>, combo: C, method: F) -> InputHookID
Expand Down Expand Up @@ -837,7 +837,7 @@ impl Window {

impl Drop for Window {
fn drop(&mut self) {
for hook_id in self.state.lock().associated_hooks.drain(..) {
for hook_id in self.state.lock().attached_input_hooks.drain(..) {
self.basalt.input_ref().remove_hook(hook_id);
}
}
Expand Down

0 comments on commit af8a63b

Please sign in to comment.