1
1
use crate :: CustomEvent ;
2
2
use crate :: cef:: WindowSize ;
3
- use crate :: consts:: APP_NAME ;
3
+ use crate :: consts:: { APP_NAME , CEF_MESSAGE_LOOP_MAX_ITERATIONS } ;
4
4
use crate :: render:: GraphicsState ;
5
5
use graphite_desktop_wrapper:: messages:: { DesktopFrontendMessage , DesktopWrapperMessage } ;
6
6
use graphite_desktop_wrapper:: { DesktopWrapper , NodeGraphExecutionResult , WgpuContext , serialize_frontend_messages} ;
7
+
7
8
use rfd:: AsyncFileDialog ;
8
9
use std:: sync:: Arc ;
9
10
use std:: sync:: mpsc:: Sender ;
11
+ use std:: sync:: mpsc:: SyncSender ;
10
12
use std:: thread;
11
13
use std:: time:: Duration ;
12
14
use std:: time:: Instant ;
13
15
use winit:: application:: ApplicationHandler ;
14
16
use winit:: dpi:: PhysicalSize ;
15
- use winit:: event:: StartCause ;
16
17
use winit:: event:: WindowEvent ;
17
18
use winit:: event_loop:: ActiveEventLoop ;
18
19
use winit:: event_loop:: ControlFlow ;
@@ -31,11 +32,23 @@ pub(crate) struct WinitApp {
31
32
wgpu_context : WgpuContext ,
32
33
event_loop_proxy : EventLoopProxy < CustomEvent > ,
33
34
desktop_wrapper : DesktopWrapper ,
35
+ last_ui_update : Instant ,
36
+ avg_frame_time : f32 ,
37
+ start_render_sender : SyncSender < ( ) > ,
34
38
}
35
39
36
40
impl WinitApp {
37
41
pub ( crate ) fn new ( cef_context : cef:: Context < cef:: Initialized > , window_size_sender : Sender < WindowSize > , wgpu_context : WgpuContext , event_loop_proxy : EventLoopProxy < CustomEvent > ) -> Self {
38
- let desktop_wrapper = DesktopWrapper :: new ( ) ;
42
+ let rendering_loop_proxy = event_loop_proxy. clone ( ) ;
43
+ let ( start_render_sender, start_render_receiver) = std:: sync:: mpsc:: sync_channel ( 1 ) ;
44
+ std:: thread:: spawn ( move || {
45
+ loop {
46
+ let result = futures:: executor:: block_on ( DesktopWrapper :: execute_node_graph ( ) ) ;
47
+ let _ = rendering_loop_proxy. send_event ( CustomEvent :: NodeGraphExecutionResult ( result) ) ;
48
+ let _ = start_render_receiver. recv ( ) ;
49
+ }
50
+ } ) ;
51
+
39
52
Self {
40
53
cef_context,
41
54
window : None ,
@@ -44,7 +57,10 @@ impl WinitApp {
44
57
window_size_sender,
45
58
wgpu_context,
46
59
event_loop_proxy,
47
- desktop_wrapper,
60
+ desktop_wrapper : DesktopWrapper :: new ( ) ,
61
+ last_ui_update : Instant :: now ( ) ,
62
+ avg_frame_time : 0. ,
63
+ start_render_sender,
48
64
}
49
65
}
50
66
@@ -152,23 +168,20 @@ impl ApplicationHandler<CustomEvent> for WinitApp {
152
168
// Set a timeout in case we miss any cef schedule requests
153
169
let timeout = Instant :: now ( ) + Duration :: from_millis ( 10 ) ;
154
170
let wait_until = timeout. min ( self . cef_schedule . unwrap_or ( timeout) ) ;
155
- self . cef_context . work ( ) ;
156
-
157
- event_loop. set_control_flow ( ControlFlow :: WaitUntil ( wait_until) ) ;
158
- }
159
-
160
- fn new_events ( & mut self , _event_loop : & ActiveEventLoop , cause : StartCause ) {
161
171
if let Some ( schedule) = self . cef_schedule
162
172
&& schedule < Instant :: now ( )
163
173
{
164
174
self . cef_schedule = None ;
165
- self . cef_context . work ( ) ;
166
- }
167
- if let StartCause :: ResumeTimeReached { .. } = cause {
168
- if let Some ( window) = & self . window {
169
- window. request_redraw ( ) ;
175
+ // Poll cef message loop multiple times to avoid message loop starvation
176
+ for _ in 0 ..CEF_MESSAGE_LOOP_MAX_ITERATIONS {
177
+ self . cef_context . work ( ) ;
170
178
}
171
179
}
180
+ if let Some ( window) = & self . window . as_ref ( ) {
181
+ window. request_redraw ( ) ;
182
+ }
183
+
184
+ event_loop. set_control_flow ( ControlFlow :: WaitUntil ( wait_until) ) ;
172
185
}
173
186
174
187
fn resumed ( & mut self , event_loop : & ActiveEventLoop ) {
@@ -220,6 +233,11 @@ impl ApplicationHandler<CustomEvent> for WinitApp {
220
233
if let Some ( graphics_state) = self . graphics_state . as_mut ( ) {
221
234
graphics_state. resize ( texture. width ( ) , texture. height ( ) ) ;
222
235
graphics_state. bind_ui_texture ( texture) ;
236
+ let elapsed = self . last_ui_update . elapsed ( ) . as_secs_f32 ( ) ;
237
+ self . last_ui_update = Instant :: now ( ) ;
238
+ if elapsed < 0.5 {
239
+ self . avg_frame_time = ( self . avg_frame_time * 3. + elapsed) / 4. ;
240
+ }
223
241
}
224
242
if let Some ( window) = & self . window {
225
243
window. request_redraw ( ) ;
@@ -251,16 +269,18 @@ impl ApplicationHandler<CustomEvent> for WinitApp {
251
269
WindowEvent :: RedrawRequested => {
252
270
let Some ( ref mut graphics_state) = self . graphics_state else { return } ;
253
271
// Only rerender once we have a new ui texture to display
254
-
255
- match graphics_state. render ( ) {
256
- Ok ( _) => { }
257
- Err ( wgpu:: SurfaceError :: Lost ) => {
258
- tracing:: warn!( "lost surface" ) ;
259
- }
260
- Err ( wgpu:: SurfaceError :: OutOfMemory ) => {
261
- event_loop. exit ( ) ;
272
+ if let Some ( window) = & self . window {
273
+ match graphics_state. render ( window. as_ref ( ) ) {
274
+ Ok ( _) => { }
275
+ Err ( wgpu:: SurfaceError :: Lost ) => {
276
+ tracing:: warn!( "lost surface" ) ;
277
+ }
278
+ Err ( wgpu:: SurfaceError :: OutOfMemory ) => {
279
+ event_loop. exit ( ) ;
280
+ }
281
+ Err ( e) => tracing:: error!( "{:?}" , e) ,
262
282
}
263
- Err ( e ) => tracing :: error! ( "{:?}" , e ) ,
283
+ let _ = self . start_render_sender . try_send ( ( ) ) ;
264
284
}
265
285
}
266
286
// Currently not supported on wayland see https://github.com/rust-windowing/winit/issues/1881
0 commit comments