start porting "query" systems from SystemBuilder to functions

This commit is contained in:
Carter Anderson 2020-05-28 17:32:51 -07:00
parent 83d5275e10
commit 0472cbfc7c
7 changed files with 226 additions and 194 deletions

View File

@ -28,7 +28,7 @@ pub mod prelude {
entity::Entity, entity::Entity,
event::Event, event::Event,
filter::filter_fns::*, filter::filter_fns::*,
query::{IntoQuery, Query, Read, Tagged, TryRead, TryWrite, Write}, query::{IntoQuery, Query as FilteredQuery, Read, Tagged, TryRead, TryWrite, Write},
world::{Universe, World}, world::{Universe, World},
}; };
} }

View File

@ -21,5 +21,7 @@ pub mod prelude {
ResMut, ResMut,
System, System,
SystemBuilder, SystemBuilder,
Query,
SubWorld
}; };
} }

View File

@ -54,106 +54,99 @@ impl SystemNode for LightsNode {
let mut tmp_light_buffer = None; let mut tmp_light_buffer = None;
let mut command_queue = self.command_queue.clone(); let mut command_queue = self.command_queue.clone();
let max_lights = self.max_lights; let max_lights = self.max_lights;
SystemBuilder::new("light_node") (move |world: &mut SubWorld,
.read_resource::<RenderResources>() render_resources: Res<RenderResources>,
// TODO: this write on RenderResourceAssignments will prevent this system from running in parallel with other systems that do the same // TODO: this write on RenderResourceAssignments will prevent this system from running in parallel with other systems that do the same
.write_resource::<RenderResourceAssignments>() mut render_resource_assignments: ResMut<RenderResourceAssignments>,
.with_query(<(Read<Light>, Read<LocalToWorld>, Read<Translation>)>::query()) query: &mut Query<(Read<Light>, Read<LocalToWorld>, Read<Translation>)>| {
.build( if !lights_are_dirty {
move |_, return;
world, }
(render_resource_context, ref mut render_resource_assignments),
query| {
if !lights_are_dirty {
return;
}
let render_resources = &render_resource_context.context; let render_resources = &render_resources.context;
if light_buffer.is_none() { if light_buffer.is_none() {
let light_uniform_size = std::mem::size_of::<LightCount>() let light_uniform_size = std::mem::size_of::<LightCount>()
+ max_lights * std::mem::size_of::<LightRaw>(); + max_lights * std::mem::size_of::<LightRaw>();
let buffer = render_resources.create_buffer(BufferInfo { let buffer = render_resources.create_buffer(BufferInfo {
size: light_uniform_size, size: light_uniform_size,
buffer_usage: BufferUsage::UNIFORM buffer_usage: BufferUsage::UNIFORM
| BufferUsage::COPY_SRC | BufferUsage::COPY_SRC
| BufferUsage::COPY_DST, | BufferUsage::COPY_DST,
..Default::default() ..Default::default()
}); });
render_resource_assignments.set( render_resource_assignments.set(
resource_name::uniform::LIGHTS, resource_name::uniform::LIGHTS,
RenderResourceAssignment::Buffer { RenderResourceAssignment::Buffer {
resource: buffer, resource: buffer,
range: 0..light_uniform_size as u64, range: 0..light_uniform_size as u64,
dynamic_index: None, dynamic_index: None,
}, },
); );
light_buffer = Some(buffer); light_buffer = Some(buffer);
} }
let light_count = query.iter(world).count(); let light_count = query.iter(world).count();
if light_count == 0 { if light_count == 0 {
return; return;
} }
lights_are_dirty = false; lights_are_dirty = false;
let size = std::mem::size_of::<LightRaw>(); let size = std::mem::size_of::<LightRaw>();
let total_size = size * light_count; let total_size = size * light_count;
let light_count_size = std::mem::size_of::<LightCount>(); let light_count_size = std::mem::size_of::<LightCount>();
if let Some(old_tmp_light_buffer) = tmp_light_buffer { if let Some(old_tmp_light_buffer) = tmp_light_buffer {
render_resources.remove_buffer(old_tmp_light_buffer); render_resources.remove_buffer(old_tmp_light_buffer);
} }
if let Some(old_tmp_count_buffer) = tmp_count_buffer { if let Some(old_tmp_count_buffer) = tmp_count_buffer {
render_resources.remove_buffer(old_tmp_count_buffer); render_resources.remove_buffer(old_tmp_count_buffer);
} }
tmp_light_buffer = Some(render_resources.create_buffer_mapped( tmp_light_buffer = Some(render_resources.create_buffer_mapped(
BufferInfo { BufferInfo {
size: total_size, size: total_size,
buffer_usage: BufferUsage::COPY_SRC, buffer_usage: BufferUsage::COPY_SRC,
..Default::default() ..Default::default()
},
&mut |data, _renderer| {
for ((light, local_to_world, translation), slot) in
query.iter(world).zip(data.chunks_exact_mut(size))
{
slot.copy_from_slice(
LightRaw::from(&light, &local_to_world.0, &translation)
.as_bytes(),
);
}
},
));
tmp_count_buffer = Some(render_resources.create_buffer_mapped(
BufferInfo {
size: light_count_size,
buffer_usage: BufferUsage::COPY_SRC,
..Default::default()
},
&mut |data, _renderer| {
data.copy_from_slice([light_count as u32, 0, 0, 0].as_bytes());
},
));
command_queue.copy_buffer_to_buffer(
tmp_count_buffer.unwrap(),
0,
light_buffer.unwrap(),
0,
light_count_size as u64,
);
command_queue.copy_buffer_to_buffer(
tmp_light_buffer.unwrap(),
0,
light_buffer.unwrap(),
light_count_size as u64,
total_size as u64,
);
}, },
) &mut |data, _renderer| {
for ((light, local_to_world, translation), slot) in
query.iter(world).zip(data.chunks_exact_mut(size))
{
slot.copy_from_slice(
LightRaw::from(&light, &local_to_world.0, &translation).as_bytes(),
);
}
},
));
tmp_count_buffer = Some(render_resources.create_buffer_mapped(
BufferInfo {
size: light_count_size,
buffer_usage: BufferUsage::COPY_SRC,
..Default::default()
},
&mut |data, _renderer| {
data.copy_from_slice([light_count as u32, 0, 0, 0].as_bytes());
},
));
command_queue.copy_buffer_to_buffer(
tmp_count_buffer.unwrap(),
0,
light_buffer.unwrap(),
0,
light_count_size as u64,
);
command_queue.copy_buffer_to_buffer(
tmp_light_buffer.unwrap(),
0,
light_buffer.unwrap(),
light_count_size as u64,
total_size as u64,
);
}).system()
} }
} }

View File

@ -1,9 +1,9 @@
use bevy_app::{Events, GetEventReader}; use bevy_app::{Events, GetEventReader};
use bevy_window::WindowResized;
use bevy_property::{Properties, Property}; use bevy_property::{Properties, Property};
use bevy_window::WindowResized;
use glam::Mat4; use glam::Mat4;
use legion::prelude::*; use legion::prelude::*;
use serde::{Serialize, Deserialize}; use serde::{Deserialize, Serialize};
#[derive(Default, Properties)] #[derive(Default, Properties)]
pub struct ActiveCamera; pub struct ActiveCamera;
@ -127,19 +127,19 @@ impl Camera {
pub fn camera_update_system(resources: &mut Resources) -> Box<dyn Schedulable> { pub fn camera_update_system(resources: &mut Resources) -> Box<dyn Schedulable> {
let mut window_resized_event_reader = resources.get_event_reader::<WindowResized>(); let mut window_resized_event_reader = resources.get_event_reader::<WindowResized>();
SystemBuilder::new("camera_update") (move |world: &mut SubWorld,
.read_resource::<Events<WindowResized>>() window_resized_events: Res<Events<WindowResized>>,
.with_query(<Write<Camera>>::query()) query: &mut Query<Write<Camera>>| {
.build(move |_, world, window_resized_events, query| { let primary_window_resized_event = window_resized_event_reader
let primary_window_resized_event = window_resized_event_reader .find_latest(&window_resized_events, |event| event.is_primary);
.find_latest(&window_resized_events, |event| event.is_primary); if let Some(primary_window_resized_event) = primary_window_resized_event {
if let Some(primary_window_resized_event) = primary_window_resized_event { for mut camera in query.iter_mut(world) {
for mut camera in query.iter_mut(world) { camera.update(
camera.update( primary_window_resized_event.width,
primary_window_resized_event.width, primary_window_resized_event.height,
primary_window_resized_event.height, );
);
}
} }
}) }
})
.system()
} }

View File

@ -341,93 +341,91 @@ pub fn mesh_resource_provider_system(resources: &mut Resources) -> Box<dyn Sched
// TODO: allow pipelines to specialize on vertex_buffer_descriptor and index_format // TODO: allow pipelines to specialize on vertex_buffer_descriptor and index_format
let vertex_buffer_descriptor = Vertex::get_vertex_buffer_descriptor().unwrap(); let vertex_buffer_descriptor = Vertex::get_vertex_buffer_descriptor().unwrap();
vertex_buffer_descriptors.set(vertex_buffer_descriptor.clone()); vertex_buffer_descriptors.set(vertex_buffer_descriptor.clone());
SystemBuilder::new("mesh_resource_provider") (move |world: &mut SubWorld,
.read_resource::<RenderResources>() render_resources: Res<RenderResources>,
.read_resource::<Assets<Mesh>>() meshes: Res<Assets<Mesh>>,
.read_resource::<Events<AssetEvent<Mesh>>>() mesh_events: Res<Events<AssetEvent<Mesh>>>,
.with_query(<(Read<Handle<Mesh>>, Write<Renderable>)>::query()) query: &mut Query<(Read<Handle<Mesh>>, Write<Renderable>)>| {
.build( let render_resources = &*render_resources.context;
move |_, world, (render_resources, meshes, mesh_events), query| { let mut changed_meshes = HashSet::new();
let render_resources = &*render_resources.context; for event in mesh_event_reader.iter(&mesh_events) {
let mut changed_meshes = HashSet::new(); match event {
for event in mesh_event_reader.iter(&mesh_events) { AssetEvent::Created { handle } => {
match event { changed_meshes.insert(*handle);
AssetEvent::Created { handle } => {
changed_meshes.insert(*handle);
}
AssetEvent::Modified { handle } => {
changed_meshes.insert(*handle);
remove_current_mesh_resources(render_resources, *handle);
}
AssetEvent::Removed { handle } => {
remove_current_mesh_resources(render_resources, *handle);
// if mesh was modified and removed in the same update, ignore the modification
// events are ordered so future modification events are ok
changed_meshes.remove(handle);
}
}
} }
AssetEvent::Modified { handle } => {
for changed_mesh_handle in changed_meshes.iter() { changed_meshes.insert(*handle);
if let Some(mesh) = meshes.get(changed_mesh_handle) { remove_current_mesh_resources(render_resources, *handle);
let vertex_bytes = mesh
.get_vertex_buffer_bytes(&vertex_buffer_descriptor)
.unwrap();
// TODO: use a staging buffer here
let vertex_buffer = render_resources.create_buffer_with_data(
BufferInfo {
buffer_usage: BufferUsage::VERTEX,
..Default::default()
},
&vertex_bytes,
);
let index_bytes = mesh.get_index_buffer_bytes(IndexFormat::Uint16).unwrap();
let index_buffer = render_resources.create_buffer_with_data(
BufferInfo {
buffer_usage: BufferUsage::INDEX,
..Default::default()
},
&index_bytes,
);
render_resources.set_asset_resource(
*changed_mesh_handle,
vertex_buffer,
VERTEX_BUFFER_ASSET_INDEX,
);
render_resources.set_asset_resource(
*changed_mesh_handle,
index_buffer,
INDEX_BUFFER_ASSET_INDEX,
);
}
} }
AssetEvent::Removed { handle } => {
// TODO: remove this once batches are pipeline specific and deprecate assigned_meshes draw target remove_current_mesh_resources(render_resources, *handle);
for (handle, mut renderable) in query.iter_mut(world) { // if mesh was modified and removed in the same update, ignore the modification
if let Some(mesh) = meshes.get(&handle) { // events are ordered so future modification events are ok
renderable changed_meshes.remove(handle);
.render_resource_assignments
.pipeline_specialization
.primitive_topology = mesh.primitive_topology;
}
if let Some(vertex_buffer) =
render_resources.get_asset_resource(*handle, VERTEX_BUFFER_ASSET_INDEX)
{
let index_buffer =
render_resources.get_asset_resource(*handle, INDEX_BUFFER_ASSET_INDEX);
renderable.render_resource_assignments.set_vertex_buffer(
"Vertex",
vertex_buffer,
index_buffer,
);
}
} }
}, }
) }
for changed_mesh_handle in changed_meshes.iter() {
if let Some(mesh) = meshes.get(changed_mesh_handle) {
let vertex_bytes = mesh
.get_vertex_buffer_bytes(&vertex_buffer_descriptor)
.unwrap();
// TODO: use a staging buffer here
let vertex_buffer = render_resources.create_buffer_with_data(
BufferInfo {
buffer_usage: BufferUsage::VERTEX,
..Default::default()
},
&vertex_bytes,
);
let index_bytes = mesh.get_index_buffer_bytes(IndexFormat::Uint16).unwrap();
let index_buffer = render_resources.create_buffer_with_data(
BufferInfo {
buffer_usage: BufferUsage::INDEX,
..Default::default()
},
&index_bytes,
);
render_resources.set_asset_resource(
*changed_mesh_handle,
vertex_buffer,
VERTEX_BUFFER_ASSET_INDEX,
);
render_resources.set_asset_resource(
*changed_mesh_handle,
index_buffer,
INDEX_BUFFER_ASSET_INDEX,
);
}
}
// TODO: remove this once batches are pipeline specific and deprecate assigned_meshes draw target
for (handle, mut renderable) in query.iter_mut(world) {
if let Some(mesh) = meshes.get(&handle) {
renderable
.render_resource_assignments
.pipeline_specialization
.primitive_topology = mesh.primitive_topology;
}
if let Some(vertex_buffer) =
render_resources.get_asset_resource(*handle, VERTEX_BUFFER_ASSET_INDEX)
{
let index_buffer =
render_resources.get_asset_resource(*handle, INDEX_BUFFER_ASSET_INDEX);
renderable.render_resource_assignments.set_vertex_buffer(
"Vertex",
vertex_buffer,
index_buffer,
);
}
}
})
.system()
} }
#[cfg(test)] #[cfg(test)]

View File

@ -6,6 +6,45 @@ use bevy_render::{
}; };
use legion::prelude::*; use legion::prelude::*;
// TODO: replace with system_fn once configurable "archetype access" is sorted out
// pub fn render_resource_sets_system(
// world: &mut SubWorld,
// pipelines: Res<Assets<PipelineDescriptor>>,
// pipeline_compiler: Res<PipelineCompiler>,
// pipeline_assignments: Res<PipelineAssignments>,
// entity_render_resource_assignments: Res<EntityRenderResourceAssignments>,
// query: &mut Query<Write<Renderable>>, // gives SubWorld write access to Renderable
// ) {
// // PERF: consider doing a par-iter over all renderable components so this can be parallelized
// for compiled_pipeline_handle in pipeline_compiler.iter_all_compiled_pipelines() {
// if let Some(compiled_pipeline_assignments) = pipeline_assignments
// .assignments
// .get(compiled_pipeline_handle)
// {
// let compiled_pipeline = pipelines.get(compiled_pipeline_handle).unwrap();
// let pipeline_layout = compiled_pipeline.get_layout().unwrap();
// for assignment_id in compiled_pipeline_assignments.iter() {
// let entity = entity_render_resource_assignments
// .get(*assignment_id)
// .unwrap();
// let mut renderable = world.get_component_mut::<Renderable>(*entity).unwrap();
// if !renderable.is_visible || renderable.is_instanced {
// continue;
// }
// for bind_group in pipeline_layout.bind_groups.iter() {
// renderable
// .render_resource_assignments
// .update_render_resource_set_id(bind_group);
// }
// }
// }
// }
// }
pub fn render_resource_sets_system() -> Box<dyn Schedulable> { pub fn render_resource_sets_system() -> Box<dyn Schedulable> {
SystemBuilder::new("update_render_resource_sets") SystemBuilder::new("update_render_resource_sets")
.read_resource::<Assets<PipelineDescriptor>>() .read_resource::<Assets<PipelineDescriptor>>()