Moved from push constants to uniforms
This move also fixed display issues on Vulkan since the matrix's data alignement was not properly handled
This commit is contained in:
parent
2591b60a5d
commit
d3bc7ecc7f
@ -74,6 +74,7 @@ impl Canvas {
|
||||
self.default_texture.clone(),
|
||||
size,
|
||||
self.renderer.create_texture_mesh(),
|
||||
self.renderer.create_matrix_uniform(),
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@ -58,6 +58,7 @@ impl Application<ExampleState> for ExampleApp {
|
||||
fn init(canvas: &mut Canvas) -> Result<ExampleState, &'static str> {
|
||||
use canvas::{
|
||||
utils::{Position, Size},
|
||||
sprite::Sprite,
|
||||
};
|
||||
|
||||
//// 20 x 20 sprite of a picture
|
||||
@ -101,7 +102,7 @@ impl Application<ExampleState> for ExampleApp {
|
||||
//state.sub_sprite.for_each(|pix| unsafe {pix.flat = pix.flat.wrapping_add(1);});
|
||||
|
||||
state.last_offset += 1;
|
||||
state.last_pos.x += 1;
|
||||
state.last_pos.y += 1;
|
||||
state.last_rot += 1.0;
|
||||
state.tex_sprite.set_texture(state.texture.clone(), None, state.last_rot/100.0);
|
||||
state.sub_sprite.set_texture(state.texture.clone(),
|
||||
|
||||
163
src/renderer.rs
163
src/renderer.rs
@ -7,7 +7,7 @@ use wgpu_hal;
|
||||
use cgmath::Matrix3;
|
||||
|
||||
use crate::{
|
||||
sprite::{Sprite, ModelMatrix},
|
||||
sprite::{Sprite, ModelMatrix, MATRIX_SIZE},
|
||||
texture::{GpuTexture},
|
||||
utils::{Pixel, Size},
|
||||
};
|
||||
@ -25,9 +25,10 @@ pub struct WgpuRenderer {
|
||||
config: wgpu::SurfaceConfiguration,
|
||||
|
||||
surface_size: Size,
|
||||
aspect_matrix: Matrix3<f32>,
|
||||
output: Option<wgpu::SurfaceTexture>,
|
||||
|
||||
matrix_bind_group_layout: wgpu::BindGroupLayout,
|
||||
|
||||
texture_bind_group_layout: wgpu::BindGroupLayout,
|
||||
texture_render_pipeline: wgpu::RenderPipeline,
|
||||
|
||||
@ -57,14 +58,11 @@ impl WgpuRenderer {
|
||||
},
|
||||
).await.unwrap();
|
||||
|
||||
let mut limits = wgpu::Limits::downlevel_defaults();
|
||||
limits.max_push_constant_size = 36;
|
||||
|
||||
let (device, queue) = adapter.request_device(
|
||||
&wgpu::DeviceDescriptor {
|
||||
//using minimum requirements possible since 2D isn't very demanding anyway
|
||||
features: wgpu::Features::PUSH_CONSTANTS,
|
||||
limits,
|
||||
limits: wgpu::Limits::downlevel_webgl2_defaults(),
|
||||
label: None,
|
||||
},
|
||||
None, // Trace path
|
||||
@ -82,12 +80,35 @@ impl WgpuRenderer {
|
||||
surface.configure(&device, &config);
|
||||
|
||||
let surface_size = size;
|
||||
let aspect_matrix
|
||||
= Matrix3::from_nonuniform_scale(1.0 / size.w as f32, 1.0 / size.h as f32);
|
||||
//let aspect_matrix = {
|
||||
// use cgmath::{Basis3, Rotation3, Deg};
|
||||
|
||||
// //Matrix3::from(Basis3::from_angle_x(Deg(-0.0)))
|
||||
// //* Matrix3::identity()
|
||||
// //* Matrix3::from_nonuniform_scale(1.0 / size.w as f32, 1.0 / size.h as f32)
|
||||
// Matrix3::from_nonuniform_scale(1.0, 1.0)
|
||||
//};
|
||||
|
||||
let output = Some(surface.get_current_texture()
|
||||
.map_err(|_| "Failed to create SurfaceTexture")?);
|
||||
|
||||
let matrix_bind_group_layout =
|
||||
device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
|
||||
entries: &[
|
||||
wgpu::BindGroupLayoutEntry {
|
||||
binding: 0,
|
||||
visibility: wgpu::ShaderStages::VERTEX,
|
||||
ty: wgpu::BindingType::Buffer {
|
||||
ty: wgpu::BufferBindingType::Uniform,
|
||||
has_dynamic_offset: false,
|
||||
min_binding_size: None,
|
||||
},
|
||||
count: None,
|
||||
}
|
||||
],
|
||||
label: Some("matrix_bind_group_layout"),
|
||||
});
|
||||
|
||||
let texture_bind_group_layout =
|
||||
device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
|
||||
entries: &[
|
||||
@ -113,11 +134,6 @@ impl WgpuRenderer {
|
||||
label: Some("texture_bind_group_layout"),
|
||||
});
|
||||
|
||||
let mvp_push_constant = wgpu::PushConstantRange {
|
||||
stages: wgpu::ShaderStages::VERTEX,
|
||||
range: 0..36,
|
||||
};
|
||||
|
||||
let texture_render_pipeline = {
|
||||
let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
|
||||
label: Some("texture shader"),
|
||||
@ -127,8 +143,11 @@ impl WgpuRenderer {
|
||||
let render_pipeline_layout =
|
||||
device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
|
||||
label: Some("texture render pipeline layout"),
|
||||
bind_group_layouts: &[&texture_bind_group_layout],
|
||||
push_constant_ranges: &[mvp_push_constant],
|
||||
bind_group_layouts: &[
|
||||
&matrix_bind_group_layout,
|
||||
&texture_bind_group_layout,
|
||||
],
|
||||
push_constant_ranges: &[],
|
||||
});
|
||||
|
||||
device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
|
||||
@ -154,7 +173,7 @@ impl WgpuRenderer {
|
||||
topology: wgpu::PrimitiveTopology::TriangleList,
|
||||
strip_index_format: None,
|
||||
front_face: wgpu::FrontFace::Ccw,
|
||||
cull_mode: Some(wgpu::Face::Back),
|
||||
cull_mode: None,//Some(wgpu::Face::Back),
|
||||
// Setting this to anything other than Fill requires
|
||||
// Features::NON_FILL_POLYGON_MODE
|
||||
polygon_mode: wgpu::PolygonMode::Fill,
|
||||
@ -183,7 +202,9 @@ impl WgpuRenderer {
|
||||
let render_pipeline_layout =
|
||||
device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
|
||||
label: Some("shape render pipeline layout"),
|
||||
bind_group_layouts: &[],
|
||||
bind_group_layouts: &[
|
||||
&matrix_bind_group_layout,
|
||||
],
|
||||
push_constant_ranges: &[],
|
||||
});
|
||||
|
||||
@ -253,8 +274,8 @@ impl WgpuRenderer {
|
||||
queue,
|
||||
config,
|
||||
surface_size,
|
||||
aspect_matrix,
|
||||
output,
|
||||
matrix_bind_group_layout,
|
||||
texture_bind_group_layout,
|
||||
texture_render_pipeline,
|
||||
shape_render_pipeline,
|
||||
@ -262,15 +283,16 @@ impl WgpuRenderer {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn create_gpu_texture(&mut self, buf: &[u8], size: Size)
|
||||
-> GpuTexture
|
||||
{
|
||||
GpuTexture::create(&self.device, &self.texture_bind_group_layout, buf, size)
|
||||
pub fn create_gpu_texture(&mut self, buf: &[u8], size: Size) -> GpuTexture {
|
||||
GpuTexture::create(&self.device, &self.texture_bind_group_layout, buf, size)
|
||||
}
|
||||
|
||||
pub fn create_texture_mesh(&self) -> GpuMesh<TextureVertex, 4, 6>
|
||||
{
|
||||
GpuMesh::create(&self.device, TEXTURE_QUAD)
|
||||
pub fn create_texture_mesh(&self) -> GpuMesh<TextureVertex, 4, 6> {
|
||||
GpuMesh::create(&self.device, TEXTURE_QUAD)
|
||||
}
|
||||
|
||||
pub fn create_matrix_uniform(&self) -> GpuUniform<MATRIX_SIZE> {
|
||||
GpuUniform::create(&self.device, &self.matrix_bind_group_layout)
|
||||
}
|
||||
|
||||
pub fn render<S: Sprite>(&mut self, sprite: &mut S) {
|
||||
@ -290,6 +312,8 @@ impl WgpuRenderer {
|
||||
RenderData::Texture ((matrix, gpu_mesh, texture)) => {
|
||||
let mut texture = texture.borrow_mut();
|
||||
|
||||
let matrix_bind_group = matrix.get_bind_group(&mut self.queue);
|
||||
|
||||
if texture.is_synced == false {
|
||||
texture.update(&mut self.queue);
|
||||
}
|
||||
@ -318,12 +342,13 @@ impl WgpuRenderer {
|
||||
render_pass.set_vertex_buffer(0, gpu_mesh.vertex_buffer.slice(..));
|
||||
render_pass.set_index_buffer(gpu_mesh.index_buffer.slice(..),
|
||||
wgpu::IndexFormat::Uint16);
|
||||
render_pass.set_bind_group(0, &texture.bind_group, &[]);
|
||||
render_pass.set_push_constants(
|
||||
wgpu::ShaderStages::VERTEX,
|
||||
0,
|
||||
bytemuck::bytes_of(&(self.aspect_matrix * matrix.get_matrix()))
|
||||
);
|
||||
render_pass.set_bind_group(0, matrix_bind_group, &[]);
|
||||
render_pass.set_bind_group(1, &texture.bind_group, &[]);
|
||||
//render_pass.set_push_constants(
|
||||
// wgpu::ShaderStages::VERTEX,
|
||||
// 0,
|
||||
// bytemuck::bytes_of(&(self.aspect_matrix))// * matrix.get_matrix()))
|
||||
//);
|
||||
render_pass.draw_indexed(0..gpu_mesh.index_number, 0, 0..1);
|
||||
|
||||
drop(render_pass);
|
||||
@ -373,8 +398,15 @@ impl WgpuRenderer {
|
||||
}
|
||||
|
||||
self.surface_size = size;
|
||||
self.aspect_matrix
|
||||
= Matrix3::from_nonuniform_scale(1.0 / size.w as f32, 1.0 / size.h as f32);
|
||||
//self.aspect_matrix = {
|
||||
// use cgmath::{Basis3, Rotation3, Deg};
|
||||
|
||||
// //Matrix3::from(Basis3::from_angle_x(Deg(-0.0)))
|
||||
// //* Matrix3::identity()
|
||||
// // * Matrix3::from_nonuniform_scale(1.0 / size.w as f32, 1.0 / size.h as f32)
|
||||
// Matrix3::from_nonuniform_scale(1.0, 1.0)
|
||||
|
||||
//};
|
||||
self.config.width = size.w;
|
||||
self.config.height = size.h;
|
||||
self.surface.configure(&self.device, &self.config);
|
||||
@ -404,6 +436,7 @@ impl WgpuRenderer {
|
||||
}
|
||||
}
|
||||
|
||||
//--GpuMesh struct----------------------------------------------------------------------------------
|
||||
pub struct GpuMesh<V, const V_NB: usize, const I_NB: usize>
|
||||
where
|
||||
V: Copy + Clone + bytemuck::Pod + bytemuck::Zeroable,
|
||||
@ -429,7 +462,7 @@ where
|
||||
&wgpu_types::BufferDescriptor {
|
||||
label: Some("Vertex Buffer"),
|
||||
size: (V_NB * size_of::<V>()) as u64,
|
||||
usage: Usages::VERTEX.union(Usages::COPY_DST),
|
||||
usage: Usages::VERTEX | Usages::COPY_DST,
|
||||
mapped_at_creation: false,
|
||||
}
|
||||
);
|
||||
@ -437,7 +470,7 @@ where
|
||||
let index_buffer = device.create_buffer( &wgpu_types::BufferDescriptor {
|
||||
label: Some("Index Buffer"),
|
||||
size: (I_NB * size_of::<u16>()) as u64,
|
||||
usage: Usages::INDEX.union(Usages::COPY_DST),
|
||||
usage: Usages::INDEX | Usages::COPY_DST,
|
||||
mapped_at_creation: false,
|
||||
}
|
||||
);
|
||||
@ -470,9 +503,67 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
//--GpuUniform struct-------------------------------------------------------------------------------
|
||||
pub struct GpuUniform<const S: usize> {
|
||||
uniform: wgpu::Buffer,
|
||||
bind_group: wgpu::BindGroup,
|
||||
data: [u8; S],
|
||||
is_synced: bool,
|
||||
}
|
||||
|
||||
impl<const S: usize> GpuUniform<S> {
|
||||
|
||||
pub fn create(device: &wgpu::Device, layout: &wgpu::BindGroupLayout) -> Self {
|
||||
|
||||
let uniform = device.create_buffer(
|
||||
&wgpu_types::BufferDescriptor {
|
||||
label: Some("Uniform Buffer"),
|
||||
size: S as u64,
|
||||
usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
|
||||
mapped_at_creation: false,
|
||||
}
|
||||
);
|
||||
|
||||
let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
|
||||
layout,
|
||||
entries: &[
|
||||
wgpu::BindGroupEntry {
|
||||
binding: 0,
|
||||
resource: uniform.as_entire_binding(),
|
||||
}
|
||||
],
|
||||
label: Some("uniform_bind_group"),
|
||||
});
|
||||
|
||||
Self {
|
||||
uniform,
|
||||
bind_group,
|
||||
data: [0; S],
|
||||
is_synced: false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update(&mut self, data: [u8; S]) {
|
||||
|
||||
self.data = data;
|
||||
self.is_synced = false;
|
||||
}
|
||||
|
||||
pub fn get_bind_group(&mut self, queue: &wgpu::Queue) -> &wgpu::BindGroup {
|
||||
|
||||
if self.is_synced == false {
|
||||
queue.write_buffer(&self.uniform, 0, &self.data);
|
||||
self.is_synced = true;
|
||||
}
|
||||
|
||||
&self.bind_group
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub enum RenderData<'a> {
|
||||
Texture ((
|
||||
&'a mut ModelMatrix,
|
||||
&'a mut GpuUniform<MATRIX_SIZE>,
|
||||
&'a mut GpuMesh<TextureVertex, 4, 6>,
|
||||
&'a Rc<RefCell<GpuTexture>>,
|
||||
)),
|
||||
|
||||
@ -1,7 +1,5 @@
|
||||
// Vertex shader
|
||||
|
||||
var<push_constant> model_matrix: mat3x3<f32>;
|
||||
|
||||
struct VertexInput {
|
||||
@location(0) position: vec2<f32>,
|
||||
@location(1) tex_coords: vec2<f32>,
|
||||
@ -12,6 +10,9 @@ struct VertexOutput {
|
||||
@location(0) tex_coords: vec2<f32>,
|
||||
}
|
||||
|
||||
@group(0)@binding(0)
|
||||
var<uniform> model_matrix: mat3x3<f32>;
|
||||
|
||||
@vertex
|
||||
fn vs_main(model: VertexInput) -> VertexOutput {
|
||||
|
||||
@ -24,9 +25,9 @@ fn vs_main(model: VertexInput) -> VertexOutput {
|
||||
|
||||
// Fragment shader
|
||||
|
||||
@group(0) @binding(0)
|
||||
@group(1)@binding(0)
|
||||
var t_diffuse: texture_2d<f32>;
|
||||
@group(0)@binding(1)
|
||||
@group(1)@binding(1)
|
||||
var s_diffuse: sampler;
|
||||
|
||||
@fragment
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
use log::{debug, error, info, trace, warn};
|
||||
|
||||
use crate::{
|
||||
renderer::{Mesh, GpuMesh, RenderData, TextureVertex},
|
||||
renderer::{Mesh, GpuMesh, RenderData, TextureVertex, GpuUniform},
|
||||
shape::Shape,
|
||||
texture::Texture,
|
||||
utils::{Pixel, Position, Size, NormalizedSize},
|
||||
@ -37,13 +37,18 @@ pub struct ModelMatrix {
|
||||
rotation: Deg<f32>,
|
||||
scale: f32,
|
||||
|
||||
matrix: Matrix3<f32>,
|
||||
uniform: GpuUniform<MATRIX_SIZE>,
|
||||
is_synced: bool,
|
||||
}
|
||||
|
||||
impl ModelMatrix {
|
||||
|
||||
pub fn new(pos: Position, rot: f32, scale: f32) -> Self {
|
||||
pub fn new(pos: Position,
|
||||
rot: f32,
|
||||
scale: f32,
|
||||
uniform: GpuUniform<MATRIX_SIZE>)
|
||||
-> Self
|
||||
{
|
||||
use cgmath::SquareMatrix;
|
||||
|
||||
Self {
|
||||
@ -51,13 +56,13 @@ impl ModelMatrix {
|
||||
rotation: Deg (rot),
|
||||
scale,
|
||||
|
||||
matrix: Matrix3::identity(),
|
||||
uniform,
|
||||
is_synced: false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn default() -> Self {
|
||||
Self::new(Position::origin(), 0.0, 1.0)
|
||||
pub fn default(uniform: GpuUniform<MATRIX_SIZE>) -> Self {
|
||||
Self::new(Position::origin(), 0.0, 1.0, uniform)
|
||||
}
|
||||
|
||||
pub fn set_position(&mut self, pos: Position) {
|
||||
@ -75,7 +80,7 @@ impl ModelMatrix {
|
||||
self.is_synced = false;
|
||||
}
|
||||
|
||||
pub fn get_matrix(&mut self) -> Matrix3<f32> {
|
||||
pub fn get_uniform(&mut self) -> &mut GpuUniform<MATRIX_SIZE> {
|
||||
use cgmath::{Basis3, Rotation3, SquareMatrix};
|
||||
|
||||
if self.is_synced == false {
|
||||
@ -87,15 +92,30 @@ impl ModelMatrix {
|
||||
let rotation_mat = Matrix3::from(Basis3::from_angle_z(self.rotation));
|
||||
let scale_mat = Matrix3::from_scale(self.scale);
|
||||
let translation_mat = Matrix3::from_translation(pos_vec);
|
||||
let aspect_mat = Matrix3::from_nonuniform_scale(1.0/1280.0, 1.0/720.0);
|
||||
|
||||
self.matrix = translation_mat * rotation_mat * scale_mat;
|
||||
let matrix = aspect_mat * translation_mat * rotation_mat * scale_mat;
|
||||
let mat_bytes: [u8; 36] = bytemuck::bytes_of(&matrix).try_into().unwrap();
|
||||
let mut bytes = [0; 48];
|
||||
for i in 0..12 {
|
||||
bytes[i] = mat_bytes[i];
|
||||
}
|
||||
for i in 0..12 {
|
||||
bytes[i+16] = mat_bytes[i+12];
|
||||
}
|
||||
for i in 0..12 {
|
||||
bytes[i+32] = mat_bytes[i+24];
|
||||
}
|
||||
self.uniform.update(bytes);
|
||||
self.is_synced = true;
|
||||
}
|
||||
|
||||
self.matrix
|
||||
&mut self.uniform
|
||||
}
|
||||
}
|
||||
|
||||
pub const MATRIX_SIZE: usize = 48;//std::mem::size_of::<Matrix3<f32>>();
|
||||
|
||||
//--TextureSprite struct----------------------------------------------------------------------------
|
||||
pub struct TextureSprite {
|
||||
matrix: ModelMatrix,
|
||||
@ -109,10 +129,14 @@ pub struct TextureSprite {
|
||||
|
||||
impl TextureSprite {
|
||||
|
||||
pub fn create(texture: Texture, size: Size, gpu_mesh: GpuMesh<TextureVertex, 4, 6>) -> Self {
|
||||
|
||||
pub fn create(texture: Texture,
|
||||
size: Size,
|
||||
gpu_mesh: GpuMesh<TextureVertex, 4, 6>,
|
||||
matrix_uniform: GpuUniform<MATRIX_SIZE>)
|
||||
-> Self
|
||||
{
|
||||
let mut sprite = Self {
|
||||
matrix: ModelMatrix::default(),
|
||||
matrix: ModelMatrix::default(matrix_uniform),
|
||||
gpu_mesh,
|
||||
inner_size: size,
|
||||
|
||||
@ -205,7 +229,11 @@ impl Sprite for TextureSprite {
|
||||
}
|
||||
|
||||
fn render_data(&mut self) -> RenderData {
|
||||
RenderData::Texture ((&mut self.matrix, &mut self.gpu_mesh, &self.texture.gpu_texture()))
|
||||
RenderData::Texture ((
|
||||
self.matrix.get_uniform(),
|
||||
&mut self.gpu_mesh,
|
||||
&self.texture.gpu_texture(),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user