Optimized vertex and index buffers
* buffers are no-longer re-created at each frame * re-use existing buffers when updating mesh
This commit is contained in:
parent
330a93fac8
commit
88078e128a
10
Cargo.lock
generated
10
Cargo.lock
generated
@ -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",
|
||||
]
|
||||
|
||||
@ -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]
|
||||
|
||||
@ -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<S: Sprite>(&mut self, sprite: &S) {
|
||||
pub fn draw<S: Sprite>(&mut self, sprite: &mut S) {
|
||||
|
||||
//update texture
|
||||
self.renderer.render(sprite);
|
||||
|
||||
@ -154,8 +154,8 @@ impl Application<ExampleState> 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(())
|
||||
|
||||
130
src/renderer.rs
130
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<TextureVertex>,
|
||||
quad_mesh: GpuMesh<ColorVertex>, //TODO temporary, to be moved to shapes.rs
|
||||
texture_quad: GpuMesh<TextureVertex, 4, 6>,
|
||||
quad_mesh: GpuMesh<ColorVertex, 4, 6>, //TODO temporary, to be moved to shapes.rs
|
||||
output: Option<wgpu::SurfaceTexture>,
|
||||
}
|
||||
|
||||
@ -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()
|
||||
@ -267,7 +267,12 @@ impl WgpuRenderer {
|
||||
GpuTexture::create(&self.device, &self.texture_bind_group_layout, buf, size)
|
||||
}
|
||||
|
||||
pub fn render<S: Sprite>(&mut self, sprite: &S) {
|
||||
pub fn create_texture_mesh(&self) -> GpuMesh<TextureVertex, 4, 6>
|
||||
{
|
||||
GpuMesh::create(&self.device, TEXTURE_QUAD)
|
||||
}
|
||||
|
||||
pub fn render<S: Sprite>(&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<V: Copy + Clone + bytemuck::Pod + bytemuck::Zeroable> {
|
||||
pub struct GpuMesh<V, const V_NB: usize, const I_NB: usize>
|
||||
where
|
||||
V: Copy + Clone + bytemuck::Pod + bytemuck::Zeroable,
|
||||
{
|
||||
vertex_buffer: wgpu::Buffer,
|
||||
index_buffer: wgpu::Buffer,
|
||||
index_number: u32,
|
||||
|
||||
phantom: PhantomData<V>, //keep track of wich type of vertex is used
|
||||
mesh: Mesh<V, V_NB, I_NB>,
|
||||
is_synced: bool,
|
||||
}
|
||||
|
||||
impl<V: Copy + Clone + bytemuck::Pod + bytemuck::Zeroable> GpuMesh<V> {
|
||||
impl<V, const V_NB: usize, const I_NB: usize> GpuMesh<V, V_NB, I_NB>
|
||||
where
|
||||
V: Copy + Clone + bytemuck::Pod + bytemuck::Zeroable,
|
||||
{
|
||||
|
||||
fn create(device: &wgpu::Device, mesh: &Mesh<V>) -> Self {
|
||||
use wgpu::util::DeviceExt;
|
||||
pub fn create(device: &wgpu::Device, mesh: Mesh<V, V_NB, I_NB>) -> 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::<V>()) 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::<u16>()) as u64,
|
||||
usage: Usages::INDEX.union(Usages::COPY_DST),
|
||||
mapped_at_creation: false,
|
||||
}
|
||||
);
|
||||
|
||||
@ -422,14 +436,33 @@ impl<V: Copy + Clone + bytemuck::Pod + bytemuck::Zeroable> GpuMesh<V> {
|
||||
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<V, V_NB, I_NB>) {
|
||||
|
||||
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<TextureVertex>, &'a Rc<RefCell<GpuTexture>>)),
|
||||
Shape (&'a GpuMesh<ColorVertex>),
|
||||
Texture ((&'a mut GpuMesh<TextureVertex, 4, 6>, &'a Rc<RefCell<GpuTexture>>)),
|
||||
Shape (&'a GpuMesh<ColorVertex, 4, 6>),
|
||||
}
|
||||
|
||||
//--Renderer struct utils---------------------------------------------------------------------------
|
||||
@ -475,23 +508,26 @@ impl ColorVertex {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Mesh<V: Copy + Clone + bytemuck::Pod + bytemuck::Zeroable> {
|
||||
pub vertices: Vec<V>,
|
||||
pub indices: Vec<u16>,
|
||||
pub struct Mesh<V, const V_NB: usize, const I_NB: usize>
|
||||
where
|
||||
V: Copy + Clone + bytemuck::Pod + bytemuck::Zeroable,
|
||||
{
|
||||
pub vertices: [V; V_NB],
|
||||
pub indices: [u16; I_NB],
|
||||
}
|
||||
|
||||
//pub const TEXTURE_QUAD: Mesh<TextureVertex> = 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<TextureVertex, 4, 6> = 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<ColorVertex> = Mesh {
|
||||
// vertices: [
|
||||
|
||||
@ -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<f32>,
|
||||
mesh: Mesh<TextureVertex>,
|
||||
gpu_mesh: GpuMesh<TextureVertex, 4, 6>,
|
||||
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<TextureVertex, 4, 6>) -> 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!();
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user