[oden] Move graphics thread off main thread

So we can do frame pacing a little bit better maybe.
This commit is contained in:
John Doty 2023-06-30 16:54:16 -07:00
parent 26bfcc7a94
commit b1b97cee75
2 changed files with 79 additions and 106 deletions

View file

@ -23,4 +23,5 @@ export function draw() {
use_texture(the_texture);
spr((320 - 256) / 2, 0, 256, 240, 0, 0);
}
// print("FRAME TIME:", since_last_frame());
}

View file

@ -1,12 +1,9 @@
use bytemuck;
use std::collections::HashMap;
use std::sync::mpsc::Receiver;
use std::time::Instant;
use wgpu::util::DeviceExt;
use winit::{
event::*,
event_loop::{ControlFlow, EventLoop},
window::Window,
window::WindowBuilder,
};
use winit::{event::*, event_loop::EventLoop, window::Window, window::WindowBuilder};
mod script;
use script::graphics::GraphicsCommand;
@ -142,17 +139,12 @@ impl State {
format: surface_format,
width: size.width,
height: size.height,
present_mode: surface_caps.present_modes[0],
present_mode: wgpu::PresentMode::Fifo,
alpha_mode: surface_caps.alpha_modes[0],
view_formats: vec![],
};
surface.configure(&device, &config);
// TODO: DELETE THIS
// let diffuse_bytes = include_bytes!("happy-tree.png");
// let diffuse_texture =
// texture::Texture::from_bytes(&device, &queue, diffuse_bytes, "happy-tree.png").unwrap();
let sprite_bind_group_layout =
device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
entries: &[
@ -475,116 +467,96 @@ impl State {
self.queue.submit(std::iter::once(encoder.finish()));
}
// {
// // BEGIN GARBAGE
// let r: f64 = (self.mouse_x / f64::from(self.size.width)).clamp(0.0, 1.0) * 0.1;
// let g: f64 = (self.mouse_y / f64::from(self.size.height)).clamp(0.0, 1.0) * 0.2;
// // END GARBAGE
// let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
// label: Some("Render Pass"),
// color_attachments: &[Some(wgpu::RenderPassColorAttachment {
// view: &view,
// resolve_target: None,
// ops: wgpu::Operations {
// load: wgpu::LoadOp::Clear(wgpu::Color {
// r, //0.1,
// g, //0.2,
// b: 0.3,
// a: 1.0,
// }),
// store: true,
// },
// })],
// depth_stencil_attachment: None,
// });
// render_pass.set_pipeline(&self.render_pipeline);
// render_pass.set_bind_group(0, &self.diffuse_bind_group, &[]);
// render_pass.set_vertex_buffer(0, self.vertex_buffer.slice(..));
// render_pass.set_index_buffer(self.index_buffer.slice(..), wgpu::IndexFormat::Uint16);
// render_pass.draw_indexed(0..self.num_indices, 0, 0..1);
// }
output.present();
Ok(())
}
}
struct UIEvent {
winit: Event<'static, ()>,
#[allow(unused)]
time: Instant,
}
// TODO: flume? (https://docs.rs/flume/latest/flume/)
fn main_thread(state: State, reciever: Receiver<UIEvent>) {
let mut state = state;
let mut context = script::ScriptContext::new();
context.init();
loop {
while let Ok(event) = reciever.try_recv() {
match event.winit {
Event::WindowEvent {
ref event,
window_id,
} if window_id == state.window().id() => {
if !state.input(event) {
match event {
WindowEvent::CursorMoved { position, .. } => {
state.mouse_x = position.x;
state.mouse_y = position.y;
}
WindowEvent::Resized(physical_size) => {
state.resize(*physical_size);
}
WindowEvent::ScaleFactorChanged { new_inner_size, .. } => {
// new_inner_size is &&mut so we have to dereference it twice
state.resize(**new_inner_size);
}
_ => {}
}
}
}
_ => {}
}
}
context.update();
state.update();
match state.render(context.render()) {
Ok(_) => {}
// Reconfigure the surface if lost
Err(wgpu::SurfaceError::Lost) => state.resize(state.size),
// The system is out of memory, we should probably quit
Err(wgpu::SurfaceError::OutOfMemory) => panic!("Out of memory"),
// All other errors (Outdated, Timeout) should be resolved by the next frame
Err(e) => eprintln!("{:?}", e),
}
// TODO: FRAME PACING.
}
}
pub async fn run() {
env_logger::init();
let event_loop = EventLoop::new();
let window = WindowBuilder::new().build(&event_loop).unwrap();
let mut state = State::new(window).await;
let state = State::new(window).await;
let (sender, reciever) = std::sync::mpsc::channel();
let mut context = script::ScriptContext::new();
context.init();
std::thread::spawn(move || {
main_thread(state, reciever);
});
event_loop.run(move |event, _, control_flow| {
control_flow.set_poll();
match event {
Event::WindowEvent {
ref event,
window_id,
} if window_id == state.window().id() => {
if !state.input(event) {
match event {
WindowEvent::CloseRequested
| WindowEvent::KeyboardInput {
input:
KeyboardInput {
state: ElementState::Pressed,
virtual_keycode: Some(VirtualKeyCode::Escape),
..
},
..
} => *control_flow = ControlFlow::Exit,
WindowEvent::CursorMoved { position, .. } => {
state.mouse_x = position.x;
state.mouse_y = position.y;
state.window().request_redraw();
}
WindowEvent::Resized(physical_size) => {
state.resize(*physical_size);
}
WindowEvent::ScaleFactorChanged { new_inner_size, .. } => {
// new_inner_size is &&mut so we have to dereference it twice
state.resize(**new_inner_size);
}
_ => {}
}
}
}
Event::RedrawRequested(window_id) if window_id == state.window().id() => {
context.update();
state.update();
match state.render(context.render()) {
Ok(_) => {}
// Reconfigure the surface if lost
Err(wgpu::SurfaceError::Lost) => state.resize(state.size),
// The system is out of memory, we should probably quit
Err(wgpu::SurfaceError::OutOfMemory) => *control_flow = ControlFlow::Exit,
// All other errors (Outdated, Timeout) should be resolved by the next frame
Err(e) => eprintln!("{:?}", e),
}
}
Event::MainEventsCleared => {
// RedrawRequested will only trigger once, unless we manually
// request it.
state.window().request_redraw();
}
_ => {}
if let Some(e) = event.to_static() {
sender
.send(UIEvent {
winit: e,
time: Instant::now(),
})
.unwrap();
}
});
}