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"
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"

View file

@ -11,7 +11,6 @@ pub fn get_winit_run() -> Box<dyn Fn(App)> {
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::<Window>().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);
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<dyn Fn(App)> {
&mut app.world,
&mut app.resources,
);
} else {
println!("no renderer {} {}", size.width, size.height);
}
}
event::Event::WindowEvent { event, .. } => match event {

View file

@ -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<PipelineDescriptor>,
render_pass: &mut dyn RenderPass,
pipeline_handle: Handle<PipelineDescriptor>,
) {
log::debug!("drawing batches for pipeline {:?}", pipeline_handle);
let asset_batches = resources.get::<AssetBatchers>().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::<RenderResourceAssignments>().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::<Renderable>(*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<PipelineDescriptor>,
world: &mut World,
resources: &Resources,
renderer: &mut dyn Renderer,
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 {

View file

@ -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);
})
}
}

View file

@ -110,6 +110,13 @@ impl AssetBatchers {
.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>>
where
T: 'static,

View file

@ -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,

View file

@ -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::<Handle<Mesh>>()),
}
}
fn setup_mesh_resources(renderer: &mut dyn Renderer, mesh_storage: &mut AssetStorage<Mesh>, handle: Handle<Mesh>, 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::<AssetStorage<Mesh>>().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(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::<AssetStorage<Mesh>>().unwrap();
// let mut asset_batchers = resources.get_mut::<AssetBatchers>().unwrap();
// for batch in asset_batchers.get_handle_batches::<Mesh>() {
// }
let mut mesh_storage = resources.get_mut::<AssetStorage<Mesh>>().unwrap();
let mut asset_batchers = resources.get_mut::<AssetBatchers>().unwrap();
// 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 {
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::<T>(),
total_size,
new_capacity,
item_size
);
buffer_array_status.buffer = Some(buffer);
}
}

View file

@ -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<u32, (RenderResourceSetId)>,
}
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<Range<u32>> {
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
}
}

View file

@ -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);
}
}
}

View file

@ -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;