[oden] Tracing and also actual 60fps

Sleeping is completely and utterly unreliable.
This commit is contained in:
John Doty 2023-07-01 07:15:55 -07:00
parent b149b28f31
commit 734a1279a6
4 changed files with 237 additions and 42 deletions

View file

@ -2,6 +2,7 @@ use bytemuck;
use std::collections::HashMap;
use std::sync::mpsc::Receiver;
use std::time::Instant;
use tracy_client::{frame_mark, set_thread_name, span};
use wgpu::util::DeviceExt;
use winit::{event::*, event_loop::EventLoop, window::Window, window::WindowBuilder};
@ -309,6 +310,7 @@ impl State {
}
fn render(&mut self, commands: Vec<GraphicsCommand>) -> Result<(), wgpu::SurfaceError> {
let _span = span!("context render");
let output = self.surface.get_current_texture()?;
let view = output
.texture
@ -486,56 +488,77 @@ fn main_thread(state: State, reciever: Receiver<UIEvent>) {
let mut context = script::ScriptContext::new();
context.init();
const SPF: f64 = 1.0 / 60.0;
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;
}
frame_mark();
let start = Instant::now();
WindowEvent::Resized(physical_size) => {
state.resize(*physical_size);
}
{
let _span = span!("events");
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::ScaleFactorChanged { new_inner_size, .. } => {
// new_inner_size is &&mut so we have to dereference it twice
state.resize(**new_inner_size);
}
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),
{
let _span = span!("update");
context.update();
state.update();
}
// TODO: FRAME PACING.
{
let _span = span!("render");
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),
}
}
{
let _span = span!("sleep");
while start.elapsed().as_secs_f64() < SPF {
std::thread::yield_now();
}
}
}
}
pub async fn run() {
let _client = tracy_client::Client::start();
set_thread_name!("ui thread");
env_logger::init();
let event_loop = EventLoop::new();
let window = WindowBuilder::new().build(&event_loop).unwrap();
@ -544,6 +567,7 @@ pub async fn run() {
let (sender, reciever) = std::sync::mpsc::channel();
std::thread::spawn(move || {
set_thread_name!("game thread");
main_thread(state, reciever);
});

View file

@ -5,6 +5,7 @@ use oden_js::{
use std::ffi::OsStr;
use std::sync::mpsc::{channel, Receiver};
use std::time::Instant;
use tracy_client::span;
pub mod graphics;
use graphics::GraphicsCommand;
@ -99,29 +100,41 @@ impl ScriptContext {
// game thread go to fast probably? And to discard whole frames &c.
pub fn init(&mut self) {
let _span = span!("script init");
self.init
.call(&self.context, &[])
.expect("Exception in init");
}
pub fn update(&mut self) {
let _span = span!("script update");
// Do we update the frame time before of after async completion?
// Hmmmmm.
self.time.set_frame_time(Instant::now());
// Tell the runtime to process all pending "jobs". This includes
// promise completions.
self.context
.process_all_jobs()
.expect("Error processing async jobs");
{
let _span = span!("process jobs");
self.context
.process_all_jobs()
.expect("Error processing async jobs");
}
// Now run the update function.
self.update
.call(&self.context, &[])
.expect("Exception in update");
{
let _span = span!("javascript update");
self.update
.call(&self.context, &[])
.expect("Exception in update");
}
}
pub fn render(&mut self) -> Vec<graphics::GraphicsCommand> {
let _span = span!("script render");
self.draw
.call(&self.context, &[])
.expect("Exception in draw");