diff --git a/desktop/src/app.rs b/desktop/src/app.rs index c713e6569d..ef7715d5a7 100644 --- a/desktop/src/app.rs +++ b/desktop/src/app.rs @@ -4,14 +4,12 @@ use crate::WindowSize; use crate::render::GraphicsState; use std::sync::Arc; use std::sync::mpsc::Sender; -use std::time::Duration; +use std::thread::JoinHandle; use std::time::Instant; use winit::application::ApplicationHandler; use winit::dpi::PhysicalSize; -use winit::event::StartCause; use winit::event::WindowEvent; use winit::event_loop::ActiveEventLoop; -use winit::event_loop::ControlFlow; use winit::event_loop::EventLoopProxy; use winit::window::Window; use winit::window::WindowId; @@ -27,10 +25,11 @@ pub(crate) struct WinitApp { _viewport_frame_buffer: Option, graphics_state: Option, event_loop_proxy: EventLoopProxy, + handle: Option>, } impl WinitApp { - pub(crate) fn new(cef_context: cef::Context, window_size_sender: Sender, event_loop_proxy: EventLoopProxy) -> Self { + pub(crate) fn new(cef_context: cef::Context, window_size_sender: Sender, event_loop_proxy: EventLoopProxy, handle: JoinHandle<()>) -> Self { Self { cef_context, window: None, @@ -40,27 +39,12 @@ impl WinitApp { graphics_state: None, window_size_sender, event_loop_proxy, + handle: Some(handle), } } } impl ApplicationHandler for WinitApp { - fn about_to_wait(&mut self, event_loop: &ActiveEventLoop) { - // Set a timeout in case we miss any cef schedule requests - let timeout = Instant::now() + Duration::from_millis(100); - let wait_until = timeout.min(self.cef_schedule.unwrap_or(timeout)); - event_loop.set_control_flow(ControlFlow::WaitUntil(wait_until)); - } - - fn new_events(&mut self, _event_loop: &ActiveEventLoop, _cause: StartCause) { - if let Some(schedule) = self.cef_schedule - && schedule < Instant::now() - { - self.cef_schedule = None; - self.cef_context.work(); - } - } - fn resumed(&mut self, event_loop: &ActiveEventLoop) { let window = Arc::new( event_loop @@ -90,15 +74,16 @@ impl ApplicationHandler for WinitApp { window.request_redraw(); } } - CustomEvent::ScheduleBrowserWork(instant) => { - if let Some(graphics_state) = self.graphics_state.as_mut() - && let Some(frame_buffer) = &self.ui_frame_buffer - && graphics_state.ui_texture_outdated(frame_buffer) - { - self.cef_context.work(); - let _ = self.event_loop_proxy.send_event(CustomEvent::ScheduleBrowserWork(Instant::now() + Duration::from_millis(1))); - } - self.cef_schedule = Some(instant); + CustomEvent::WorkCef => { + self.cef_context.work(); + } + CustomEvent::KeepProcessAliveWhenResizing(window_size) => { + let Some(frame_buffer) = &self.ui_frame_buffer else { + return; + }; + if window_size.width != frame_buffer.width() || window_size.height != frame_buffer.height() { + let _ = self.event_loop_proxy.send_event(CustomEvent::KeepProcessAliveWhenResizing(window_size)); + }; } } } @@ -112,17 +97,15 @@ impl ApplicationHandler for WinitApp { event_loop.exit(); } WindowEvent::Resized(PhysicalSize { width, height }) => { - let _ = self.window_size_sender.send(WindowSize::new(width as usize, height as usize)); - if let Some(ref mut graphics_state) = self.graphics_state { - graphics_state.resize(width, height); - } + let window_size = WindowSize::new(width as usize, height as usize); + let _ = self.window_size_sender.send(window_size); self.cef_context.notify_of_resize(); + self.event_loop_proxy.send_event(CustomEvent::KeepProcessAliveWhenResizing(window_size)); } WindowEvent::RedrawRequested => { let Some(ref mut graphics_state) = self.graphics_state else { return }; // Only rerender once we have a new ui texture to display - match graphics_state.render() { Ok(_) => {} Err(wgpu::SurfaceError::Lost) => { @@ -136,8 +119,9 @@ impl ApplicationHandler for WinitApp { } _ => {} } + } - // Notify cef of possible input events - self.cef_context.work(); + fn exiting(&mut self, _event_loop: &ActiveEventLoop) { + let _ = self.handle.take().unwrap().join(); } } diff --git a/desktop/src/cef.rs b/desktop/src/cef.rs index ef63672f79..1b1d68f580 100644 --- a/desktop/src/cef.rs +++ b/desktop/src/cef.rs @@ -1,6 +1,9 @@ use crate::{CustomEvent, FrameBuffer}; use std::{ - sync::{Arc, Mutex, mpsc::Receiver}, + sync::{ + Arc, Mutex, + mpsc::{Receiver, Sender}, + }, time::Instant, }; @@ -21,7 +24,7 @@ pub(crate) trait CefEventHandler: Clone { fn schedule_cef_message_loop_work(&self, scheduled_time: Instant); } -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Debug)] pub(crate) struct WindowSize { pub(crate) width: usize, pub(crate) height: usize, @@ -33,11 +36,6 @@ impl WindowSize { } } -#[derive(Clone)] -pub(crate) struct CefHandler { - window_size_receiver: Arc>, - event_loop_proxy: EventLoopProxy, -} struct WindowSizeReceiver { receiver: Receiver, window_size: WindowSize, @@ -50,11 +48,20 @@ impl WindowSizeReceiver { } } } + +#[derive(Clone)] +pub(crate) struct CefHandler { + window_size_receiver: Arc>, + event_loop_proxy: EventLoopProxy, + poll_cef_sender: Sender, +} + impl CefHandler { - pub(crate) fn new(window_size_receiver: Receiver, event_loop_proxy: EventLoopProxy) -> Self { + pub(crate) fn new(window_size_receiver: Receiver, event_loop_proxy: EventLoopProxy, poll_cef_sender: Sender) -> Self { Self { window_size_receiver: Arc::new(Mutex::new(WindowSizeReceiver::new(window_size_receiver))), event_loop_proxy, + poll_cef_sender, } } } @@ -71,11 +78,12 @@ impl CefEventHandler for CefHandler { } *window_size } + fn draw(&self, frame_buffer: FrameBuffer) { let _ = self.event_loop_proxy.send_event(CustomEvent::UiUpdate(frame_buffer)); } fn schedule_cef_message_loop_work(&self, scheduled_time: std::time::Instant) { - let _ = self.event_loop_proxy.send_event(CustomEvent::ScheduleBrowserWork(scheduled_time)); + let _ = self.poll_cef_sender.send(scheduled_time); } } diff --git a/desktop/src/main.rs b/desktop/src/main.rs index f748b3111e..cbd7c54797 100644 --- a/desktop/src/main.rs +++ b/desktop/src/main.rs @@ -1,6 +1,6 @@ -use std::fmt::Debug; use std::process::exit; -use std::time::Instant; +use std::time::{Duration, Instant}; +use std::{fmt::Debug, thread}; use tracing_subscriber::EnvFilter; use winit::event_loop::EventLoop; @@ -19,7 +19,8 @@ mod dirs; #[derive(Debug)] pub(crate) enum CustomEvent { UiUpdate(FrameBuffer), - ScheduleBrowserWork(Instant), + WorkCef, + KeepProcessAliveWhenResizing(WindowSize), } fn main() { @@ -35,10 +36,12 @@ fn main() { }; let event_loop = EventLoop::::with_user_event().build().unwrap(); + let event_loop_proxy = event_loop.create_proxy(); let (window_size_sender, window_size_receiver) = std::sync::mpsc::channel(); + let (poll_cef_sender, poll_cef_receiver) = std::sync::mpsc::channel(); - let cef_context = match cef_context.init(cef::CefHandler::new(window_size_receiver, event_loop.create_proxy())) { + let cef_context = match cef_context.init(cef::CefHandler::new(window_size_receiver, event_loop_proxy.clone(), poll_cef_sender)) { Ok(c) => c, Err(cef::InitError::InitializationFailed) => { tracing::error!("Cef initialization failed"); @@ -47,8 +50,24 @@ fn main() { }; tracing::info!("Cef initialized successfully"); + let poll_cef_elp = event_loop_proxy.clone(); + let handle = thread::spawn(move || { + loop { + match poll_cef_receiver.recv_timeout(Duration::from_millis(100)) { + Ok(scheduled_instant) => { + if scheduled_instant > Instant::now() { + thread::sleep(scheduled_instant - Instant::now()); + } + let _ = poll_cef_elp.send_event(CustomEvent::WorkCef); + } + Err(_) => { + let _ = poll_cef_elp.send_event(CustomEvent::WorkCef); + } + } + } + }); - let mut winit_app = WinitApp::new(cef_context, window_size_sender, event_loop.create_proxy()); + let mut winit_app = WinitApp::new(cef_context, window_size_sender, event_loop_proxy.clone(), handle); event_loop.run_app(&mut winit_app).unwrap(); } diff --git a/desktop/src/render.rs b/desktop/src/render.rs index 6d3755a803..9f79ac26b9 100644 --- a/desktop/src/render.rs +++ b/desktop/src/render.rs @@ -223,13 +223,7 @@ impl GraphicsState { graphics_state } - pub(crate) fn ui_texture_outdated(&self, frame_buffer: &FrameBuffer) -> bool { - let width = frame_buffer.width() as u32; - let height = frame_buffer.height() as u32; - - self.config.width != width || self.config.height != height - } - pub(crate) fn resize(&mut self, width: u32, height: u32) { + pub(crate) fn try_resize(&mut self, width: u32, height: u32) { if width > 0 && height > 0 && (self.config.width != width || self.config.height != height) { self.config.width = width; self.config.height = height; @@ -248,7 +242,26 @@ impl GraphicsState { usage: wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::COPY_DST, view_formats: &[], }); + + let texture_view = texture.create_view(&wgpu::TextureViewDescriptor::default()); self.texture = Some(texture); + + let bind_group = self.device.create_bind_group(&wgpu::BindGroupDescriptor { + layout: &self.render_pipeline.get_bind_group_layout(0), + entries: &[ + wgpu::BindGroupEntry { + binding: 0, + resource: wgpu::BindingResource::TextureView(&texture_view), + }, + wgpu::BindGroupEntry { + binding: 1, + resource: wgpu::BindingResource::Sampler(&self.sampler), + }, + ], + label: Some("texture_bind_group"), + }); + + self.bind_group = Some(bind_group); } } @@ -257,7 +270,7 @@ impl GraphicsState { let width = frame_buffer.width() as u32; let height = frame_buffer.height() as u32; - self.resize(width, height); + self.try_resize(width, height); let Some(ref texture) = self.texture else { return }; @@ -280,25 +293,6 @@ impl GraphicsState { depth_or_array_layers: 1, }, ); - - let texture_view = texture.create_view(&wgpu::TextureViewDescriptor::default()); - - let bind_group = self.device.create_bind_group(&wgpu::BindGroupDescriptor { - layout: &self.render_pipeline.get_bind_group_layout(0), - entries: &[ - wgpu::BindGroupEntry { - binding: 0, - resource: wgpu::BindingResource::TextureView(&texture_view), - }, - wgpu::BindGroupEntry { - binding: 1, - resource: wgpu::BindingResource::Sampler(&self.sampler), - }, - ], - label: Some("texture_bind_group"), - }); - - self.bind_group = Some(bind_group); } pub(crate) fn render(&mut self) -> Result<(), wgpu::SurfaceError> {