11use crate :: CustomEvent ;
22use crate :: cef:: WindowSize ;
3- use crate :: consts:: APP_NAME ;
3+ use crate :: consts:: { APP_NAME , CEF_MESSAGE_LOOP_MAX_ITERATIONS } ;
44use crate :: render:: GraphicsState ;
55use graphite_desktop_wrapper:: messages:: { DesktopFrontendMessage , DesktopWrapperMessage } ;
66use graphite_desktop_wrapper:: { DesktopWrapper , NodeGraphExecutionResult , WgpuContext , serialize_frontend_messages} ;
7+
78use rfd:: AsyncFileDialog ;
89use std:: sync:: Arc ;
910use std:: sync:: mpsc:: Sender ;
11+ use std:: sync:: mpsc:: SyncSender ;
1012use std:: thread;
1113use std:: time:: Duration ;
1214use std:: time:: Instant ;
1315use winit:: application:: ApplicationHandler ;
1416use winit:: dpi:: PhysicalSize ;
15- use winit:: event:: StartCause ;
1617use winit:: event:: WindowEvent ;
1718use winit:: event_loop:: ActiveEventLoop ;
1819use winit:: event_loop:: ControlFlow ;
@@ -31,11 +32,23 @@ pub(crate) struct WinitApp {
3132 wgpu_context : WgpuContext ,
3233 event_loop_proxy : EventLoopProxy < CustomEvent > ,
3334 desktop_wrapper : DesktopWrapper ,
35+ last_ui_update : Instant ,
36+ avg_frame_time : f32 ,
37+ start_render_sender : SyncSender < ( ) > ,
3438}
3539
3640impl WinitApp {
3741 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+
3952 Self {
4053 cef_context,
4154 window : None ,
@@ -44,7 +57,10 @@ impl WinitApp {
4457 window_size_sender,
4558 wgpu_context,
4659 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,
4864 }
4965 }
5066
@@ -152,23 +168,20 @@ impl ApplicationHandler<CustomEvent> for WinitApp {
152168 // Set a timeout in case we miss any cef schedule requests
153169 let timeout = Instant :: now ( ) + Duration :: from_millis ( 10 ) ;
154170 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 ) {
161171 if let Some ( schedule) = self . cef_schedule
162172 && schedule < Instant :: now ( )
163173 {
164174 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 ( ) ;
170178 }
171179 }
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) ) ;
172185 }
173186
174187 fn resumed ( & mut self , event_loop : & ActiveEventLoop ) {
@@ -220,6 +233,11 @@ impl ApplicationHandler<CustomEvent> for WinitApp {
220233 if let Some ( graphics_state) = self . graphics_state . as_mut ( ) {
221234 graphics_state. resize ( texture. width ( ) , texture. height ( ) ) ;
222235 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+ }
223241 }
224242 if let Some ( window) = & self . window {
225243 window. request_redraw ( ) ;
@@ -251,16 +269,18 @@ impl ApplicationHandler<CustomEvent> for WinitApp {
251269 WindowEvent :: RedrawRequested => {
252270 let Some ( ref mut graphics_state) = self . graphics_state else { return } ;
253271 // 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) ,
262282 }
263- Err ( e ) => tracing :: error! ( "{:?}" , e ) ,
283+ let _ = self . start_render_sender . try_send ( ( ) ) ;
264284 }
265285 }
266286 // Currently not supported on wayland see https://github.com/rust-windowing/winit/issues/1881
0 commit comments