Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 20 additions & 36 deletions desktop/src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -27,10 +25,11 @@ pub(crate) struct WinitApp {
_viewport_frame_buffer: Option<FrameBuffer>,
graphics_state: Option<GraphicsState>,
event_loop_proxy: EventLoopProxy<CustomEvent>,
handle: Option<JoinHandle<()>>,
}

impl WinitApp {
pub(crate) fn new(cef_context: cef::Context<cef::Initialized>, window_size_sender: Sender<WindowSize>, event_loop_proxy: EventLoopProxy<CustomEvent>) -> Self {
pub(crate) fn new(cef_context: cef::Context<cef::Initialized>, window_size_sender: Sender<WindowSize>, event_loop_proxy: EventLoopProxy<CustomEvent>, handle: JoinHandle<()>) -> Self {
Self {
cef_context,
window: None,
Expand All @@ -40,27 +39,12 @@ impl WinitApp {
graphics_state: None,
window_size_sender,
event_loop_proxy,
handle: Some(handle),
}
}
}

impl ApplicationHandler<CustomEvent> 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
Expand Down Expand Up @@ -90,15 +74,16 @@ impl ApplicationHandler<CustomEvent> 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));
};
}
}
}
Expand All @@ -112,17 +97,15 @@ impl ApplicationHandler<CustomEvent> 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) => {
Expand All @@ -136,8 +119,9 @@ impl ApplicationHandler<CustomEvent> 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();
}
}
26 changes: 17 additions & 9 deletions desktop/src/cef.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
use crate::{CustomEvent, FrameBuffer};
use std::{
sync::{Arc, Mutex, mpsc::Receiver},
sync::{
Arc, Mutex,
mpsc::{Receiver, Sender},
},
time::Instant,
};

Expand All @@ -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,
Expand All @@ -33,11 +36,6 @@ impl WindowSize {
}
}

#[derive(Clone)]
pub(crate) struct CefHandler {
window_size_receiver: Arc<Mutex<WindowSizeReceiver>>,
event_loop_proxy: EventLoopProxy<CustomEvent>,
}
struct WindowSizeReceiver {
receiver: Receiver<WindowSize>,
window_size: WindowSize,
Expand All @@ -50,11 +48,20 @@ impl WindowSizeReceiver {
}
}
}

#[derive(Clone)]
pub(crate) struct CefHandler {
window_size_receiver: Arc<Mutex<WindowSizeReceiver>>,
event_loop_proxy: EventLoopProxy<CustomEvent>,
poll_cef_sender: Sender<Instant>,
}

impl CefHandler {
pub(crate) fn new(window_size_receiver: Receiver<WindowSize>, event_loop_proxy: EventLoopProxy<CustomEvent>) -> Self {
pub(crate) fn new(window_size_receiver: Receiver<WindowSize>, event_loop_proxy: EventLoopProxy<CustomEvent>, poll_cef_sender: Sender<Instant>) -> Self {
Self {
window_size_receiver: Arc::new(Mutex::new(WindowSizeReceiver::new(window_size_receiver))),
event_loop_proxy,
poll_cef_sender,
}
}
}
Expand All @@ -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);
}
}
29 changes: 24 additions & 5 deletions desktop/src/main.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -19,7 +19,8 @@ mod dirs;
#[derive(Debug)]
pub(crate) enum CustomEvent {
UiUpdate(FrameBuffer),
ScheduleBrowserWork(Instant),
WorkCef,
KeepProcessAliveWhenResizing(WindowSize),
}

fn main() {
Expand All @@ -35,10 +36,12 @@ fn main() {
};

let event_loop = EventLoop::<CustomEvent>::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");
Expand All @@ -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();
}
48 changes: 21 additions & 27 deletions desktop/src/render.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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);
}
}

Expand All @@ -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 };

Expand All @@ -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> {
Expand Down
Loading