AssetRenderResourceNodes now consume asset change events. Remove EntitiesWaitingForAssets in favor of DrawState.

This commit is contained in:
Carter Anderson 2020-06-10 18:54:17 -07:00
parent 2e48269923
commit fc4160ea41
14 changed files with 202 additions and 167 deletions

View File

@ -71,6 +71,7 @@ impl<T> Assets<T> {
} }
pub fn get_mut(&mut self, handle: &Handle<T>) -> Option<&mut T> { pub fn get_mut(&mut self, handle: &Handle<T>) -> Option<&mut T> {
self.events.send(AssetEvent::Modified { handle: *handle });
self.assets.get_mut(&handle) self.assets.get_mut(&handle)
} }

View File

@ -4,7 +4,7 @@ use bevy_render::{
base_render_graph, base_render_graph,
pipeline::PipelineDescriptor, pipeline::PipelineDescriptor,
render_graph::{ render_graph::{
nodes::{AssetUniformNode, UniformNode}, nodes::{AssetRenderResourcesNode, RenderResourcesNode},
RenderGraph, RenderGraph,
}, },
shader::Shader, shader::Shader,
@ -28,10 +28,10 @@ pub trait ForwardPbrRenderGraphBuilder {
impl ForwardPbrRenderGraphBuilder for RenderGraph { impl ForwardPbrRenderGraphBuilder for RenderGraph {
fn add_pbr_graph(&mut self, resources: &Resources) -> &mut Self { fn add_pbr_graph(&mut self, resources: &Resources) -> &mut Self {
self.add_system_node(node::TRANSFORM, UniformNode::<Transform>::new(true)); self.add_system_node(node::TRANSFORM, RenderResourcesNode::<Transform>::new(true));
self.add_system_node( self.add_system_node(
node::STANDARD_MATERIAL, node::STANDARD_MATERIAL,
AssetUniformNode::<StandardMaterial>::new(true), AssetRenderResourcesNode::<StandardMaterial>::new(true),
); );
self.add_system_node(node::LIGHTS, LightsNode::new(10)); self.add_system_node(node::LIGHTS, LightsNode::new(10));
let mut shaders = resources.get_mut::<Assets<Shader>>().unwrap(); let mut shaders = resources.get_mut::<Assets<Shader>>().unwrap();

View File

@ -39,7 +39,6 @@ use draw::{clear_draw_system, Draw, RenderPipelines};
use legion::prelude::IntoSystem; use legion::prelude::IntoSystem;
use mesh::mesh_resource_provider_system; use mesh::mesh_resource_provider_system;
use render_graph::RenderGraph; use render_graph::RenderGraph;
use render_resource::EntitiesWaitingForAssets;
use std::ops::Range; use std::ops::Range;
use texture::{PngTextureLoader, TextureResourceSystemState}; use texture::{PngTextureLoader, TextureResourceSystemState};
@ -83,7 +82,6 @@ impl AppPlugin for RenderPlugin {
.init_resource::<PipelineCompiler>() .init_resource::<PipelineCompiler>()
.init_resource::<RenderResourceAssignments>() .init_resource::<RenderResourceAssignments>()
.init_resource::<VertexBufferDescriptors>() .init_resource::<VertexBufferDescriptors>()
.init_resource::<EntitiesWaitingForAssets>()
.init_resource::<TextureResourceSystemState>() .init_resource::<TextureResourceSystemState>()
.add_system_to_stage(bevy_app::stage::PRE_UPDATE, clear_draw_system.system()) .add_system_to_stage(bevy_app::stage::PRE_UPDATE, clear_draw_system.system())
.init_system_to_stage( .init_system_to_stage(
@ -94,10 +92,6 @@ impl AppPlugin for RenderPlugin {
bevy_app::stage::POST_UPDATE, bevy_app::stage::POST_UPDATE,
camera::camera_system::<PerspectiveProjection>, camera::camera_system::<PerspectiveProjection>,
) )
.add_system_to_stage(
bevy_app::stage::PRE_UPDATE,
EntitiesWaitingForAssets::clear_system.system(),
)
.init_system_to_stage(stage::RENDER_RESOURCE, mesh_resource_provider_system) .init_system_to_stage(stage::RENDER_RESOURCE, mesh_resource_provider_system)
.add_system_to_stage( .add_system_to_stage(
stage::RENDER_RESOURCE, stage::RENDER_RESOURCE,

View File

@ -1,13 +1,13 @@
mod camera_node; mod camera_node;
mod pass_node; mod pass_node;
mod texture_copy_node; mod texture_copy_node;
mod uniform_node; mod render_resources_node;
mod window_swapchain_node; mod window_swapchain_node;
mod window_texture_node; mod window_texture_node;
pub use camera_node::*; pub use camera_node::*;
pub use pass_node::*; pub use pass_node::*;
pub use texture_copy_node::*; pub use texture_copy_node::*;
pub use uniform_node::*; pub use render_resources_node::*;
pub use window_swapchain_node::*; pub use window_swapchain_node::*;
pub use window_texture_node::*; pub use window_texture_node::*;

View File

@ -1,10 +1,14 @@
use crate::{ use crate::{
draw::{Draw, RenderCommand}, draw::{Draw, RenderCommand},
pass::{PassDescriptor, TextureAttachment}, pass::{PassDescriptor, TextureAttachment},
pipeline::PipelineDescriptor,
render_graph::{Node, ResourceSlotInfo, ResourceSlots}, render_graph::{Node, ResourceSlotInfo, ResourceSlots},
render_resource::{EntitiesWaitingForAssets, RenderResourceAssignments, ResourceInfo}, render_resource::{
RenderResourceAssignments, RenderResourceId, RenderResourceSetId, ResourceInfo,
},
renderer::RenderContext, renderer::RenderContext,
}; };
use bevy_asset::{Assets, Handle};
use legion::prelude::*; use legion::prelude::*;
pub struct MainPassNode { pub struct MainPassNode {
@ -63,8 +67,8 @@ impl Node for MainPassNode {
input: &ResourceSlots, input: &ResourceSlots,
_output: &mut ResourceSlots, _output: &mut ResourceSlots,
) { ) {
let entities_waiting_for_assets = resources.get::<EntitiesWaitingForAssets>().unwrap();
let render_resource_assignments = resources.get::<RenderResourceAssignments>().unwrap(); let render_resource_assignments = resources.get::<RenderResourceAssignments>().unwrap();
let pipelines = resources.get::<Assets<PipelineDescriptor>>().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] {
@ -85,8 +89,9 @@ impl Node for MainPassNode {
&self.descriptor, &self.descriptor,
&render_resource_assignments, &render_resource_assignments,
&mut |render_pass| { &mut |render_pass| {
for (entity, draw) in <Read<Draw>>::query().iter_entities(&world) { let mut draw_state = DrawState::default();
if !draw.is_visible || entities_waiting_for_assets.contains(&entity) { for draw in <Read<Draw>>::query().iter(&world) {
if !draw.is_visible {
continue; continue;
} }
@ -95,17 +100,23 @@ impl Node for MainPassNode {
RenderCommand::SetPipeline { pipeline } => { RenderCommand::SetPipeline { pipeline } => {
// TODO: Filter pipelines // TODO: Filter pipelines
render_pass.set_pipeline(*pipeline); render_pass.set_pipeline(*pipeline);
let descriptor = pipelines.get(pipeline).unwrap();
draw_state.set_pipeline(*pipeline, descriptor);
} }
RenderCommand::DrawIndexed { RenderCommand::DrawIndexed {
base_vertex, base_vertex,
indices, indices,
instances, instances,
} => { } => {
if draw_state.can_draw_indexed() {
render_pass.draw_indexed( render_pass.draw_indexed(
indices.clone(), indices.clone(),
*base_vertex, *base_vertex,
instances.clone(), instances.clone(),
); );
} else {
log::info!("Could not draw indexed because the pipeline layout wasn't fully set for pipeline: {:?}", draw_state.pipeline);
}
} }
RenderCommand::SetVertexBuffer { RenderCommand::SetVertexBuffer {
buffer, buffer,
@ -113,9 +124,11 @@ impl Node for MainPassNode {
slot, slot,
} => { } => {
render_pass.set_vertex_buffer(*slot, *buffer, *offset); render_pass.set_vertex_buffer(*slot, *buffer, *offset);
draw_state.set_vertex_buffer(*slot, *buffer);
} }
RenderCommand::SetIndexBuffer { buffer, offset } => { RenderCommand::SetIndexBuffer { buffer, offset } => {
render_pass.set_index_buffer(*buffer, *offset); render_pass.set_index_buffer(*buffer, *offset);
draw_state.set_index_buffer(*buffer)
} }
RenderCommand::SetBindGroup { RenderCommand::SetBindGroup {
index, index,
@ -131,6 +144,7 @@ impl Node for MainPassNode {
.as_ref() .as_ref()
.map(|indices| indices.as_slice()), .map(|indices| indices.as_slice()),
); );
draw_state.set_bind_group(*index, *render_resource_set);
} }
} }
} }
@ -139,3 +153,48 @@ impl Node for MainPassNode {
); );
} }
} }
/// Tracks the current pipeline state to ensure draw calls are valid.
#[derive(Default)]
struct DrawState {
pipeline: Option<Handle<PipelineDescriptor>>,
bind_groups: Vec<Option<RenderResourceSetId>>,
vertex_buffers: Vec<Option<RenderResourceId>>,
index_buffer: Option<RenderResourceId>,
}
impl DrawState {
pub fn set_bind_group(&mut self, index: u32, render_resource_set: RenderResourceSetId) {
self.bind_groups[index as usize] = Some(render_resource_set);
}
pub fn set_vertex_buffer(&mut self, index: u32, buffer: RenderResourceId) {
self.vertex_buffers[index as usize] = Some(buffer);
}
pub fn set_index_buffer(&mut self, buffer: RenderResourceId) {
self.index_buffer = Some(buffer);
}
pub fn can_draw_indexed(&self) -> bool {
self.bind_groups.iter().all(|b| b.is_some())
&& self.vertex_buffers.iter().all(|v| v.is_some())
&& self.index_buffer.is_some()
}
pub fn set_pipeline(
&mut self,
handle: Handle<PipelineDescriptor>,
descriptor: &PipelineDescriptor,
) {
self.bind_groups.clear();
self.vertex_buffers.clear();
self.index_buffer = None;
self.pipeline = Some(handle);
let layout = descriptor.get_layout().unwrap();
self.bind_groups.resize(layout.bind_groups.len(), None);
self.vertex_buffers
.resize(layout.vertex_buffer_descriptors.len(), None);
}
}

View File

@ -2,19 +2,21 @@ use crate::{
draw::{Draw, RenderPipelines}, draw::{Draw, RenderPipelines},
render_graph::{CommandQueue, Node, ResourceSlots, SystemNode}, render_graph::{CommandQueue, Node, ResourceSlots, SystemNode},
render_resource::{ render_resource::{
self, BufferInfo, BufferUsage, EntitiesWaitingForAssets, RenderResourceAssignment, self, BufferInfo, BufferUsage, RenderResourceAssignment, RenderResourceAssignments,
RenderResourceAssignments, RenderResourceAssignmentsId, RenderResourceHints, RenderResourceAssignmentsId, RenderResourceHints, RenderResourceId,
RenderResourceId,
}, },
renderer::{RenderContext, RenderResourceContext, RenderResources}, renderer::{RenderContext, RenderResourceContext, RenderResources},
texture, texture,
}; };
use bevy_app::EventReader; use bevy_app::{EventReader, Events};
use bevy_asset::{AssetEvent, Assets, Handle}; use bevy_asset::{AssetEvent, Assets, Handle};
use legion::prelude::*; use legion::prelude::*;
use render_resource::ResourceInfo; use render_resource::ResourceInfo;
use std::{collections::HashMap, marker::PhantomData}; use std::{
collections::{HashMap, HashSet},
marker::PhantomData,
};
pub const BIND_BUFFER_ALIGNMENT: usize = 256; pub const BIND_BUFFER_ALIGNMENT: usize = 256;
#[derive(Debug)] #[derive(Debug)]
@ -25,7 +27,7 @@ struct QueuedBufferWrite {
#[derive(Debug)] #[derive(Debug)]
struct BufferArrayStatus { struct BufferArrayStatus {
new_item_count: usize, changed_item_count: usize,
item_size: usize, item_size: usize,
aligned_size: usize, aligned_size: usize,
staging_buffer_offset: usize, staging_buffer_offset: usize,
@ -78,15 +80,15 @@ impl<T> UniformBufferArrays<T>
where where
T: render_resource::RenderResources, T: render_resource::RenderResources,
{ {
fn reset_new_item_counts(&mut self) { fn reset_changed_item_counts(&mut self) {
for buffer_status in self.uniform_arrays.iter_mut() { for buffer_status in self.uniform_arrays.iter_mut() {
if let Some((_name, buffer_status)) = buffer_status { if let Some((_name, buffer_status)) = buffer_status {
buffer_status.new_item_count = 0; buffer_status.changed_item_count = 0;
} }
} }
} }
fn increment_uniform_counts(&mut self, uniforms: &T) { fn increment_changed_item_counts(&mut self, uniforms: &T) {
if self.uniform_arrays.len() != uniforms.render_resources_len() { if self.uniform_arrays.len() != uniforms.render_resources_len() {
self.uniform_arrays self.uniform_arrays
.resize_with(uniforms.render_resources_len(), || None); .resize_with(uniforms.render_resources_len(), || None);
@ -96,12 +98,12 @@ where
let render_resource_name = uniforms.get_render_resource_name(i).unwrap(); let render_resource_name = uniforms.get_render_resource_name(i).unwrap();
let size = render_resource.buffer_byte_len().unwrap(); let size = render_resource.buffer_byte_len().unwrap();
if let Some((ref _name, ref mut buffer_array_status)) = self.uniform_arrays[i] { if let Some((ref _name, ref mut buffer_array_status)) = self.uniform_arrays[i] {
buffer_array_status.new_item_count += 1; buffer_array_status.changed_item_count += 1;
} else { } else {
self.uniform_arrays[i] = Some(( self.uniform_arrays[i] = Some((
render_resource_name.to_string(), render_resource_name.to_string(),
BufferArrayStatus { BufferArrayStatus {
new_item_count: 1, changed_item_count: 1,
queued_buffer_writes: Vec::new(), queued_buffer_writes: Vec::new(),
aligned_size: Self::get_aligned_dynamic_uniform_size(size), aligned_size: Self::get_aligned_dynamic_uniform_size(size),
item_size: size, item_size: size,
@ -134,7 +136,7 @@ where
} }
buffer_array_status.queued_buffer_writes = buffer_array_status.queued_buffer_writes =
Vec::with_capacity(buffer_array_status.new_item_count); Vec::with_capacity(buffer_array_status.changed_item_count);
} }
} }
} }
@ -144,9 +146,9 @@ where
render_resource_context: &dyn RenderResourceContext, render_resource_context: &dyn RenderResourceContext,
align: bool, align: bool,
) { ) {
if buffer_array_status.current_item_capacity < buffer_array_status.new_item_count { if buffer_array_status.current_item_capacity < buffer_array_status.changed_item_count {
let new_capacity = let new_capacity =
buffer_array_status.new_item_count + buffer_array_status.new_item_count / 2; buffer_array_status.changed_item_count + buffer_array_status.changed_item_count / 2;
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);
@ -177,7 +179,7 @@ where
for dynamic_buffer_array_status in self.uniform_arrays.iter_mut() { for dynamic_buffer_array_status in self.uniform_arrays.iter_mut() {
if let Some((_name, ref mut buffer_array_status)) = dynamic_buffer_array_status { if let Some((_name, ref mut buffer_array_status)) = dynamic_buffer_array_status {
buffer_array_status.staging_buffer_offset = size; buffer_array_status.staging_buffer_offset = size;
size += buffer_array_status.item_size * buffer_array_status.new_item_count; size += buffer_array_status.item_size * buffer_array_status.changed_item_count;
} }
} }
@ -298,7 +300,7 @@ where
} }
#[derive(Default)] #[derive(Default)]
pub struct UniformNode<T> pub struct RenderResourcesNode<T>
where where
T: render_resource::RenderResources, T: render_resource::RenderResources,
{ {
@ -307,12 +309,12 @@ where
_marker: PhantomData<T>, _marker: PhantomData<T>,
} }
impl<T> UniformNode<T> impl<T> RenderResourcesNode<T>
where where
T: render_resource::RenderResources, T: render_resource::RenderResources,
{ {
pub fn new(dynamic_uniforms: bool) -> Self { pub fn new(dynamic_uniforms: bool) -> Self {
UniformNode { RenderResourcesNode {
command_queue: CommandQueue::default(), command_queue: CommandQueue::default(),
dynamic_uniforms, dynamic_uniforms,
_marker: PhantomData::default(), _marker: PhantomData::default(),
@ -320,7 +322,7 @@ where
} }
} }
impl<T> Node for UniformNode<T> impl<T> Node for RenderResourcesNode<T>
where where
T: render_resource::RenderResources, T: render_resource::RenderResources,
{ {
@ -336,7 +338,7 @@ where
} }
} }
impl<T> SystemNode for UniformNode<T> impl<T> SystemNode for RenderResourcesNode<T>
where where
T: render_resource::RenderResources, T: render_resource::RenderResources,
{ {
@ -347,35 +349,30 @@ where
// TODO: maybe run "update" here // TODO: maybe run "update" here
(move |world: &mut SubWorld, (move |world: &mut SubWorld,
render_resources: Res<RenderResources>, render_resources: Res<RenderResources>,
entities_waiting_for_assets: Res<EntitiesWaitingForAssets>,
query: &mut Query<(Read<T>, Read<Draw>, Write<RenderPipelines>)>| { query: &mut Query<(Read<T>, Read<Draw>, Write<RenderPipelines>)>| {
let render_resource_context = &*render_resources.context; let render_resource_context = &*render_resources.context;
uniform_buffer_arrays.reset_new_item_counts(); uniform_buffer_arrays.reset_changed_item_counts();
// update uniforms info // update uniforms info
for (uniforms, draw, _render_pipelines) in query.iter_mut(world) { for (uniforms, draw, _render_pipelines) in query.iter_mut(world) {
if !draw.is_visible { if !draw.is_visible {
return; return;
} }
uniform_buffer_arrays.increment_uniform_counts(&uniforms); uniform_buffer_arrays.increment_changed_item_counts(&uniforms);
} }
uniform_buffer_arrays.setup_buffer_arrays(render_resource_context, dynamic_uniforms); uniform_buffer_arrays.setup_buffer_arrays(render_resource_context, dynamic_uniforms);
let staging_buffer_size = uniform_buffer_arrays.update_staging_buffer_offsets(); let staging_buffer_size = uniform_buffer_arrays.update_staging_buffer_offsets();
for (entity, (uniforms, draw, mut render_pipelines)) in for (uniforms, draw, mut render_pipelines) in query.iter_mut(world) {
query.iter_entities_mut(world)
{
if !draw.is_visible { if !draw.is_visible {
return; return;
} }
setup_uniform_texture_resources::<T>( setup_uniform_texture_resources::<T>(
entity,
&uniforms, &uniforms,
render_resource_context, render_resource_context,
&entities_waiting_for_assets,
&mut render_pipelines.render_resource_assignments, &mut render_pipelines.render_resource_assignments,
) )
} }
@ -403,9 +400,7 @@ where
..Default::default() ..Default::default()
}, },
&mut |mut staging_buffer, _render_resources| { &mut |mut staging_buffer, _render_resources| {
for (uniforms, draw, mut render_pipelines) in for (uniforms, draw, mut render_pipelines) in query.iter_mut(world) {
query.iter_mut(world)
{
if !draw.is_visible { if !draw.is_visible {
return; return;
} }
@ -431,7 +426,7 @@ where
} }
#[derive(Default)] #[derive(Default)]
pub struct AssetUniformNode<T> pub struct AssetRenderResourcesNode<T>
where where
T: render_resource::RenderResources, T: render_resource::RenderResources,
{ {
@ -440,12 +435,12 @@ where
_marker: PhantomData<T>, _marker: PhantomData<T>,
} }
impl<T> AssetUniformNode<T> impl<T> AssetRenderResourcesNode<T>
where where
T: render_resource::RenderResources, T: render_resource::RenderResources,
{ {
pub fn new(dynamic_uniforms: bool) -> Self { pub fn new(dynamic_uniforms: bool) -> Self {
AssetUniformNode { AssetRenderResourcesNode {
dynamic_uniforms, dynamic_uniforms,
command_queue: Default::default(), command_queue: Default::default(),
_marker: Default::default(), _marker: Default::default(),
@ -453,7 +448,7 @@ where
} }
} }
impl<T> Node for AssetUniformNode<T> impl<T> Node for AssetRenderResourcesNode<T>
where where
T: render_resource::RenderResources, T: render_resource::RenderResources,
{ {
@ -469,72 +464,79 @@ where
} }
} }
impl<T> SystemNode for AssetUniformNode<T> const EXPECT_ASSET_MESSAGE: &str = "Only assets that exist should be in the modified assets list";
impl<T> SystemNode for AssetRenderResourcesNode<T>
where where
T: render_resource::RenderResources, T: render_resource::RenderResources,
{ {
fn get_system(&self) -> Box<dyn Schedulable> { fn get_system(&self) -> Box<dyn Schedulable> {
let mut command_queue = self.command_queue.clone(); let mut command_queue = self.command_queue.clone();
let mut uniform_buffer_arrays = UniformBufferArrays::<T>::default(); let mut uniform_buffer_arrays = UniformBufferArrays::<T>::default();
let mut asset_event_reader = EventReader::<AssetEvent<T>>::default();
let mut asset_render_resource_assignments =
HashMap::<Handle<T>, RenderResourceAssignments>::default();
let dynamic_uniforms = self.dynamic_uniforms; let dynamic_uniforms = self.dynamic_uniforms;
(move |world: &mut SubWorld, (move |world: &mut SubWorld,
assets: Res<Assets<T>>, assets: Res<Assets<T>>,
asset_events: Res<Events<AssetEvent<T>>>,
render_resources: Res<RenderResources>, render_resources: Res<RenderResources>,
entities_waiting_for_assets: Res<EntitiesWaitingForAssets>,
query: &mut Query<(Read<Handle<T>>, Read<Draw>, Write<RenderPipelines>)>| { query: &mut Query<(Read<Handle<T>>, Read<Draw>, Write<RenderPipelines>)>| {
let render_resource_context = &*render_resources.context; let render_resource_context = &*render_resources.context;
uniform_buffer_arrays.reset_new_item_counts(); uniform_buffer_arrays.reset_changed_item_counts();
let mut modified_assets = HashSet::new();
for event in asset_event_reader.iter(&asset_events) {
match event {
AssetEvent::Created { handle } => {
modified_assets.insert(*handle);
}
AssetEvent::Modified { handle } => {
modified_assets.insert(*handle);
}
AssetEvent::Removed { handle } => {
// TODO: handle removals
modified_assets.remove(handle);
}
}
}
// update uniform handles info // update uniform handles info
for (entity, (handle, draw, _render_pipelines)) in query.iter_entities_mut(world) { for asset_handle in modified_assets.iter() {
if !draw.is_visible { let asset = assets.get(&asset_handle).expect(EXPECT_ASSET_MESSAGE);
return; uniform_buffer_arrays.increment_changed_item_counts(&asset);
}
if let Some(uniforms) = assets.get(&handle) {
// TODO: only increment count if we haven't seen this uniform handle before
uniform_buffer_arrays.increment_uniform_counts(&uniforms);
} else {
entities_waiting_for_assets.add(entity)
}
} }
uniform_buffer_arrays.setup_buffer_arrays(render_resource_context, dynamic_uniforms); uniform_buffer_arrays.setup_buffer_arrays(render_resource_context, dynamic_uniforms);
let staging_buffer_size = uniform_buffer_arrays.update_staging_buffer_offsets(); let staging_buffer_size = uniform_buffer_arrays.update_staging_buffer_offsets();
for (entity, (handle, draw, mut render_pipelines)) in for asset_handle in modified_assets.iter() {
query.iter_entities_mut(world) let asset = assets.get(&asset_handle).expect(EXPECT_ASSET_MESSAGE);
{ let mut render_resource_assignments = asset_render_resource_assignments
if !draw.is_visible { .entry(*asset_handle)
return; .or_insert_with(|| RenderResourceAssignments::default());
}
if let Some(uniforms) = assets.get(&handle) {
setup_uniform_texture_resources::<T>( setup_uniform_texture_resources::<T>(
entity, &asset,
&uniforms,
render_resource_context, render_resource_context,
&entities_waiting_for_assets, &mut render_resource_assignments,
&mut render_pipelines.render_resource_assignments,
)
}
}
if staging_buffer_size == 0 {
let mut staging_buffer: [u8; 0] = [];
for (handle, draw, mut render_pipelines) in query.iter_mut(world) {
if !draw.is_visible {
return;
}
if let Some(uniforms) = assets.get(&handle) {
// TODO: only setup buffer if we haven't seen this handle before
uniform_buffer_arrays.setup_uniform_buffer_resources(
&uniforms,
dynamic_uniforms,
render_resource_context,
&mut render_pipelines.render_resource_assignments,
&mut staging_buffer,
); );
} }
if staging_buffer_size == 0 {
let mut staging_buffer: [u8; 0] = [];
for asset_handle in modified_assets.iter() {
let asset = assets.get(&asset_handle).expect(EXPECT_ASSET_MESSAGE);
let mut render_resource_assignments = asset_render_resource_assignments
.entry(*asset_handle)
.or_insert_with(|| RenderResourceAssignments::default());
// TODO: only setup buffer if we haven't seen this handle before
uniform_buffer_arrays.setup_uniform_buffer_resources(
&asset,
dynamic_uniforms,
render_resource_context,
&mut render_resource_assignments,
&mut staging_buffer,
);
} }
} else { } else {
let staging_buffer = render_resource_context.create_buffer_mapped( let staging_buffer = render_resource_context.create_buffer_mapped(
@ -544,21 +546,20 @@ where
..Default::default() ..Default::default()
}, },
&mut |mut staging_buffer, _render_resources| { &mut |mut staging_buffer, _render_resources| {
for (handle, draw, mut render_pipelines) in query.iter_mut(world) { for asset_handle in modified_assets.iter() {
if !draw.is_visible { let asset = assets.get(&asset_handle).expect(EXPECT_ASSET_MESSAGE);
return; let mut render_resource_assignments = asset_render_resource_assignments
} .entry(*asset_handle)
if let Some(uniforms) = assets.get(&handle) { .or_insert_with(|| RenderResourceAssignments::default());
// TODO: only setup buffer if we haven't seen this handle before // TODO: only setup buffer if we haven't seen this handle before
uniform_buffer_arrays.setup_uniform_buffer_resources( uniform_buffer_arrays.setup_uniform_buffer_resources(
&uniforms, &asset,
dynamic_uniforms, dynamic_uniforms,
render_resource_context, render_resource_context,
&mut render_pipelines.render_resource_assignments, &mut render_resource_assignments,
&mut staging_buffer, &mut staging_buffer,
); );
} }
}
}, },
); );
@ -566,16 +567,20 @@ where
.copy_staging_buffer_to_final_buffers(&mut command_queue, staging_buffer); .copy_staging_buffer_to_final_buffers(&mut command_queue, staging_buffer);
command_queue.free_buffer(staging_buffer); command_queue.free_buffer(staging_buffer);
} }
for (asset_handle, _draw, mut render_pipelines) in query.iter_mut(world) {
if let Some(asset_assignments) = asset_render_resource_assignments.get(&asset_handle) {
render_pipelines.render_resource_assignments.extend(asset_assignments);
}
}
}) })
.system() .system()
} }
} }
fn setup_uniform_texture_resources<T>( fn setup_uniform_texture_resources<T>(
entity: Entity,
uniforms: &T, uniforms: &T,
render_resource_context: &dyn RenderResourceContext, render_resource_context: &dyn RenderResourceContext,
entities_waiting_for_assets: &EntitiesWaitingForAssets,
render_resource_assignments: &mut RenderResourceAssignments, render_resource_assignments: &mut RenderResourceAssignments,
) where ) where
T: render_resource::RenderResources, T: render_resource::RenderResources,
@ -600,11 +605,7 @@ fn setup_uniform_texture_resources<T>(
RenderResourceAssignment::Sampler(sampler_resource), RenderResourceAssignment::Sampler(sampler_resource),
); );
continue; continue;
} else { }
entities_waiting_for_assets.add(entity);
}
} else {
entities_waiting_for_assets.add(entity);
} }
} }
} }

View File

@ -1,31 +0,0 @@
use legion::prelude::{Entity, Res};
use std::{collections::HashSet, sync::RwLock};
#[derive(Default)]
pub struct EntitiesWaitingForAssets {
pub entities: RwLock<HashSet<Entity>>,
}
impl EntitiesWaitingForAssets {
pub fn add(&self, entity: Entity) {
self.entities
.write()
.expect("RwLock poisoned")
.insert(entity);
}
pub fn contains(&self, entity: &Entity) -> bool {
self.entities
.read()
.expect("RwLock poisoned")
.contains(entity)
}
pub fn clear(&self) {
self.entities.write().expect("RwLock poisoned").clear();
}
pub fn clear_system(entities_waiting_for_assets: Res<EntitiesWaitingForAssets>) {
entities_waiting_for_assets.clear();
}
}

View File

@ -1,5 +1,4 @@
mod buffer; mod buffer;
mod entities_waiting_for_assets;
mod render_resource; mod render_resource;
mod render_resource_set; mod render_resource_set;
mod render_resource_assignments; mod render_resource_assignments;
@ -7,7 +6,6 @@ mod resource_info;
mod systems; mod systems;
pub use buffer::*; pub use buffer::*;
pub use entities_waiting_for_assets::*;
pub use render_resource::*; pub use render_resource::*;
pub use render_resource_set::*; pub use render_resource_set::*;
pub use render_resource_assignments::*; pub use render_resource_assignments::*;

View File

@ -2,7 +2,7 @@ use super::{RenderResourceId, RenderResourceSet, RenderResourceSetId};
use crate::pipeline::{BindGroupDescriptor, BindGroupDescriptorId, PipelineSpecialization}; use crate::pipeline::{BindGroupDescriptor, BindGroupDescriptorId, PipelineSpecialization};
use std::{ use std::{
collections::{HashMap, HashSet}, collections::{HashMap, HashSet},
hash::{Hash, Hasher}, hash::Hash,
ops::Range, ops::Range,
}; };
use uuid::Uuid; use uuid::Uuid;
@ -60,6 +60,7 @@ impl RenderResourceAssignments {
fn try_set_dirty(&mut self, name: &str, assignment: &RenderResourceAssignment) { fn try_set_dirty(&mut self, name: &str, assignment: &RenderResourceAssignment) {
if let Some(current_assignment) = self.render_resources.get(name) { if let Some(current_assignment) = self.render_resources.get(name) {
if current_assignment != assignment { if current_assignment != assignment {
// TODO: this is crude. we shouldn't need to invalidate all render resource sets
for id in self.render_resource_sets.keys() { for id in self.render_resource_sets.keys() {
self.dirty_render_resource_sets.insert(*id); self.dirty_render_resource_sets.insert(*id);
} }
@ -67,6 +68,18 @@ impl RenderResourceAssignments {
} }
} }
pub fn extend(&mut self, render_resource_assignments: &RenderResourceAssignments) {
for (name, assignment) in render_resource_assignments.render_resources.iter() {
self.set(name, assignment.clone());
}
for (name, (vertex_buffer, index_buffer)) in
render_resource_assignments.vertex_buffers.iter()
{
self.set_vertex_buffer(name, *vertex_buffer, index_buffer.clone());
}
}
pub fn get_vertex_buffer( pub fn get_vertex_buffer(
&self, &self,
name: &str, name: &str,

View File

@ -16,10 +16,10 @@ pub struct IndexedRenderResourceAssignment {
} }
// TODO: consider renaming this to BindGroup for parity with renderer terminology // TODO: consider renaming this to BindGroup for parity with renderer terminology
#[derive(Eq, PartialEq, Debug)] #[derive(Clone, Eq, PartialEq, Debug)]
pub struct RenderResourceSet { pub struct RenderResourceSet {
pub id: RenderResourceSetId, pub id: RenderResourceSetId,
pub indexed_assignments: Vec<IndexedRenderResourceAssignment>, pub indexed_assignments: Arc<Vec<IndexedRenderResourceAssignment>>,
pub dynamic_uniform_indices: Option<Arc<Vec<u32>>>, pub dynamic_uniform_indices: Option<Arc<Vec<u32>>>,
} }
@ -99,7 +99,7 @@ impl RenderResourceSetBuilder {
self.indexed_assignments.sort_by_key(|i| i.index); self.indexed_assignments.sort_by_key(|i| i.index);
RenderResourceSet { RenderResourceSet {
id: RenderResourceSetId(self.hasher.finish()), id: RenderResourceSetId(self.hasher.finish()),
indexed_assignments: self.indexed_assignments, indexed_assignments: Arc::new(self.indexed_assignments),
dynamic_uniform_indices: if self.dynamic_uniform_indices.is_empty() { dynamic_uniform_indices: if self.dynamic_uniform_indices.is_empty() {
None None
} else { } else {

View File

@ -4,7 +4,7 @@ use bevy_render::{
base_render_graph, base_render_graph,
pipeline::{state_descriptors::*, PipelineDescriptor}, pipeline::{state_descriptors::*, PipelineDescriptor},
render_graph::{ render_graph::{
nodes::{AssetUniformNode, UniformNode}, nodes::{AssetRenderResourcesNode, RenderResourcesNode},
RenderGraph, RenderGraph,
}, },
shader::{Shader, ShaderStage, ShaderStages}, shader::{Shader, ShaderStage, ShaderStages},
@ -123,23 +123,23 @@ impl SpriteRenderGraphBuilder for RenderGraph {
fn add_sprite_graph(&mut self, resources: &Resources) -> &mut Self { fn add_sprite_graph(&mut self, resources: &Resources) -> &mut Self {
self.add_system_node( self.add_system_node(
node::COLOR_MATERIAL, node::COLOR_MATERIAL,
AssetUniformNode::<ColorMaterial>::new(false), AssetRenderResourcesNode::<ColorMaterial>::new(false),
); );
self.add_node_edge(node::COLOR_MATERIAL, base_render_graph::node::MAIN_PASS) self.add_node_edge(node::COLOR_MATERIAL, base_render_graph::node::MAIN_PASS)
.unwrap(); .unwrap();
self.add_system_node(node::QUAD, UniformNode::<Quad>::new(false)); self.add_system_node(node::QUAD, RenderResourcesNode::<Quad>::new(false));
self.add_node_edge(node::QUAD, base_render_graph::node::MAIN_PASS) self.add_node_edge(node::QUAD, base_render_graph::node::MAIN_PASS)
.unwrap(); .unwrap();
self.add_system_node( self.add_system_node(
node::SPRITE_SHEET, node::SPRITE_SHEET,
AssetUniformNode::<TextureAtlas>::new(false), AssetRenderResourcesNode::<TextureAtlas>::new(false),
); );
self.add_system_node( self.add_system_node(
node::SPRITE_SHEET_SPRITE, node::SPRITE_SHEET_SPRITE,
UniformNode::<TextureAtlasSprite>::new(true), RenderResourcesNode::<TextureAtlasSprite>::new(true),
); );
let mut pipelines = resources.get_mut::<Assets<PipelineDescriptor>>().unwrap(); let mut pipelines = resources.get_mut::<Assets<PipelineDescriptor>>().unwrap();

View File

@ -53,7 +53,7 @@ fn setup(
fragment: Some(shaders.add(Shader::from_glsl(ShaderStage::Fragment, FRAGMENT_SHADER))), fragment: Some(shaders.add(Shader::from_glsl(ShaderStage::Fragment, FRAGMENT_SHADER))),
})); }));
render_graph.add_system_node("my_material", AssetUniformNode::<MyMaterial>::new(true)); render_graph.add_system_node("my_material", AssetRenderResourcesNode::<MyMaterial>::new(true));
pipeline_handle pipeline_handle
}; };

View File

@ -63,7 +63,7 @@ fn setup(
vertex: shaders.add(Shader::from_glsl(ShaderStage::Vertex, VERTEX_SHADER)), vertex: shaders.add(Shader::from_glsl(ShaderStage::Vertex, VERTEX_SHADER)),
fragment: Some(shaders.add(Shader::from_glsl(ShaderStage::Fragment, FRAGMENT_SHADER))), fragment: Some(shaders.add(Shader::from_glsl(ShaderStage::Fragment, FRAGMENT_SHADER))),
})); }));
render_graph.add_system_node("my_material", AssetUniformNode::<MyMaterial>::new(true)); render_graph.add_system_node("my_material", AssetRenderResourcesNode::<MyMaterial>::new(true));
pipeline_handle pipeline_handle
}; };

View File

@ -19,7 +19,7 @@ pub use crate::{
pipeline::PipelineDescriptor, pipeline::PipelineDescriptor,
render_graph::{ render_graph::{
nodes::{ nodes::{
AssetUniformNode, CameraNode, MainPassNode, UniformNode, WindowSwapChainNode, AssetRenderResourcesNode, CameraNode, MainPassNode, RenderResourcesNode, WindowSwapChainNode,
WindowTextureNode, WindowTextureNode,
}, },
RenderGraph, RenderGraph,