remove DrawTargets in favor of PassNodes and in preparation for "immediate mode" drawing api

This commit is contained in:
Carter Anderson 2020-06-08 14:35:13 -07:00
parent 6531ccddab
commit 1426208e2f
17 changed files with 253 additions and 392 deletions

View File

@ -2,7 +2,6 @@ use crate::{material::StandardMaterial, nodes::LightsNode, pipelines::build_forw
use bevy_asset::Assets; use bevy_asset::Assets;
use bevy_render::{ use bevy_render::{
base_render_graph, base_render_graph,
draw_target::AssignedMeshesDrawTarget,
pipeline::PipelineDescriptor, pipeline::PipelineDescriptor,
render_graph::{ render_graph::{
nodes::{AssetUniformNode, PassNode, UniformNode}, nodes::{AssetUniformNode, PassNode, UniformNode},
@ -41,10 +40,7 @@ impl ForwardPbrRenderGraphBuilder for RenderGraph {
let main_pass: &mut PassNode = self let main_pass: &mut PassNode = self
.get_node_mut(base_render_graph::node::MAIN_PASS) .get_node_mut(base_render_graph::node::MAIN_PASS)
.unwrap(); .unwrap();
main_pass.add_pipeline( main_pass.add_pipeline(pipelines.add_default(build_forward_pipeline(&mut shaders)));
pipelines.add_default(build_forward_pipeline(&mut shaders)),
vec![Box::new(AssignedMeshesDrawTarget)],
);
} }
// TODO: replace these with "autowire" groups // TODO: replace these with "autowire" groups

View File

@ -0,0 +1,41 @@
use crate::{render_resource::RenderResourceId, pipeline::PipelineDescriptor};
use bevy_asset::Handle;
use std::ops::Range;
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum DrawType {
Instanced {
indices: Range<u32>,
base_vertex: i32,
instances: Range<u32>,
}
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct VertexBufferBinding {
pub slot: u32,
pub vertex_buffer: RenderResourceId,
pub offset: u64,
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct IndexBufferBinding {
pub vertex_buffer: RenderResourceId,
pub offset: u64,
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct BindGroupBinding {
pub vertex_buffer: RenderResourceId,
pub offset: u64,
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct DrawCall {
pub pipeline: Handle<PipelineDescriptor>,
pub draw_type: DrawType,
pub vertex_buffers: Vec<VertexBufferBinding>,
pub index_buffer: Option<IndexBufferBinding>,
}
pub struct Draw {}

View File

@ -1,25 +0,0 @@
use crate::{pass::RenderPass, pipeline::PipelineDescriptor, renderer::RenderContext};
use bevy_asset::Handle;
use legion::prelude::{Resources, World};
// A set of draw calls. ex: get + draw meshes, get + draw instanced meshes, draw ui meshes, etc
pub trait DrawTarget: Send + Sync + 'static {
fn draw(
&self,
world: &World,
resources: &Resources,
render_pass: &mut dyn RenderPass,
pipeline_handle: Handle<PipelineDescriptor>,
pipeline_descriptor: &PipelineDescriptor,
);
fn setup(
&mut self,
_world: &World,
_resources: &Resources,
_render_context: &mut dyn RenderContext,
_pipeline_handle: Handle<PipelineDescriptor>,
_pipeline_descriptor: &PipelineDescriptor,
) {
}
fn get_name(&self) -> String;
}

View File

@ -1,106 +0,0 @@
use bevy_asset::Handle;
use legion::prelude::*;
use crate::{
draw_target::DrawTarget,
pass::RenderPass,
pipeline::{PipelineAssignments, PipelineDescriptor},
render_resource::{
EntitiesWaitingForAssets, EntityRenderResourceAssignments, RenderResourceAssignments,
},
renderer::RenderContext,
Renderable,
};
#[derive(Default)]
pub struct AssignedMeshesDrawTarget;
impl AssignedMeshesDrawTarget {
pub const NAME: &'static str = "AssignedMeshes";
}
impl DrawTarget for AssignedMeshesDrawTarget {
fn draw(
&self,
world: &World,
resources: &Resources,
render_pass: &mut dyn RenderPass,
pipeline_handle: Handle<PipelineDescriptor>,
pipeline_descriptor: &PipelineDescriptor,
) {
let shader_pipeline_assignments = resources.get::<PipelineAssignments>().unwrap();
let entity_render_resource_assignments =
resources.get::<EntityRenderResourceAssignments>().unwrap();
let entities_waiting_for_assets = resources.get::<EntitiesWaitingForAssets>().unwrap();
let global_render_resource_assignments =
resources.get::<RenderResourceAssignments>().unwrap();
render_pass.set_render_resources(pipeline_descriptor, &global_render_resource_assignments);
let assigned_render_resource_assignments = shader_pipeline_assignments
.assignments
.get(&pipeline_handle);
if let Some(assigned_render_resource_assignments) = assigned_render_resource_assignments {
for assignment_id in assigned_render_resource_assignments.iter() {
// TODO: hopefully legion has better random access apis that are more like queries?
let entity = entity_render_resource_assignments
.get(*assignment_id)
.unwrap();
let renderable = world.get_component::<Renderable>(*entity).unwrap();
if !renderable.is_visible
|| renderable.is_instanced
|| entities_waiting_for_assets.contains(entity)
{
continue;
}
if let Some(indices) = render_pass.set_render_resources(
pipeline_descriptor,
&renderable.render_resource_assignments,
) {
render_pass.draw_indexed(indices, 0, 0..1);
}
}
}
}
fn setup(
&mut self,
world: &World,
resources: &Resources,
render_context: &mut dyn RenderContext,
pipeline_handle: Handle<PipelineDescriptor>,
pipeline_descriptor: &PipelineDescriptor,
) {
let pipeline_assignments = resources.get::<PipelineAssignments>().unwrap();
let entity_render_resource_assignments =
resources.get::<EntityRenderResourceAssignments>().unwrap();
let assigned_render_resource_assignments =
pipeline_assignments.assignments.get(&pipeline_handle);
let global_render_resource_assignments =
resources.get::<RenderResourceAssignments>().unwrap();
render_context
.resources()
.setup_bind_groups(pipeline_descriptor, &global_render_resource_assignments);
if let Some(assigned_render_resource_assignments) = assigned_render_resource_assignments {
for assignment_id in assigned_render_resource_assignments.iter() {
let entity = entity_render_resource_assignments
.get(*assignment_id)
.unwrap();
let renderable = world.get_component::<Renderable>(*entity).unwrap();
if !renderable.is_visible || renderable.is_instanced {
continue;
}
render_context.resources().setup_bind_groups(
pipeline_descriptor,
&renderable.render_resource_assignments,
);
}
}
}
fn get_name(&self) -> String {
AssignedMeshesDrawTarget::NAME.to_string()
}
}

View File

@ -1,71 +0,0 @@
use crate::{
draw_target::DrawTarget,
mesh::{self, Mesh},
pass::RenderPass,
pipeline::PipelineDescriptor,
render_resource::ResourceInfo,
Renderable,
};
use bevy_asset::Handle;
use legion::prelude::*;
#[derive(Default)]
pub struct MeshesDrawTarget;
impl MeshesDrawTarget {
pub const NAME: &'static str = "Meshes";
}
impl DrawTarget for MeshesDrawTarget {
fn draw(
&self,
world: &World,
_resources: &Resources,
render_pass: &mut dyn RenderPass,
_pipeline_handle: Handle<PipelineDescriptor>,
pipeline_descriptor: &PipelineDescriptor,
) {
let mut current_mesh_handle = None;
let mut current_mesh_index_len = 0;
let mesh_query = <(Read<Handle<Mesh>>, Read<Renderable>)>::query();
for (mesh_handle, renderable) in mesh_query.iter(world) {
if !renderable.is_visible || renderable.is_instanced {
continue;
}
let render_context = render_pass.get_render_context();
let render_resources = render_context.resources();
if current_mesh_handle != Some(*mesh_handle) {
if let Some(vertex_buffer_resource) = render_resources
.get_asset_resource(*mesh_handle, mesh::VERTEX_BUFFER_ASSET_INDEX)
{
let index_buffer_resource = render_resources
.get_asset_resource(*mesh_handle, mesh::INDEX_BUFFER_ASSET_INDEX)
.unwrap();
render_resources.get_resource_info(
index_buffer_resource,
&mut |resource_info| match resource_info {
Some(ResourceInfo::Buffer(Some(buffer_info))) => {
current_mesh_index_len = (buffer_info.size / 2) as u32
}
_ => panic!("expected a buffer type"),
},
);
render_pass.set_index_buffer(index_buffer_resource, 0);
render_pass.set_vertex_buffer(0, vertex_buffer_resource, 0);
}
// TODO: Verify buffer format matches render pass
current_mesh_handle = Some(*mesh_handle);
}
// TODO: validate bind group properties against shader uniform properties at least once
render_pass
.set_render_resources(pipeline_descriptor, &renderable.render_resource_assignments);
render_pass.draw_indexed(0..current_mesh_index_len, 0, 0..1);
}
}
fn get_name(&self) -> String {
MeshesDrawTarget::NAME.to_string()
}
}

View File

@ -1,5 +0,0 @@
mod assigned_meshes_draw_target;
mod meshes_draw_target;
pub use assigned_meshes_draw_target::*;
pub use meshes_draw_target::*;

View File

@ -1,5 +0,0 @@
mod draw_target;
mod draw_targets;
pub use draw_target::*;
pub use draw_targets::*;

View File

@ -1,5 +1,6 @@
pub mod batch; pub mod batch;
mod camera; mod camera;
pub mod draw;
pub mod entity; pub mod entity;
pub mod mesh; pub mod mesh;
pub mod render_graph; pub mod render_graph;
@ -16,7 +17,6 @@ pub use renderable::*;
pub use vertex::Vertex; pub use vertex::Vertex;
pub mod base_render_graph; pub mod base_render_graph;
pub mod draw_target;
pub mod pass; pub mod pass;
pub mod pipeline; pub mod pipeline;
pub mod render_resource; pub mod render_resource;

View File

@ -1,6 +1,6 @@
use crate::{ use crate::{
pipeline::PipelineDescriptor, pipeline::{BindGroupDescriptor, PipelineDescriptor},
render_resource::{RenderResourceId, RenderResourceAssignments}, render_resource::{RenderResourceId, RenderResourceSet},
renderer::RenderContext, renderer::RenderContext,
}; };
use bevy_asset::Handle; use bevy_asset::Handle;
@ -15,10 +15,9 @@ pub trait RenderPass {
fn set_stencil_reference(&mut self, reference: u32); fn set_stencil_reference(&mut self, reference: u32);
fn draw(&mut self, vertices: Range<u32>, instances: Range<u32>); fn draw(&mut self, vertices: Range<u32>, instances: Range<u32>);
fn draw_indexed(&mut self, indices: Range<u32>, base_vertex: i32, instances: Range<u32>); fn draw_indexed(&mut self, indices: Range<u32>, base_vertex: i32, instances: Range<u32>);
// TODO: try to somehow take into account the "set" pipeline instead of passing it in here fn set_bind_group(
fn set_render_resources(
&mut self, &mut self,
pipeline_descriptor: &PipelineDescriptor, bind_group_descriptor: &BindGroupDescriptor,
render_resource_assignments: &RenderResourceAssignments, render_resource_set: &RenderResourceSet,
) -> Option<Range<u32>>; );
} }

View File

@ -1,18 +1,22 @@
use crate::{ use crate::{
draw_target::DrawTarget, pass::{PassDescriptor, RenderPass, TextureAttachment},
pass::{PassDescriptor, TextureAttachment}, pipeline::{PipelineAssignments, PipelineCompiler, PipelineDescriptor},
pipeline::{PipelineCompiler, PipelineDescriptor},
render_graph::{Node, ResourceSlotInfo, ResourceSlots}, render_graph::{Node, ResourceSlotInfo, ResourceSlots},
render_resource::{ResourceInfo, RenderResourceAssignments}, render_resource::{
EntitiesWaitingForAssets, EntityRenderResourceAssignments, RenderResourceAssignments,
ResourceInfo,
},
renderer::RenderContext, renderer::RenderContext,
shader::Shader, shader::Shader,
Renderable,
}; };
use bevy_asset::{Assets, Handle}; use bevy_asset::{Assets, Handle};
use legion::prelude::*; use legion::prelude::*;
use std::ops::Range;
pub struct PassNode { pub struct PassNode {
descriptor: PassDescriptor, descriptor: PassDescriptor,
pipelines: Vec<(Handle<PipelineDescriptor>, Vec<Box<dyn DrawTarget>>)>, pipelines: Vec<Handle<PipelineDescriptor>>,
inputs: Vec<ResourceSlotInfo>, inputs: Vec<ResourceSlotInfo>,
color_attachment_input_indices: Vec<Option<usize>>, color_attachment_input_indices: Vec<Option<usize>>,
depth_stencil_attachment_input_index: Option<usize>, depth_stencil_attachment_input_index: Option<usize>,
@ -54,12 +58,64 @@ impl PassNode {
} }
} }
pub fn add_pipeline( pub fn add_pipeline(&mut self, pipeline_handle: Handle<PipelineDescriptor>) {
&mut self, self.pipelines.push(pipeline_handle);
pipeline_handle: Handle<PipelineDescriptor>, }
draw_targets: Vec<Box<dyn DrawTarget>>,
) { fn set_render_resources(
self.pipelines.push((pipeline_handle, draw_targets)); render_pass: &mut dyn RenderPass,
pipeline_descriptor: &PipelineDescriptor,
render_resource_assignments: &RenderResourceAssignments,
) -> Option<Range<u32>> {
let pipeline_layout = 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
);
render_pass.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
);
render_pass.set_index_buffer(index_buffer, 0);
render_pass
.get_render_context()
.resources()
.get_resource_info(
index_buffer,
&mut |resource_info| match resource_info {
Some(ResourceInfo::Buffer(Some(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) =
render_resource_assignments.get_render_resource_set(bind_group.id)
{
render_pass.set_bind_group(bind_group, &render_resource_set);
}
}
indices
} }
} }
@ -78,6 +134,12 @@ impl Node for PassNode {
) { ) {
let pipeline_compiler = resources.get::<PipelineCompiler>().unwrap(); let pipeline_compiler = resources.get::<PipelineCompiler>().unwrap();
let pipelines = resources.get::<Assets<PipelineDescriptor>>().unwrap(); let pipelines = resources.get::<Assets<PipelineDescriptor>>().unwrap();
let shader_pipeline_assignments = resources.get::<PipelineAssignments>().unwrap();
let entity_render_resource_assignments =
resources.get::<EntityRenderResourceAssignments>().unwrap();
let entities_waiting_for_assets = resources.get::<EntitiesWaitingForAssets>().unwrap();
let mut render_resource_assignments =
resources.get_mut::<RenderResourceAssignments>().unwrap();
for (i, color_attachment) in self.descriptor.color_attachments.iter_mut().enumerate() { for (i, color_attachment) in self.descriptor.color_attachments.iter_mut().enumerate() {
if let Some(input_index) = self.color_attachment_input_indices[i] { if let Some(input_index) = self.color_attachment_input_indices[i] {
@ -94,50 +156,71 @@ impl Node for PassNode {
.attachment = TextureAttachment::RenderResource(input.get(input_index).unwrap()); .attachment = TextureAttachment::RenderResource(input.get(input_index).unwrap());
} }
let shaders = resources.get::<Assets<Shader>>().unwrap(); {
for (pipeline_handle, draw_targets) in self.pipelines.iter_mut() { let render_resource_context = render_context.resources();
if let Some(compiled_pipelines_iter) =
pipeline_compiler.iter_compiled_pipelines(*pipeline_handle)
{
for compiled_pipeline_handle in compiled_pipelines_iter {
let compiled_pipeline_descriptor =
pipelines.get(compiled_pipeline_handle).unwrap();
let pipeline_layout = compiled_pipeline_descriptor.get_layout().unwrap(); // TODO: try merging the two pipeline loops below
{ let shaders = resources.get::<Assets<Shader>>().unwrap();
// TODO: this breaks down in a parallel setting. it needs to change. ideally in a way that for pipeline_handle in self.pipelines.iter() {
// doesn't require modifying RenderResourceAssignments if let Some(compiled_pipelines_iter) =
let mut render_resource_assignments = pipeline_compiler.iter_compiled_pipelines(*pipeline_handle)
resources.get_mut::<RenderResourceAssignments>().unwrap(); {
for bind_group in pipeline_layout.bind_groups.iter() { for compiled_pipeline_handle in compiled_pipelines_iter {
render_resource_assignments.update_render_resource_set_id(bind_group); let compiled_pipeline_descriptor =
pipelines.get(compiled_pipeline_handle).unwrap();
let pipeline_layout = compiled_pipeline_descriptor.get_layout().unwrap();
{
// TODO: this breaks down in a parallel setting. it needs to change. ideally in a way that
// doesn't require modifying RenderResourceAssignments
for bind_group in pipeline_layout.bind_groups.iter() {
render_resource_assignments
.update_render_resource_set_id(bind_group);
}
} }
}
render_context.resources().create_render_pipeline( render_resource_context.create_render_pipeline(
*compiled_pipeline_handle,
&compiled_pipeline_descriptor,
&shaders,
);
for draw_target in draw_targets.iter_mut() {
draw_target.setup(
world,
resources,
render_context,
*compiled_pipeline_handle, *compiled_pipeline_handle,
compiled_pipeline_descriptor, &compiled_pipeline_descriptor,
&shaders,
); );
render_resource_context.setup_bind_groups(
compiled_pipeline_descriptor,
&render_resource_assignments,
);
let assigned_render_resource_assignments = shader_pipeline_assignments
.assignments
.get(&compiled_pipeline_handle);
if let Some(assigned_render_resource_assignments) =
assigned_render_resource_assignments
{
for assignment_id in assigned_render_resource_assignments.iter() {
let entity = entity_render_resource_assignments
.get(*assignment_id)
.unwrap();
let renderable =
world.get_component::<Renderable>(*entity).unwrap();
if !renderable.is_visible || renderable.is_instanced {
continue;
}
render_resource_context.setup_bind_groups(
compiled_pipeline_descriptor,
&renderable.render_resource_assignments,
);
}
}
} }
} }
} }
} }
let render_resource_assignments = resources.get::<RenderResourceAssignments>().unwrap();
render_context.begin_pass( render_context.begin_pass(
&self.descriptor, &self.descriptor,
&render_resource_assignments, &render_resource_assignments,
&mut |render_pass| { &mut |render_pass| {
for (pipeline_handle, draw_targets) in self.pipelines.iter() { for pipeline_handle in self.pipelines.iter() {
if let Some(compiled_pipelines_iter) = if let Some(compiled_pipelines_iter) =
pipeline_compiler.iter_compiled_pipelines(*pipeline_handle) pipeline_compiler.iter_compiled_pipelines(*pipeline_handle)
{ {
@ -145,14 +228,45 @@ impl Node for PassNode {
let compiled_pipeline_descriptor = let compiled_pipeline_descriptor =
pipelines.get(compiled_pipeline_handle).unwrap(); pipelines.get(compiled_pipeline_handle).unwrap();
render_pass.set_pipeline(*compiled_pipeline_handle); render_pass.set_pipeline(*compiled_pipeline_handle);
for draw_target in draw_targets.iter() {
draw_target.draw( // set global render resources
world, Self::set_render_resources(
resources, render_pass,
render_pass, compiled_pipeline_descriptor,
*compiled_pipeline_handle, &render_resource_assignments,
compiled_pipeline_descriptor, );
);
// draw entities assigned to this pipeline
let assigned_render_resource_assignments = shader_pipeline_assignments
.assignments
.get(&compiled_pipeline_handle);
if let Some(assigned_render_resource_assignments) =
assigned_render_resource_assignments
{
for assignment_id in assigned_render_resource_assignments.iter() {
// TODO: hopefully legion has better random access apis that are more like queries?
let entity = entity_render_resource_assignments
.get(*assignment_id)
.unwrap();
let renderable =
world.get_component::<Renderable>(*entity).unwrap();
if !renderable.is_visible
|| renderable.is_instanced
|| entities_waiting_for_assets.contains(entity)
{
continue;
}
// set local render resources
if let Some(indices) = Self::set_render_resources(
render_pass,
compiled_pipeline_descriptor,
&renderable.render_resource_assignments,
) {
render_pass.draw_indexed(indices, 0, 0..1);
}
}
} }
} }
} }

View File

@ -2,7 +2,6 @@ use crate::{ColorMaterial, Quad, TextureAtlas, TextureAtlasSprite};
use bevy_asset::{Assets, Handle}; use bevy_asset::{Assets, Handle};
use bevy_render::{ use bevy_render::{
base_render_graph, base_render_graph,
draw_target::AssignedMeshesDrawTarget,
pipeline::{state_descriptors::*, PipelineDescriptor}, pipeline::{state_descriptors::*, PipelineDescriptor},
render_graph::{ render_graph::{
nodes::{AssetUniformNode, PassNode, UniformNode}, nodes::{AssetUniformNode, PassNode, UniformNode},
@ -153,14 +152,8 @@ impl SpriteRenderGraphBuilder for RenderGraph {
let main_pass: &mut PassNode = self let main_pass: &mut PassNode = self
.get_node_mut(base_render_graph::node::MAIN_PASS) .get_node_mut(base_render_graph::node::MAIN_PASS)
.unwrap(); .unwrap();
main_pass.add_pipeline( main_pass.add_pipeline(SPRITE_PIPELINE_HANDLE);
SPRITE_PIPELINE_HANDLE, main_pass.add_pipeline(SPRITE_SHEET_PIPELINE_HANDLE);
vec![Box::new(AssignedMeshesDrawTarget)],
);
main_pass.add_pipeline(
SPRITE_SHEET_PIPELINE_HANDLE,
vec![Box::new(AssignedMeshesDrawTarget)],
);
self self
} }
} }

View File

@ -1,7 +1,6 @@
use bevy_asset::{Assets, Handle}; use bevy_asset::{Assets, Handle};
use bevy_render::{ use bevy_render::{
base_render_graph, base_render_graph,
draw_target::AssignedMeshesDrawTarget,
pipeline::{state_descriptors::*, PipelineDescriptor}, pipeline::{state_descriptors::*, PipelineDescriptor},
render_graph::{ render_graph::{
nodes::{CameraNode, PassNode}, nodes::{CameraNode, PassNode},
@ -83,7 +82,7 @@ impl UiRenderGraphBuilder for RenderGraph {
let main_pass: &mut PassNode = self let main_pass: &mut PassNode = self
.get_node_mut(base_render_graph::node::MAIN_PASS) .get_node_mut(base_render_graph::node::MAIN_PASS)
.unwrap(); .unwrap();
main_pass.add_pipeline(UI_PIPELINE_HANDLE, vec![Box::new(AssignedMeshesDrawTarget)]); main_pass.add_pipeline(UI_PIPELINE_HANDLE);
self self
} }
} }

View File

@ -6,12 +6,12 @@ use bevy_render::{
PassDescriptor, RenderPass, RenderPassColorAttachmentDescriptor, PassDescriptor, RenderPass, RenderPassColorAttachmentDescriptor,
RenderPassDepthStencilAttachmentDescriptor, TextureAttachment, RenderPassDepthStencilAttachmentDescriptor, TextureAttachment,
}, },
render_resource::{RenderResourceId, RenderResourceAssignment, RenderResourceAssignments}, render_resource::{RenderResourceAssignment, RenderResourceAssignments, RenderResourceId},
renderer::{RenderContext, RenderResourceContext}, renderer::{RenderContext, RenderResourceContext},
texture::Extent3d, texture::Extent3d,
}; };
use std::{collections::HashMap, sync::Arc}; use std::sync::Arc;
#[derive(Default)] #[derive(Default)]
pub struct LazyCommandEncoder { pub struct LazyCommandEncoder {
@ -138,10 +138,10 @@ impl RenderContext for WgpuRenderContext {
&mut encoder, &mut encoder,
); );
let mut wgpu_render_pass = WgpuRenderPass { let mut wgpu_render_pass = WgpuRenderPass {
render_context: self,
render_pass, render_pass,
render_context: self,
render_resources: refs, render_resources: refs,
bound_bind_groups: HashMap::default(), pipeline_descriptor: None,
}; };
run_pass(&mut wgpu_render_pass); run_pass(&mut wgpu_render_pass);

View File

@ -2,19 +2,17 @@ use crate::{renderer::WgpuRenderContext, WgpuResourceRefs};
use bevy_asset::Handle; use bevy_asset::Handle;
use bevy_render::{ use bevy_render::{
pass::RenderPass, pass::RenderPass,
pipeline::PipelineDescriptor, pipeline::{BindGroupDescriptor, PipelineDescriptor},
render_resource::{ render_resource::{RenderResourceId, RenderResourceSet},
RenderResourceId, RenderResourceAssignments, RenderResourceSetId, ResourceInfo,
},
renderer::RenderContext, renderer::RenderContext,
}; };
use std::{collections::HashMap, ops::Range}; use std::ops::Range;
pub struct WgpuRenderPass<'a> { pub struct WgpuRenderPass<'a> {
pub render_pass: wgpu::RenderPass<'a>, pub render_pass: wgpu::RenderPass<'a>,
pub render_context: &'a WgpuRenderContext, pub render_context: &'a WgpuRenderContext,
pub render_resources: WgpuResourceRefs<'a>, pub render_resources: WgpuResourceRefs<'a>,
pub bound_bind_groups: HashMap<u32, RenderResourceSetId>, pub pipeline_descriptor: Option<&'a PipelineDescriptor>,
} }
impl<'a> RenderPass for WgpuRenderPass<'a> { impl<'a> RenderPass for WgpuRenderPass<'a> {
@ -51,102 +49,42 @@ impl<'a> RenderPass for WgpuRenderPass<'a> {
self.render_pass.draw(vertices, instances); self.render_pass.draw(vertices, instances);
} }
fn set_render_resources( fn set_bind_group(
&mut self, &mut self,
pipeline_descriptor: &PipelineDescriptor, bind_group_descriptor: &BindGroupDescriptor,
render_resource_assignments: &RenderResourceAssignments, render_resource_set: &RenderResourceSet,
) -> Option<Range<u32>> { ) {
let pipeline_layout = pipeline_descriptor.get_layout().unwrap(); if let Some(bind_group_info) = self
// PERF: vertex buffer lookup comes at a cost when vertex buffers aren't in render_resource_assignments. iterating over render_resource_assignment vertex buffers .render_resources
// would likely be faster .bind_groups
let mut indices = None; .get(&bind_group_descriptor.id)
for (i, vertex_buffer_descriptor) in
pipeline_layout.vertex_buffer_descriptors.iter().enumerate()
{ {
if let Some((vertex_buffer, index_buffer)) = if let Some(wgpu_bind_group) = bind_group_info.bind_groups.get(&render_resource_set.id)
render_resource_assignments.get_vertex_buffer(&vertex_buffer_descriptor.name)
{ {
log::trace!( const EMPTY: &'static [u32] = &[];
"set vertex buffer {}: {} ({:?})", let dynamic_uniform_indices = if let Some(ref dynamic_uniform_indices) =
i, render_resource_set.dynamic_uniform_indices
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);
self.render_context.resources().get_resource_info(
index_buffer,
&mut |resource_info| match resource_info {
Some(ResourceInfo::Buffer(Some(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(resource_set) =
render_resource_assignments.get_render_resource_set(bind_group.id)
{
if let Some(bind_group_info) = self.render_resources.bind_groups.get(&bind_group.id)
{ {
if let Some(wgpu_bind_group) = bind_group_info.bind_groups.get(&resource_set.id) dynamic_uniform_indices.as_slice()
{ } else {
const EMPTY: &'static [u32] = &[]; EMPTY
let dynamic_uniform_indices = if let Some(ref dynamic_uniform_indices) =
resource_set.dynamic_uniform_indices
{
dynamic_uniform_indices.as_slice()
} else {
EMPTY
};
// don't bind bind groups if they are already set
// TODO: these checks come at a performance cost. make sure it's worth it!
if let Some(bound_render_resource_set) =
self.bound_bind_groups.get(&bind_group.index)
{
if *bound_render_resource_set == resource_set.id
&& dynamic_uniform_indices.len() == 0
{
continue;
}
}
if dynamic_uniform_indices.len() == 0 {
self.bound_bind_groups
.insert(bind_group.index, resource_set.id);
} else {
self.bound_bind_groups.remove(&bind_group.index);
}
log::trace!(
"set bind group {} {:?}: {:?}",
bind_group.index,
dynamic_uniform_indices,
resource_set.id
);
self.render_pass.set_bind_group(
bind_group.index,
wgpu_bind_group,
dynamic_uniform_indices,
);
}
}; };
log::trace!(
"set bind group {:?} {:?}: {:?}",
bind_group_descriptor.id,
dynamic_uniform_indices,
render_resource_set.id
);
self.render_pass.set_bind_group(
bind_group_descriptor.index,
wgpu_bind_group,
dynamic_uniform_indices,
);
} }
} }
indices
} }
fn set_pipeline(&mut self, pipeline_handle: Handle<PipelineDescriptor>) { fn set_pipeline(&mut self, pipeline_handle: Handle<PipelineDescriptor>) {
let pipeline = self.render_resources.render_pipelines.get(&pipeline_handle).expect( let pipeline = self.render_resources.render_pipelines.get(&pipeline_handle).expect(
"Attempted to use a pipeline that does not exist in this RenderPass's RenderContext", "Attempted to use a pipeline that does not exist in this RenderPass's RenderContext",

View File

@ -55,10 +55,7 @@ fn setup(
render_graph.add_system_node("my_material", AssetUniformNode::<MyMaterial>::new(true)); render_graph.add_system_node("my_material", AssetUniformNode::<MyMaterial>::new(true));
let main_pass: &mut PassNode = render_graph.get_node_mut("main_pass").unwrap(); let main_pass: &mut PassNode = render_graph.get_node_mut("main_pass").unwrap();
main_pass.add_pipeline( main_pass.add_pipeline(pipeline_handle);
pipeline_handle,
vec![Box::new(draw_target::AssignedMeshesDrawTarget)],
);
pipeline_handle pipeline_handle
}; };

View File

@ -65,10 +65,7 @@ fn setup(
})); }));
render_graph.add_system_node("my_material", AssetUniformNode::<MyMaterial>::new(true)); render_graph.add_system_node("my_material", AssetUniformNode::<MyMaterial>::new(true));
let main_pass: &mut PassNode = render_graph.get_node_mut("main_pass").unwrap(); let main_pass: &mut PassNode = render_graph.get_node_mut("main_pass").unwrap();
main_pass.add_pipeline( main_pass.add_pipeline(pipeline_handle);
pipeline_handle,
vec![Box::new(draw_target::AssignedMeshesDrawTarget)],
);
pipeline_handle pipeline_handle
}; };

View File

@ -14,7 +14,6 @@ pub use crate::{
pbr::{entity::*, light::Light, material::StandardMaterial}, pbr::{entity::*, light::Light, material::StandardMaterial},
property::{DynamicProperties, Properties, PropertiesVal, Property, PropertyVal}, property::{DynamicProperties, Properties, PropertiesVal, Property, PropertyVal},
render::{ render::{
draw_target,
entity::*, entity::*,
mesh::{shape, Mesh}, mesh::{shape, Mesh},
pipeline::PipelineDescriptor, pipeline::PipelineDescriptor,