mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-10-01 21:28:11 +08:00
Add bind group caching
This commit is contained in:
+46
-34
@@ -20,6 +20,7 @@ pub struct Application {
|
|||||||
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: ResourceCache<wgpu::ShaderModule>,
|
pub shader_cache: ResourceCache<wgpu::ShaderModule>,
|
||||||
|
pub bind_group_cache: ResourceCache<wgpu::BindGroup>,
|
||||||
pub pipeline_cache: ResourceCache<Pipeline>,
|
pub pipeline_cache: ResourceCache<Pipeline>,
|
||||||
pub texture_cache: ResourceCache<Texture>,
|
pub texture_cache: ResourceCache<Texture>,
|
||||||
pub draw_command_queue: VecDeque<DrawCommand>,
|
pub draw_command_queue: VecDeque<DrawCommand>,
|
||||||
@@ -67,6 +68,7 @@ impl Application {
|
|||||||
|
|
||||||
// Resource caches that own the application's shaders, pipelines, and textures
|
// Resource caches that own the application's shaders, pipelines, and textures
|
||||||
let shader_cache = ResourceCache::<wgpu::ShaderModule>::new();
|
let shader_cache = ResourceCache::<wgpu::ShaderModule>::new();
|
||||||
|
let bind_group_cache = ResourceCache::<wgpu::BindGroup>::new();
|
||||||
let pipeline_cache = ResourceCache::<Pipeline>::new();
|
let pipeline_cache = ResourceCache::<Pipeline>::new();
|
||||||
let texture_cache = ResourceCache::<Texture>::new();
|
let texture_cache = ResourceCache::<Texture>::new();
|
||||||
|
|
||||||
@@ -84,6 +86,7 @@ impl Application {
|
|||||||
swap_chain_descriptor,
|
swap_chain_descriptor,
|
||||||
swap_chain,
|
swap_chain,
|
||||||
shader_cache,
|
shader_cache,
|
||||||
|
bind_group_cache,
|
||||||
pipeline_cache,
|
pipeline_cache,
|
||||||
texture_cache,
|
texture_cache,
|
||||||
draw_command_queue,
|
draw_command_queue,
|
||||||
@@ -95,26 +98,24 @@ impl Application {
|
|||||||
pub fn example(&mut self) {
|
pub fn example(&mut self) {
|
||||||
// Example vertex data
|
// Example vertex data
|
||||||
const VERTICES: &[[f32; 2]] = &[
|
const VERTICES: &[[f32; 2]] = &[
|
||||||
[-0.0868241, 0.49240386],
|
[-0.5, 0.5],
|
||||||
[-0.49513406, 0.06958647],
|
[0.5, 0.5],
|
||||||
[-0.21918549, -0.44939706],
|
[0.5, 1.0],
|
||||||
[0.35966998, -0.3473291],
|
[-0.5, 1.0],
|
||||||
[0.44147372, 0.2347359],
|
|
||||||
];
|
];
|
||||||
const INDICES: &[u16] = &[
|
const INDICES: &[u16] = &[
|
||||||
0, 1, 4,
|
0, 1, 2,
|
||||||
1, 2, 4,
|
0, 2, 3,
|
||||||
2, 3, 4,
|
|
||||||
];
|
];
|
||||||
|
|
||||||
// Load the vertex shader
|
// If uncached, construct a vertex shader loaded from its source code file
|
||||||
let vertex_shader_path = "shaders/shader.vert";
|
let vertex_shader_path = "shaders/shader.vert";
|
||||||
if self.shader_cache.get(vertex_shader_path).is_none() {
|
if self.shader_cache.get(vertex_shader_path).is_none() {
|
||||||
let vertex_shader_module = compile_from_glsl(&self.device, vertex_shader_path, glsl_to_spirv::ShaderType::Vertex).unwrap();
|
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);
|
self.shader_cache.set(vertex_shader_path, vertex_shader_module);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load the fragment shader
|
// If uncached, construct a fragment shader loaded from its source code file
|
||||||
let fragment_shader_path = "shaders/shader.frag";
|
let fragment_shader_path = "shaders/shader.frag";
|
||||||
if self.shader_cache.get(fragment_shader_path).is_none() {
|
if self.shader_cache.get(fragment_shader_path).is_none() {
|
||||||
let fragment_shader_module = compile_from_glsl(&self.device, fragment_shader_path, glsl_to_spirv::ShaderType::Fragment).unwrap();
|
let fragment_shader_module = compile_from_glsl(&self.device, fragment_shader_path, glsl_to_spirv::ShaderType::Fragment).unwrap();
|
||||||
@@ -125,15 +126,23 @@ impl Application {
|
|||||||
let vertex_shader = self.shader_cache.get(vertex_shader_path).unwrap();
|
let vertex_shader = self.shader_cache.get(vertex_shader_path).unwrap();
|
||||||
let fragment_shader = self.shader_cache.get(fragment_shader_path).unwrap();
|
let fragment_shader = self.shader_cache.get(fragment_shader_path).unwrap();
|
||||||
|
|
||||||
// Construct a pipeline from the shader pair
|
// If uncached, construct a pipeline from the shader pair
|
||||||
let pipeline_name = "example";
|
let pipeline_name = "example-pipeline";
|
||||||
if self.pipeline_cache.get(pipeline_name).is_none() {
|
if self.pipeline_cache.get(pipeline_name).is_none() {
|
||||||
let pipeline = Pipeline::new(&self.device, vertex_shader, fragment_shader);
|
let bind_group_layout_binding_types = vec![
|
||||||
|
wgpu::BindingType::SampledTexture {
|
||||||
|
dimension: wgpu::TextureViewDimension::D2,
|
||||||
|
component_type: wgpu::TextureComponentType::Float,
|
||||||
|
multisampled: false,
|
||||||
|
},
|
||||||
|
// ty: wgpu::BindingType::Sampler,
|
||||||
|
];
|
||||||
|
let pipeline = Pipeline::new(&self.device, vertex_shader, fragment_shader, bind_group_layout_binding_types);
|
||||||
self.pipeline_cache.set(pipeline_name, pipeline);
|
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
|
// If uncached, construct a texture loaded from the image file
|
||||||
let texture_path = "textures/grid.png";
|
let texture_path = "textures/grid.png";
|
||||||
if self.texture_cache.get(texture_path).is_none() {
|
if self.texture_cache.get(texture_path).is_none() {
|
||||||
let texture = Texture::from_filepath(&self.device, &mut self.queue, texture_path).unwrap();
|
let texture = Texture::from_filepath(&self.device, &mut self.queue, texture_path).unwrap();
|
||||||
@@ -141,24 +150,18 @@ impl Application {
|
|||||||
}
|
}
|
||||||
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
|
// If uncached, construct a bind group with resources matching the pipeline's bind group layout
|
||||||
let bind_group = self.device.create_bind_group(&wgpu::BindGroupDescriptor {
|
let bind_group_name = "example-bindgroup";
|
||||||
layout: &example_pipeline.bind_group_layout,
|
if self.bind_group_cache.get(bind_group_name).is_none() {
|
||||||
bindings: &[
|
let binding_resources = vec![
|
||||||
wgpu::Binding {
|
wgpu::BindingResource::TextureView(&grid_texture.texture_view),
|
||||||
binding: 0,
|
];
|
||||||
resource: wgpu::BindingResource::TextureView(&grid_texture.texture_view),
|
let bind_group = example_pipeline.build_bind_group(&self.device, binding_resources);
|
||||||
},
|
self.bind_group_cache.set(bind_group_name, bind_group);
|
||||||
// wgpu::Binding {
|
}
|
||||||
// binding: 1,
|
|
||||||
// resource: wgpu::BindingResource::Sampler(&texture.sampler),
|
|
||||||
// }
|
|
||||||
],
|
|
||||||
label: None,
|
|
||||||
});
|
|
||||||
|
|
||||||
// Create a draw command with the vertex data and bind group and push it to the GPU command queue
|
// 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);
|
let draw_command = DrawCommand::new(&self.device, pipeline_name, bind_group_name, VERTICES, INDICES);
|
||||||
self.draw_command_queue.push_back(draw_command);
|
self.draw_command_queue.push_back(draw_command);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -232,15 +235,24 @@ impl Application {
|
|||||||
depth_stencil_attachment: None,
|
depth_stencil_attachment: None,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let mut current_pipeline = String::new();
|
||||||
|
|
||||||
// Turn the queue of pipelines each into a command buffer and submit it to the render queue
|
// Turn the queue of pipelines each into a command buffer and submit it to the render queue
|
||||||
self.draw_command_queue.iter().for_each(|command| {
|
self.draw_command_queue.iter().for_each(|command| {
|
||||||
let pipeline = self.pipeline_cache.get(&command.pipeline_name).unwrap();
|
// Tell the GPU which pipeline to draw in this render pass
|
||||||
render_pass.set_pipeline(&pipeline.render_pipeline);
|
if current_pipeline != command.pipeline_name {
|
||||||
|
let pipeline = self.pipeline_cache.get(&command.pipeline_name).unwrap();
|
||||||
|
render_pass.set_pipeline(&pipeline.render_pipeline);
|
||||||
|
current_pipeline = command.pipeline_name.clone();
|
||||||
|
}
|
||||||
|
|
||||||
// Commands sent to the GPU for drawing during this render pass
|
// Send the GPU the vertices and triangle indices
|
||||||
render_pass.set_vertex_buffer(0, &command.vertex_buffer, 0, 0);
|
render_pass.set_vertex_buffer(0, &command.vertex_buffer, 0, 0);
|
||||||
render_pass.set_index_buffer(&command.index_buffer, 0, 0);
|
render_pass.set_index_buffer(&command.index_buffer, 0, 0);
|
||||||
render_pass.set_bind_group(0, &command.bind_group, &[]);
|
|
||||||
|
// Send the GPU the bind group resources
|
||||||
|
let bind_group = self.bind_group_cache.get(&command.bind_group_name).unwrap();
|
||||||
|
render_pass.set_bind_group(0, bind_group, &[]);
|
||||||
|
|
||||||
// Draw call
|
// Draw call
|
||||||
render_pass.draw_indexed(0..command.index_count, 0, 0..1);
|
render_pass.draw_indexed(0..command.index_count, 0, 0..1);
|
||||||
|
|||||||
+3
-3
@@ -1,20 +1,20 @@
|
|||||||
pub struct DrawCommand {
|
pub struct DrawCommand {
|
||||||
pub pipeline_name: String,
|
pub pipeline_name: String,
|
||||||
pub bind_group: wgpu::BindGroup,
|
pub bind_group_name: String,
|
||||||
pub vertex_buffer: wgpu::Buffer,
|
pub vertex_buffer: wgpu::Buffer,
|
||||||
pub index_buffer: wgpu::Buffer,
|
pub index_buffer: wgpu::Buffer,
|
||||||
pub index_count: u32,
|
pub index_count: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DrawCommand {
|
impl DrawCommand {
|
||||||
pub fn new(device: &wgpu::Device, pipeline_name: &str, vertices: &[[f32; 2]], indices: &[u16], bind_group: wgpu::BindGroup) -> Self {
|
pub fn new(device: &wgpu::Device, pipeline_name: &str, bind_group_name: &str, vertices: &[[f32; 2]], indices: &[u16]) -> 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_name: String::from(pipeline_name),
|
pipeline_name: String::from(pipeline_name),
|
||||||
bind_group,
|
bind_group_name: String::from(bind_group_name),
|
||||||
vertex_buffer,
|
vertex_buffer,
|
||||||
index_buffer,
|
index_buffer,
|
||||||
index_count,
|
index_count,
|
||||||
|
|||||||
+34
-31
@@ -6,24 +6,16 @@ pub struct Pipeline {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Pipeline {
|
impl Pipeline {
|
||||||
pub fn new(device: &wgpu::Device, vertex_shader: &wgpu::ShaderModule, fragment_shader: &wgpu::ShaderModule) -> Self {
|
pub fn new(device: &wgpu::Device, vertex_shader: &wgpu::ShaderModule, fragment_shader: &wgpu::ShaderModule, bind_group_layout_binding_types: Vec<wgpu::BindingType>) -> Self {
|
||||||
|
let bind_group_layout_entries = bind_group_layout_binding_types.into_iter().enumerate().map(|(index, binding_type)|
|
||||||
|
wgpu::BindGroupLayoutEntry {
|
||||||
|
binding: index as u32,
|
||||||
|
visibility: wgpu::ShaderStage::all(),
|
||||||
|
ty: binding_type,
|
||||||
|
}
|
||||||
|
).collect::<Vec<_>>();
|
||||||
let bind_group_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
|
let bind_group_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
|
||||||
bindings: &[
|
bindings: bind_group_layout_entries.as_slice(),
|
||||||
wgpu::BindGroupLayoutEntry {
|
|
||||||
binding: 0,
|
|
||||||
visibility: wgpu::ShaderStage::FRAGMENT,
|
|
||||||
ty: wgpu::BindingType::SampledTexture {
|
|
||||||
dimension: wgpu::TextureViewDimension::D2,
|
|
||||||
component_type: wgpu::TextureComponentType::Float,
|
|
||||||
multisampled: false,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
// wgpu::BindGroupLayoutEntry {
|
|
||||||
// binding: 1,
|
|
||||||
// visibility: wgpu::ShaderStage::FRAGMENT,
|
|
||||||
// ty: wgpu::BindingType::Sampler,
|
|
||||||
// },
|
|
||||||
],
|
|
||||||
label: None,
|
label: None,
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -42,20 +34,18 @@ impl Pipeline {
|
|||||||
}),
|
}),
|
||||||
rasterization_state: Some(wgpu::RasterizationStateDescriptor {
|
rasterization_state: Some(wgpu::RasterizationStateDescriptor {
|
||||||
front_face: wgpu::FrontFace::Ccw,
|
front_face: wgpu::FrontFace::Ccw,
|
||||||
cull_mode: wgpu::CullMode::Back,
|
cull_mode: wgpu::CullMode::None,
|
||||||
depth_bias: 0,
|
depth_bias: 0,
|
||||||
depth_bias_slope_scale: 0.0,
|
depth_bias_slope_scale: 0.0,
|
||||||
depth_bias_clamp: 0.0,
|
depth_bias_clamp: 0.0,
|
||||||
}),
|
}),
|
||||||
primitive_topology: wgpu::PrimitiveTopology::TriangleList,
|
primitive_topology: wgpu::PrimitiveTopology::TriangleList,
|
||||||
color_states: &[
|
color_states: &[wgpu::ColorStateDescriptor {
|
||||||
wgpu::ColorStateDescriptor {
|
format: wgpu::TextureFormat::Bgra8UnormSrgb, // TODO: Make this match Application.swap_chain_descriptor
|
||||||
format: wgpu::TextureFormat::Bgra8UnormSrgb, // TODO: Make this match Application.swap_chain_descriptor
|
color_blend: wgpu::BlendDescriptor::REPLACE,
|
||||||
color_blend: wgpu::BlendDescriptor::REPLACE,
|
alpha_blend: wgpu::BlendDescriptor::REPLACE,
|
||||||
alpha_blend: wgpu::BlendDescriptor::REPLACE,
|
write_mask: wgpu::ColorWrite::ALL,
|
||||||
write_mask: wgpu::ColorWrite::ALL,
|
}],
|
||||||
},
|
|
||||||
],
|
|
||||||
depth_stencil_state: None,
|
depth_stencil_state: None,
|
||||||
vertex_state: wgpu::VertexStateDescriptor {
|
vertex_state: wgpu::VertexStateDescriptor {
|
||||||
index_format: wgpu::IndexFormat::Uint16,
|
index_format: wgpu::IndexFormat::Uint16,
|
||||||
@@ -63,11 +53,10 @@ impl Pipeline {
|
|||||||
stride: 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,
|
||||||
shader_location: 0,
|
shader_location: 0,
|
||||||
format: wgpu::VertexFormat::Float2,
|
format: wgpu::VertexFormat::Float2,
|
||||||
},
|
}],
|
||||||
],
|
|
||||||
}],
|
}],
|
||||||
},
|
},
|
||||||
sample_count: 1,
|
sample_count: 1,
|
||||||
@@ -80,4 +69,18 @@ impl Pipeline {
|
|||||||
render_pipeline,
|
render_pipeline,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn build_bind_group(&self, device: &wgpu::Device, binding_resources: Vec<wgpu::BindingResource>) -> wgpu::BindGroup {
|
||||||
|
let bindings = binding_resources.into_iter().enumerate().map(|(index, binding_resource)|
|
||||||
|
wgpu::Binding {
|
||||||
|
binding: index as u32,
|
||||||
|
resource: binding_resource,
|
||||||
|
}
|
||||||
|
).collect::<Vec<_>>();
|
||||||
|
device.create_bind_group(&wgpu::BindGroupDescriptor {
|
||||||
|
layout: &self.bind_group_layout,
|
||||||
|
bindings: bindings.as_slice(),
|
||||||
|
label: None,
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user