Caching for resources is now used instead of ignored

This commit is contained in:
Keavon Chambers 2020-05-04 03:01:56 -07:00
parent 38b36ed4c6
commit 59cb448872
7 changed files with 84 additions and 94 deletions

View file

@ -1,6 +1,5 @@
// use super::render_state::RenderState;
use super::color_palette::ColorPalette; use super::color_palette::ColorPalette;
use super::gui_rect::GuiRect; use super::window_events;
use super::pipeline::Pipeline; use super::pipeline::Pipeline;
use super::texture::Texture; use super::texture::Texture;
use super::shader_stage::compile_from_glsl; use super::shader_stage::compile_from_glsl;
@ -9,8 +8,7 @@ use super::draw_command::DrawCommand;
use super::gui_tree::GuiTree; use super::gui_tree::GuiTree;
use std::collections::VecDeque; use std::collections::VecDeque;
use winit::event::*; use winit::event::*;
use winit::event_loop::ControlFlow; use winit::event_loop::*;
use winit::event_loop::EventLoop;
use winit::window::Window; use winit::window::Window;
use futures::executor::block_on; use futures::executor::block_on;
@ -111,13 +109,17 @@ impl Application {
// Load the vertex shader // Load the vertex shader
let vertex_shader_path = "shaders/shader.vert"; let vertex_shader_path = "shaders/shader.vert";
let vertex_shader_module = compile_from_glsl(&self.device, vertex_shader_path, glsl_to_spirv::ShaderType::Vertex).unwrap(); if self.shader_cache.get(vertex_shader_path).is_none() {
self.shader_cache.set(vertex_shader_path, vertex_shader_module); let vertex_shader_module = compile_from_glsl(&self.device, vertex_shader_path, glsl_to_spirv::ShaderType::Vertex).unwrap();
self.shader_cache.set(vertex_shader_path, vertex_shader_module);
}
// Load the fragment shader // Load the fragment shader
let fragment_shader_path = "shaders/shader.frag"; let fragment_shader_path = "shaders/shader.frag";
let fragment_shader_module = compile_from_glsl(&self.device, fragment_shader_path, glsl_to_spirv::ShaderType::Fragment).unwrap(); if self.shader_cache.get(fragment_shader_path).is_none() {
self.shader_cache.set(fragment_shader_path, fragment_shader_module); let fragment_shader_module = compile_from_glsl(&self.device, fragment_shader_path, glsl_to_spirv::ShaderType::Fragment).unwrap();
self.shader_cache.set(fragment_shader_path, fragment_shader_module);
}
// Get the shader pair // Get the shader pair
let vertex_shader = self.shader_cache.get(vertex_shader_path).unwrap(); let vertex_shader = self.shader_cache.get(vertex_shader_path).unwrap();
@ -125,14 +127,18 @@ impl Application {
// Construct a pipeline from the shader pair // Construct a pipeline from the shader pair
let pipeline_name = "example"; let pipeline_name = "example";
let pipeline = Pipeline::new(&self.device, vertex_shader, fragment_shader); if self.pipeline_cache.get(pipeline_name).is_none() {
self.pipeline_cache.set(pipeline_name, pipeline); let pipeline = Pipeline::new(&self.device, vertex_shader, fragment_shader);
self.pipeline_cache.set(pipeline_name, pipeline);
}
let example_pipeline = self.pipeline_cache.get(pipeline_name).unwrap(); let example_pipeline = self.pipeline_cache.get(pipeline_name).unwrap();
// Load a texture from the image file // Load a texture from the image file
let texture_path = "textures/grid.png"; let texture_path = "textures/grid.png";
let texture = Texture::from_filepath(&self.device, &mut self.queue, texture_path).unwrap(); if self.texture_cache.get(texture_path).is_none() {
self.texture_cache.set(texture_path, texture); let texture = Texture::from_filepath(&self.device, &mut self.queue, texture_path).unwrap();
self.texture_cache.set(texture_path, texture);
}
let grid_texture = self.texture_cache.get(texture_path).unwrap(); let grid_texture = self.texture_cache.get(texture_path).unwrap();
// Create a BindGroup that holds a new TextureView // Create a BindGroup that holds a new TextureView
@ -156,17 +162,19 @@ impl Application {
self.draw_command_queue.push_back(draw_command); self.draw_command_queue.push_back(draw_command);
} }
// Initializes the event loop for rendering and event handling
pub fn begin_lifecycle(mut self, event_loop: EventLoop<()>, window: Window) { pub fn begin_lifecycle(mut self, event_loop: EventLoop<()>, window: Window) {
event_loop.run(move |event, _, control_flow| self.main_event_loop(event, control_flow, &window)); event_loop.run(move |event, _, control_flow| self.main_event_loop(event, control_flow, &window));
} }
// Called every time by the event loop
pub fn main_event_loop<T>(&mut self, event: Event<'_, T>, control_flow: &mut ControlFlow, window: &Window) { pub fn main_event_loop<T>(&mut self, event: Event<'_, T>, control_flow: &mut ControlFlow, window: &Window) {
// Wait for the next event to cause a subsequent event loop run, instead of looping instantly as a game would need // Wait for the next event to cause a subsequent event loop run, instead of looping instantly as a game would need
*control_flow = ControlFlow::Wait; *control_flow = ControlFlow::Wait;
match event { match event {
// Handle all window events (like input and resize) in sequence // Handle all window events (like input and resize) in sequence
Event::WindowEvent { window_id, ref event } if window_id == window.id() => self.window_event(event, control_flow), Event::WindowEvent { window_id, ref event } if window_id == window.id() => window_events::window_event(self, control_flow, event),
// Handle raw hardware-related events not related to a window // Handle raw hardware-related events not related to a window
Event::DeviceEvent { .. } => (), Event::DeviceEvent { .. } => (),
// Handle custom-dispatched events // Handle custom-dispatched events
@ -185,54 +193,10 @@ impl Application {
} }
} }
pub fn window_event(&mut self, event: &WindowEvent, control_flow: &mut ControlFlow) {
match event {
WindowEvent::Resized(physical_size) => self.resize(*physical_size),
WindowEvent::Moved(_) => (),
WindowEvent::CloseRequested => self.quit(control_flow),
WindowEvent::Destroyed => (),
WindowEvent::DroppedFile(_) => (),
WindowEvent::HoveredFile(_) => (),
WindowEvent::HoveredFileCancelled => (),
WindowEvent::ReceivedCharacter(_) => (),
WindowEvent::Focused(_) => (),
WindowEvent::KeyboardInput { input, .. } => self.keyboard_event(input, control_flow),
WindowEvent::CursorMoved { .. } => (),
WindowEvent::CursorEntered { .. } => (),
WindowEvent::CursorLeft { .. } => (),
WindowEvent::MouseWheel { .. } => (),
WindowEvent::MouseInput { .. } => (),
WindowEvent::TouchpadPressure { .. } => (),
WindowEvent::AxisMotion { .. } => (),
WindowEvent::Touch(_) => (),
WindowEvent::ScaleFactorChanged { new_inner_size, .. } => self.resize(**new_inner_size),
WindowEvent::ThemeChanged(_) => (),
}
}
pub fn keyboard_event(&mut self, input: &KeyboardInput, control_flow: &mut ControlFlow) {
match input {
KeyboardInput { state: ElementState::Pressed, virtual_keycode: Some(VirtualKeyCode::Escape), .. } => self.quit(control_flow),
KeyboardInput { state: ElementState::Pressed, virtual_keycode: Some(VirtualKeyCode::Space), .. } => self.example(),
_ => *control_flow = ControlFlow::Wait,
}
}
pub fn quit(&self, control_flow: &mut ControlFlow) {
*control_flow = ControlFlow::Exit;
}
pub fn resize(&mut self, new_size: winit::dpi::PhysicalSize<u32>) {
self.swap_chain_descriptor.width = new_size.width;
self.swap_chain_descriptor.height = new_size.height;
self.swap_chain = self.device.create_swap_chain(&self.surface, &self.swap_chain_descriptor);
// TODO: Mark root of GUI as dirty to force redraw of everything
}
// Traverse dirty GUI elements and turn GUI changes into draw commands added to the render pipeline queue // Traverse dirty GUI elements and turn GUI changes into draw commands added to the render pipeline queue
pub fn redraw_gui(&mut self, window: &Window) { pub fn redraw_gui(&mut self, window: &Window) {
self.example();
// If any draw commands were actually added, ask the window to dispatch a redraw event // If any draw commands were actually added, ask the window to dispatch a redraw event
if !self.draw_command_queue.is_empty() { if !self.draw_command_queue.is_empty() {
window.request_redraw(); window.request_redraw();

View file

@ -7,6 +7,7 @@ mod resource_cache;
mod shader_stage; mod shader_stage;
mod draw_command; mod draw_command;
mod gui_tree; mod gui_tree;
mod window_events;
use application::Application; use application::Application;
use winit::event_loop::EventLoop; use winit::event_loop::EventLoop;
@ -20,11 +21,7 @@ fn main() {
let window = WindowBuilder::new().with_title("Graphite").build(&event_loop).unwrap(); let window = WindowBuilder::new().with_title("Graphite").build(&event_loop).unwrap();
// Initialize the render pipeline // Initialize the render pipeline
let mut app = Application::new(&window); let app = Application::new(&window);
app.example();
// State managers for render pipeline and program logic
// let app_render_state = RenderState::new(&mut app);
// Begin the application lifecycle // Begin the application lifecycle
app.begin_lifecycle(event_loop, window); app.begin_lifecycle(event_loop, window);

View file

@ -1,3 +1,5 @@
use std::mem;
pub struct Pipeline { pub struct Pipeline {
pub bind_group_layout: wgpu::BindGroupLayout, pub bind_group_layout: wgpu::BindGroupLayout,
pub render_pipeline: wgpu::RenderPipeline, pub render_pipeline: wgpu::RenderPipeline,
@ -58,7 +60,7 @@ impl Pipeline {
vertex_state: wgpu::VertexStateDescriptor { vertex_state: wgpu::VertexStateDescriptor {
index_format: wgpu::IndexFormat::Uint16, index_format: wgpu::IndexFormat::Uint16,
vertex_buffers: &[wgpu::VertexBufferDescriptor { vertex_buffers: &[wgpu::VertexBufferDescriptor {
stride: std::mem::size_of::<[f32; 2]>() as wgpu::BufferAddress, stride: mem::size_of::<[f32; 2]>() as wgpu::BufferAddress,
step_mode: wgpu::InputStepMode::Vertex, step_mode: wgpu::InputStepMode::Vertex,
attributes: &[wgpu::VertexAttributeDescriptor { attributes: &[wgpu::VertexAttributeDescriptor {
offset: 0, offset: 0,

View file

@ -1,26 +0,0 @@
// use super::texture::Texture;
// use super::application::Application;
// use std::collections::HashMap;
// pub struct RenderState {
// pub render_pipeline: wgpu::RenderPipeline,
// pub vertex_buffer: wgpu::Buffer,
// pub index_buffer: wgpu::Buffer,
// pub num_indices: u32,
// pub texture: Texture,
// pub texture_bind_group: wgpu::BindGroup,
// }
// impl RenderState {
// pub fn new(application: &mut Application) -> Self {
// Self {
// vertex_buffer,
// index_buffer,
// num_indices,
// }
// }
// }

View file

@ -1,5 +1,8 @@
pub fn compile_from_glsl(device: &wgpu::Device, path: &str, shader_type: glsl_to_spirv::ShaderType) -> std::io::Result<wgpu::ShaderModule> { use std::fs;
let source = std::fs::read_to_string(path)?; use std::io;
pub fn compile_from_glsl(device: &wgpu::Device, path: &str, shader_type: glsl_to_spirv::ShaderType) -> io::Result<wgpu::ShaderModule> {
let source = fs::read_to_string(path)?;
let spirv = match glsl_to_spirv::compile(&source[..], shader_type) { let spirv = match glsl_to_spirv::compile(&source[..], shader_type) {
Ok(spirv_output) => spirv_output, Ok(spirv_output) => spirv_output,
Err(message) => { Err(message) => {

View file

@ -1,3 +1,4 @@
use std::fs;
use image::GenericImageView; use image::GenericImageView;
pub struct Texture { pub struct Texture {
@ -9,7 +10,7 @@ pub struct Texture {
impl Texture { impl Texture {
pub fn from_filepath(device: &wgpu::Device, queue: &mut wgpu::Queue, path: &str) -> Result<Self, failure::Error> { pub fn from_filepath(device: &wgpu::Device, queue: &mut wgpu::Queue, path: &str) -> Result<Self, failure::Error> {
// Read the raw bytes from the specified file // Read the raw bytes from the specified file
let bytes = std::fs::read(path)?; let bytes = fs::read(path)?;
// Construct and return a Texture from the bytes // Construct and return a Texture from the bytes
Texture::from_bytes(device, queue, &bytes[..]) Texture::from_bytes(device, queue, &bytes[..])

49
src/window_events.rs Normal file
View file

@ -0,0 +1,49 @@
use super::application::Application;
use winit::event::*;
use winit::event_loop::ControlFlow;
pub fn window_event(application: &mut Application, control_flow: &mut ControlFlow, event: &WindowEvent) {
match event {
WindowEvent::Resized(physical_size) => resize(application, *physical_size),
WindowEvent::Moved(_) => (),
WindowEvent::CloseRequested => quit(control_flow),
WindowEvent::Destroyed => (),
WindowEvent::DroppedFile(_) => (),
WindowEvent::HoveredFile(_) => (),
WindowEvent::HoveredFileCancelled => (),
WindowEvent::ReceivedCharacter(_) => (),
WindowEvent::Focused(_) => (),
WindowEvent::KeyboardInput { input, .. } => keyboard_event(application, control_flow, input),
WindowEvent::CursorMoved { .. } => (),
WindowEvent::CursorEntered { .. } => (),
WindowEvent::CursorLeft { .. } => (),
WindowEvent::MouseWheel { .. } => (),
WindowEvent::MouseInput { .. } => (),
WindowEvent::TouchpadPressure { .. } => (),
WindowEvent::AxisMotion { .. } => (),
WindowEvent::Touch(_) => (),
WindowEvent::ScaleFactorChanged { new_inner_size, .. } => resize(application, **new_inner_size),
WindowEvent::ThemeChanged(_) => (),
}
}
fn keyboard_event(application: &mut Application, control_flow: &mut ControlFlow, input: &KeyboardInput) {
match input {
KeyboardInput { state: ElementState::Pressed, virtual_keycode: Some(VirtualKeyCode::Escape), .. } => quit(control_flow),
KeyboardInput { state: ElementState::Pressed, virtual_keycode: Some(VirtualKeyCode::Space), .. } => application.example(),
_ => *control_flow = ControlFlow::Wait,
}
}
fn quit(control_flow: &mut ControlFlow) {
*control_flow = ControlFlow::Exit;
}
fn resize(application: &mut Application, new_size: winit::dpi::PhysicalSize<u32>) {
application.swap_chain_descriptor.width = new_size.width;
application.swap_chain_descriptor.height = new_size.height;
application.swap_chain = application.device.create_swap_chain(&application.surface, &application.swap_chain_descriptor);
// TODO: Mark root of GUI as dirty to force redraw of everything
}