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 cube = Mesh::load(MeshType::Cube);
let plane = Mesh::load(MeshType::Plane{ size: 24.5 }); 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 mut mesh_storage = AssetStorage::<Mesh, MeshType>::new();
let _cube_handle = mesh_storage.add(cube, "cube"); let _cube_handle = mesh_storage.add(cube, "cube");
let plane_handle = mesh_storage.add(plane, "plane"); let plane_handle = mesh_storage.add(plane, "plane");
let quad_handle = mesh_storage.add(quad, "quad");
world.resources.insert(mesh_storage); world.resources.insert(mesh_storage);
let transform_system_bundle = transform_system_bundle::build(&mut world); let transform_system_bundle = transform_system_bundle::build(&mut world);
@ -287,16 +280,37 @@ fn main() {
]); ]);
world.insert((), vec![ world.insert((), vec![
// camera
( (
quad_handle, Rect {
Mesh2d, 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(); let mut rng = StdRng::from_entropy();
for _ in 0 .. 70000 { for _ in 0 .. 5 {
create_person(&mut world, _cube_handle.clone(), 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))); 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 mesh;
pub mod render_resources; pub mod render_resources;
pub mod passes; pub mod passes;
pub mod instancing;
mod light; mod light;
mod render_graph; mod render_graph;
mod material; mod material;
mod rect;
pub use light::*; pub use light::*;
pub use shader::*; pub use shader::*;
@ -14,6 +16,7 @@ pub use render_graph::*;
pub use material::*; pub use material::*;
pub use mesh::*; pub use mesh::*;
pub use camera::*; pub use camera::*;
pub use rect::*;
use std::mem; use std::mem;
use crate::vertex::Vertex; 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 legion::prelude::*;
use std::mem; use std::mem;
use zerocopy::AsBytes; use zerocopy::AsBytes;
use wgpu::{Device, SwapChainOutput}; use wgpu::{Device, SwapChainOutput};
pub struct InstanceBufferInfo {
pub buffer: wgpu::Buffer,
pub instance_count: usize,
pub mesh_id: usize,
}
pub struct ForwardInstancedPipeline { pub struct ForwardInstancedPipeline {
pub pipeline: Option<wgpu::RenderPipeline>, pub pipeline: Option<wgpu::RenderPipeline>,
pub depth_format: wgpu::TextureFormat, 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 legion::prelude::*;
use zerocopy::{AsBytes, FromBytes};
use wgpu::SwapChainOutput; 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 struct UiPipeline {
pub pipeline: Option<wgpu::RenderPipeline>, pub pipeline: Option<wgpu::RenderPipeline>,
pub depth_format: wgpu::TextureFormat, pub depth_format: wgpu::TextureFormat,
pub quad: Option<Handle<Mesh>>,
pub bind_group: Option<wgpu::BindGroup>, pub bind_group: Option<wgpu::BindGroup>,
} }
@ -13,13 +24,48 @@ impl UiPipeline {
UiPipeline { UiPipeline {
pipeline: None, pipeline: None,
bind_group: None, bind_group: None,
quad: None,
depth_format: wgpu::TextureFormat::Depth32Float 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 { 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( let vs_bytes = shader::load_glsl(
include_str!("ui.vert"), include_str!("ui.vert"),
shader::ShaderStage::Vertex, 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 { let pipeline_layout = render_graph.device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
bind_group_layouts: &[&bind_group_layout], bind_group_layouts: &[&bind_group_layout],
}); });
let vertex_buffer_descriptor = get_vertex_buffer_descriptor(); 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 vs_module = render_graph.device.create_shader_module(&vs_bytes);
let fs_module = render_graph.device.create_shader_module(&fs_bytes); let fs_module = render_graph.device.create_shader_module(&fs_bytes);
@ -101,7 +186,7 @@ impl Pipeline for UiPipeline {
stencil_write_mask: 0, stencil_write_mask: 0,
}), }),
index_format: wgpu::IndexFormat::Uint16, index_format: wgpu::IndexFormat::Uint16,
vertex_buffers: &[vertex_buffer_descriptor], vertex_buffers: &[vertex_buffer_descriptor, instance_buffer_descriptor],
sample_count: 1, sample_count: 1,
sample_mask: !0, sample_mask: !0,
alpha_to_coverage_enabled: false, 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) { 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(), &[]); 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 mesh_storage = world.resources.get_mut::<AssetStorage<Mesh, MeshType>>().unwrap();
let mut last_mesh_id = None; for instance_buffer_info in instance_buffer_infos.as_ref().unwrap().iter() {
let mut mesh_query = if let Some(mesh_asset) = mesh_storage.get(instance_buffer_info.mesh_id) {
<(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()) {
mesh_asset.setup_buffers(&render_graph.device); mesh_asset.setup_buffers(&render_graph.device);
pass.set_index_buffer(mesh_asset.index_buffer.as_ref().unwrap(), 0); 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(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) { fn resize(&mut self, _: &RenderGraphData) {

View file

@ -1,10 +1,9 @@
#version 450 #version 450
layout(location = 0) in vec3 v_Normal; layout(location = 0) in vec4 v_Color;
layout(location = 1) in vec4 v_Position;
layout(location = 0) out vec4 o_Target; layout(location = 0) out vec4 o_Target;
void main() { 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 #version 450
// vertex attributes
layout(location = 0) in vec4 a_Pos; layout(location = 0) in vec4 a_Pos;
layout(location = 1) in vec4 a_Normal; layout(location = 1) in vec4 a_Normal;
layout(location = 0) out vec3 v_Normal; // instanced attributes (RectData)
layout(location = 1) out vec4 v_Position; 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 { layout(set = 0, binding = 0) uniform Globals {
mat4 u_ViewProj; mat4 u_ViewProj;
}; };
void main() { void main() {
v_Normal = vec3(a_Normal.xyz); v_Color = a_RectColor;
v_Position = vec4(a_Pos); vec4 position = a_Pos * vec4(a_RectDimensions, 0.0, 1.0);
gl_Position = u_ViewProj * v_Position; 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,
}
}
}