Refactor resource caches and use it with textures now

This commit is contained in:
Keavon Chambers
2020-05-02 22:34:23 -07:00
parent 2ab74f7ba1
commit f4900dd919
8 changed files with 192 additions and 77 deletions
+40 -24
View File
@@ -3,8 +3,8 @@ use super::color_palette::ColorPalette;
use super::gui_rect::GUIRect; use super::gui_rect::GUIRect;
use super::pipeline::Pipeline; use super::pipeline::Pipeline;
use super::texture::Texture; use super::texture::Texture;
use super::shader_cache::ShaderCache; use super::shader_stage::compile_from_glsl;
use super::pipeline_cache::PipelineCache; use super::resource_cache::ResourceCache;
use super::draw_command::DrawCommand; use super::draw_command::DrawCommand;
use std::collections::VecDeque; use std::collections::VecDeque;
use winit::event::*; use winit::event::*;
@@ -20,9 +20,9 @@ pub struct Application {
pub queue: wgpu::Queue, pub queue: wgpu::Queue,
pub swap_chain_descriptor: wgpu::SwapChainDescriptor, pub swap_chain_descriptor: wgpu::SwapChainDescriptor,
pub swap_chain: wgpu::SwapChain, pub swap_chain: wgpu::SwapChain,
pub shader_cache: ShaderCache, pub shader_cache: ResourceCache<wgpu::ShaderModule>,
pub pipeline_cache: PipelineCache, pub pipeline_cache: ResourceCache<Pipeline>,
// pub texture_cache: TextureCache, pub texture_cache: ResourceCache<Texture>,
pub gui_rect_queue: VecDeque<GUIRect>, pub gui_rect_queue: VecDeque<GUIRect>,
pub draw_command_queue: VecDeque<DrawCommand>, pub draw_command_queue: VecDeque<DrawCommand>,
pub temp_color_toggle: bool, pub temp_color_toggle: bool,
@@ -67,8 +67,9 @@ impl Application {
let swap_chain = device.create_swap_chain(&surface, &swap_chain_descriptor); let swap_chain = device.create_swap_chain(&surface, &swap_chain_descriptor);
// Cache of all loaded shaders and the Pipeline programs they form // Cache of all loaded shaders and the Pipeline programs they form
let shader_cache = ShaderCache::new(); let shader_cache = ResourceCache::<wgpu::ShaderModule>::new();
let pipeline_cache = PipelineCache::new(); let pipeline_cache = ResourceCache::<Pipeline>::new();
let texture_cache = ResourceCache::<Texture>::new();
let gui_rect_queue = VecDeque::new(); let gui_rect_queue = VecDeque::new();
@@ -83,6 +84,7 @@ impl Application {
swap_chain, swap_chain,
shader_cache, shader_cache,
pipeline_cache, pipeline_cache,
texture_cache,
gui_rect_queue, gui_rect_queue,
draw_command_queue, draw_command_queue,
temp_color_toggle: true, temp_color_toggle: true,
@@ -104,21 +106,39 @@ impl Application {
2, 3, 4, 2, 3, 4,
]; ];
// Load the vertex and fragment shaders // Load the vertex shader
self.shader_cache.load(&self.device, "shaders/shader.vert", glsl_to_spirv::ShaderType::Vertex).unwrap(); let vertex_shader_path = "shaders/shader.vert";
self.shader_cache.load(&self.device, "shaders/shader.frag", glsl_to_spirv::ShaderType::Fragment).unwrap(); let vertex_shader_module = compile_from_glsl(&self.device, vertex_shader_path, glsl_to_spirv::ShaderType::Vertex).unwrap();
let vertex_shader = self.shader_cache.get_by_path("shaders/shader.vert").unwrap(); self.shader_cache.set(vertex_shader_path, vertex_shader_module);
let fragment_shader = self.shader_cache.get_by_path("shaders/shader.frag").unwrap();
// Construct a pipeline from the shader pair and a new BindGroup that holds a new TextureView, then store the pipeline in the cache // Load the fragment shader
let example_pipeline = Pipeline::new(&self.device, vertex_shader, fragment_shader); let fragment_shader_path = "shaders/shader.frag";
let example_texture_view = Texture::from_filepath(&self.device, &mut self.queue, "textures/grid.png").unwrap().texture_view; 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
let vertex_shader = self.shader_cache.get(vertex_shader_path).unwrap();
let fragment_shader = self.shader_cache.get(fragment_shader_path).unwrap();
// Construct a pipeline from the shader pair
let pipeline_name = "example";
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();
// Load a texture from the image file
let texture_path = "textures/grid.png";
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();
// Create a BindGroup that holds a new TextureView
let bind_group = self.device.create_bind_group(&wgpu::BindGroupDescriptor { let bind_group = self.device.create_bind_group(&wgpu::BindGroupDescriptor {
layout: &example_pipeline.bind_group_layout, layout: &example_pipeline.bind_group_layout,
bindings: &[ bindings: &[
wgpu::Binding { wgpu::Binding {
binding: 0, binding: 0,
resource: wgpu::BindingResource::TextureView(&example_texture_view), resource: wgpu::BindingResource::TextureView(&grid_texture.texture_view),
}, },
// wgpu::Binding { // wgpu::Binding {
// binding: 1, // binding: 1,
@@ -127,14 +147,10 @@ impl Application {
], ],
label: None, label: None,
}); });
let pipeline_id = self.pipeline_cache.set("example", example_pipeline);
assert_eq!(pipeline_id, super::pipeline_cache::PipelineID::new(0)); // Create a draw command with the vertex data and bind group and push it to the GPU command queue
let draw_command = DrawCommand::new(&self.device, pipeline_name, VERTICES, INDICES, bind_group);
// Create a draw command with the vertex data and bind group self.draw_command_queue.push_back(draw_command);
let example_draw_command = DrawCommand::new(&self.device, pipeline_id, VERTICES, INDICES, bind_group);
self.draw_command_queue.push_back(example_draw_command);
} }
pub fn begin_lifecycle(mut self, event_loop: EventLoop<()>, window: Window) { pub fn begin_lifecycle(mut self, event_loop: EventLoop<()>, window: Window) {
@@ -256,7 +272,7 @@ impl Application {
// println!("Set pipeline"); // println!("Set pipeline");
// } // }
let pipeline = self.pipeline_cache.get_by_id(command.pipeline_id).unwrap(); let pipeline = self.pipeline_cache.get(&command.pipeline_name).unwrap();
render_pass.set_pipeline(&pipeline.render_pipeline); render_pass.set_pipeline(&pipeline.render_pipeline);
// Commands sent to the GPU for drawing during this render pass // Commands sent to the GPU for drawing during this render pass
+3 -5
View File
@@ -1,7 +1,5 @@
use super::pipeline_cache::PipelineID;
pub struct DrawCommand { pub struct DrawCommand {
pub pipeline_id: PipelineID, pub pipeline_name: String,
pub bind_group: wgpu::BindGroup, pub bind_group: wgpu::BindGroup,
pub vertex_buffer: wgpu::Buffer, pub vertex_buffer: wgpu::Buffer,
pub index_buffer: wgpu::Buffer, pub index_buffer: wgpu::Buffer,
@@ -9,13 +7,13 @@ pub struct DrawCommand {
} }
impl DrawCommand { impl DrawCommand {
pub fn new(device: &wgpu::Device, pipeline_id: PipelineID, vertices: &[[f32; 2]], indices: &[u16], bind_group: wgpu::BindGroup) -> Self { pub fn new(device: &wgpu::Device, pipeline_name: &str, vertices: &[[f32; 2]], indices: &[u16], bind_group: wgpu::BindGroup) -> Self {
let vertex_buffer = device.create_buffer_with_data(bytemuck::cast_slice(vertices), wgpu::BufferUsage::VERTEX); let vertex_buffer = device.create_buffer_with_data(bytemuck::cast_slice(vertices), wgpu::BufferUsage::VERTEX);
let index_buffer = device.create_buffer_with_data(bytemuck::cast_slice(indices), wgpu::BufferUsage::INDEX); let index_buffer = device.create_buffer_with_data(bytemuck::cast_slice(indices), wgpu::BufferUsage::INDEX);
let index_count = indices.len() as u32; let index_count = indices.len() as u32;
Self { Self {
pipeline_id, pipeline_name: String::from(pipeline_name),
bind_group, bind_group,
vertex_buffer, vertex_buffer,
index_buffer, index_buffer,
+3
View File
@@ -5,6 +5,9 @@ mod texture;
mod color_palette; mod color_palette;
mod shader_cache; mod shader_cache;
mod pipeline_cache; mod pipeline_cache;
mod texture_cache;
mod resource_cache;
mod shader_stage;
mod draw_command; mod draw_command;
use application::Application; use application::Application;
+15 -13
View File
@@ -2,19 +2,19 @@ use std::collections::HashMap;
use super::pipeline::Pipeline; use super::pipeline::Pipeline;
#[derive(Copy, Clone, PartialEq, Debug)] #[derive(Copy, Clone, PartialEq, Debug)]
pub struct PipelineID { struct CacheID {
index: usize, index: usize,
} }
impl PipelineID { impl CacheID {
pub fn new(index: usize) -> Self { fn new(index: usize) -> Self {
Self { index } Self { index }
} }
} }
pub struct PipelineCache { pub struct PipelineCache {
pub pipelines: Vec<Pipeline>, pub pipelines: Vec<Pipeline>,
pub name_to_id: HashMap<String, PipelineID>, name_to_id: HashMap<String, CacheID>,
} }
impl PipelineCache { impl PipelineCache {
@@ -28,30 +28,32 @@ impl PipelineCache {
} }
} }
pub fn get_by_name(&self, name: &str) -> Option<&Pipeline> { #[allow(dead_code)]
pub fn get(&self, name: &str) -> Option<&Pipeline> {
match self.name_to_id.get(name) { match self.name_to_id.get(name) {
Some(id) => self.pipelines.get(id.index), Some(id) => self.pipelines.get(id.index),
None => None, None => None,
} }
} }
pub fn get_by_id(&self, id: PipelineID) -> Option<&Pipeline> { #[allow(dead_code)]
self.pipelines.get(id.index) pub fn set(&mut self, name: &str, pipeline: Pipeline) {
}
pub fn set(&mut self, name: &str, pipeline: Pipeline) -> PipelineID {
match self.name_to_id.get(name) { match self.name_to_id.get(name) {
Some(id) => { Some(id) => {
self.pipelines[id.index] = pipeline; self.pipelines[id.index] = pipeline;
id.clone()
}, },
None => { None => {
let last_index = self.name_to_id.len(); let last_index = self.name_to_id.len();
let id = PipelineID::new(last_index); let id = CacheID::new(last_index);
self.name_to_id.insert(String::from(name), id); self.name_to_id.insert(String::from(name), id);
self.pipelines.push(pipeline); self.pipelines.push(pipeline);
id
} }
} }
} }
#[allow(dead_code)]
pub fn load(&mut self, device: &wgpu::Device, name: &str, vertex_shader: &wgpu::ShaderModule, fragment_shader: &wgpu::ShaderModule) {
let pipeline = Pipeline::new(device, vertex_shader, fragment_shader);
self.set(name, pipeline);
}
} }
+52
View File
@@ -0,0 +1,52 @@
use std::collections::HashMap;
#[derive(Copy, Clone, PartialEq, Debug)]
struct CacheID {
index: usize,
}
impl CacheID {
fn new(index: usize) -> Self {
Self { index }
}
}
pub struct ResourceCache<T> {
pub resources: Vec<T>,
name_to_id: HashMap<String, CacheID>,
}
impl<T> ResourceCache<T> {
pub fn new() -> Self {
let resources = Vec::new();
let name_to_id = HashMap::new();
Self {
resources,
name_to_id,
}
}
#[allow(dead_code)]
pub fn get(&self, name: &str) -> Option<&T> {
match self.name_to_id.get(name) {
Some(id) => self.resources.get(id.index),
None => None,
}
}
#[allow(dead_code)]
pub fn set(&mut self, name: &str, resource: T) {
match self.name_to_id.get(name) {
Some(id) => {
self.resources[id.index] = resource;
},
None => {
let last_index = self.name_to_id.len();
let id = CacheID::new(last_index);
self.name_to_id.insert(String::from(name), id);
self.resources.push(resource);
}
}
}
}
+28 -14
View File
@@ -1,45 +1,59 @@
use std::collections::HashMap; use std::collections::HashMap;
#[derive(Copy, Clone, PartialEq, Debug)] #[derive(Copy, Clone, PartialEq, Debug)]
pub struct ShaderID { struct CacheID {
index: usize, index: usize,
} }
impl ShaderID { impl CacheID {
pub fn new(index: usize) -> Self { fn new(index: usize) -> Self {
Self { index } Self { index }
} }
} }
pub struct ShaderCache { pub struct ShaderCache {
pub shaders: Vec<wgpu::ShaderModule>, pub shaders: Vec<wgpu::ShaderModule>,
pub path_to_id: HashMap<String, ShaderID>, name_to_id: HashMap<String, CacheID>,
} }
impl ShaderCache { impl ShaderCache {
pub fn new() -> Self { pub fn new() -> Self {
let shaders = Vec::new(); let shaders = Vec::new();
let path_to_id = HashMap::new(); let name_to_id = HashMap::new();
Self { Self {
shaders, shaders,
path_to_id, name_to_id,
} }
} }
pub fn get_by_path(&self, path: &str) -> Option<&wgpu::ShaderModule> { #[allow(dead_code)]
match self.path_to_id.get(path) { pub fn get(&self, name: &str) -> Option<&wgpu::ShaderModule> {
match self.name_to_id.get(name) {
Some(id) => self.shaders.get(id.index), Some(id) => self.shaders.get(id.index),
None => None, None => None,
} }
} }
// pub fn get_by_id(&self, id: ShaderID) -> Option<&wgpu::ShaderModule> { #[allow(dead_code)]
// self.shaders.get(id.index) pub fn set(&mut self, name: &str, shader: wgpu::ShaderModule) {
// } match self.name_to_id.get(name) {
Some(id) => {
self.shaders[id.index] = shader;
},
None => {
let last_index = self.name_to_id.len();
let id = CacheID::new(last_index);
self.name_to_id.insert(String::from(name), id);
self.shaders.push(shader);
}
}
}
#[allow(dead_code)]
pub fn load(&mut self, device: &wgpu::Device, path: &str, shader_type: glsl_to_spirv::ShaderType) -> std::io::Result<()> { pub fn load(&mut self, device: &wgpu::Device, path: &str, shader_type: glsl_to_spirv::ShaderType) -> std::io::Result<()> {
if self.path_to_id.get(path).is_none() { if self.name_to_id.get(path).is_none() {
let source = std::fs::read_to_string(path)?; let source = std::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,
@@ -51,8 +65,8 @@ impl ShaderCache {
let compiled = wgpu::read_spirv(spirv)?; let compiled = wgpu::read_spirv(spirv)?;
let shader = device.create_shader_module(&compiled); let shader = device.create_shader_module(&compiled);
let last_index = self.path_to_id.len(); let last_index = self.name_to_id.len();
self.path_to_id.insert(String::from(path), ShaderID { index: last_index }); self.name_to_id.insert(String::from(path), CacheID::new(last_index));
self.shaders.push(shader); self.shaders.push(shader);
} }
+14
View File
@@ -0,0 +1,14 @@
pub fn compile_from_glsl(device: &wgpu::Device, path: &str, shader_type: glsl_to_spirv::ShaderType) -> std::io::Result<wgpu::ShaderModule> {
let source = std::fs::read_to_string(path)?;
let spirv = match glsl_to_spirv::compile(&source[..], shader_type) {
Ok(spirv_output) => spirv_output,
Err(message) => {
println!("Error compiling GLSL to SPIRV shader: {}", message);
panic!("{}", message);
}
};
let compiled = wgpu::read_spirv(spirv)?;
let shader = device.create_shader_module(&compiled);
Ok(shader)
}
+37 -21
View File
@@ -1,48 +1,64 @@
use std::collections::HashMap; use std::collections::HashMap;
use std::collections::HashMap; use super::texture::Texture;
#[derive(Copy, Clone)] #[derive(Copy, Clone, PartialEq, Debug)]
pub struct TextureID { struct CacheID {
pub index: usize, index: usize,
}
impl CacheID {
fn new(index: usize) -> Self {
Self { index }
}
} }
pub struct TextureCache { pub struct TextureCache {
pub textures: Vec<wgpu::Texture>, pub textures: Vec<Texture>,
pub name_to_id: HashMap<String, TextureID>, name_to_id: HashMap<String, CacheID>,
} }
impl ShaderCache { impl TextureCache {
pub fn new() -> Self { pub fn new() -> Self {
let shaders = Vec::new(); let textures = Vec::new();
let name_to_id = HashMap::new(); let name_to_id = HashMap::new();
Self { Self {
shaders, textures,
name_to_id, name_to_id,
} }
} }
pub fn get_by_path(&self, path: &str) -> Option<&wgpu::ShaderModule> { #[allow(dead_code)]
match self.name_to_id.get(path) { pub fn get(&self, name: &str) -> Option<&Texture> {
Some(id) => self.shaders.get(id.index), match self.name_to_id.get(name) {
Some(id) => self.textures.get(id.index),
None => None, None => None,
} }
} }
pub fn get_by_id(&self, id: ShaderID) -> Option<&wgpu::ShaderModule> { #[allow(dead_code)]
self.shaders.get(id.index) pub fn set(&mut self, name: &str, texture: Texture) {
match self.name_to_id.get(name) {
Some(id) => {
self.textures[id.index] = texture;
},
None => {
let last_index = self.name_to_id.len();
let id = CacheID::new(last_index);
self.name_to_id.insert(String::from(name), id);
self.textures.push(texture);
}
}
} }
pub fn load(&mut self, device: &wgpu::Device, path: &str, shader_type: glsl_to_spirv::ShaderType) -> std::io::Result<()> { #[allow(dead_code)]
pub fn load(&mut self, device: &wgpu::Device, queue: &mut wgpu::Queue, path: &str) -> std::io::Result<()> {
if self.name_to_id.get(path).is_none() { if self.name_to_id.get(path).is_none() {
let source = std::fs::read_to_string(path)?; let texture = Texture::from_filepath(device, queue, "textures/grid.png").unwrap();
let spirv = glsl_to_spirv::compile(&source[..], shader_type).unwrap();
let compiled = wgpu::read_spirv(spirv).unwrap();
let shader = device.create_shader_module(&compiled);
let length = self.name_to_id.len(); let length = self.name_to_id.len();
self.name_to_id.insert(String::from(path), ShaderID { index: length }); self.name_to_id.insert(String::from(path), CacheID::new(length));
self.shaders.push(shader); self.textures.push(texture);
} }
Ok(()) Ok(())