mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-27 14:48:11 +08:00
Desktop: Refactor window state to not require locking (#2928)
* Replace window state with channels and improve resize performance * Move Cef Handler into the cef module * Reuse textures * Test cef scheduling * Schedule self render if texture is outdated * Address review comments
This commit is contained in:
+7
-130
@@ -1,16 +1,15 @@
|
||||
use std::fmt::Debug;
|
||||
use std::process::exit;
|
||||
use std::sync::{Arc, Mutex, MutexGuard, PoisonError};
|
||||
use std::time::Instant;
|
||||
|
||||
use tracing_subscriber::EnvFilter;
|
||||
use winit::event_loop::{EventLoop, EventLoopProxy};
|
||||
use winit::event_loop::EventLoop;
|
||||
|
||||
mod cef;
|
||||
use cef::Setup;
|
||||
use cef::{Setup, WindowSize};
|
||||
|
||||
mod render;
|
||||
use render::{FrameBuffer, GraphicsState};
|
||||
use render::FrameBuffer;
|
||||
|
||||
mod app;
|
||||
use app::WinitApp;
|
||||
@@ -19,123 +18,10 @@ mod dirs;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) enum CustomEvent {
|
||||
UiUpdate,
|
||||
UiUpdate(FrameBuffer),
|
||||
ScheduleBrowserWork(Instant),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct WindowState {
|
||||
width: Option<usize>,
|
||||
height: Option<usize>,
|
||||
ui_frame_buffer: Option<FrameBuffer>,
|
||||
_viewport_frame_buffer: Option<FrameBuffer>,
|
||||
graphics_state: Option<GraphicsState>,
|
||||
event_loop_proxy: Option<EventLoopProxy<CustomEvent>>,
|
||||
}
|
||||
|
||||
impl WindowState {
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
width: None,
|
||||
height: None,
|
||||
ui_frame_buffer: None,
|
||||
_viewport_frame_buffer: None,
|
||||
graphics_state: None,
|
||||
event_loop_proxy: None,
|
||||
}
|
||||
}
|
||||
|
||||
fn handle(self) -> WindowStateHandle {
|
||||
WindowStateHandle { inner: Arc::new(Mutex::new(self)) }
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct WindowStateHandle {
|
||||
inner: Arc<Mutex<WindowState>>,
|
||||
}
|
||||
|
||||
impl WindowStateHandle {
|
||||
fn with<'a, P>(&self, p: P) -> Result<(), PoisonError<MutexGuard<'a, WindowState>>>
|
||||
where
|
||||
P: FnOnce(&mut WindowState),
|
||||
{
|
||||
match self.inner.lock() {
|
||||
Ok(mut guard) => {
|
||||
p(&mut guard);
|
||||
Ok(())
|
||||
}
|
||||
Err(_) => todo!("not error handling yet"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for WindowStateHandle {
|
||||
fn clone(&self) -> Self {
|
||||
Self { inner: self.inner.clone() }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct CefHandler {
|
||||
window_state: WindowStateHandle,
|
||||
}
|
||||
|
||||
impl CefHandler {
|
||||
fn new(window_state: WindowStateHandle) -> Self {
|
||||
Self { window_state }
|
||||
}
|
||||
}
|
||||
|
||||
impl cef::CefEventHandler for CefHandler {
|
||||
fn window_size(&self) -> cef::WindowSize {
|
||||
let mut w = 1;
|
||||
let mut h = 1;
|
||||
|
||||
self.window_state
|
||||
.with(|s| {
|
||||
if let WindowState {
|
||||
width: Some(width),
|
||||
height: Some(height),
|
||||
..
|
||||
} = s
|
||||
{
|
||||
w = *width;
|
||||
h = *height;
|
||||
}
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
cef::WindowSize::new(w, h)
|
||||
}
|
||||
|
||||
fn draw(&self, frame_buffer: FrameBuffer) -> bool {
|
||||
let mut correct_size = true;
|
||||
self.window_state
|
||||
.with(|s| {
|
||||
if let Some(event_loop_proxy) = &s.event_loop_proxy {
|
||||
let _ = event_loop_proxy.send_event(CustomEvent::UiUpdate);
|
||||
}
|
||||
if frame_buffer.width() != s.width.unwrap_or(1) || frame_buffer.height() != s.height.unwrap_or(1) {
|
||||
correct_size = false;
|
||||
} else {
|
||||
s.ui_frame_buffer = Some(frame_buffer);
|
||||
}
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
correct_size
|
||||
}
|
||||
|
||||
fn schedule_cef_message_loop_work(&self, scheduled_time: std::time::Instant) {
|
||||
self.window_state
|
||||
.with(|s| {
|
||||
let Some(event_loop_proxy) = &mut s.event_loop_proxy else { return };
|
||||
let _ = event_loop_proxy.send_event(CustomEvent::ScheduleBrowserWork(scheduled_time));
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
tracing_subscriber::fmt().with_env_filter(EnvFilter::from_default_env()).init();
|
||||
|
||||
@@ -148,20 +34,11 @@ fn main() {
|
||||
}
|
||||
};
|
||||
|
||||
let window_state = WindowState::new().handle();
|
||||
|
||||
window_state
|
||||
.with(|s| {
|
||||
s.width = Some(1200);
|
||||
s.height = Some(800);
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
let event_loop = EventLoop::<CustomEvent>::with_user_event().build().unwrap();
|
||||
|
||||
window_state.with(|s| s.event_loop_proxy = Some(event_loop.create_proxy())).unwrap();
|
||||
let (window_size_sender, window_size_receiver) = std::sync::mpsc::channel();
|
||||
|
||||
let cef_context = match cef_context.init(CefHandler::new(window_state.clone())) {
|
||||
let cef_context = match cef_context.init(cef::CefHandler::new(window_size_receiver, event_loop.create_proxy())) {
|
||||
Ok(c) => c,
|
||||
Err(cef::InitError::InitializationFailed) => {
|
||||
tracing::error!("Cef initialization failed");
|
||||
@@ -171,7 +48,7 @@ fn main() {
|
||||
|
||||
tracing::info!("Cef initialized successfully");
|
||||
|
||||
let mut winit_app = WinitApp::new(window_state, cef_context);
|
||||
let mut winit_app = WinitApp::new(cef_context, window_size_sender, event_loop.create_proxy());
|
||||
|
||||
event_loop.run_app(&mut winit_app).unwrap();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user