what I got done before giving up on thread chaining

This commit is contained in:
Quaternions 2023-10-24 18:51:01 -07:00
parent de063f4d74
commit 4cf10dad78
7 changed files with 133 additions and 129 deletions

View File

@ -8,12 +8,6 @@ pub struct ModelUpdate{
color:Option<glam::Vec4>, color:Option<glam::Vec4>,
} }
#[derive(Clone)]
pub enum GraphicsInstruction{
UpdateModel(ModelUpdate),
Render,
}
struct Entity { struct Entity {
index_count: u32, index_count: u32,
index_buf: wgpu::Buffer, index_buf: wgpu::Buffer,
@ -878,31 +872,27 @@ impl GraphicsState{
device:&wgpu::Device, device:&wgpu::Device,
queue:&wgpu::Queue, queue:&wgpu::Queue,
config:&wgpu::SurfaceConfiguration, config:&wgpu::SurfaceConfiguration,
user_settings:&crate::settings::UserSettings,
) { ) {
self.depth_view = Self::create_depth_texture(config,device); self.depth_view = Self::create_depth_texture(config,device);
self.camera.screen_size=glam::uvec2(config.width, config.height); self.camera.screen_size=glam::uvec2(config.width, config.height);
self.load_user_settings(&self.user_settings); self.load_user_settings(user_settings);
} }
pub fn render( pub fn render(
&mut self, &mut self,
view: &wgpu::TextureView, view:&wgpu::TextureView,
device: &wgpu::Device, device:&wgpu::Device,
queue: &wgpu::Queue, queue:&wgpu::Queue,
predicted_time:crate::integer::Time,
physics_output:crate::physics::PhysicsOutputState,
) { ) {
//ideally this would be scheduled to execute and finish right before the render. //TODO: use scheduled frame times to create beautiful smoothing simulation physics extrapolation assuming no input
let time=crate::integer::Time::from_nanos(self.start_time.elapsed().as_nanos() as i64);
self.physics_thread.send(crate::instruction::TimedInstruction{
time,
instruction:crate::render_thread::InputInstruction::Idle,
}).unwrap();
//update time lol
self.mouse.time=time;
let mut encoder = let mut encoder =
device.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None }); device.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None });
// update rotation // update rotation
let camera_uniforms = self.camera.to_uniform_data(self.physics_thread.grab_clone().adjust_mouse(&self.mouse)); let camera_uniforms = self.camera.to_uniform_data(physics_output.extrapolate(self.global_mouse.lock().clone(),predicted_time));
self.staging_belt self.staging_belt
.write_buffer( .write_buffer(
&mut encoder, &mut encoder,

View File

@ -1,13 +0,0 @@
struct Context<'a>{
device:&'a wgpu::Device,
queue:&'a wgpu::Queue,
}
impl Context{
pub fn new(user_settings:&crate::settings::UserSettings,indexed_model_instances:&crate::model::IndexedModelInstances){
let mut graphics=crate::graphics::GraphicsState::new();
graphics.load_user_settings(user_settings);
graphics.generate_models(indexed_model_instances);
}
//into_worker
}

46
src/graphics_worker.rs Normal file
View File

@ -0,0 +1,46 @@
#[derive(Clone)]
pub enum GraphicsInstruction{
Render(crate::physics::PhysicsOutputState,crate::integer::Time),
//UpdateModel(crate::graphics::ModelUpdate),
}
//Ideally the graphics thread worker description is:
/*
WorkerDescription{
input:Immediate,
output:Realtime(PoolOrdering::Ordered(3)),
}
*/
//up to three frames in flight, dropping new frame requests when all three are busy, and dropping output frames when one renders out of order
pub fn new(
graphics:crate::graphics::GraphicsState,
surface:&wgpu::Surface,
device:&wgpu::Device,
queue:&wgpu::Queue,
)->crate::worker::INWorker<GraphicsInstruction>{
crate::worker::INWorker::new(a,move |ins:GraphicsInstruction|{
match ins{
GraphicsInstruction::Render(physics_output,predicted_time)=>{
//this has to go deeper somehow
let frame=match surface.get_current_texture(){
Ok(frame)=>frame,
Err(_)=>{
surface.configure(device,config);
surface
.get_current_texture()
.expect("Failed to acquire next surface texture!")
}
};
let view=frame.texture.create_view(&wgpu::TextureViewDescriptor{
format:Some(config.view_formats[0]),
..wgpu::TextureViewDescriptor::default()
});
graphics.render(&view,device,queue,physics_output,predicted_time);
frame.present();
}
}
})
}

View File

@ -13,8 +13,8 @@ mod primitives;
mod instruction; mod instruction;
mod load_roblox; mod load_roblox;
mod model_graphics; mod model_graphics;
mod physics_context; mod physics_worker;
mod graphics_context; mod graphics_worker;
fn load_file(path: std::path::PathBuf)->Option<model::IndexedModelInstances>{ fn load_file(path: std::path::PathBuf)->Option<model::IndexedModelInstances>{
println!("Loading file: {:?}", &path); println!("Loading file: {:?}", &path);

View File

@ -533,8 +533,8 @@ pub struct PhysicsOutputState{
body:Body, body:Body,
} }
impl PhysicsOutputState{ impl PhysicsOutputState{
pub fn adjust_mouse(&self,mouse:&MouseState)->(glam::Vec3,glam::Vec2){ pub fn extrapolate(&self,mouse_pos:glam::IVec2,time:Time)->(glam::Vec3,glam::Vec2){
((self.body.extrapolated_position(mouse.time)+self.camera.offset).into(),self.camera.simulate_move_angles(mouse.pos)) ((self.body.extrapolated_position(time)+self.camera.offset).into(),self.camera.simulate_move_angles(mouse_pos))
} }
} }

View File

@ -20,29 +20,9 @@ pub enum InputInstruction {
//to be 1 instruction ahead to generate the next state for interpolation. //to be 1 instruction ahead to generate the next state for interpolation.
} }
pub struct Context{ pub fn new(physics:crate::physics::PhysicsState,graphics_worker:crate::worker::INWorker<crate::graphics::GraphicsInstruction>)->crate::worker::QNWorker<TimedInstruction<InputInstruction>>{
//Ideally the graphics thread worker description is:
/*
WorkerDescription{
input:Immediate,
output:Realtime(PoolOrdering::Ordered(3)),
}
*/
//up to three frames in flight, dropping new frame requests when all three are busy, and dropping output frames when one renders out of order
graphics_thread:crate::worker::INWorker<crate::graphics::GraphicsInstruction>,
}
impl Context{
pub fn new(user_settings:&crate::settings::UserSettings,indexed_model_instances:&crate::model::IndexedModelInstances){
let mut physics=crate::physics::PhysicsState::default();
physics.spawn(indexed_model_instances.spawn_point);
physics.load_user_settings(user_settings);
physics.generate_models(&indexed_model_instances);
}
pub fn into_worker(mut self)->crate::worker::QNWorker<TimedInstruction<InputInstruction>>{
let graphics_context=crate::graphics_context::Context::new();
let graphics_thread=graphics_context.into_worker();
let mut mouse_blocking=true; let mut mouse_blocking=true;
let mut last_mouse_time=self.physics.next_mouse.time; let mut last_mouse_time=physics.next_mouse.time;
let mut timeline=std::collections::VecDeque::new(); let mut timeline=std::collections::VecDeque::new();
crate::worker::QNWorker::new(move |ins:TimedInstruction<InputInstruction>|{ crate::worker::QNWorker::new(move |ins:TimedInstruction<InputInstruction>|{
let mut render=false; let mut render=false;
@ -60,7 +40,7 @@ impl Context{
timeline.push_front(TimedInstruction{ timeline.push_front(TimedInstruction{
time:last_mouse_time, time:last_mouse_time,
instruction:PhysicsInputInstruction::ReplaceMouse( instruction:PhysicsInputInstruction::ReplaceMouse(
MouseState{time:last_mouse_time,pos:self.physics.next_mouse.pos}, MouseState{time:last_mouse_time,pos:physics.next_mouse.pos},
MouseState{time:ins.time,pos:m} MouseState{time:ins.time,pos:m}
), ),
}); });
@ -92,11 +72,11 @@ impl Context{
//shitty mice are 125Hz which is 8ms so this should cover that. //shitty mice are 125Hz which is 8ms so this should cover that.
//setting this to 100us still doesn't print even though it's 10x lower than the polling rate, //setting this to 100us still doesn't print even though it's 10x lower than the polling rate,
//so mouse events are probably not handled separately from drawing and fire right before it :( //so mouse events are probably not handled separately from drawing and fire right before it :(
if Time::from_millis(10)<ins.time-self.physics.next_mouse.time{ if Time::from_millis(10)<ins.time-physics.next_mouse.time{
//push an event to extrapolate no movement from //push an event to extrapolate no movement from
timeline.push_front(TimedInstruction{ timeline.push_front(TimedInstruction{
time:last_mouse_time, time:last_mouse_time,
instruction:PhysicsInputInstruction::SetNextMouse(MouseState{time:ins.time,pos:self.physics.next_mouse.pos}), instruction:PhysicsInputInstruction::SetNextMouse(MouseState{time:ins.time,pos:physics.next_mouse.pos}),
}); });
last_mouse_time=ins.time; last_mouse_time=ins.time;
//stop blocking. the mouse is not moving so the physics does not need to live in the past and wait for interpolation targets. //stop blocking. the mouse is not moving so the physics does not need to live in the past and wait for interpolation targets.
@ -117,16 +97,15 @@ impl Context{
}{ }{
//empty queue //empty queue
while let Some(instruction)=timeline.pop_front(){ while let Some(instruction)=timeline.pop_front(){
self.physics.run(instruction.time); physics.run(instruction.time);
self.physics.process_instruction(TimedInstruction{ physics.process_instruction(TimedInstruction{
time:instruction.time, time:instruction.time,
instruction:crate::physics::PhysicsInstruction::Input(instruction.instruction), instruction:crate::physics::PhysicsInstruction::Input(instruction.instruction),
}); });
} }
} }
if render{ if render{
graphics_thread.send(TimedInstruction{time:ins.time,instruction:crate::graphics_context::GraphicsInstruction::Render}); graphics_worker.send(TimedInstruction{time:ins.time,instruction:crate::graphics_worker::GraphicsInstruction::Render});
} }
}) })
} }
}

View File

@ -12,55 +12,26 @@ pub enum RunInstruction{
//holds thread handles to dispatch to //holds thread handles to dispatch to
struct RunContext{ struct RunContext{
physics_thread:crate::worker::QNWorker<TimedInstruction<InputInstruction>>,
}
pub struct RunContextSetup{
manual_mouse_lock:bool, manual_mouse_lock:bool,
mouse:crate::physics::MouseState,//std::sync::Arc<std::sync::Mutex<>> mouse:crate::physics::MouseState,//std::sync::Arc<std::sync::Mutex<>>
screen_size:glam::UVec2,
user_settings:crate::settings::UserSettings, user_settings:crate::settings::UserSettings,
window:winit::window::Window, window:winit::window::Window,
physics:crate::physics::PhysicsState, //physics_thread:crate::worker::QNWorker<TimedInstruction<InputInstruction>>,
graphics:crate::graphics::GraphicsState,
} }
impl RunContextSetup { impl RunContext{
pub fn new(context:&crate::setup::SetupContext,window:winit::window::Window)->Self{ fn window_event(&mut self,time:crate::integer::Time,event: winit::event::WindowEvent) {
//wee
let user_settings=crate::settings::read_user_settings();
let args:Vec<String>=std::env::args().collect();
let indexed_model_instances=if args.len()==2{
crate::load_file(std::path::PathBuf::from(&args[1]))
}else{
None
}.unwrap_or(crate::default_models());
let mut graphics=crate::graphics::GraphicsState::new(&context.device,&context.queue);
graphics.load_user_settings(&user_settings);
graphics.generate_models(&context.device,&context.queue,indexed_model_instances);
let mut physics=crate::physics::PhysicsState::default();
physics.load_user_settings(&user_settings);
physics.generate_models(&indexed_model_instances);
Self{
manual_mouse_lock:false,
mouse:crate::physics::MouseState::default(),
user_settings,
window,
graphics,
physics,
}
}
fn window_event(&self,time:crate::integer::Time,event: winit::event::WindowEvent) {
match event { match event {
winit::event::WindowEvent::DroppedFile(path)=>{ winit::event::WindowEvent::DroppedFile(path)=>{
let sender=self.sender.clone();//mpsc // let sender=self.sender.clone();//mpsc
std::thread::spawn(move ||{ // std::thread::spawn(move ||{
// let indexed_model_instances=crate::load_file(path);
// sender.send(Instruction::Die(indexed_model_instances));
// });
let indexed_model_instances=crate::load_file(path); let indexed_model_instances=crate::load_file(path);
sender.send(Instruction::Die(indexed_model_instances)); //self.physics=
}); println!("unimplemented");
}, },
winit::event::WindowEvent::Focused(state)=>{ winit::event::WindowEvent::Focused(state)=>{
//pause unpause //pause unpause
@ -187,44 +158,75 @@ impl RunContextSetup {
_=>(), _=>(),
} }
} }
}
pub fn into_worker(self)->crate::worker::QNWorker<TimedInstruction<RunInstruction>>{ pub struct RunContextSetup{
user_settings:crate::settings::UserSettings,
window:winit::window::Window,
physics:crate::physics::PhysicsState,
graphics:crate::graphics::GraphicsState,
}
impl RunContextSetup{
pub fn new(context:&crate::setup::SetupContext,window:winit::window::Window)->Self{
//wee
let user_settings=crate::settings::read_user_settings();
let args:Vec<String>=std::env::args().collect();
let indexed_model_instances=if args.len()==2{
crate::load_file(std::path::PathBuf::from(&args[1]))
}else{
None
}.unwrap_or(crate::default_models());
let mut graphics=crate::graphics::GraphicsState::new(&context.device,&context.queue);
graphics.load_user_settings(&user_settings);
graphics.generate_models(&context.device,&context.queue,indexed_model_instances);
let mut physics=crate::physics::PhysicsState::default();
physics.load_user_settings(&user_settings);
physics.generate_models(&indexed_model_instances);
Self{
user_settings,
window,
graphics,
physics,
}
}
fn into_context(self)->RunContext{
RunContext{
manual_mouse_lock:false,
mouse:crate::physics::MouseState::default(),
user_settings:self.user_settings,
window:self.window,
physics:self.physics,
graphics:self.graphics,
}
}
pub fn into_worker(self,setup_context:crate::setup::SetupContext)->crate::worker::QNWorker<TimedInstruction<RunInstruction>>{
let run_context=self.into_context(); let run_context=self.into_context();
crate::worker::QNWorker::new(move |ins:TimedInstruction<RunInstruction>|{ crate::worker::QNWorker::new(move |ins:TimedInstruction<RunInstruction>|{
match ins.instruction{ match ins.instruction{
RunInstruction::RequestRedraw=>{ RunInstruction::RequestRedraw=>{
self.window.request_redraw(); run_context.window.request_redraw();
} }
RunInstruction::WindowEvent(window_event)=>{ RunInstruction::WindowEvent(window_event)=>{
self.window_event(ins.time,window_event); run_context.window_event(ins.time,window_event);
}, },
RunInstruction::DeviceEvent(device_event)=>{ RunInstruction::DeviceEvent(device_event)=>{
self.device_event(ins.time,device_event); run_context.device_event(ins.time,device_event);
}, },
RunInstruction::Resize(size)=>{ RunInstruction::Resize(size)=>{
setup_context.config.width=size.width.max(1); setup_context.config.width=size.width.max(1);
setup_context.config.height=size.height.max(1); setup_context.config.height=size.height.max(1);
setup_context.surface.configure(&setup_context.device,&setup_context.config); setup_context.surface.configure(&setup_context.device,&setup_context.config);
physics_thread.send(TimedInstruction{time:ins.time,instruction:PhysicsInstruction::Resize(size)}); run_context.physics_thread.send(TimedInstruction{time:ins.time,instruction:PhysicsInstruction::Resize(size)});
} }
RunInstruction::Render=>{ RunInstruction::Render=>{
let frame=match setup_context.surface.get_current_texture(){ //
Ok(frame)=>frame,
Err(_)=>{
setup_context.surface.configure(&setup_context.device,&setup_context.config);
setup_context.surface
.get_current_texture()
.expect("Failed to acquire next surface texture!")
}
};
let view=frame.texture.create_view(&wgpu::TextureViewDescriptor{
format:Some(setup_context.config.view_formats[0]),
..wgpu::TextureViewDescriptor::default()
});
physics_thread.send(TimedInstruction{time:ins.time,instruction:PhysicsInstruction::Render(view)});
frame.present();
} }
} }
}) })