From 5db5f6de9c2b79ecff2068f526e7daa2e707c662 Mon Sep 17 00:00:00 2001 From: Carter Anderson Date: Sat, 28 Mar 2020 20:33:11 -0700 Subject: [PATCH] batched draw target works! embrace the "log" crate --- Cargo.toml | 2 +- src/core/window/winit/mod.rs | 5 +- .../assigned_batches_draw_target.rs | 97 +++++++++++++++---- src/render/pipeline/pipelines/forward/mod.rs | 3 +- .../render_resource/batching/asset_batcher.rs | 7 ++ src/render/render_resource/resource_info.rs | 4 +- .../mesh_resource_provider.rs | 87 ++++++++++------- .../uniform_resource_provider.rs | 13 ++- .../wgpu_renderer/wgpu_render_pass.rs | 58 ++++++++--- .../renderers/wgpu_renderer/wgpu_renderer.rs | 3 + .../renderers/wgpu_renderer/wgpu_resources.rs | 6 ++ 11 files changed, 210 insertions(+), 75 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 4f2d9a5916..b00a8bda4c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,7 +14,7 @@ bitflags = "1.0" glam = "0.8.6" winit = { version = "0.22.0", optional = true } zerocopy = "0.3" -log = "0.4" +log = { version = "0.4", features = ["release_max_level_info"] } env_logger = "0.7" rand = "0.7.2" gltf = "0.14.0" diff --git a/src/core/window/winit/mod.rs b/src/core/window/winit/mod.rs index 7b6e777d72..e9d4b5137c 100644 --- a/src/core/window/winit/mod.rs +++ b/src/core/window/winit/mod.rs @@ -11,7 +11,6 @@ pub fn get_winit_run() -> Box { Box::new(|mut app: App| { env_logger::init(); let event_loop = EventLoop::new(); - log::info!("Initializing the window..."); let winit_window = { let window = app.resources.get::().unwrap(); let winit_window = winit::window::Window::new(&event_loop).unwrap(); @@ -22,7 +21,7 @@ pub fn get_winit_run() -> Box { app.resources.insert(winit_window); - log::info!("Entering render loop..."); + log::debug!("Entering render loop"); event_loop.run(move |event, _, control_flow| { *control_flow = if cfg!(feature = "metal-auto-capture") { ControlFlow::Exit @@ -45,8 +44,6 @@ pub fn get_winit_run() -> Box { &mut app.world, &mut app.resources, ); - } else { - println!("no renderer {} {}", size.width, size.height); } } event::Event::WindowEvent { event, .. } => match event { diff --git a/src/render/draw_target/draw_targets/assigned_batches_draw_target.rs b/src/render/draw_target/draw_targets/assigned_batches_draw_target.rs index c36348b7f9..eb8042bed2 100644 --- a/src/render/draw_target/draw_targets/assigned_batches_draw_target.rs +++ b/src/render/draw_target/draw_targets/assigned_batches_draw_target.rs @@ -1,10 +1,11 @@ use crate::{ - asset::Handle, + asset::{AssetStorage, Handle}, legion::prelude::*, + prelude::Renderable, render::{ draw_target::DrawTarget, pipeline::PipelineDescriptor, - render_resource::{resource_name, AssetBatchers}, + render_resource::{resource_name, AssetBatchers, RenderResourceAssignments}, renderer::{RenderPass, Renderer}, }, }; @@ -15,32 +16,90 @@ pub struct AssignedBatchesDrawTarget; impl DrawTarget for AssignedBatchesDrawTarget { fn draw( &self, - _world: &World, + world: &World, resources: &Resources, - _render_pass: &mut dyn RenderPass, - _pipeline_handle: Handle, + render_pass: &mut dyn RenderPass, + pipeline_handle: Handle, ) { + log::debug!("drawing batches for pipeline {:?}", pipeline_handle); let asset_batches = resources.get::().unwrap(); - // let renderer = render_pass.get_renderer(); - // println!("Drawing batches"); - for _batch in asset_batches.get_batches() { - // println!("{:?}", batch); - // render_pass.set_bind_groups(batch.render_resource_assignments.as_ref()); - // render_pass.draw_indexed(0..1, 0, 0..1); - } + let global_render_resource_assignments = + resources.get::().unwrap(); + render_pass.set_render_resources(&global_render_resource_assignments); + for batch in asset_batches.get_batches() { + let indices = render_pass.set_render_resources(&batch.render_resource_assignments); + log::debug!("drawing batch {:?}", batch.render_resource_assignments.id); + log::trace!("{:#?}", batch); + for batched_entity in batch.entities.iter() { + let renderable = world.get_component::(*batched_entity).unwrap(); + if !renderable.is_visible { + continue; + } - // println!(); - // println!(); - // println!(); + log::trace!("start drawing batched entity: {:?}", batched_entity); + log::trace!("{:#?}", renderable.render_resource_assignments); + 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( &mut self, - _world: &World, - _resources: &Resources, - _renderer: &mut dyn Renderer, - _pipeline_handle: Handle, + world: &mut World, + resources: &Resources, + renderer: &mut dyn Renderer, + pipeline_handle: Handle, ) { + let mut asset_batches = resources.get_mut::().unwrap(); + let pipeline_storage = resources.get::>().unwrap(); + let pipeline_descriptor = pipeline_storage.get(&pipeline_handle).unwrap(); + + let mut global_render_resource_assignments = + resources.get_mut::().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::(*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 { diff --git a/src/render/pipeline/pipelines/forward/mod.rs b/src/render/pipeline/pipelines/forward/mod.rs index a17984cdff..e453f0cef4 100644 --- a/src/render/pipeline/pipelines/forward/mod.rs +++ b/src/render/pipeline/pipelines/forward/mod.rs @@ -55,8 +55,7 @@ impl<'a> ForwardPipelineBuilder for RenderGraphBuilder<'a> { }, 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); }) } } diff --git a/src/render/render_resource/batching/asset_batcher.rs b/src/render/render_resource/batching/asset_batcher.rs index 2f0aee2b60..9c132eda3b 100644 --- a/src/render/render_resource/batching/asset_batcher.rs +++ b/src/render/render_resource/batching/asset_batcher.rs @@ -110,6 +110,13 @@ impl AssetBatchers { .flatten() } + pub fn get_batches_mut(&mut self) -> impl Iterator { + self.asset_batchers + .iter_mut() + .map(|a| a.get_batches_mut()) + .flatten() + } + pub fn get_handle_batches(&self) -> Option> where T: 'static, diff --git a/src/render/render_resource/resource_info.rs b/src/render/render_resource/resource_info.rs index 0db7f3c622..c3ce5b0555 100644 --- a/src/render/render_resource/resource_info.rs +++ b/src/render/render_resource/resource_info.rs @@ -2,7 +2,7 @@ use super::RenderResourceAssignmentsId; use crate::render::render_resource::BufferUsage; use std::collections::HashMap; -#[derive(Default)] +#[derive(Default, Debug)] pub struct BufferArrayInfo { pub item_count: usize, pub item_size: usize, @@ -32,6 +32,7 @@ impl BufferArrayInfo { } } +#[derive(Debug)] pub struct BufferInfo { pub size: usize, pub buffer_usage: BufferUsage, @@ -50,6 +51,7 @@ impl Default for BufferInfo { } } +#[derive(Debug)] pub enum ResourceInfo { Buffer(BufferInfo), Texture, diff --git a/src/render/render_resource/resource_providers/mesh_resource_provider.rs b/src/render/render_resource/resource_providers/mesh_resource_provider.rs index 7072a15a2d..752c11218f 100644 --- a/src/render/render_resource/resource_providers/mesh_resource_provider.rs +++ b/src/render/render_resource/resource_providers/mesh_resource_provider.rs @@ -4,7 +4,9 @@ use crate::{ render::{ mesh::Mesh, render_graph::RenderGraph, - render_resource::{AssetBatchers, BufferInfo, BufferUsage, ResourceProvider}, + render_resource::{ + AssetBatchers, BufferInfo, BufferUsage, RenderResourceAssignments, ResourceProvider, + }, renderer::Renderer, shader::AsUniforms, Vertex, @@ -39,6 +41,38 @@ impl MeshResourceProvider { .filter(changed::>()), } } + + fn setup_mesh_resources(renderer: &mut dyn Renderer, mesh_storage: &mut AssetStorage, handle: Handle, render_resource_assignments: &mut RenderResourceAssignments) { + let (vertex_buffer, index_buffer) = if let Some(vertex_buffer) = renderer + .get_render_resources() + .get_mesh_vertices_resource(handle) + { + (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( + BufferInfo { + buffer_usage: BufferUsage::VERTEX, + ..Default::default() + }, + mesh_asset.vertices.as_bytes(), + ); + let index_buffer = renderer.create_buffer_with_data( + BufferInfo { + buffer_usage: BufferUsage::INDEX, + ..Default::default() + }, + mesh_asset.indices.as_bytes(), + ); + + let render_resources = renderer.get_render_resources_mut(); + render_resources.set_mesh_vertices_resource(handle, vertex_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 { @@ -53,48 +87,31 @@ impl ResourceProvider for MeshResourceProvider { .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::>().unwrap(); + fn update(&mut self, _renderer: &mut dyn Renderer, world: &mut World, resources: &Resources) { let mut asset_batchers = resources.get_mut::().unwrap(); - for (entity, (mesh_handle, _renderable)) in self.mesh_query.iter_entities(world) { + for (entity, (mesh_handle, _renderable)) in self.mesh_query.iter_entities_mut(world) { asset_batchers.set_entity_handle(entity, *mesh_handle); - if let None = renderer - .get_render_resources() - .get_mesh_vertices_resource(*mesh_handle) - { - let mesh_asset = mesh_storage.get(&mesh_handle).unwrap(); - let vertex_buffer = renderer.create_buffer_with_data( - BufferInfo { - buffer_usage: BufferUsage::VERTEX, - ..Default::default() - }, - mesh_asset.vertices.as_bytes(), - ); - let index_buffer = renderer.create_buffer_with_data( - BufferInfo { - buffer_usage: BufferUsage::INDEX, - ..Default::default() - }, - mesh_asset.indices.as_bytes(), - ); - - let render_resources = renderer.get_render_resources_mut(); - render_resources.set_mesh_vertices_resource(*mesh_handle, vertex_buffer); - render_resources.set_mesh_indices_resource(*mesh_handle, index_buffer); - } } } fn finish_update( &mut self, - _renderer: &mut dyn Renderer, + renderer: &mut dyn Renderer, _world: &mut World, - _resources: &Resources, + resources: &Resources, ) { - // TODO: assign vertex buffers - // let mesh_storage = resources.get_mut::>().unwrap(); - // let mut asset_batchers = resources.get_mut::().unwrap(); - // for batch in asset_batchers.get_handle_batches::() { - // } + let mut mesh_storage = resources.get_mut::>().unwrap(); + let mut asset_batchers = resources.get_mut::().unwrap(); + + // this scope is necessary because the Fetch pointer behaves weirdly + { + if let Some(batches) = asset_batchers.get_handle_batches_mut::() { + for batch in batches { + let handle = batch.get_handle::().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); + } + } + }; } } diff --git a/src/render/render_resource/resource_providers/uniform_resource_provider.rs b/src/render/render_resource/resource_providers/uniform_resource_provider.rs index b997b085c2..aed2d25521 100644 --- a/src/render/render_resource/resource_providers/uniform_resource_provider.rs +++ b/src/render/render_resource/resource_providers/uniform_resource_provider.rs @@ -512,12 +512,13 @@ where }; if let Some(new_capacity) = new_capacity { - println!("creating buffer {}", new_capacity); let mut item_size = buffer_array_status.item_size; if align { item_size = Self::get_aligned_dynamic_uniform_size(item_size); } + let total_size = item_size * new_capacity; + let buffer = renderer.create_buffer(BufferInfo { array_info: Some(BufferArrayInfo { item_capacity: new_capacity, @@ -525,11 +526,19 @@ where item_size, ..Default::default() }), - size: item_size * new_capacity, + size: total_size, buffer_usage: BufferUsage::COPY_DST | BufferUsage::UNIFORM, is_dynamic: true, }); + log::trace!( + "creating buffer for uniform {}. size: {} item_capacity: {} item_size: {}", + std::any::type_name::(), + total_size, + new_capacity, + item_size + ); + buffer_array_status.buffer = Some(buffer); } } diff --git a/src/render/renderer/renderers/wgpu_renderer/wgpu_render_pass.rs b/src/render/renderer/renderers/wgpu_renderer/wgpu_render_pass.rs index 2bf4b49da7..990275ed2e 100644 --- a/src/render/renderer/renderers/wgpu_renderer/wgpu_render_pass.rs +++ b/src/render/renderer/renderers/wgpu_renderer/wgpu_render_pass.rs @@ -1,16 +1,17 @@ use super::{WgpuRenderer, WgpuResources}; use crate::render::{ - pipeline::PipelineDescriptor, - render_resource::{RenderResource, RenderResourceAssignments}, + pipeline::{BindGroupDescriptorId, PipelineDescriptor}, + render_resource::{RenderResource, RenderResourceAssignments, ResourceInfo, RenderResourceSetId}, renderer::{RenderPass, Renderer}, }; -use std::ops::Range; +use std::{collections::HashMap, ops::Range}; pub struct WgpuRenderPass<'a, 'b, 'c, 'd> { pub render_pass: &'b mut wgpu::RenderPass<'a>, pub pipeline_descriptor: &'c PipelineDescriptor, pub wgpu_resources: &'a WgpuResources, pub renderer: &'d WgpuRenderer, + pub bound_bind_groups: HashMap, } 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, ) -> Option> { 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() { if let Some((render_resource_set_id, dynamic_uniform_indices)) = 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 .get_bind_group(bind_group.id, *render_resource_set_id) { - // TODO: check to see if bind group is already set - let empty = &[]; + const EMPTY: &'static [u32] = &[]; let dynamic_uniform_indices = if let Some(dynamic_uniform_indices) = dynamic_uniform_indices { dynamic_uniform_indices.as_slice() } else { - empty + EMPTY }; - // TODO: remove this - // if dynamic_uniform_indices.len() == 0 && bind_group.index > 0 { - // continue; - // } + // don't bind bind groups if they are already set + // TODO: these checks come at a performance cost. make sure its worth it! + 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( bind_group.index, &wgpu_bind_group, @@ -74,6 +110,6 @@ impl<'a, 'b, 'c, 'd> RenderPass for WgpuRenderPass<'a, 'b, 'c, 'd> { } } - None + indices } } diff --git a/src/render/renderer/renderers/wgpu_renderer/wgpu_renderer.rs b/src/render/renderer/renderers/wgpu_renderer/wgpu_renderer.rs index 602be10f7f..b2c0af2674 100644 --- a/src/render/renderer/renderers/wgpu_renderer/wgpu_renderer.rs +++ b/src/render/renderer/renderers/wgpu_renderer/wgpu_renderer.rs @@ -490,6 +490,7 @@ impl Renderer for WgpuRenderer { pipeline_descriptor, wgpu_resources: &self.wgpu_resources, renderer: &self, + bound_bind_groups: HashMap::default(), }; for draw_target_name in pipeline_descriptor.draw_targets.iter() { @@ -614,6 +615,8 @@ impl Renderer for WgpuRenderer { bind_group, render_resource_assignments, ); + } else { + log::trace!("reusing RenderResourceSet {:?} for bind group {}", render_resource_set_id, bind_group.index); } } } diff --git a/src/render/renderer/renderers/wgpu_renderer/wgpu_resources.rs b/src/render/renderer/renderers/wgpu_renderer/wgpu_resources.rs index 254536040e..366bc6ea1c 100644 --- a/src/render/renderer/renderers/wgpu_renderer/wgpu_resources.rs +++ b/src/render/renderer/renderers/wgpu_renderer/wgpu_resources.rs @@ -57,12 +57,15 @@ impl WgpuResources { if let Some((render_resource_set_id, _indices)) = 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 .bindings .iter() .map(|binding| { if let Some(resource) = render_resource_assignments.get(&binding.name) { + let resource_info = self.resource_info.get(&resource).unwrap(); + log::trace!("found binding {} ({}) resource: {:?} {:?}", binding.index, binding.name, resource, resource_info); wgpu::Binding { binding: binding.index, resource: match &binding.bind_type { @@ -122,6 +125,9 @@ impl WgpuResources { bind_group_info .bind_groups .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; } else { return false;