mirror of
https://github.com/CloudNebulaProject/wayray.git
synced 2026-04-10 13:10:41 +00:00
Use EventLoopProxy for efficient frame wake instead of busy-poll
Replace ControlFlow::Poll (CPU-hungry busy loop) with an EventLoopProxy that the network thread uses to wake the winit event loop only when a new frame arrives. Zero CPU when idle, instant wake on new frames.
This commit is contained in:
parent
b805f9f6c8
commit
a7ad184774
1 changed files with 33 additions and 7 deletions
|
|
@ -14,7 +14,7 @@ use std::sync::mpsc;
|
||||||
use tracing::{error, info, warn};
|
use tracing::{error, info, warn};
|
||||||
use winit::application::ApplicationHandler;
|
use winit::application::ApplicationHandler;
|
||||||
use winit::event::WindowEvent;
|
use winit::event::WindowEvent;
|
||||||
use winit::event_loop::{ActiveEventLoop, EventLoop};
|
use winit::event_loop::{ActiveEventLoop, EventLoop, EventLoopProxy};
|
||||||
use winit::window::{Window, WindowAttributes, WindowId};
|
use winit::window::{Window, WindowAttributes, WindowId};
|
||||||
|
|
||||||
use wayray_protocol::messages::InputMessage;
|
use wayray_protocol::messages::InputMessage;
|
||||||
|
|
@ -102,12 +102,10 @@ impl ApplicationHandler for App {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn about_to_wait(&mut self, event_loop: &ActiveEventLoop) {
|
fn about_to_wait(&mut self, _event_loop: &ActiveEventLoop) {
|
||||||
// Use Poll mode so the event loop continuously checks for new frames
|
|
||||||
// instead of blocking until user input arrives.
|
|
||||||
event_loop.set_control_flow(winit::event_loop::ControlFlow::Poll);
|
|
||||||
|
|
||||||
// Drain any pending frames from the network thread.
|
// Drain any pending frames from the network thread.
|
||||||
|
// The network thread wakes us via EventLoopProxy when frames arrive,
|
||||||
|
// so we don't need to busy-poll.
|
||||||
let mut got_frame = false;
|
let mut got_frame = false;
|
||||||
while let Ok(frame) = self.frame_rx.try_recv() {
|
while let Ok(frame) = self.frame_rx.try_recv() {
|
||||||
if let Some(display) = &self.display {
|
if let Some(display) = &self.display {
|
||||||
|
|
@ -121,6 +119,22 @@ impl ApplicationHandler for App {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn user_event(&mut self, _event_loop: &ActiveEventLoop, _event: ()) {
|
||||||
|
// Woken by the network thread — new frame available.
|
||||||
|
// The actual frame processing happens in about_to_wait.
|
||||||
|
// Just request a redraw check.
|
||||||
|
let mut got_frame = false;
|
||||||
|
while let Ok(frame) = self.frame_rx.try_recv() {
|
||||||
|
if let Some(display) = &self.display {
|
||||||
|
display.update_frame(&frame.pixels);
|
||||||
|
got_frame = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if got_frame && let Some(window) = &self.window {
|
||||||
|
window.request_redraw();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn window_event(
|
fn window_event(
|
||||||
&mut self,
|
&mut self,
|
||||||
event_loop: &ActiveEventLoop,
|
event_loop: &ActiveEventLoop,
|
||||||
|
|
@ -214,10 +228,18 @@ fn main() {
|
||||||
// dimensions back before entering its frame-receive loop.
|
// dimensions back before entering its frame-receive loop.
|
||||||
let (dim_tx, dim_rx) = mpsc::channel::<(u32, u32)>();
|
let (dim_tx, dim_rx) = mpsc::channel::<(u32, u32)>();
|
||||||
|
|
||||||
|
// Create the event loop early so we can get a proxy for cross-thread wake.
|
||||||
|
let event_loop = EventLoop::<()>::with_user_event()
|
||||||
|
.build()
|
||||||
|
.expect("failed to create event loop");
|
||||||
|
let proxy: EventLoopProxy<()> = event_loop.create_proxy();
|
||||||
|
|
||||||
// Spawn the network thread with its own tokio runtime.
|
// Spawn the network thread with its own tokio runtime.
|
||||||
|
let net_proxy = proxy.clone();
|
||||||
std::thread::Builder::new()
|
std::thread::Builder::new()
|
||||||
.name("wrclient-network".into())
|
.name("wrclient-network".into())
|
||||||
.spawn(move || {
|
.spawn(move || {
|
||||||
|
let proxy = net_proxy;
|
||||||
let rt = tokio::runtime::Builder::new_current_thread()
|
let rt = tokio::runtime::Builder::new_current_thread()
|
||||||
.enable_all()
|
.enable_all()
|
||||||
.build()
|
.build()
|
||||||
|
|
@ -312,6 +334,9 @@ fn main() {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Wake the winit event loop to process the new frame.
|
||||||
|
let _ = proxy.send_event(());
|
||||||
|
|
||||||
// Acknowledge the frame.
|
// Acknowledge the frame.
|
||||||
if let Err(e) = conn.send_frame_ack(update.sequence).await {
|
if let Err(e) = conn.send_frame_ack(update.sequence).await {
|
||||||
warn!(error = %e, "failed to send frame ack");
|
warn!(error = %e, "failed to send frame ack");
|
||||||
|
|
@ -342,7 +367,8 @@ fn main() {
|
||||||
info!(width, height, "starting display");
|
info!(width, height, "starting display");
|
||||||
|
|
||||||
// Run the winit event loop on the main thread.
|
// Run the winit event loop on the main thread.
|
||||||
let event_loop = EventLoop::new().expect("failed to create event loop");
|
// The event loop was created earlier (before spawning the network thread)
|
||||||
|
// so we could pass an EventLoopProxy to wake it on new frames.
|
||||||
let mut app = App::new(width, height, frame_rx, input_tx);
|
let mut app = App::new(width, height, frame_rx, input_tx);
|
||||||
event_loop.run_app(&mut app).expect("event loop error");
|
event_loop.run_app(&mut app).expect("event loop error");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue