mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2025-07-08 00:05:00 +00:00
Refactor resource caches and use it with textures now
This commit is contained in:
parent
2ab74f7ba1
commit
f4900dd919
8 changed files with 192 additions and 77 deletions
|
@ -3,8 +3,8 @@ use super::color_palette::ColorPalette;
|
|||
use super::gui_rect::GUIRect;
|
||||
use super::pipeline::Pipeline;
|
||||
use super::texture::Texture;
|
||||
use super::shader_cache::ShaderCache;
|
||||
use super::pipeline_cache::PipelineCache;
|
||||
use super::shader_stage::compile_from_glsl;
|
||||
use super::resource_cache::ResourceCache;
|
||||
use super::draw_command::DrawCommand;
|
||||
use std::collections::VecDeque;
|
||||
use winit::event::*;
|
||||
|
@ -20,9 +20,9 @@ pub struct Application {
|
|||
pub queue: wgpu::Queue,
|
||||
pub swap_chain_descriptor: wgpu::SwapChainDescriptor,
|
||||
pub swap_chain: wgpu::SwapChain,
|
||||
pub shader_cache: ShaderCache,
|
||||
pub pipeline_cache: PipelineCache,
|
||||
// pub texture_cache: TextureCache,
|
||||
pub shader_cache: ResourceCache<wgpu::ShaderModule>,
|
||||
pub pipeline_cache: ResourceCache<Pipeline>,
|
||||
pub texture_cache: ResourceCache<Texture>,
|
||||
pub gui_rect_queue: VecDeque<GUIRect>,
|
||||
pub draw_command_queue: VecDeque<DrawCommand>,
|
||||
pub temp_color_toggle: bool,
|
||||
|
@ -67,8 +67,9 @@ impl Application {
|
|||
let swap_chain = device.create_swap_chain(&surface, &swap_chain_descriptor);
|
||||
|
||||
// Cache of all loaded shaders and the Pipeline programs they form
|
||||
let shader_cache = ShaderCache::new();
|
||||
let pipeline_cache = PipelineCache::new();
|
||||
let shader_cache = ResourceCache::<wgpu::ShaderModule>::new();
|
||||
let pipeline_cache = ResourceCache::<Pipeline>::new();
|
||||
let texture_cache = ResourceCache::<Texture>::new();
|
||||
|
||||
let gui_rect_queue = VecDeque::new();
|
||||
|
||||
|
@ -83,6 +84,7 @@ impl Application {
|
|||
swap_chain,
|
||||
shader_cache,
|
||||
pipeline_cache,
|
||||
texture_cache,
|
||||
gui_rect_queue,
|
||||
draw_command_queue,
|
||||
temp_color_toggle: true,
|
||||
|
@ -104,21 +106,39 @@ impl Application {
|
|||
2, 3, 4,
|
||||
];
|
||||
|
||||
// Load the vertex and fragment shaders
|
||||
self.shader_cache.load(&self.device, "shaders/shader.vert", glsl_to_spirv::ShaderType::Vertex).unwrap();
|
||||
self.shader_cache.load(&self.device, "shaders/shader.frag", glsl_to_spirv::ShaderType::Fragment).unwrap();
|
||||
let vertex_shader = self.shader_cache.get_by_path("shaders/shader.vert").unwrap();
|
||||
let fragment_shader = self.shader_cache.get_by_path("shaders/shader.frag").unwrap();
|
||||
// Load the vertex shader
|
||||
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();
|
||||
self.shader_cache.set(vertex_shader_path, vertex_shader_module);
|
||||
|
||||
// Construct a pipeline from the shader pair and a new BindGroup that holds a new TextureView, then store the pipeline in the cache
|
||||
let example_pipeline = Pipeline::new(&self.device, vertex_shader, fragment_shader);
|
||||
let example_texture_view = Texture::from_filepath(&self.device, &mut self.queue, "textures/grid.png").unwrap().texture_view;
|
||||
// Load the fragment shader
|
||||
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();
|
||||
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 {
|
||||
layout: &example_pipeline.bind_group_layout,
|
||||
bindings: &[
|
||||
wgpu::Binding {
|
||||
binding: 0,
|
||||
resource: wgpu::BindingResource::TextureView(&example_texture_view),
|
||||
resource: wgpu::BindingResource::TextureView(&grid_texture.texture_view),
|
||||
},
|
||||
// wgpu::Binding {
|
||||
// binding: 1,
|
||||
|
@ -127,14 +147,10 @@ impl Application {
|
|||
],
|
||||
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
|
||||
let example_draw_command = DrawCommand::new(&self.device, pipeline_id, VERTICES, INDICES, bind_group);
|
||||
|
||||
self.draw_command_queue.push_back(example_draw_command);
|
||||
// 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);
|
||||
self.draw_command_queue.push_back(draw_command);
|
||||
}
|
||||
|
||||
pub fn begin_lifecycle(mut self, event_loop: EventLoop<()>, window: Window) {
|
||||
|
@ -256,7 +272,7 @@ impl Application {
|
|||
// 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);
|
||||
|
||||
// Commands sent to the GPU for drawing during this render pass
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
use super::pipeline_cache::PipelineID;
|
||||
|
||||
pub struct DrawCommand {
|
||||
pub pipeline_id: PipelineID,
|
||||
pub pipeline_name: String,
|
||||
pub bind_group: wgpu::BindGroup,
|
||||
pub vertex_buffer: wgpu::Buffer,
|
||||
pub index_buffer: wgpu::Buffer,
|
||||
|
@ -9,13 +7,13 @@ pub struct 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 index_buffer = device.create_buffer_with_data(bytemuck::cast_slice(indices), wgpu::BufferUsage::INDEX);
|
||||
let index_count = indices.len() as u32;
|
||||
|
||||
Self {
|
||||
pipeline_id,
|
||||
pipeline_name: String::from(pipeline_name),
|
||||
bind_group,
|
||||
vertex_buffer,
|
||||
index_buffer,
|
||||
|
|
|
@ -5,6 +5,9 @@ mod texture;
|
|||
mod color_palette;
|
||||
mod shader_cache;
|
||||
mod pipeline_cache;
|
||||
mod texture_cache;
|
||||
mod resource_cache;
|
||||
mod shader_stage;
|
||||
mod draw_command;
|
||||
|
||||
use application::Application;
|
||||
|
|
|
@ -2,19 +2,19 @@ use std::collections::HashMap;
|
|||
use super::pipeline::Pipeline;
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Debug)]
|
||||
pub struct PipelineID {
|
||||
struct CacheID {
|
||||
index: usize,
|
||||
}
|
||||
|
||||
impl PipelineID {
|
||||
pub fn new(index: usize) -> Self {
|
||||
impl CacheID {
|
||||
fn new(index: usize) -> Self {
|
||||
Self { index }
|
||||
}
|
||||
}
|
||||
|
||||
pub struct PipelineCache {
|
||||
pub pipelines: Vec<Pipeline>,
|
||||
pub name_to_id: HashMap<String, PipelineID>,
|
||||
name_to_id: HashMap<String, CacheID>,
|
||||
}
|
||||
|
||||
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) {
|
||||
Some(id) => self.pipelines.get(id.index),
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_by_id(&self, id: PipelineID) -> Option<&Pipeline> {
|
||||
self.pipelines.get(id.index)
|
||||
}
|
||||
|
||||
pub fn set(&mut self, name: &str, pipeline: Pipeline) -> PipelineID {
|
||||
#[allow(dead_code)]
|
||||
pub fn set(&mut self, name: &str, pipeline: Pipeline) {
|
||||
match self.name_to_id.get(name) {
|
||||
Some(id) => {
|
||||
self.pipelines[id.index] = pipeline;
|
||||
id.clone()
|
||||
},
|
||||
None => {
|
||||
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.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
src/resource_cache.rs
Normal file
52
src/resource_cache.rs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,45 +1,59 @@
|
|||
use std::collections::HashMap;
|
||||
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Debug)]
|
||||
pub struct ShaderID {
|
||||
struct CacheID {
|
||||
index: usize,
|
||||
}
|
||||
|
||||
impl ShaderID {
|
||||
pub fn new(index: usize) -> Self {
|
||||
impl CacheID {
|
||||
fn new(index: usize) -> Self {
|
||||
Self { index }
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ShaderCache {
|
||||
pub shaders: Vec<wgpu::ShaderModule>,
|
||||
pub path_to_id: HashMap<String, ShaderID>,
|
||||
name_to_id: HashMap<String, CacheID>,
|
||||
}
|
||||
|
||||
impl ShaderCache {
|
||||
pub fn new() -> Self {
|
||||
let shaders = Vec::new();
|
||||
let path_to_id = HashMap::new();
|
||||
let name_to_id = HashMap::new();
|
||||
|
||||
Self {
|
||||
shaders,
|
||||
path_to_id,
|
||||
name_to_id,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_by_path(&self, path: &str) -> Option<&wgpu::ShaderModule> {
|
||||
match self.path_to_id.get(path) {
|
||||
#[allow(dead_code)]
|
||||
pub fn get(&self, name: &str) -> Option<&wgpu::ShaderModule> {
|
||||
match self.name_to_id.get(name) {
|
||||
Some(id) => self.shaders.get(id.index),
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
|
||||
// pub fn get_by_id(&self, id: ShaderID) -> Option<&wgpu::ShaderModule> {
|
||||
// self.shaders.get(id.index)
|
||||
// }
|
||||
#[allow(dead_code)]
|
||||
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<()> {
|
||||
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 spirv = match glsl_to_spirv::compile(&source[..], shader_type) {
|
||||
Ok(spirv_output) => spirv_output,
|
||||
|
@ -51,8 +65,8 @@ impl ShaderCache {
|
|||
let compiled = wgpu::read_spirv(spirv)?;
|
||||
let shader = device.create_shader_module(&compiled);
|
||||
|
||||
let last_index = self.path_to_id.len();
|
||||
self.path_to_id.insert(String::from(path), ShaderID { index: last_index });
|
||||
let last_index = self.name_to_id.len();
|
||||
self.name_to_id.insert(String::from(path), CacheID::new(last_index));
|
||||
self.shaders.push(shader);
|
||||
}
|
||||
|
||||
|
|
14
src/shader_stage.rs
Normal file
14
src/shader_stage.rs
Normal 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)
|
||||
}
|
|
@ -1,48 +1,64 @@
|
|||
use std::collections::HashMap;
|
||||
use std::collections::HashMap;
|
||||
use super::texture::Texture;
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct TextureID {
|
||||
pub index: usize,
|
||||
#[derive(Copy, Clone, PartialEq, Debug)]
|
||||
struct CacheID {
|
||||
index: usize,
|
||||
}
|
||||
|
||||
impl CacheID {
|
||||
fn new(index: usize) -> Self {
|
||||
Self { index }
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TextureCache {
|
||||
pub textures: Vec<wgpu::Texture>,
|
||||
pub name_to_id: HashMap<String, TextureID>,
|
||||
pub textures: Vec<Texture>,
|
||||
name_to_id: HashMap<String, CacheID>,
|
||||
}
|
||||
|
||||
impl ShaderCache {
|
||||
impl TextureCache {
|
||||
pub fn new() -> Self {
|
||||
let shaders = Vec::new();
|
||||
let textures = Vec::new();
|
||||
let name_to_id = HashMap::new();
|
||||
|
||||
Self {
|
||||
shaders,
|
||||
textures,
|
||||
name_to_id,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_by_path(&self, path: &str) -> Option<&wgpu::ShaderModule> {
|
||||
match self.name_to_id.get(path) {
|
||||
Some(id) => self.shaders.get(id.index),
|
||||
#[allow(dead_code)]
|
||||
pub fn get(&self, name: &str) -> Option<&Texture> {
|
||||
match self.name_to_id.get(name) {
|
||||
Some(id) => self.textures.get(id.index),
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_by_id(&self, id: ShaderID) -> Option<&wgpu::ShaderModule> {
|
||||
self.shaders.get(id.index)
|
||||
#[allow(dead_code)]
|
||||
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() {
|
||||
let source = std::fs::read_to_string(path)?;
|
||||
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 texture = Texture::from_filepath(device, queue, "textures/grid.png").unwrap();
|
||||
|
||||
let length = self.name_to_id.len();
|
||||
self.name_to_id.insert(String::from(path), ShaderID { index: length });
|
||||
self.shaders.push(shader);
|
||||
self.name_to_id.insert(String::from(path), CacheID::new(length));
|
||||
self.textures.push(texture);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue