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:
Dennis Kobert
2025-07-24 17:51:55 +00:00
committed by GitHub
parent 9f4f3681c3
commit f184e4aab2
7 changed files with 165 additions and 247 deletions
+7 -130
View File
@@ -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();
}