Skip to content

Commit 06d5c44

Browse files
committed
Poll cef from separate thread
1 parent f184e4a commit 06d5c44

4 files changed

Lines changed: 82 additions & 77 deletions

File tree

desktop/src/app.rs

Lines changed: 20 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,12 @@ use crate::WindowSize;
44
use crate::render::GraphicsState;
55
use std::sync::Arc;
66
use std::sync::mpsc::Sender;
7-
use std::time::Duration;
7+
use std::thread::JoinHandle;
88
use std::time::Instant;
99
use winit::application::ApplicationHandler;
1010
use winit::dpi::PhysicalSize;
11-
use winit::event::StartCause;
1211
use winit::event::WindowEvent;
1312
use winit::event_loop::ActiveEventLoop;
14-
use winit::event_loop::ControlFlow;
1513
use winit::event_loop::EventLoopProxy;
1614
use winit::window::Window;
1715
use winit::window::WindowId;
@@ -27,10 +25,11 @@ pub(crate) struct WinitApp {
2725
_viewport_frame_buffer: Option<FrameBuffer>,
2826
graphics_state: Option<GraphicsState>,
2927
event_loop_proxy: EventLoopProxy<CustomEvent>,
28+
handle: Option<JoinHandle<()>>,
3029
}
3130

3231
impl WinitApp {
33-
pub(crate) fn new(cef_context: cef::Context<cef::Initialized>, window_size_sender: Sender<WindowSize>, event_loop_proxy: EventLoopProxy<CustomEvent>) -> Self {
32+
pub(crate) fn new(cef_context: cef::Context<cef::Initialized>, window_size_sender: Sender<WindowSize>, event_loop_proxy: EventLoopProxy<CustomEvent>, handle: JoinHandle<()>) -> Self {
3433
Self {
3534
cef_context,
3635
window: None,
@@ -40,27 +39,12 @@ impl WinitApp {
4039
graphics_state: None,
4140
window_size_sender,
4241
event_loop_proxy,
42+
handle: Some(handle),
4343
}
4444
}
4545
}
4646

4747
impl ApplicationHandler<CustomEvent> for WinitApp {
48-
fn about_to_wait(&mut self, event_loop: &ActiveEventLoop) {
49-
// Set a timeout in case we miss any cef schedule requests
50-
let timeout = Instant::now() + Duration::from_millis(100);
51-
let wait_until = timeout.min(self.cef_schedule.unwrap_or(timeout));
52-
event_loop.set_control_flow(ControlFlow::WaitUntil(wait_until));
53-
}
54-
55-
fn new_events(&mut self, _event_loop: &ActiveEventLoop, _cause: StartCause) {
56-
if let Some(schedule) = self.cef_schedule
57-
&& schedule < Instant::now()
58-
{
59-
self.cef_schedule = None;
60-
self.cef_context.work();
61-
}
62-
}
63-
6448
fn resumed(&mut self, event_loop: &ActiveEventLoop) {
6549
let window = Arc::new(
6650
event_loop
@@ -90,15 +74,16 @@ impl ApplicationHandler<CustomEvent> for WinitApp {
9074
window.request_redraw();
9175
}
9276
}
93-
CustomEvent::ScheduleBrowserWork(instant) => {
94-
if let Some(graphics_state) = self.graphics_state.as_mut()
95-
&& let Some(frame_buffer) = &self.ui_frame_buffer
96-
&& graphics_state.ui_texture_outdated(frame_buffer)
97-
{
98-
self.cef_context.work();
99-
let _ = self.event_loop_proxy.send_event(CustomEvent::ScheduleBrowserWork(Instant::now() + Duration::from_millis(1)));
100-
}
101-
self.cef_schedule = Some(instant);
77+
CustomEvent::WorkCef => {
78+
self.cef_context.work();
79+
}
80+
CustomEvent::KeepProcessAliveWhenResizing(window_size) => {
81+
let Some(frame_buffer) = &self.ui_frame_buffer else {
82+
return;
83+
};
84+
if window_size.width != frame_buffer.width() || window_size.height != frame_buffer.height() {
85+
let _ = self.event_loop_proxy.send_event(CustomEvent::KeepProcessAliveWhenResizing(window_size));
86+
};
10287
}
10388
}
10489
}
@@ -112,17 +97,15 @@ impl ApplicationHandler<CustomEvent> for WinitApp {
11297
event_loop.exit();
11398
}
11499
WindowEvent::Resized(PhysicalSize { width, height }) => {
115-
let _ = self.window_size_sender.send(WindowSize::new(width as usize, height as usize));
116-
if let Some(ref mut graphics_state) = self.graphics_state {
117-
graphics_state.resize(width, height);
118-
}
100+
let window_size = WindowSize::new(width as usize, height as usize);
101+
let _ = self.window_size_sender.send(window_size);
119102
self.cef_context.notify_of_resize();
103+
self.event_loop_proxy.send_event(CustomEvent::KeepProcessAliveWhenResizing(window_size));
120104
}
121105

122106
WindowEvent::RedrawRequested => {
123107
let Some(ref mut graphics_state) = self.graphics_state else { return };
124108
// Only rerender once we have a new ui texture to display
125-
126109
match graphics_state.render() {
127110
Ok(_) => {}
128111
Err(wgpu::SurfaceError::Lost) => {
@@ -136,8 +119,9 @@ impl ApplicationHandler<CustomEvent> for WinitApp {
136119
}
137120
_ => {}
138121
}
122+
}
139123

140-
// Notify cef of possible input events
141-
self.cef_context.work();
124+
fn exiting(&mut self, _event_loop: &ActiveEventLoop) {
125+
let _ = self.handle.take().unwrap().join();
142126
}
143127
}

desktop/src/cef.rs

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
use crate::{CustomEvent, FrameBuffer};
22
use std::{
3-
sync::{Arc, Mutex, mpsc::Receiver},
3+
sync::{
4+
Arc, Mutex,
5+
mpsc::{Receiver, Sender},
6+
},
47
time::Instant,
58
};
69

@@ -21,7 +24,7 @@ pub(crate) trait CefEventHandler: Clone {
2124
fn schedule_cef_message_loop_work(&self, scheduled_time: Instant);
2225
}
2326

24-
#[derive(Clone, Copy)]
27+
#[derive(Clone, Copy, Debug)]
2528
pub(crate) struct WindowSize {
2629
pub(crate) width: usize,
2730
pub(crate) height: usize,
@@ -33,11 +36,6 @@ impl WindowSize {
3336
}
3437
}
3538

36-
#[derive(Clone)]
37-
pub(crate) struct CefHandler {
38-
window_size_receiver: Arc<Mutex<WindowSizeReceiver>>,
39-
event_loop_proxy: EventLoopProxy<CustomEvent>,
40-
}
4139
struct WindowSizeReceiver {
4240
receiver: Receiver<WindowSize>,
4341
window_size: WindowSize,
@@ -50,11 +48,20 @@ impl WindowSizeReceiver {
5048
}
5149
}
5250
}
51+
52+
#[derive(Clone)]
53+
pub(crate) struct CefHandler {
54+
window_size_receiver: Arc<Mutex<WindowSizeReceiver>>,
55+
event_loop_proxy: EventLoopProxy<CustomEvent>,
56+
poll_cef_sender: Sender<Instant>,
57+
}
58+
5359
impl CefHandler {
54-
pub(crate) fn new(window_size_receiver: Receiver<WindowSize>, event_loop_proxy: EventLoopProxy<CustomEvent>) -> Self {
60+
pub(crate) fn new(window_size_receiver: Receiver<WindowSize>, event_loop_proxy: EventLoopProxy<CustomEvent>, poll_cef_sender: Sender<Instant>) -> Self {
5561
Self {
5662
window_size_receiver: Arc::new(Mutex::new(WindowSizeReceiver::new(window_size_receiver))),
5763
event_loop_proxy,
64+
poll_cef_sender,
5865
}
5966
}
6067
}
@@ -71,11 +78,12 @@ impl CefEventHandler for CefHandler {
7178
}
7279
*window_size
7380
}
81+
7482
fn draw(&self, frame_buffer: FrameBuffer) {
7583
let _ = self.event_loop_proxy.send_event(CustomEvent::UiUpdate(frame_buffer));
7684
}
7785

7886
fn schedule_cef_message_loop_work(&self, scheduled_time: std::time::Instant) {
79-
let _ = self.event_loop_proxy.send_event(CustomEvent::ScheduleBrowserWork(scheduled_time));
87+
let _ = self.poll_cef_sender.send(scheduled_time);
8088
}
8189
}

desktop/src/main.rs

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
use std::fmt::Debug;
21
use std::process::exit;
3-
use std::time::Instant;
2+
use std::time::{Duration, Instant};
3+
use std::{fmt::Debug, thread};
44

55
use tracing_subscriber::EnvFilter;
66
use winit::event_loop::EventLoop;
@@ -19,7 +19,8 @@ mod dirs;
1919
#[derive(Debug)]
2020
pub(crate) enum CustomEvent {
2121
UiUpdate(FrameBuffer),
22-
ScheduleBrowserWork(Instant),
22+
WorkCef,
23+
KeepProcessAliveWhenResizing(WindowSize),
2324
}
2425

2526
fn main() {
@@ -35,10 +36,12 @@ fn main() {
3536
};
3637

3738
let event_loop = EventLoop::<CustomEvent>::with_user_event().build().unwrap();
39+
let event_loop_proxy = event_loop.create_proxy();
3840

3941
let (window_size_sender, window_size_receiver) = std::sync::mpsc::channel();
42+
let (poll_cef_sender, poll_cef_receiver) = std::sync::mpsc::channel();
4043

41-
let cef_context = match cef_context.init(cef::CefHandler::new(window_size_receiver, event_loop.create_proxy())) {
44+
let cef_context = match cef_context.init(cef::CefHandler::new(window_size_receiver, event_loop_proxy.clone(), poll_cef_sender)) {
4245
Ok(c) => c,
4346
Err(cef::InitError::InitializationFailed) => {
4447
tracing::error!("Cef initialization failed");
@@ -47,8 +50,24 @@ fn main() {
4750
};
4851

4952
tracing::info!("Cef initialized successfully");
53+
let poll_cef_elp = event_loop_proxy.clone();
54+
let handle = thread::spawn(move || {
55+
loop {
56+
match poll_cef_receiver.recv_timeout(Duration::from_millis(100)) {
57+
Ok(scheduled_instant) => {
58+
if scheduled_instant > Instant::now() {
59+
thread::sleep(scheduled_instant - Instant::now());
60+
}
61+
let _ = poll_cef_elp.send_event(CustomEvent::WorkCef);
62+
}
63+
Err(_) => {
64+
let _ = poll_cef_elp.send_event(CustomEvent::WorkCef);
65+
}
66+
}
67+
}
68+
});
5069

51-
let mut winit_app = WinitApp::new(cef_context, window_size_sender, event_loop.create_proxy());
70+
let mut winit_app = WinitApp::new(cef_context, window_size_sender, event_loop_proxy.clone(), handle);
5271

5372
event_loop.run_app(&mut winit_app).unwrap();
5473
}

desktop/src/render.rs

Lines changed: 21 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -223,13 +223,7 @@ impl GraphicsState {
223223
graphics_state
224224
}
225225

226-
pub(crate) fn ui_texture_outdated(&self, frame_buffer: &FrameBuffer) -> bool {
227-
let width = frame_buffer.width() as u32;
228-
let height = frame_buffer.height() as u32;
229-
230-
self.config.width != width || self.config.height != height
231-
}
232-
pub(crate) fn resize(&mut self, width: u32, height: u32) {
226+
pub(crate) fn try_resize(&mut self, width: u32, height: u32) {
233227
if width > 0 && height > 0 && (self.config.width != width || self.config.height != height) {
234228
self.config.width = width;
235229
self.config.height = height;
@@ -248,7 +242,26 @@ impl GraphicsState {
248242
usage: wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::COPY_DST,
249243
view_formats: &[],
250244
});
245+
246+
let texture_view = texture.create_view(&wgpu::TextureViewDescriptor::default());
251247
self.texture = Some(texture);
248+
249+
let bind_group = self.device.create_bind_group(&wgpu::BindGroupDescriptor {
250+
layout: &self.render_pipeline.get_bind_group_layout(0),
251+
entries: &[
252+
wgpu::BindGroupEntry {
253+
binding: 0,
254+
resource: wgpu::BindingResource::TextureView(&texture_view),
255+
},
256+
wgpu::BindGroupEntry {
257+
binding: 1,
258+
resource: wgpu::BindingResource::Sampler(&self.sampler),
259+
},
260+
],
261+
label: Some("texture_bind_group"),
262+
});
263+
264+
self.bind_group = Some(bind_group);
252265
}
253266
}
254267

@@ -257,7 +270,7 @@ impl GraphicsState {
257270
let width = frame_buffer.width() as u32;
258271
let height = frame_buffer.height() as u32;
259272

260-
self.resize(width, height);
273+
self.try_resize(width, height);
261274

262275
let Some(ref texture) = self.texture else { return };
263276

@@ -280,25 +293,6 @@ impl GraphicsState {
280293
depth_or_array_layers: 1,
281294
},
282295
);
283-
284-
let texture_view = texture.create_view(&wgpu::TextureViewDescriptor::default());
285-
286-
let bind_group = self.device.create_bind_group(&wgpu::BindGroupDescriptor {
287-
layout: &self.render_pipeline.get_bind_group_layout(0),
288-
entries: &[
289-
wgpu::BindGroupEntry {
290-
binding: 0,
291-
resource: wgpu::BindingResource::TextureView(&texture_view),
292-
},
293-
wgpu::BindGroupEntry {
294-
binding: 1,
295-
resource: wgpu::BindingResource::Sampler(&self.sampler),
296-
},
297-
],
298-
label: Some("texture_bind_group"),
299-
});
300-
301-
self.bind_group = Some(bind_group);
302296
}
303297

304298
pub(crate) fn render(&mut self) -> Result<(), wgpu::SurfaceError> {

0 commit comments

Comments
 (0)