From 88078e128a466cfccda63617044c8ad03afa33e9 Mon Sep 17 00:00:00 2001 From: Steins7 Date: Thu, 18 Aug 2022 23:38:32 +0200 Subject: [PATCH] Optimized vertex and index buffers * buffers are no-longer re-created at each frame * re-use existing buffers when updating mesh --- Cargo.lock | 10 ++-- Cargo.toml | 4 +- src/canvas.rs | 8 ++- src/main.rs | 4 +- src/renderer.rs | 130 +++++++++++++++++++++++++++++++----------------- src/sprite.rs | 38 ++++++-------- 6 files changed, 114 insertions(+), 80 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e45b364..263e1bd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -158,6 +158,8 @@ dependencies = [ "pollster", "raw-window-handle", "wgpu", + "wgpu-hal", + "wgpu-types", "winit", ] @@ -1466,9 +1468,9 @@ dependencies = [ [[package]] name = "wgpu-hal" -version = "0.13.1" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef50e48812c7eb958fa52d28a912f8b77c96453ebab21c72b01cdda61d3e65d" +checksum = "20cbdfc3d0637dba3d5536b93adef3d26023a0b96f0e1ee5ee9560a401d9f646" dependencies = [ "android_system_properties", "arrayvec", @@ -1505,9 +1507,9 @@ dependencies = [ [[package]] name = "wgpu-types" -version = "0.13.0" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f48d691b733b9d50ea8cb18f377fd1ed927c90c55ad1ec5b90f68885471977f7" +checksum = "1f762cbc08e1a51389859cf9c199c7aef544789cf3510889aab12c607f701604" dependencies = [ "bitflags", ] diff --git a/Cargo.toml b/Cargo.toml index ab3be54..96d5f07 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,7 +19,9 @@ winit = "^0.26.1" raw-window-handle = "^0.4.3" # gpu API -wgpu = "^0.13.0" +wgpu = "0.13.0" +wgpu-hal = "0.13.2" +wgpu-types = "0.13.2" bytemuck = { version = "1.4", features = [ "derive" ] } [dependencies.image] diff --git a/src/canvas.rs b/src/canvas.rs index e3095b5..24cebc8 100644 --- a/src/canvas.rs +++ b/src/canvas.rs @@ -70,7 +70,11 @@ impl Canvas { //--Create functions-- pub fn create_texture_sprite(&mut self, size: Size) -> TextureSprite { - TextureSprite::create(self.default_texture.clone(), size) + TextureSprite::create( + self.default_texture.clone(), + size, + self.renderer.create_texture_mesh(), + ) } pub fn create_text_sprite(&mut self, _size: Size, _scale: f32) -> TextSprite { @@ -129,7 +133,7 @@ impl Canvas { } //--Output functions-- - pub fn draw(&mut self, sprite: &S) { + pub fn draw(&mut self, sprite: &mut S) { //update texture self.renderer.render(sprite); diff --git a/src/main.rs b/src/main.rs index bd11462..4be5b23 100644 --- a/src/main.rs +++ b/src/main.rs @@ -154,8 +154,8 @@ impl Application for ExampleApp { //canvas.draw(&txt_sprite); - canvas.draw(&state.tex_sprite); - canvas.draw(&state.sub_sprite); + canvas.draw(&mut state.tex_sprite); + canvas.draw(&mut state.sub_sprite); canvas.update(); Ok(()) diff --git a/src/renderer.rs b/src/renderer.rs index a3bd213..c1155e4 100644 --- a/src/renderer.rs +++ b/src/renderer.rs @@ -3,15 +3,15 @@ use log::{debug, error, info, trace, warn}; use raw_window_handle::HasRawWindowHandle; use wgpu; +use wgpu_hal; use crate::{ sprite::Sprite, - texture::{GpuTexture, Texture}, - utils::{Pixel, Position, Size}, + texture::{GpuTexture}, + utils::{Pixel, Size}, }; use std::{ - marker::PhantomData, rc::Rc, cell::RefCell, }; @@ -26,8 +26,8 @@ pub struct WgpuRenderer { texture_bind_group_layout: wgpu::BindGroupLayout, texture_render_pipeline: wgpu::RenderPipeline, shape_render_pipeline: wgpu::RenderPipeline, - texture_quad: GpuMesh, - quad_mesh: GpuMesh, //TODO temporary, to be moved to shapes.rs + texture_quad: GpuMesh, + quad_mesh: GpuMesh, //TODO temporary, to be moved to shapes.rs output: Option, } @@ -211,36 +211,36 @@ impl WgpuRenderer { let texture_quad = { let mesh = Mesh { - vertices: vec![ + vertices: [ TextureVertex { position: [0.0, 0.0], tex_coords: [0.0, 1.0] }, TextureVertex { position: [1.0, 0.0], tex_coords: [1.0, 1.0] }, TextureVertex { position: [1.0, 1.0], tex_coords: [1.0, 0.0] }, TextureVertex { position: [0.0, 1.0], tex_coords: [0.0, 0.0] }, ], - indices: vec![ + indices: [ 0, 1, 2, 0, 2, 3, ], }; - GpuMesh::create(&device, &mesh) + GpuMesh::create(&device, mesh) }; let quad_mesh = { let mesh = Mesh { - vertices: vec![ + vertices: [ ColorVertex { position: [0.0, 0.0], color: [1.0, 0.0, 0.0] }, ColorVertex { position: [1.0, 0.0], color: [0.0, 1.0, 0.0] }, ColorVertex { position: [1.0, 1.0], color: [0.0, 0.0, 1.0] }, ColorVertex { position: [0.0, 1.0], color: [0.5, 0.5, 0.5] }, ], - indices: vec![ + indices: [ 0, 1, 2, 0, 2, 3, ], }; - GpuMesh::create(&device, &mesh) + GpuMesh::create(&device, mesh) }; let output = Some(surface.get_current_texture() @@ -266,8 +266,13 @@ impl WgpuRenderer { { GpuTexture::create(&self.device, &self.texture_bind_group_layout, buf, size) } + + pub fn create_texture_mesh(&self) -> GpuMesh + { + GpuMesh::create(&self.device, TEXTURE_QUAD) + } - pub fn render(&mut self, sprite: &S) { + pub fn render(&mut self, sprite: &mut S) { let output = match &self.output { Some(out) => out, @@ -281,15 +286,16 @@ impl WgpuRenderer { let view = output.texture.create_view(&wgpu::TextureViewDescriptor::default()); match sprite.render_data() { - RenderData::Texture ((mesh, texture)) => { + RenderData::Texture ((gpu_mesh, texture)) => { let mut texture = texture.borrow_mut(); if texture.is_synced == false { texture.update(&mut self.queue); } - //TODO avoid recreating buffers every time - let gpu_mesh = GpuMesh::create(&self.device, &mesh); + if gpu_mesh.is_synced() == false { + gpu_mesh.update(&mut self.queue); + } let mut encoder = self.device .create_command_encoder(&wgpu::CommandEncoderDescriptor { @@ -389,32 +395,40 @@ impl WgpuRenderer { } } -pub struct GpuMesh { +pub struct GpuMesh +where + V: Copy + Clone + bytemuck::Pod + bytemuck::Zeroable, +{ vertex_buffer: wgpu::Buffer, index_buffer: wgpu::Buffer, index_number: u32, - phantom: PhantomData, //keep track of wich type of vertex is used + mesh: Mesh, + is_synced: bool, } -impl GpuMesh { +impl GpuMesh +where + V: Copy + Clone + bytemuck::Pod + bytemuck::Zeroable, +{ - fn create(device: &wgpu::Device, mesh: &Mesh) -> Self { - use wgpu::util::DeviceExt; + pub fn create(device: &wgpu::Device, mesh: Mesh) -> Self { + use std::mem::size_of; + use wgpu_types::BufferUsages as Usages; - let vertex_buffer = device.create_buffer_init( - &wgpu::util::BufferInitDescriptor { + let vertex_buffer = device.create_buffer( + &wgpu_types::BufferDescriptor { label: Some("Vertex Buffer"), - contents: bytemuck::cast_slice(&mesh.vertices), - usage: wgpu::BufferUsages::VERTEX, + size: (V_NB * size_of::()) as u64, + usage: Usages::VERTEX.union(Usages::COPY_DST), + mapped_at_creation: false, } ); - - let index_buffer = device.create_buffer_init( - &wgpu::util::BufferInitDescriptor { +let index_buffer = device.create_buffer( &wgpu_types::BufferDescriptor { label: Some("Index Buffer"), - contents: bytemuck::cast_slice(&mesh.indices), - usage: wgpu::BufferUsages::INDEX, + size: (I_NB * size_of::()) as u64, + usage: Usages::INDEX.union(Usages::COPY_DST), + mapped_at_creation: false, } ); @@ -422,14 +436,33 @@ impl GpuMesh { vertex_buffer, index_buffer, index_number: mesh.indices.len() as u32, - phantom: PhantomData, + mesh, + is_synced: true, } } + + pub fn set_mesh(&mut self, mesh: Mesh) { + + self.mesh = mesh; + self.is_synced = false; + } + + pub fn is_synced(&self) -> bool { + self.is_synced + } + + pub fn update(&mut self, queue: &wgpu::Queue) { + + queue.write_buffer(&self.vertex_buffer, 0, bytemuck::cast_slice(&self.mesh.vertices)); + queue.write_buffer(&self.index_buffer, 0, bytemuck::cast_slice(&self.mesh.indices)); + + self.is_synced = true; + } } pub enum RenderData<'a> { - Texture ((&'a Mesh, &'a Rc>)), - Shape (&'a GpuMesh), + Texture ((&'a mut GpuMesh, &'a Rc>)), + Shape (&'a GpuMesh), } //--Renderer struct utils--------------------------------------------------------------------------- @@ -475,23 +508,26 @@ impl ColorVertex { } } -pub struct Mesh { - pub vertices: Vec, - pub indices: Vec, +pub struct Mesh +where + V: Copy + Clone + bytemuck::Pod + bytemuck::Zeroable, +{ + pub vertices: [V; V_NB], + pub indices: [u16; I_NB], } -//pub const TEXTURE_QUAD: Mesh = Mesh { -// vertices: [ -// TextureVertex { position: [0.0, 0.0], tex_coords: [0.0, 1.0] }, -// TextureVertex { position: [1.0, 0.0], tex_coords: [1.0, 1.0] }, -// TextureVertex { position: [1.0, 1.0], tex_coords: [1.0, 0.0] }, -// TextureVertex { position: [0.0, 1.0], tex_coords: [0.0, 0.0] }, -// ], -// indices: [ -// 0, 1, 2, -// 0, 2, 3, -// ], -//}; +pub const TEXTURE_QUAD: Mesh = Mesh { + vertices: [ + TextureVertex { position: [0.0, 0.0], tex_coords: [0.0, 1.0] }, + TextureVertex { position: [1.0, 0.0], tex_coords: [1.0, 1.0] }, + TextureVertex { position: [1.0, 1.0], tex_coords: [1.0, 0.0] }, + TextureVertex { position: [0.0, 1.0], tex_coords: [0.0, 0.0] }, + ], + indices: [ + 0, 1, 2, + 0, 2, 3, + ], +}; // //const QUAD: Mesh = Mesh { // vertices: [ diff --git a/src/sprite.rs b/src/sprite.rs index d12d155..ea21eb3 100644 --- a/src/sprite.rs +++ b/src/sprite.rs @@ -2,7 +2,7 @@ use log::{debug, error, info, trace, warn}; use crate::{ - renderer::{Mesh, RenderData, TextureVertex}, + renderer::{Mesh, GpuMesh, RenderData, TextureVertex}, shape::Shape, texture::Texture, utils::{Pixel, Position, Size}, @@ -23,7 +23,7 @@ pub trait Sprite { fn set_rotation(&mut self, rot: f32); fn set_alpha(&mut self, alpha: u8); fn set_scale(&mut self, scale: f32); - fn render_data(&self) -> RenderData; + fn render_data(&mut self) -> RenderData; } //--TextureSprite struct---------------------------------------------------------------------------- @@ -31,7 +31,7 @@ pub struct TextureSprite { position: Position, scale: f32, matrix: Matrix4, - mesh: Mesh, + gpu_mesh: GpuMesh, texture: Texture, texture_offset: Position, texture_size: Size, @@ -39,29 +39,17 @@ pub struct TextureSprite { impl TextureSprite { - pub fn create(texture: Texture, size: Size) -> Self { + pub fn create(texture: Texture, size: Size, gpu_mesh: GpuMesh) -> Self { let position = Position::origin(); let scale = 1.0; let matrix = Matrix4::from_scale(scale) + Matrix4::from_translation(position.into()); - let mesh = Mesh { - vertices: vec![ - TextureVertex { position: [0.0, 0.0], tex_coords: [0.0, 1.0] }, - TextureVertex { position: [1.0, 0.0], tex_coords: [1.0, 1.0] }, - TextureVertex { position: [1.0, 1.0], tex_coords: [1.0, 0.0] }, - TextureVertex { position: [0.0, 1.0], tex_coords: [0.0, 0.0] }, - ], - indices: vec![ - 0, 1, 2, - 0, 2, 3, - ], - }; Self { position, scale, matrix, - mesh, + gpu_mesh, texture, texture_offset: position, texture_size: size, @@ -82,8 +70,8 @@ impl TextureSprite { let y_offset = self.texture_offset.y as f32 / size.h as f32; // generate new sprite mesh - self.mesh = Mesh { - vertices: vec![ + let mesh = Mesh { + vertices: [ TextureVertex { position: [0.0, 0.0], tex_coords: [x_offset , y_offset + y_size], @@ -101,11 +89,13 @@ impl TextureSprite { tex_coords: [x_offset , y_offset ], }, ], - indices: vec![ + indices: [ 0, 1, 2, 0, 2, 3, ], }; + + self.gpu_mesh.set_mesh(mesh); } pub fn set_pixel(&mut self, pos: Position, pix: Pixel) { @@ -137,8 +127,8 @@ impl Sprite for TextureSprite { unimplemented!(); } - fn render_data(&self) -> RenderData { - RenderData::Texture ((&self.mesh, &self.texture.gpu_texture())) + fn render_data(&mut self) -> RenderData { + RenderData::Texture ((&mut self.gpu_mesh, &self.texture.gpu_texture())) } } @@ -178,7 +168,7 @@ impl Sprite for TextSprite { unimplemented!(); } - fn render_data(&self) -> RenderData { + fn render_data(&mut self) -> RenderData { todo!(); } } @@ -219,7 +209,7 @@ impl Sprite for ShapeSprite { unimplemented!(); } - fn render_data(&self) -> RenderData { + fn render_data(&mut self) -> RenderData { todo!(); } }