batched draw target works! embrace the "log" crate

This commit is contained in:
Carter Anderson 2020-03-28 20:33:11 -07:00
parent 2d0bff97a8
commit 5db5f6de9c
11 changed files with 210 additions and 75 deletions

View File

@ -14,7 +14,7 @@ bitflags = "1.0"
glam = "0.8.6" glam = "0.8.6"
winit = { version = "0.22.0", optional = true } winit = { version = "0.22.0", optional = true }
zerocopy = "0.3" zerocopy = "0.3"
log = "0.4" log = { version = "0.4", features = ["release_max_level_info"] }
env_logger = "0.7" env_logger = "0.7"
rand = "0.7.2" rand = "0.7.2"
gltf = "0.14.0" gltf = "0.14.0"

View File

@ -11,7 +11,6 @@ pub fn get_winit_run() -> Box<dyn Fn(App)> {
Box::new(|mut app: App| { Box::new(|mut app: App| {
env_logger::init(); env_logger::init();
let event_loop = EventLoop::new(); let event_loop = EventLoop::new();
log::info!("Initializing the window...");
let winit_window = { let winit_window = {
let window = app.resources.get::<Window>().unwrap(); let window = app.resources.get::<Window>().unwrap();
let winit_window = winit::window::Window::new(&event_loop).unwrap(); let winit_window = winit::window::Window::new(&event_loop).unwrap();
@ -22,7 +21,7 @@ pub fn get_winit_run() -> Box<dyn Fn(App)> {
app.resources.insert(winit_window); app.resources.insert(winit_window);
log::info!("Entering render loop..."); log::debug!("Entering render loop");
event_loop.run(move |event, _, control_flow| { event_loop.run(move |event, _, control_flow| {
*control_flow = if cfg!(feature = "metal-auto-capture") { *control_flow = if cfg!(feature = "metal-auto-capture") {
ControlFlow::Exit ControlFlow::Exit
@ -45,8 +44,6 @@ pub fn get_winit_run() -> Box<dyn Fn(App)> {
&mut app.world, &mut app.world,
&mut app.resources, &mut app.resources,
); );
} else {
println!("no renderer {} {}", size.width, size.height);
} }
} }
event::Event::WindowEvent { event, .. } => match event { event::Event::WindowEvent { event, .. } => match event {

View File

@ -1,10 +1,11 @@
use crate::{ use crate::{
asset::Handle, asset::{AssetStorage, Handle},
legion::prelude::*, legion::prelude::*,
prelude::Renderable,
render::{ render::{
draw_target::DrawTarget, draw_target::DrawTarget,
pipeline::PipelineDescriptor, pipeline::PipelineDescriptor,
render_resource::{resource_name, AssetBatchers}, render_resource::{resource_name, AssetBatchers, RenderResourceAssignments},
renderer::{RenderPass, Renderer}, renderer::{RenderPass, Renderer},
}, },
}; };
@ -15,32 +16,90 @@ pub struct AssignedBatchesDrawTarget;
impl DrawTarget for AssignedBatchesDrawTarget { impl DrawTarget for AssignedBatchesDrawTarget {
fn draw( fn draw(
&self, &self,
_world: &World, world: &World,
resources: &Resources, resources: &Resources,
_render_pass: &mut dyn RenderPass, render_pass: &mut dyn RenderPass,
_pipeline_handle: Handle<PipelineDescriptor>, pipeline_handle: Handle<PipelineDescriptor>,
) { ) {
log::debug!("drawing batches for pipeline {:?}", pipeline_handle);
let asset_batches = resources.get::<AssetBatchers>().unwrap(); let asset_batches = resources.get::<AssetBatchers>().unwrap();
// let renderer = render_pass.get_renderer(); let global_render_resource_assignments =
// println!("Drawing batches"); resources.get::<RenderResourceAssignments>().unwrap();
for _batch in asset_batches.get_batches() { render_pass.set_render_resources(&global_render_resource_assignments);
// println!("{:?}", batch); for batch in asset_batches.get_batches() {
// render_pass.set_bind_groups(batch.render_resource_assignments.as_ref()); let indices = render_pass.set_render_resources(&batch.render_resource_assignments);
// render_pass.draw_indexed(0..1, 0, 0..1); log::debug!("drawing batch {:?}", batch.render_resource_assignments.id);
log::trace!("{:#?}", batch);
for batched_entity in batch.entities.iter() {
let renderable = world.get_component::<Renderable>(*batched_entity).unwrap();
if !renderable.is_visible {
continue;
} }
// println!(); log::trace!("start drawing batched entity: {:?}", batched_entity);
// println!(); log::trace!("{:#?}", renderable.render_resource_assignments);
// println!(); let entity_indices =
render_pass.set_render_resources(&renderable.render_resource_assignments);
let mut draw_indices = &indices;
if entity_indices.is_some() {
if indices.is_some() {
// panic!("entities overriding their batch's vertex buffer is not currently supported");
log::trace!("using batch vertex indices");
draw_indices = &entity_indices;
} else {
log::trace!("using entity vertex indices");
draw_indices = &entity_indices;
}
}
if draw_indices.is_none() {
continue;
}
render_pass.draw_indexed(draw_indices.as_ref().unwrap().clone(), 0, 0..1);
log::trace!("finish drawing batched entity: {:?}", batched_entity);
}
}
} }
fn setup( fn setup(
&mut self, &mut self,
_world: &World, world: &mut World,
_resources: &Resources, resources: &Resources,
_renderer: &mut dyn Renderer, renderer: &mut dyn Renderer,
_pipeline_handle: Handle<PipelineDescriptor>, pipeline_handle: Handle<PipelineDescriptor>,
) { ) {
let mut asset_batches = resources.get_mut::<AssetBatchers>().unwrap();
let pipeline_storage = resources.get::<AssetStorage<PipelineDescriptor>>().unwrap();
let pipeline_descriptor = pipeline_storage.get(&pipeline_handle).unwrap();
let mut global_render_resource_assignments =
resources.get_mut::<RenderResourceAssignments>().unwrap();
log::debug!("setting up batch bind groups for pipeline: {:?}", pipeline_handle);
log::trace!("setting up global bind groups");
renderer.setup_bind_groups(&mut global_render_resource_assignments, pipeline_descriptor);
for batch in asset_batches.get_batches_mut() {
log::debug!("setting up batch bind groups: {:?}", batch.render_resource_assignments.id);
log::trace!("{:#?}", batch);
renderer.setup_bind_groups(
&mut batch.render_resource_assignments,
pipeline_descriptor,
);
for batched_entity in batch.entities.iter() {
let mut renderable = world.get_component_mut::<Renderable>(*batched_entity).unwrap();
if !renderable.is_visible || renderable.is_instanced {
continue;
}
log::trace!("setting up entity bind group {:?} for batch {:?}", batched_entity, batch.render_resource_assignments.id);
renderer.setup_bind_groups(
&mut renderable.render_resource_assignments,
pipeline_descriptor,
);
}
}
} }
fn get_name(&self) -> String { fn get_name(&self) -> String {

View File

@ -55,8 +55,7 @@ impl<'a> ForwardPipelineBuilder for RenderGraphBuilder<'a> {
}, },
write_mask: ColorWrite::ALL, write_mask: ColorWrite::ALL,
}) })
.add_draw_target(resource_name::draw_target::ASSIGNED_MESHES); .add_draw_target(resource_name::draw_target::ASSIGNED_BATCHES);
// .add_draw_target(resource_name::draw_target::ASSIGNED_BATCHES);
}) })
} }
} }

View File

@ -110,6 +110,13 @@ impl AssetBatchers {
.flatten() .flatten()
} }
pub fn get_batches_mut(&mut self) -> impl Iterator<Item = &mut Batch> {
self.asset_batchers
.iter_mut()
.map(|a| a.get_batches_mut())
.flatten()
}
pub fn get_handle_batches<T>(&self) -> Option<impl Iterator<Item = &Batch>> pub fn get_handle_batches<T>(&self) -> Option<impl Iterator<Item = &Batch>>
where where
T: 'static, T: 'static,

View File

@ -2,7 +2,7 @@ use super::RenderResourceAssignmentsId;
use crate::render::render_resource::BufferUsage; use crate::render::render_resource::BufferUsage;
use std::collections::HashMap; use std::collections::HashMap;
#[derive(Default)] #[derive(Default, Debug)]
pub struct BufferArrayInfo { pub struct BufferArrayInfo {
pub item_count: usize, pub item_count: usize,
pub item_size: usize, pub item_size: usize,
@ -32,6 +32,7 @@ impl BufferArrayInfo {
} }
} }
#[derive(Debug)]
pub struct BufferInfo { pub struct BufferInfo {
pub size: usize, pub size: usize,
pub buffer_usage: BufferUsage, pub buffer_usage: BufferUsage,
@ -50,6 +51,7 @@ impl Default for BufferInfo {
} }
} }
#[derive(Debug)]
pub enum ResourceInfo { pub enum ResourceInfo {
Buffer(BufferInfo), Buffer(BufferInfo),
Texture, Texture,

View File

@ -4,7 +4,9 @@ use crate::{
render::{ render::{
mesh::Mesh, mesh::Mesh,
render_graph::RenderGraph, render_graph::RenderGraph,
render_resource::{AssetBatchers, BufferInfo, BufferUsage, ResourceProvider}, render_resource::{
AssetBatchers, BufferInfo, BufferUsage, RenderResourceAssignments, ResourceProvider,
},
renderer::Renderer, renderer::Renderer,
shader::AsUniforms, shader::AsUniforms,
Vertex, Vertex,
@ -39,30 +41,15 @@ impl MeshResourceProvider {
.filter(changed::<Handle<Mesh>>()), .filter(changed::<Handle<Mesh>>()),
} }
} }
}
impl ResourceProvider for MeshResourceProvider { fn setup_mesh_resources(renderer: &mut dyn Renderer, mesh_storage: &mut AssetStorage<Mesh>, handle: Handle<Mesh>, render_resource_assignments: &mut RenderResourceAssignments) {
fn initialize( let (vertex_buffer, index_buffer) = if let Some(vertex_buffer) = renderer
&mut self,
_renderer: &mut dyn Renderer,
_world: &mut World,
resources: &Resources,
) {
let mut render_graph = resources.get_mut::<RenderGraph>().unwrap();
render_graph
.set_vertex_buffer_descriptor(Vertex::get_vertex_buffer_descriptor().cloned().unwrap());
}
fn update(&mut self, renderer: &mut dyn Renderer, world: &mut World, resources: &Resources) {
let mesh_storage = resources.get_mut::<AssetStorage<Mesh>>().unwrap();
let mut asset_batchers = resources.get_mut::<AssetBatchers>().unwrap();
for (entity, (mesh_handle, _renderable)) in self.mesh_query.iter_entities(world) {
asset_batchers.set_entity_handle(entity, *mesh_handle);
if let None = renderer
.get_render_resources() .get_render_resources()
.get_mesh_vertices_resource(*mesh_handle) .get_mesh_vertices_resource(handle)
{ {
let mesh_asset = mesh_storage.get(&mesh_handle).unwrap(); (vertex_buffer, renderer.get_render_resources().get_mesh_indices_resource(handle))
} else {
let mesh_asset = mesh_storage.get(&handle).unwrap();
let vertex_buffer = renderer.create_buffer_with_data( let vertex_buffer = renderer.create_buffer_with_data(
BufferInfo { BufferInfo {
buffer_usage: BufferUsage::VERTEX, buffer_usage: BufferUsage::VERTEX,
@ -79,22 +66,52 @@ impl ResourceProvider for MeshResourceProvider {
); );
let render_resources = renderer.get_render_resources_mut(); let render_resources = renderer.get_render_resources_mut();
render_resources.set_mesh_vertices_resource(*mesh_handle, vertex_buffer); render_resources.set_mesh_vertices_resource(handle, vertex_buffer);
render_resources.set_mesh_indices_resource(*mesh_handle, index_buffer); render_resources.set_mesh_indices_resource(handle, index_buffer);
(vertex_buffer, Some(index_buffer))
};
render_resource_assignments.set_vertex_buffer("Vertex", vertex_buffer, index_buffer);
} }
}
impl ResourceProvider for MeshResourceProvider {
fn initialize(
&mut self,
_renderer: &mut dyn Renderer,
_world: &mut World,
resources: &Resources,
) {
let mut render_graph = resources.get_mut::<RenderGraph>().unwrap();
render_graph
.set_vertex_buffer_descriptor(Vertex::get_vertex_buffer_descriptor().cloned().unwrap());
}
fn update(&mut self, _renderer: &mut dyn Renderer, world: &mut World, resources: &Resources) {
let mut asset_batchers = resources.get_mut::<AssetBatchers>().unwrap();
for (entity, (mesh_handle, _renderable)) in self.mesh_query.iter_entities_mut(world) {
asset_batchers.set_entity_handle(entity, *mesh_handle);
} }
} }
fn finish_update( fn finish_update(
&mut self, &mut self,
_renderer: &mut dyn Renderer, renderer: &mut dyn Renderer,
_world: &mut World, _world: &mut World,
_resources: &Resources, resources: &Resources,
) { ) {
// TODO: assign vertex buffers let mut mesh_storage = resources.get_mut::<AssetStorage<Mesh>>().unwrap();
// let mesh_storage = resources.get_mut::<AssetStorage<Mesh>>().unwrap(); let mut asset_batchers = resources.get_mut::<AssetBatchers>().unwrap();
// let mut asset_batchers = resources.get_mut::<AssetBatchers>().unwrap();
// for batch in asset_batchers.get_handle_batches::<Mesh>() { // this scope is necessary because the Fetch<AssetBatchers> pointer behaves weirdly
// } {
if let Some(batches) = asset_batchers.get_handle_batches_mut::<Mesh>() {
for batch in batches {
let handle = batch.get_handle::<Mesh>().unwrap();
log::trace!("setup mesh for {:?}", batch.render_resource_assignments.id);
Self::setup_mesh_resources(renderer, &mut mesh_storage, handle, &mut batch.render_resource_assignments);
}
}
};
} }
} }

View File

@ -512,12 +512,13 @@ where
}; };
if let Some(new_capacity) = new_capacity { if let Some(new_capacity) = new_capacity {
println!("creating buffer {}", new_capacity);
let mut item_size = buffer_array_status.item_size; let mut item_size = buffer_array_status.item_size;
if align { if align {
item_size = Self::get_aligned_dynamic_uniform_size(item_size); item_size = Self::get_aligned_dynamic_uniform_size(item_size);
} }
let total_size = item_size * new_capacity;
let buffer = renderer.create_buffer(BufferInfo { let buffer = renderer.create_buffer(BufferInfo {
array_info: Some(BufferArrayInfo { array_info: Some(BufferArrayInfo {
item_capacity: new_capacity, item_capacity: new_capacity,
@ -525,11 +526,19 @@ where
item_size, item_size,
..Default::default() ..Default::default()
}), }),
size: item_size * new_capacity, size: total_size,
buffer_usage: BufferUsage::COPY_DST | BufferUsage::UNIFORM, buffer_usage: BufferUsage::COPY_DST | BufferUsage::UNIFORM,
is_dynamic: true, is_dynamic: true,
}); });
log::trace!(
"creating buffer for uniform {}. size: {} item_capacity: {} item_size: {}",
std::any::type_name::<T>(),
total_size,
new_capacity,
item_size
);
buffer_array_status.buffer = Some(buffer); buffer_array_status.buffer = Some(buffer);
} }
} }

View File

@ -1,16 +1,17 @@
use super::{WgpuRenderer, WgpuResources}; use super::{WgpuRenderer, WgpuResources};
use crate::render::{ use crate::render::{
pipeline::PipelineDescriptor, pipeline::{BindGroupDescriptorId, PipelineDescriptor},
render_resource::{RenderResource, RenderResourceAssignments}, render_resource::{RenderResource, RenderResourceAssignments, ResourceInfo, RenderResourceSetId},
renderer::{RenderPass, Renderer}, renderer::{RenderPass, Renderer},
}; };
use std::ops::Range; use std::{collections::HashMap, ops::Range};
pub struct WgpuRenderPass<'a, 'b, 'c, 'd> { pub struct WgpuRenderPass<'a, 'b, 'c, 'd> {
pub render_pass: &'b mut wgpu::RenderPass<'a>, pub render_pass: &'b mut wgpu::RenderPass<'a>,
pub pipeline_descriptor: &'c PipelineDescriptor, pub pipeline_descriptor: &'c PipelineDescriptor,
pub wgpu_resources: &'a WgpuResources, pub wgpu_resources: &'a WgpuResources,
pub renderer: &'d WgpuRenderer, pub renderer: &'d WgpuRenderer,
pub bound_bind_groups: HashMap<u32, (RenderResourceSetId)>,
} }
impl<'a, 'b, 'c, 'd> RenderPass for WgpuRenderPass<'a, 'b, 'c, 'd> { impl<'a, 'b, 'c, 'd> RenderPass for WgpuRenderPass<'a, 'b, 'c, 'd> {
@ -43,6 +44,30 @@ impl<'a, 'b, 'c, 'd> RenderPass for WgpuRenderPass<'a, 'b, 'c, 'd> {
render_resource_assignments: &RenderResourceAssignments, render_resource_assignments: &RenderResourceAssignments,
) -> Option<Range<u32>> { ) -> Option<Range<u32>> {
let pipeline_layout = self.pipeline_descriptor.get_layout().unwrap(); let pipeline_layout = self.pipeline_descriptor.get_layout().unwrap();
// PERF: vertex buffer lookup comes at a cost when vertex buffers aren't in render_resource_assignments. iterating over render_resource_assignment vertex buffers
// would likely be faster
let mut indices = None;
for (i, vertex_buffer_descriptor) in
pipeline_layout.vertex_buffer_descriptors.iter().enumerate()
{
if let Some((vertex_buffer, index_buffer)) =
render_resource_assignments.get_vertex_buffer(&vertex_buffer_descriptor.name)
{
log::trace!("set vertex buffer {}: {} ({:?})", i, vertex_buffer_descriptor.name, vertex_buffer);
self.set_vertex_buffer(i as u32, vertex_buffer, 0);
if let Some(index_buffer) = index_buffer {
log::trace!("set index buffer: {} ({:?})", vertex_buffer_descriptor.name, index_buffer);
self.set_index_buffer(index_buffer, 0);
match self.renderer.get_resource_info(index_buffer).unwrap() {
ResourceInfo::Buffer(buffer_info) => {
indices = Some(0..(buffer_info.size / 2) as u32)
}
_ => panic!("expected a buffer type"),
}
}
}
}
for bind_group in pipeline_layout.bind_groups.iter() { for bind_group in pipeline_layout.bind_groups.iter() {
if let Some((render_resource_set_id, dynamic_uniform_indices)) = if let Some((render_resource_set_id, dynamic_uniform_indices)) =
render_resource_assignments.get_render_resource_set_id(bind_group.id) render_resource_assignments.get_render_resource_set_id(bind_group.id)
@ -51,20 +76,31 @@ impl<'a, 'b, 'c, 'd> RenderPass for WgpuRenderPass<'a, 'b, 'c, 'd> {
.wgpu_resources .wgpu_resources
.get_bind_group(bind_group.id, *render_resource_set_id) .get_bind_group(bind_group.id, *render_resource_set_id)
{ {
// TODO: check to see if bind group is already set const EMPTY: &'static [u32] = &[];
let empty = &[];
let dynamic_uniform_indices = let dynamic_uniform_indices =
if let Some(dynamic_uniform_indices) = dynamic_uniform_indices { if let Some(dynamic_uniform_indices) = dynamic_uniform_indices {
dynamic_uniform_indices.as_slice() dynamic_uniform_indices.as_slice()
} else { } else {
empty EMPTY
}; };
// TODO: remove this // don't bind bind groups if they are already set
// if dynamic_uniform_indices.len() == 0 && bind_group.index > 0 { // TODO: these checks come at a performance cost. make sure its worth it!
// continue; if let Some(bound_render_resource_set) = self.bound_bind_groups.get(&bind_group.index) {
// } if *bound_render_resource_set == *render_resource_set_id && dynamic_uniform_indices.len() == 0
{
continue;
}
}
if dynamic_uniform_indices.len() == 0 {
self.bound_bind_groups
.insert(bind_group.index, *render_resource_set_id);
} else {
self.bound_bind_groups.remove(&bind_group.index);
}
log::trace!("set bind group {} {:?}: {:?}", bind_group.index, dynamic_uniform_indices, render_resource_set_id);
self.render_pass.set_bind_group( self.render_pass.set_bind_group(
bind_group.index, bind_group.index,
&wgpu_bind_group, &wgpu_bind_group,
@ -74,6 +110,6 @@ impl<'a, 'b, 'c, 'd> RenderPass for WgpuRenderPass<'a, 'b, 'c, 'd> {
} }
} }
None indices
} }
} }

View File

@ -490,6 +490,7 @@ impl Renderer for WgpuRenderer {
pipeline_descriptor, pipeline_descriptor,
wgpu_resources: &self.wgpu_resources, wgpu_resources: &self.wgpu_resources,
renderer: &self, renderer: &self,
bound_bind_groups: HashMap::default(),
}; };
for draw_target_name in pipeline_descriptor.draw_targets.iter() { for draw_target_name in pipeline_descriptor.draw_targets.iter() {
@ -614,6 +615,8 @@ impl Renderer for WgpuRenderer {
bind_group, bind_group,
render_resource_assignments, render_resource_assignments,
); );
} else {
log::trace!("reusing RenderResourceSet {:?} for bind group {}", render_resource_set_id, bind_group.index);
} }
} }
} }

View File

@ -57,12 +57,15 @@ impl WgpuResources {
if let Some((render_resource_set_id, _indices)) = if let Some((render_resource_set_id, _indices)) =
render_resource_assignments.get_render_resource_set_id(bind_group_descriptor.id) render_resource_assignments.get_render_resource_set_id(bind_group_descriptor.id)
{ {
log::debug!("start creating bind group for RenderResourceSet {:?}", render_resource_set_id);
let bindings = bind_group_descriptor let bindings = bind_group_descriptor
.bindings .bindings
.iter() .iter()
.map(|binding| { .map(|binding| {
if let Some(resource) = render_resource_assignments.get(&binding.name) { if let Some(resource) = render_resource_assignments.get(&binding.name) {
let resource_info = self.resource_info.get(&resource).unwrap(); let resource_info = self.resource_info.get(&resource).unwrap();
log::trace!("found binding {} ({}) resource: {:?} {:?}", binding.index, binding.name, resource, resource_info);
wgpu::Binding { wgpu::Binding {
binding: binding.index, binding: binding.index,
resource: match &binding.bind_type { resource: match &binding.bind_type {
@ -122,6 +125,9 @@ impl WgpuResources {
bind_group_info bind_group_info
.bind_groups .bind_groups
.insert(*render_resource_set_id, bind_group); .insert(*render_resource_set_id, bind_group);
log::debug!("created bind group for RenderResourceSet {:?}", render_resource_set_id);
log::trace!("{:#?}", bind_group_descriptor);
return true; return true;
} else { } else {
return false; return false;