batched rect rendering

This commit is contained in:
Carter Anderson 2020-01-10 22:42:54 -08:00
parent eb1233d9f0
commit aeeb85b7b0
8 changed files with 162 additions and 54 deletions

View file

@ -168,17 +168,10 @@ fn main() {
let cube = Mesh::load(MeshType::Cube);
let plane = Mesh::load(MeshType::Plane{ size: 24.5 });
let quad = Mesh::load(MeshType::Quad {
north_west: math::vec2(100.0, 200.0),
north_east: math::vec2(200.0, 200.0),
south_west: math::vec2(100.0, 100.0),
south_east: math::vec2(200.0, 100.0),
});
let mut mesh_storage = AssetStorage::<Mesh, MeshType>::new();
let _cube_handle = mesh_storage.add(cube, "cube");
let plane_handle = mesh_storage.add(plane, "plane");
let quad_handle = mesh_storage.add(quad, "quad");
world.resources.insert(mesh_storage);
let transform_system_bundle = transform_system_bundle::build(&mut world);
@ -287,16 +280,37 @@ fn main() {
]);
world.insert((), vec![
// camera
(
quad_handle,
Mesh2d,
Rect {
position: math::vec2(75.0, 75.0),
dimensions: math::vec2(100.0, 100.0),
color: math::vec4(0.0, 1.0, 0.0, 1.0),
},
)
]);
world.insert((), vec![
(
Rect {
position: math::vec2(50.0, 50.0),
dimensions: math::vec2(100.0, 100.0),
color: math::vec4(1.0, 0.0, 0.0, 1.0),
},
)
]);
world.insert((), vec![
(
Rect {
position: math::vec2(100.0, 100.0),
dimensions: math::vec2(100.0, 100.0),
color: math::vec4(0.0, 0.0, 1.0, 1.0),
},
)
]);
let mut rng = StdRng::from_entropy();
for _ in 0 .. 70000 {
for _ in 0 .. 5 {
create_person(&mut world, _cube_handle.clone(),
Translation::new(rng.gen_range(-50.0, 50.0), 0.0, rng.gen_range(-50.0, 50.0)));
}

5
src/render/instancing.rs Normal file
View file

@ -0,0 +1,5 @@
pub struct InstanceBufferInfo {
pub buffer: wgpu::Buffer,
pub instance_count: usize,
pub mesh_id: usize,
}

View file

@ -3,10 +3,12 @@ pub mod shader;
pub mod mesh;
pub mod render_resources;
pub mod passes;
pub mod instancing;
mod light;
mod render_graph;
mod material;
mod rect;
pub use light::*;
pub use shader::*;
@ -14,6 +16,7 @@ pub use render_graph::*;
pub use material::*;
pub use mesh::*;
pub use camera::*;
pub use rect::*;
use std::mem;
use crate::vertex::Vertex;

View file

@ -1,15 +1,9 @@
use crate::{render::*, asset::*, render::mesh::*, LocalToWorld};
use crate::{render::{*, instancing::InstanceBufferInfo}, asset::*, render::mesh::*, LocalToWorld};
use legion::prelude::*;
use std::mem;
use zerocopy::AsBytes;
use wgpu::{Device, SwapChainOutput};
pub struct InstanceBufferInfo {
pub buffer: wgpu::Buffer,
pub instance_count: usize,
pub mesh_id: usize,
}
pub struct ForwardInstancedPipeline {
pub pipeline: Option<wgpu::RenderPipeline>,
pub depth_format: wgpu::TextureFormat,

View file

@ -1,10 +1,21 @@
use crate::{render::*, asset::*, render::mesh::*};
use crate::{render::{*, instancing::InstanceBufferInfo}, asset::*, render::mesh::*, math};
use legion::prelude::*;
use zerocopy::{AsBytes, FromBytes};
use wgpu::SwapChainOutput;
#[repr(C)]
#[derive(Clone, Copy, AsBytes, FromBytes)]
pub struct RectData {
pub position: [f32; 2],
pub dimensions: [f32; 2],
pub color: [f32; 4],
pub z_index: f32,
}
pub struct UiPipeline {
pub pipeline: Option<wgpu::RenderPipeline>,
pub depth_format: wgpu::TextureFormat,
pub quad: Option<Handle<Mesh>>,
pub bind_group: Option<wgpu::BindGroup>,
}
@ -13,13 +24,48 @@ impl UiPipeline {
UiPipeline {
pipeline: None,
bind_group: None,
quad: None,
depth_format: wgpu::TextureFormat::Depth32Float
}
}
pub fn create_rect_buffers(&self, device: &wgpu::Device, world: &World) -> Vec<InstanceBufferInfo> {
let mut rect_query = <Read<Rect>>::query();
let rect_count = rect_query.iter_immutable(world).count();
let mut data = Vec::with_capacity(rect_count);
// TODO: this probably isn't the best way to handle z-ordering
let mut z = 0.9999;
for rect in rect_query.iter_immutable(world)
{
data.push(RectData {
position: rect.position.into(),
dimensions: rect.dimensions.into(),
color: rect.color.into(),
z_index: z,
});
z -= 0.0001;
}
let buffer = device
.create_buffer_with_data(data.as_bytes(), wgpu::BufferUsage::COPY_SRC | wgpu::BufferUsage::VERTEX);
let mesh_id = *self.quad.as_ref().unwrap().id.read().unwrap();
let mut instance_buffer_infos = Vec::new();
instance_buffer_infos.push(InstanceBufferInfo {
mesh_id: mesh_id,
buffer: buffer,
instance_count: rect_count,
});
instance_buffer_infos
}
}
impl Pipeline for UiPipeline {
fn initialize(&mut self, render_graph: &mut RenderGraphData, _: &mut World) {
fn initialize(&mut self, render_graph: &mut RenderGraphData, world: &mut World) {
let vs_bytes = shader::load_glsl(
include_str!("ui.vert"),
shader::ShaderStage::Vertex,
@ -56,11 +102,50 @@ impl Pipeline for UiPipeline {
})
});
{
let mut mesh_storage = world.resources.get_mut::<AssetStorage<Mesh, MeshType>>().unwrap();
let quad = Mesh::load(MeshType::Quad {
north_west: math::vec2(-0.5, 0.5),
north_east: math::vec2(0.5, 0.5),
south_west: math::vec2(-0.5, -0.5),
south_east: math::vec2(0.5, -0.5),
});
self.quad = Some(mesh_storage.add(quad, "ui_quad"));
}
let pipeline_layout = render_graph.device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
bind_group_layouts: &[&bind_group_layout],
});
let vertex_buffer_descriptor = get_vertex_buffer_descriptor();
let rect_data_size = mem::size_of::<RectData>();
let instance_buffer_descriptor = wgpu::VertexBufferDescriptor {
stride: rect_data_size as wgpu::BufferAddress,
step_mode: wgpu::InputStepMode::Instance,
attributes: &[
wgpu::VertexAttributeDescriptor {
format: wgpu::VertexFormat::Float2,
offset: 0,
shader_location: 2,
},
wgpu::VertexAttributeDescriptor {
format: wgpu::VertexFormat::Float2,
offset: 2 * 4,
shader_location: 3,
},
wgpu::VertexAttributeDescriptor {
format: wgpu::VertexFormat::Float4,
offset: 4 * 4,
shader_location: 4,
},
wgpu::VertexAttributeDescriptor {
format: wgpu::VertexFormat::Float,
offset: 8 * 4,
shader_location: 5,
},
],
};
let vs_module = render_graph.device.create_shader_module(&vs_bytes);
let fs_module = render_graph.device.create_shader_module(&fs_bytes);
@ -101,7 +186,7 @@ impl Pipeline for UiPipeline {
stencil_write_mask: 0,
}),
index_format: wgpu::IndexFormat::Uint16,
vertex_buffers: &[vertex_buffer_descriptor],
vertex_buffers: &[vertex_buffer_descriptor, instance_buffer_descriptor],
sample_count: 1,
sample_mask: !0,
alpha_to_coverage_enabled: false,
@ -109,35 +194,19 @@ impl Pipeline for UiPipeline {
}
fn render(&mut self, render_graph: &RenderGraphData, pass: &mut wgpu::RenderPass, _: &SwapChainOutput, world: &mut World) {
let instance_buffer_infos = Some(self.create_rect_buffers(&render_graph.device, world));
pass.set_bind_group(0, self.bind_group.as_ref().unwrap(), &[]);
let mut mesh_storage = world.resources.get_mut::<AssetStorage<Mesh, MeshType>>().unwrap();
let mut last_mesh_id = None;
let mut mesh_query =
<(Read<Handle<Mesh>>, Read<Mesh2d>)>::query()
.filter(!component::<Instanced>());
for (mesh, _) in mesh_query.iter_immutable(world) {
let current_mesh_id = *mesh.id.read().unwrap();
let mut should_load_mesh = last_mesh_id == None;
if let Some(last) = last_mesh_id {
should_load_mesh = last != current_mesh_id;
}
if should_load_mesh {
if let Some(mesh_asset) = mesh_storage.get(*mesh.id.read().unwrap()) {
for instance_buffer_info in instance_buffer_infos.as_ref().unwrap().iter() {
if let Some(mesh_asset) = mesh_storage.get(instance_buffer_info.mesh_id) {
mesh_asset.setup_buffers(&render_graph.device);
pass.set_index_buffer(mesh_asset.index_buffer.as_ref().unwrap(), 0);
pass.set_vertex_buffers(0, &[(&mesh_asset.vertex_buffer.as_ref().unwrap(), 0)]);
pass.set_vertex_buffers(1, &[(&instance_buffer_info.buffer, 0)]);
pass.draw_indexed(0 .. mesh_asset.indices.len() as u32, 0, 0 .. instance_buffer_info.instance_count as u32);
};
}
if let Some(ref mesh_asset) = mesh_storage.get(*mesh.id.read().unwrap()) {
pass.draw_indexed(0 .. mesh_asset.indices.len() as u32, 0, 0 .. 1);
};
last_mesh_id = Some(current_mesh_id);
}
}
fn resize(&mut self, _: &RenderGraphData) {

View file

@ -1,10 +1,9 @@
#version 450
layout(location = 0) in vec3 v_Normal;
layout(location = 1) in vec4 v_Position;
layout(location = 0) in vec4 v_Color;
layout(location = 0) out vec4 o_Target;
void main() {
o_Target = vec4(1.0, 0.0, 0.0, 1.0);
o_Target = v_Color;
}

View file

@ -1,17 +1,24 @@
#version 450
// vertex attributes
layout(location = 0) in vec4 a_Pos;
layout(location = 1) in vec4 a_Normal;
layout(location = 0) out vec3 v_Normal;
layout(location = 1) out vec4 v_Position;
// instanced attributes (RectData)
layout (location = 2) in vec2 a_RectPosition;
layout (location = 3) in vec2 a_RectDimensions;
layout (location = 4) in vec4 a_RectColor;
layout (location = 5) in float a_RectZIndex;
layout(location = 0) out vec4 v_Color;
layout(set = 0, binding = 0) uniform Globals {
mat4 u_ViewProj;
};
void main() {
v_Normal = vec3(a_Normal.xyz);
v_Position = vec4(a_Pos);
gl_Position = u_ViewProj * v_Position;
v_Color = a_RectColor;
vec4 position = a_Pos * vec4(a_RectDimensions, 0.0, 1.0);
position = position + vec4(a_RectPosition, -a_RectZIndex, 0.0);
gl_Position = u_ViewProj * position;
}

17
src/render/rect.rs Normal file
View file

@ -0,0 +1,17 @@
use crate::math::{Vec2, Vec4};
pub struct Rect {
pub position: Vec2,
pub dimensions: Vec2,
pub color: Vec4,
}
impl Rect {
pub fn new(position: Vec2, dimensions: Vec2, color: Vec4) -> Self {
Rect {
position,
dimensions,
color,
}
}
}