render: Store view_matrix as a global in wgpu renderer, and only change it when changed

This commit is contained in:
Nathan Adams 2020-10-16 17:46:40 +02:00 committed by Mike Welsh
parent a2d53df49c
commit bbd8fc768c
13 changed files with 172 additions and 48 deletions

View File

@ -1,12 +1,12 @@
#version 450
layout(set = 0, binding = 2) uniform Colors {
layout(set = 1, binding = 2) uniform Colors {
vec4 mult_color;
vec4 add_color;
};
layout(set = 0, binding = 3) uniform texture2D t_color;
layout(set = 1, binding = 0) uniform sampler s_color;
layout(set = 1, binding = 3) uniform texture2D t_color;
layout(set = 2, binding = 0) uniform sampler s_color;
layout(location=0) in vec2 frag_uv;

Binary file not shown.

Binary file not shown.

View File

@ -1,11 +1,14 @@
#version 450
layout(set = 0, binding = 0) uniform Transforms {
layout(set = 0, binding = 0) uniform Globals {
mat4 view_matrix;
};
layout(set = 1, binding = 0) uniform Transforms {
mat4 world_matrix;
};
layout(set = 0, binding = 1) uniform Colors {
layout(set = 1, binding = 1) uniform Colors {
vec4 mult_color;
vec4 add_color;
};

Binary file not shown.

View File

@ -1,11 +1,11 @@
#version 450
layout(set = 0, binding = 2) uniform Colors {
layout(set = 1, binding = 2) uniform Colors {
vec4 mult_color;
vec4 add_color;
};
layout(std430, set = 0, binding = 3) buffer Gradient {
layout(std430, set = 1, binding = 3) buffer Gradient {
vec4 u_colors[16];
float u_ratios[16];
int u_gradient_type;

View File

@ -1,11 +1,14 @@
#version 450
layout(set = 0, binding = 0) uniform Transforms {
layout(set = 0, binding = 0) uniform Globals {
mat4 view_matrix;
};
layout(set = 1, binding = 0) uniform Transforms {
mat4 world_matrix;
};
layout(set = 0, binding = 1) uniform Texture {
layout(set = 1, binding = 1) uniform Texture {
mat4 u_matrix;
};

Binary file not shown.

114
render/wgpu/src/globals.rs Normal file
View File

@ -0,0 +1,114 @@
use bytemuck::{Pod, Zeroable};
use wgpu::util::DeviceExt;
#[derive(Debug)]
pub struct Globals {
layout: wgpu::BindGroupLayout,
bind_group: wgpu::BindGroup,
buffer: wgpu::Buffer,
viewport_width: u32,
viewport_height: u32,
dirty: bool,
}
#[repr(C)]
#[derive(Copy, Clone, Debug)]
struct GlobalsUniform {
view_matrix: [[f32; 4]; 4],
}
unsafe impl Pod for GlobalsUniform {}
unsafe impl Zeroable for GlobalsUniform {}
impl Globals {
pub fn new(device: &wgpu::Device) -> Self {
let layout_label = create_debug_label!("Globals bind group layout");
let layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
label: layout_label.as_deref(),
entries: &[wgpu::BindGroupLayoutEntry {
binding: 0,
visibility: wgpu::ShaderStage::VERTEX,
ty: wgpu::BindingType::UniformBuffer {
dynamic: false,
min_binding_size: None,
},
count: None,
}],
});
let buffer_label = create_debug_label!("Globals buffer");
let buffer = device.create_buffer(&wgpu::BufferDescriptor {
label: buffer_label.as_deref(),
size: std::mem::size_of::<GlobalsUniform>() as u64,
usage: wgpu::BufferUsage::UNIFORM | wgpu::BufferUsage::COPY_DST,
mapped_at_creation: false,
});
let bind_group_label = create_debug_label!("Globals bind group");
let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
label: bind_group_label.as_deref(),
layout: &layout,
entries: &[wgpu::BindGroupEntry {
binding: 0,
resource: wgpu::BindingResource::Buffer {
buffer: &buffer,
offset: 0,
size: wgpu::BufferSize::new(std::mem::size_of::<GlobalsUniform>() as u64),
},
}],
});
Self {
layout,
bind_group,
buffer,
viewport_width: 0,
viewport_height: 0,
dirty: true,
}
}
pub fn set_resolution(&mut self, viewport_width: u32, viewport_height: u32) {
if viewport_width != self.viewport_width && viewport_height != self.viewport_height {
self.viewport_width = viewport_width;
self.viewport_height = viewport_height;
self.dirty = true;
}
}
pub fn update_uniform(&mut self, device: &wgpu::Device, encoder: &mut wgpu::CommandEncoder) {
if !self.dirty {
return;
}
self.dirty = false;
let temp_label = create_debug_label!("Temporary globals buffer");
let temp_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
label: temp_label.as_deref(),
contents: bytemuck::cast_slice(&[GlobalsUniform {
view_matrix: [
[1.0 / (self.viewport_width as f32 / 2.0), 0.0, 0.0, 0.0],
[0.0, -1.0 / (self.viewport_height as f32 / 2.0), 0.0, 0.0],
[0.0, 0.0, 1.0, 0.0],
[-1.0, 1.0, 0.0, 1.0],
],
}]),
usage: wgpu::BufferUsage::COPY_SRC,
});
encoder.copy_buffer_to_buffer(
&temp_buffer,
0,
&self.buffer,
0,
std::mem::size_of::<GlobalsUniform>() as u64,
);
}
pub fn layout(&self) -> &wgpu::BindGroupLayout {
&self.layout
}
pub fn bind_group(&self) -> &wgpu::BindGroup {
&self.bind_group
}
}

View File

@ -20,9 +20,8 @@ use crate::pipelines::Pipelines;
use crate::shapes::{Draw, DrawType, GradientUniforms, IncompleteDrawType, Mesh};
use crate::target::{RenderTarget, RenderTargetFrame, SwapChainTarget};
use crate::utils::{
build_view_matrix, create_buffer_with_data, format_list, get_backend_names,
gradient_spread_mode_index, ruffle_path_to_lyon_path, swf_bitmap_to_gl_matrix,
swf_to_gl_matrix,
create_buffer_with_data, format_list, get_backend_names, gradient_spread_mode_index,
ruffle_path_to_lyon_path, swf_bitmap_to_gl_matrix, swf_to_gl_matrix,
};
use enum_map::Enum;
use ruffle_core::color_transform::ColorTransform;
@ -33,6 +32,7 @@ type Error = Box<dyn std::error::Error>;
mod utils;
mod bitmaps;
mod globals;
mod pipelines;
mod shapes;
pub mod target;
@ -41,6 +41,7 @@ pub mod target;
pub mod clap;
use crate::bitmaps::BitmapSamplers;
use crate::globals::Globals;
use ruffle_core::swf::{Matrix, Twips};
use std::path::Path;
pub use wgpu;
@ -48,6 +49,7 @@ pub use wgpu;
pub struct Descriptors {
pub device: wgpu::Device,
queue: wgpu::Queue,
globals: Globals,
pipelines: Pipelines,
bitmap_samplers: BitmapSamplers,
msaa_sample_count: u32,
@ -59,11 +61,18 @@ impl Descriptors {
let msaa_sample_count = 4;
let bitmap_samplers = BitmapSamplers::new(&device);
let pipelines = Pipelines::new(&device, msaa_sample_count, bitmap_samplers.layout())?;
let globals = Globals::new(&device);
let pipelines = Pipelines::new(
&device,
msaa_sample_count,
bitmap_samplers.layout(),
globals.layout(),
)?;
Ok(Self {
device,
queue,
globals,
pipelines,
bitmap_samplers,
msaa_sample_count,
@ -80,7 +89,6 @@ pub struct WgpuRenderBackend<T: RenderTarget> {
meshes: Vec<Mesh>,
viewport_width: f32,
viewport_height: f32,
view_matrix: [[f32; 4]; 4],
textures: Vec<(swf::CharacterId, Texture)>,
mask_state: MaskState,
num_masks: u32,
@ -100,7 +108,6 @@ pub enum MaskState {
#[repr(C)]
#[derive(Copy, Clone, Debug)]
struct Transforms {
view_matrix: [[f32; 4]; 4],
world_matrix: [[f32; 4]; 4],
}
@ -203,7 +210,7 @@ impl WgpuRenderBackend<SwapChainTarget> {
}
impl<T: RenderTarget> WgpuRenderBackend<T> {
pub fn new(descriptors: Descriptors, target: T) -> Result<Self, Error> {
pub fn new(mut descriptors: Descriptors, target: T) -> Result<Self, Error> {
let extent = wgpu::Extent3d {
width: target.width(),
height: target.height(),
@ -239,7 +246,10 @@ impl<T: RenderTarget> WgpuRenderBackend<T> {
let viewport_width = target.width() as f32;
let viewport_height = target.height() as f32;
let view_matrix = build_view_matrix(target.width(), target.height());
descriptors
.globals
.set_resolution(target.width(), target.height());
Ok(Self {
descriptors,
@ -250,7 +260,6 @@ impl<T: RenderTarget> WgpuRenderBackend<T> {
meshes: Vec::new(),
viewport_width,
viewport_height,
view_matrix,
textures: Vec::new(),
num_masks: 0,
@ -785,7 +794,7 @@ impl<T: RenderTarget + 'static> RenderBackend for WgpuRenderBackend<T> {
self.viewport_width = width as f32;
self.viewport_height = height as f32;
self.view_matrix = build_view_matrix(width, height);
self.descriptors.globals.set_resolution(width, height);
}
fn register_shape(&mut self, shape: DistilledShape) -> ShapeHandle {
@ -894,6 +903,9 @@ impl<T: RenderTarget + 'static> RenderBackend for WgpuRenderBackend<T> {
}),
}),
});
self.descriptors
.globals
.update_uniform(&self.descriptors.device, encoder);
}
}
@ -930,10 +942,7 @@ impl<T: RenderTarget + 'static> RenderBackend for WgpuRenderBackend<T> {
let transforms_ubo = create_buffer_with_data(
&self.descriptors.device,
bytemuck::cast_slice(&[Transforms {
view_matrix: self.view_matrix,
world_matrix,
}]),
bytemuck::cast_slice(&[Transforms { world_matrix }]),
wgpu::BufferUsage::UNIFORM,
create_debug_label!("Bitmap {} transforms transfer buffer", bitmap.0),
);
@ -1026,9 +1035,10 @@ impl<T: RenderTarget + 'static> RenderBackend for WgpuRenderBackend<T> {
.bitmap
.pipeline_for(self.mask_state),
);
render_pass.set_bind_group(0, &bind_group, &[]);
render_pass.set_bind_group(0, self.descriptors.globals.bind_group(), &[]);
render_pass.set_bind_group(1, &bind_group, &[]);
render_pass.set_bind_group(
1,
2,
self.descriptors.bitmap_samplers.get_bind_group(false, true),
&[],
);
@ -1094,10 +1104,7 @@ impl<T: RenderTarget + 'static> RenderBackend for WgpuRenderBackend<T> {
let transforms_temp = create_buffer_with_data(
&self.descriptors.device,
bytemuck::cast_slice(&[Transforms {
view_matrix: self.view_matrix,
world_matrix,
}]),
bytemuck::cast_slice(&[Transforms { world_matrix }]),
wgpu::BufferUsage::COPY_SRC,
create_debug_label!("Shape {} transforms transfer buffer", mesh.shape_id),
);
@ -1170,7 +1177,7 @@ impl<T: RenderTarget + 'static> RenderBackend for WgpuRenderBackend<T> {
.pipeline_for(self.mask_state),
);
render_pass.set_bind_group(
1,
2,
self.descriptors
.bitmap_samplers
.get_bind_group(*is_repeating, *is_smoothed),
@ -1179,7 +1186,8 @@ impl<T: RenderTarget + 'static> RenderBackend for WgpuRenderBackend<T> {
}
}
render_pass.set_bind_group(0, &draw.bind_group, &[]);
render_pass.set_bind_group(0, self.descriptors.globals.bind_group(), &[]);
render_pass.set_bind_group(1, &draw.bind_group, &[]);
render_pass.set_vertex_buffer(0, draw.vertex_buffer.slice(..));
render_pass.set_index_buffer(draw.index_buffer.slice(..));
@ -1230,10 +1238,7 @@ impl<T: RenderTarget + 'static> RenderBackend for WgpuRenderBackend<T> {
let transforms_ubo = create_buffer_with_data(
&self.descriptors.device,
bytemuck::cast_slice(&[Transforms {
view_matrix: self.view_matrix,
world_matrix,
}]),
bytemuck::cast_slice(&[Transforms { world_matrix }]),
wgpu::BufferUsage::UNIFORM,
create_debug_label!("Rectangle transfer buffer"),
);
@ -1311,7 +1316,8 @@ impl<T: RenderTarget + 'static> RenderBackend for WgpuRenderBackend<T> {
.color
.pipeline_for(self.mask_state),
);
render_pass.set_bind_group(0, &bind_group, &[]);
render_pass.set_bind_group(0, self.descriptors.globals.bind_group(), &[]);
render_pass.set_bind_group(1, &bind_group, &[]);
render_pass.set_vertex_buffer(0, self.quad_vbo.slice(..));
render_pass.set_index_buffer(self.quad_ibo.slice(..));

View File

@ -26,6 +26,7 @@ impl Pipelines {
device: &wgpu::Device,
msaa_sample_count: u32,
sampler_layout: &wgpu::BindGroupLayout,
globals_layout: &wgpu::BindGroupLayout,
) -> Result<Self, Error> {
let color_vs =
device.create_shader_module(wgpu::include_spirv!("../shaders/color.vert.spv"));
@ -54,6 +55,7 @@ impl Pipelines {
&color_fs,
msaa_sample_count,
&vertex_buffers_description,
globals_layout,
),
bitmap: create_bitmap_pipeline(
&device,
@ -62,6 +64,7 @@ impl Pipelines {
msaa_sample_count,
&vertex_buffers_description,
sampler_layout,
globals_layout,
),
gradient: create_gradient_pipeline(
&device,
@ -69,6 +72,7 @@ impl Pipelines {
&gradient_fs,
msaa_sample_count,
&vertex_buffers_description,
globals_layout,
),
})
}
@ -124,6 +128,7 @@ fn create_color_pipelines(
fragment_shader: &wgpu::ShaderModule,
msaa_sample_count: u32,
vertex_buffers_description: &[wgpu::VertexBufferDescriptor<'_>],
globals_layout: &wgpu::BindGroupLayout,
) -> ShapePipeline {
let bind_layout_label = create_debug_label!("Color shape bind group");
let bind_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
@ -153,7 +158,7 @@ fn create_color_pipelines(
let pipeline_layout_label = create_debug_label!("Color shape pipeline layout");
let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
label: pipeline_layout_label.as_deref(),
bind_group_layouts: &[&bind_layout],
bind_group_layouts: &[globals_layout, &bind_layout],
push_constant_ranges: &[],
});
@ -300,6 +305,7 @@ fn create_bitmap_pipeline(
msaa_sample_count: u32,
vertex_buffers_description: &[wgpu::VertexBufferDescriptor<'_>],
sampler_layout: &wgpu::BindGroupLayout,
globals_layout: &wgpu::BindGroupLayout,
) -> ShapePipeline {
let bind_layout_label = create_debug_label!("Bitmap shape bind group");
let bind_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
@ -348,7 +354,7 @@ fn create_bitmap_pipeline(
let pipeline_layout_label = create_debug_label!("Bitmap shape pipeline layout");
let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
label: pipeline_layout_label.as_deref(),
bind_group_layouts: &[&bind_layout, sampler_layout],
bind_group_layouts: &[globals_layout, &bind_layout, sampler_layout],
push_constant_ranges: &[],
});
@ -494,6 +500,7 @@ fn create_gradient_pipeline(
fragment_shader: &wgpu::ShaderModule,
msaa_sample_count: u32,
vertex_buffers_description: &[wgpu::VertexBufferDescriptor<'_>],
globals_layout: &wgpu::BindGroupLayout,
) -> ShapePipeline {
let bind_layout_label = create_debug_label!("Gradient shape bind group");
let bind_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
@ -542,7 +549,7 @@ fn create_gradient_pipeline(
let pipeline_layout_label = create_debug_label!("Gradient shape pipeline layout");
let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
label: pipeline_layout_label.as_deref(),
bind_group_layouts: &[&bind_layout],
bind_group_layouts: &[globals_layout, &bind_layout],
push_constant_ranges: &[],
});

View File

@ -169,15 +169,6 @@ pub fn swf_bitmap_to_gl_matrix(
]
}
pub fn build_view_matrix(viewport_width: u32, viewport_height: u32) -> [[f32; 4]; 4] {
[
[1.0 / (viewport_width as f32 / 2.0), 0.0, 0.0, 0.0],
[0.0, -1.0 / (viewport_height as f32 / 2.0), 0.0, 0.0],
[0.0, 0.0, 1.0, 0.0],
[-1.0, 1.0, 0.0, 1.0],
]
}
/// Map for SWF gradient spread mode to the uniform value used by the gradient shader.
pub fn gradient_spread_mode_index(spread: GradientSpread) -> i32 {
match spread {