mirror of
https://github.com/bevyengine/bevy
synced 2024-11-22 20:53:53 +00:00
RenderGraph2: UniformNode
This commit is contained in:
parent
209b4b48d9
commit
512bf118bf
7 changed files with 673 additions and 20 deletions
|
@ -54,7 +54,7 @@ use bevy_window::{WindowCreated, WindowReference, WindowResized};
|
||||||
use pass::PassDescriptor;
|
use pass::PassDescriptor;
|
||||||
use pipeline::pipelines::build_forward_pipeline;
|
use pipeline::pipelines::build_forward_pipeline;
|
||||||
use render_graph_2::{
|
use render_graph_2::{
|
||||||
nodes::{Camera2dNode, CameraNode, PassNode, WindowSwapChainNode, WindowTextureNode},
|
nodes::{Camera2dNode, CameraNode, PassNode, WindowSwapChainNode, WindowTextureNode, UniformNode},
|
||||||
RenderGraph2,
|
RenderGraph2,
|
||||||
};
|
};
|
||||||
use render_resource::resource_providers::mesh_resource_provider_system;
|
use render_resource::resource_providers::mesh_resource_provider_system;
|
||||||
|
@ -78,7 +78,6 @@ impl RenderPlugin {
|
||||||
render_graph
|
render_graph
|
||||||
.build(&mut pipelines, &mut shaders)
|
.build(&mut pipelines, &mut shaders)
|
||||||
.add_resource_provider(LightResourceProvider::new(10))
|
.add_resource_provider(LightResourceProvider::new(10))
|
||||||
.add_resource_provider(UniformResourceProvider::<StandardMaterial>::new(true))
|
|
||||||
.add_resource_provider(UniformResourceProvider::<LocalToWorld>::new(true));
|
.add_resource_provider(UniformResourceProvider::<LocalToWorld>::new(true));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -124,6 +123,7 @@ impl AppPlugin for RenderPlugin {
|
||||||
let resources = app.resources_mut();
|
let resources = app.resources_mut();
|
||||||
render_graph.add_system_node_named("camera", CameraNode::default(), resources);
|
render_graph.add_system_node_named("camera", CameraNode::default(), resources);
|
||||||
render_graph.add_system_node_named("camera2d", Camera2dNode::default(), resources);
|
render_graph.add_system_node_named("camera2d", Camera2dNode::default(), resources);
|
||||||
|
render_graph.add_system_node_named("standard_material", UniformNode::<StandardMaterial>::new(true), resources);
|
||||||
render_graph.add_node_named(
|
render_graph.add_node_named(
|
||||||
"swapchain",
|
"swapchain",
|
||||||
WindowSwapChainNode::new(
|
WindowSwapChainNode::new(
|
||||||
|
@ -185,6 +185,7 @@ impl AppPlugin for RenderPlugin {
|
||||||
// TODO: replace these with "autowire" groups
|
// TODO: replace these with "autowire" groups
|
||||||
render_graph.add_node_edge("camera", "main_pass").unwrap();
|
render_graph.add_node_edge("camera", "main_pass").unwrap();
|
||||||
render_graph.add_node_edge("camera2d", "main_pass").unwrap();
|
render_graph.add_node_edge("camera2d", "main_pass").unwrap();
|
||||||
|
render_graph.add_node_edge("standard_material", "main_pass").unwrap();
|
||||||
render_graph
|
render_graph
|
||||||
.add_slot_edge(
|
.add_slot_edge(
|
||||||
"swapchain",
|
"swapchain",
|
||||||
|
|
|
@ -6,7 +6,7 @@ use crate::{
|
||||||
render_resource::{
|
render_resource::{
|
||||||
BufferInfo, RenderResourceAssignments, RenderResourceAssignmentsId, ResourceInfo,
|
BufferInfo, RenderResourceAssignments, RenderResourceAssignmentsId, ResourceInfo,
|
||||||
},
|
},
|
||||||
renderer_2::RenderContext,
|
renderer_2::{RenderResourceContext, GlobalRenderResourceContext},
|
||||||
shader::{Shader, ShaderSource},
|
shader::{Shader, ShaderSource},
|
||||||
Renderable,
|
Renderable,
|
||||||
};
|
};
|
||||||
|
@ -48,7 +48,7 @@ impl PipelineCompiler {
|
||||||
shader_storage: &AssetStorage<Shader>,
|
shader_storage: &AssetStorage<Shader>,
|
||||||
vertex_buffer_descriptors: &VertexBufferDescriptors,
|
vertex_buffer_descriptors: &VertexBufferDescriptors,
|
||||||
pipeline_descriptor: &mut PipelineDescriptor,
|
pipeline_descriptor: &mut PipelineDescriptor,
|
||||||
render_context: &dyn RenderContext,
|
render_resource_context: &dyn RenderResourceContext,
|
||||||
render_resource_assignments: &RenderResourceAssignments,
|
render_resource_assignments: &RenderResourceAssignments,
|
||||||
) {
|
) {
|
||||||
let vertex_spirv = shader_storage
|
let vertex_spirv = shader_storage
|
||||||
|
@ -75,7 +75,7 @@ impl PipelineCompiler {
|
||||||
for bind_group in layout.bind_groups.iter_mut() {
|
for bind_group in layout.bind_groups.iter_mut() {
|
||||||
for binding in bind_group.bindings.iter_mut() {
|
for binding in bind_group.bindings.iter_mut() {
|
||||||
if let Some(render_resource) = render_resource_assignments.get(&binding.name) {
|
if let Some(render_resource) = render_resource_assignments.get(&binding.name) {
|
||||||
render_context.resources().get_resource_info(
|
render_resource_context.get_resource_info(
|
||||||
render_resource,
|
render_resource,
|
||||||
&mut |resource_info| {
|
&mut |resource_info| {
|
||||||
if let Some(ResourceInfo::Buffer(BufferInfo { is_dynamic, .. })) =
|
if let Some(ResourceInfo::Buffer(BufferInfo { is_dynamic, .. })) =
|
||||||
|
@ -142,7 +142,7 @@ impl PipelineCompiler {
|
||||||
&mut self,
|
&mut self,
|
||||||
vertex_buffer_descriptors: &VertexBufferDescriptors,
|
vertex_buffer_descriptors: &VertexBufferDescriptors,
|
||||||
shader_storage: &mut AssetStorage<Shader>,
|
shader_storage: &mut AssetStorage<Shader>,
|
||||||
render_context: &dyn RenderContext,
|
render_resource_context: &dyn RenderResourceContext,
|
||||||
pipeline_descriptor: &PipelineDescriptor,
|
pipeline_descriptor: &PipelineDescriptor,
|
||||||
render_resource_assignments: &RenderResourceAssignments,
|
render_resource_assignments: &RenderResourceAssignments,
|
||||||
) -> PipelineDescriptor {
|
) -> PipelineDescriptor {
|
||||||
|
@ -173,7 +173,7 @@ impl PipelineCompiler {
|
||||||
shader_storage,
|
shader_storage,
|
||||||
vertex_buffer_descriptors,
|
vertex_buffer_descriptors,
|
||||||
&mut compiled_pipeline_descriptor,
|
&mut compiled_pipeline_descriptor,
|
||||||
render_context,
|
render_resource_context,
|
||||||
render_resource_assignments,
|
render_resource_assignments,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -187,7 +187,7 @@ impl PipelineCompiler {
|
||||||
&mut self,
|
&mut self,
|
||||||
vertex_buffer_descriptors: &VertexBufferDescriptors,
|
vertex_buffer_descriptors: &VertexBufferDescriptors,
|
||||||
shader_pipeline_assignments: &mut PipelineAssignments,
|
shader_pipeline_assignments: &mut PipelineAssignments,
|
||||||
render_context: &dyn RenderContext,
|
render_resource_context: &dyn RenderResourceContext,
|
||||||
pipeline_storage: &mut AssetStorage<PipelineDescriptor>,
|
pipeline_storage: &mut AssetStorage<PipelineDescriptor>,
|
||||||
shader_storage: &mut AssetStorage<Shader>,
|
shader_storage: &mut AssetStorage<Shader>,
|
||||||
pipelines: &[Handle<PipelineDescriptor>],
|
pipelines: &[Handle<PipelineDescriptor>],
|
||||||
|
@ -213,7 +213,7 @@ impl PipelineCompiler {
|
||||||
let compiled_pipeline = self.compile_pipeline(
|
let compiled_pipeline = self.compile_pipeline(
|
||||||
vertex_buffer_descriptors,
|
vertex_buffer_descriptors,
|
||||||
shader_storage,
|
shader_storage,
|
||||||
render_context,
|
render_resource_context,
|
||||||
pipeline_descriptor,
|
pipeline_descriptor,
|
||||||
render_resource_assignments,
|
render_resource_assignments,
|
||||||
);
|
);
|
||||||
|
@ -286,7 +286,6 @@ impl PipelineAssignments {
|
||||||
pub fn update_shader_assignments(
|
pub fn update_shader_assignments(
|
||||||
world: &mut World,
|
world: &mut World,
|
||||||
resources: &Resources,
|
resources: &Resources,
|
||||||
render_context: &dyn RenderContext,
|
|
||||||
) {
|
) {
|
||||||
// PERF: this seems like a lot of work for things that don't change that often.
|
// PERF: this seems like a lot of work for things that don't change that often.
|
||||||
// lots of string + hashset allocations. sees uniform_resource_provider for more context
|
// lots of string + hashset allocations. sees uniform_resource_provider for more context
|
||||||
|
@ -295,6 +294,7 @@ pub fn update_shader_assignments(
|
||||||
let mut pipeline_compiler = resources.get_mut::<PipelineCompiler>().unwrap();
|
let mut pipeline_compiler = resources.get_mut::<PipelineCompiler>().unwrap();
|
||||||
let mut shader_storage = resources.get_mut::<AssetStorage<Shader>>().unwrap();
|
let mut shader_storage = resources.get_mut::<AssetStorage<Shader>>().unwrap();
|
||||||
let vertex_buffer_descriptors = resources.get::<VertexBufferDescriptors>().unwrap();
|
let vertex_buffer_descriptors = resources.get::<VertexBufferDescriptors>().unwrap();
|
||||||
|
let global_render_resource_context = resources.get::<GlobalRenderResourceContext>().unwrap();
|
||||||
let mut pipeline_descriptor_storage = resources
|
let mut pipeline_descriptor_storage = resources
|
||||||
.get_mut::<AssetStorage<PipelineDescriptor>>()
|
.get_mut::<AssetStorage<PipelineDescriptor>>()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
@ -312,7 +312,7 @@ pub fn update_shader_assignments(
|
||||||
pipeline_compiler.update_shader_assignments(
|
pipeline_compiler.update_shader_assignments(
|
||||||
&vertex_buffer_descriptors,
|
&vertex_buffer_descriptors,
|
||||||
&mut shader_pipeline_assignments,
|
&mut shader_pipeline_assignments,
|
||||||
render_context,
|
&*global_render_resource_context.context,
|
||||||
&mut pipeline_descriptor_storage,
|
&mut pipeline_descriptor_storage,
|
||||||
&mut shader_storage,
|
&mut shader_storage,
|
||||||
&renderable.pipelines,
|
&renderable.pipelines,
|
||||||
|
|
|
@ -3,9 +3,11 @@ mod camera2d_node;
|
||||||
mod window_texture_node;
|
mod window_texture_node;
|
||||||
mod window_swapchain_node;
|
mod window_swapchain_node;
|
||||||
mod pass_node;
|
mod pass_node;
|
||||||
|
mod uniform_node;
|
||||||
|
|
||||||
pub use camera_node::*;
|
pub use camera_node::*;
|
||||||
pub use camera2d_node::*;
|
pub use camera2d_node::*;
|
||||||
pub use window_texture_node::*;
|
pub use window_texture_node::*;
|
||||||
pub use window_swapchain_node::*;
|
pub use window_swapchain_node::*;
|
||||||
pub use pass_node::*;
|
pub use pass_node::*;
|
||||||
|
pub use uniform_node::*;
|
649
bevy_render/src/render_graph_2/nodes/uniform_node.rs
Normal file
649
bevy_render/src/render_graph_2/nodes/uniform_node.rs
Normal file
|
@ -0,0 +1,649 @@
|
||||||
|
use crate::{
|
||||||
|
pipeline::VertexBufferDescriptors,
|
||||||
|
render_graph_2::{CommandQueue, Node, ResourceSlots, SystemNode},
|
||||||
|
render_resource::{
|
||||||
|
BufferArrayInfo, BufferInfo, BufferUsage, RenderResource, RenderResourceAssignments,
|
||||||
|
RenderResourceAssignmentsId, ResourceInfo,
|
||||||
|
},
|
||||||
|
renderer_2::{GlobalRenderResourceContext, RenderContext, RenderResourceContext},
|
||||||
|
shader::{AsUniforms, FieldBindType},
|
||||||
|
texture, Renderable,
|
||||||
|
};
|
||||||
|
|
||||||
|
use bevy_asset::{AssetStorage, Handle};
|
||||||
|
use legion::prelude::*;
|
||||||
|
use std::{collections::HashMap, marker::PhantomData};
|
||||||
|
use texture::{SamplerDescriptor, Texture, TextureDescriptor};
|
||||||
|
|
||||||
|
pub const BIND_BUFFER_ALIGNMENT: usize = 256;
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct QueuedBufferWrite {
|
||||||
|
buffer: RenderResource,
|
||||||
|
offset: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct BufferArrayStatus {
|
||||||
|
new_item_count: usize,
|
||||||
|
item_size: usize,
|
||||||
|
aligned_size: usize,
|
||||||
|
staging_buffer_offset: usize,
|
||||||
|
buffer: Option<RenderResource>,
|
||||||
|
queued_buffer_writes: Vec<QueuedBufferWrite>,
|
||||||
|
current_item_count: usize,
|
||||||
|
current_item_capacity: usize,
|
||||||
|
indices: HashMap<RenderResourceAssignmentsId, usize>,
|
||||||
|
current_index: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BufferArrayStatus {
|
||||||
|
pub fn get_or_assign_index(&mut self, id: RenderResourceAssignmentsId) -> usize {
|
||||||
|
if let Some(offset) = self.indices.get(&id) {
|
||||||
|
*offset
|
||||||
|
} else {
|
||||||
|
if self.current_index == self.current_item_capacity {
|
||||||
|
panic!("no empty slots available in array");
|
||||||
|
}
|
||||||
|
|
||||||
|
let index = self.current_index;
|
||||||
|
self.indices.insert(id, index);
|
||||||
|
self.current_index += 1;
|
||||||
|
index
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct UniformBufferArrays<T>
|
||||||
|
where
|
||||||
|
T: AsUniforms,
|
||||||
|
{
|
||||||
|
uniform_arrays: Vec<Option<(String, BufferArrayStatus)>>,
|
||||||
|
_marker: PhantomData<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> UniformBufferArrays<T>
|
||||||
|
where
|
||||||
|
T: AsUniforms,
|
||||||
|
{
|
||||||
|
fn new() -> Self {
|
||||||
|
let mut uniform_arrays = Vec::new();
|
||||||
|
let field_infos = T::get_field_infos();
|
||||||
|
uniform_arrays.resize_with(field_infos.len(), || None);
|
||||||
|
UniformBufferArrays {
|
||||||
|
uniform_arrays,
|
||||||
|
_marker: PhantomData::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn reset_new_item_counts(&mut self) {
|
||||||
|
for buffer_status in self.uniform_arrays.iter_mut() {
|
||||||
|
if let Some((_name, buffer_status)) = buffer_status {
|
||||||
|
buffer_status.new_item_count = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn increment_uniform_counts(&mut self, uniforms: &T) {
|
||||||
|
for (i, field_info) in T::get_field_infos().iter().enumerate() {
|
||||||
|
if let Some(FieldBindType::Uniform { size }) =
|
||||||
|
uniforms.get_field_bind_type(&field_info.name)
|
||||||
|
{
|
||||||
|
if let Some((ref _name, ref mut buffer_array_status)) = self.uniform_arrays[i] {
|
||||||
|
buffer_array_status.new_item_count += 1;
|
||||||
|
} else {
|
||||||
|
self.uniform_arrays[i] = Some((
|
||||||
|
field_info.uniform_name.to_string(),
|
||||||
|
BufferArrayStatus {
|
||||||
|
new_item_count: 1,
|
||||||
|
queued_buffer_writes: Vec::new(),
|
||||||
|
aligned_size: Self::get_aligned_dynamic_uniform_size(size),
|
||||||
|
item_size: size,
|
||||||
|
staging_buffer_offset: 0,
|
||||||
|
buffer: None,
|
||||||
|
current_index: 0,
|
||||||
|
current_item_count: 0,
|
||||||
|
current_item_capacity: 0,
|
||||||
|
indices: HashMap::new(),
|
||||||
|
},
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_aligned_dynamic_uniform_size(data_size: usize) -> usize {
|
||||||
|
BIND_BUFFER_ALIGNMENT * ((data_size as f32 / BIND_BUFFER_ALIGNMENT as f32).ceil() as usize)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn setup_buffer_arrays(
|
||||||
|
&mut self,
|
||||||
|
render_resource_context: &dyn RenderResourceContext,
|
||||||
|
dynamic_uniforms: bool,
|
||||||
|
) {
|
||||||
|
for buffer_array_status in self.uniform_arrays.iter_mut() {
|
||||||
|
if let Some((_name, buffer_array_status)) = buffer_array_status {
|
||||||
|
if dynamic_uniforms {
|
||||||
|
Self::setup_buffer_array(buffer_array_status, render_resource_context, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer_array_status.queued_buffer_writes =
|
||||||
|
Vec::with_capacity(buffer_array_status.new_item_count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn setup_buffer_array(
|
||||||
|
buffer_array_status: &mut BufferArrayStatus,
|
||||||
|
render_resource_context: &dyn RenderResourceContext,
|
||||||
|
align: bool,
|
||||||
|
) {
|
||||||
|
let new_capacity = if let Some(buffer) = buffer_array_status.buffer {
|
||||||
|
let mut new_capacity = None;
|
||||||
|
render_resource_context.get_resource_info(buffer, &mut |resource_info| {
|
||||||
|
new_capacity = if let Some(ResourceInfo::Buffer(BufferInfo {
|
||||||
|
array_info: Some(array_info),
|
||||||
|
..
|
||||||
|
})) = resource_info
|
||||||
|
{
|
||||||
|
if array_info.item_capacity < buffer_array_status.new_item_count {
|
||||||
|
// over capacity. lets resize
|
||||||
|
Some(
|
||||||
|
buffer_array_status.new_item_count
|
||||||
|
+ buffer_array_status.new_item_count / 2,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
// under capacity. no change needed
|
||||||
|
None
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// incorrect resource type. overwrite with new buffer
|
||||||
|
Some(buffer_array_status.new_item_count)
|
||||||
|
};
|
||||||
|
});
|
||||||
|
new_capacity
|
||||||
|
} else {
|
||||||
|
// buffer does not exist. create it now.
|
||||||
|
Some(buffer_array_status.new_item_count)
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(new_capacity) = 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 = render_resource_context.create_buffer(BufferInfo {
|
||||||
|
array_info: Some(BufferArrayInfo {
|
||||||
|
item_capacity: new_capacity,
|
||||||
|
item_size,
|
||||||
|
..Default::default()
|
||||||
|
}),
|
||||||
|
size: total_size,
|
||||||
|
buffer_usage: BufferUsage::COPY_DST | BufferUsage::UNIFORM,
|
||||||
|
is_dynamic: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
buffer_array_status.current_item_capacity = new_capacity;
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn update_staging_buffer_offsets(&mut self) -> usize {
|
||||||
|
let mut size = 0;
|
||||||
|
for dynamic_buffer_array_status in self.uniform_arrays.iter_mut() {
|
||||||
|
if let Some((_name, ref mut buffer_array_status)) = dynamic_buffer_array_status {
|
||||||
|
buffer_array_status.staging_buffer_offset = size;
|
||||||
|
size += buffer_array_status.item_size * buffer_array_status.new_item_count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
size
|
||||||
|
}
|
||||||
|
|
||||||
|
fn setup_uniform_buffer_resources(
|
||||||
|
&mut self,
|
||||||
|
uniforms: &T,
|
||||||
|
dynamic_uniforms: bool,
|
||||||
|
render_resources: &dyn RenderResourceContext,
|
||||||
|
render_resource_assignments: &mut RenderResourceAssignments,
|
||||||
|
staging_buffer: &mut [u8],
|
||||||
|
) {
|
||||||
|
for (i, field_info) in T::get_field_infos().iter().enumerate() {
|
||||||
|
let bind_type = uniforms.get_field_bind_type(&field_info.name);
|
||||||
|
match bind_type {
|
||||||
|
Some(FieldBindType::Uniform { size }) => {
|
||||||
|
let (_name, uniform_buffer_status) = self.uniform_arrays[i].as_mut().unwrap();
|
||||||
|
let (target_buffer, target_offset) = if dynamic_uniforms {
|
||||||
|
let buffer = uniform_buffer_status.buffer.unwrap();
|
||||||
|
let mut offset = 0;
|
||||||
|
render_resources.get_resource_info(buffer, &mut |resource_info| {
|
||||||
|
if let Some(ResourceInfo::Buffer(BufferInfo {
|
||||||
|
array_info: Some(ref array_info),
|
||||||
|
is_dynamic: true,
|
||||||
|
..
|
||||||
|
})) = resource_info
|
||||||
|
{
|
||||||
|
let index = uniform_buffer_status
|
||||||
|
.get_or_assign_index(render_resource_assignments.id);
|
||||||
|
render_resource_assignments.set_indexed(
|
||||||
|
&field_info.uniform_name,
|
||||||
|
buffer,
|
||||||
|
(index * array_info.item_size) as u32,
|
||||||
|
);
|
||||||
|
offset = index * uniform_buffer_status.aligned_size;
|
||||||
|
} else {
|
||||||
|
panic!("Expected a dynamic uniform buffer");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
(buffer, offset)
|
||||||
|
} else {
|
||||||
|
let resource = match render_resource_assignments
|
||||||
|
.get(field_info.uniform_name)
|
||||||
|
{
|
||||||
|
Some(render_resource) => render_resource,
|
||||||
|
None => {
|
||||||
|
let resource = render_resources.create_buffer(BufferInfo {
|
||||||
|
size,
|
||||||
|
buffer_usage: BufferUsage::COPY_DST | BufferUsage::UNIFORM,
|
||||||
|
..Default::default()
|
||||||
|
});
|
||||||
|
render_resource_assignments.set(&field_info.uniform_name, resource);
|
||||||
|
resource
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
(resource, 0)
|
||||||
|
};
|
||||||
|
|
||||||
|
let staging_buffer_start = uniform_buffer_status.staging_buffer_offset
|
||||||
|
+ (uniform_buffer_status.queued_buffer_writes.len()
|
||||||
|
* uniform_buffer_status.item_size);
|
||||||
|
if let Some(uniform_bytes) =
|
||||||
|
uniforms.get_uniform_bytes_ref(&field_info.uniform_name)
|
||||||
|
{
|
||||||
|
if size != uniform_bytes.len() {
|
||||||
|
panic!("The number of bytes produced for {} do not match the expected count. Actual: {}. Expected: {}.", field_info.uniform_name, uniform_bytes.len(), size);
|
||||||
|
}
|
||||||
|
|
||||||
|
staging_buffer
|
||||||
|
[staging_buffer_start..(staging_buffer_start + uniform_bytes.len())]
|
||||||
|
.copy_from_slice(uniform_bytes);
|
||||||
|
} else if let Some(uniform_bytes) =
|
||||||
|
uniforms.get_uniform_bytes(field_info.uniform_name)
|
||||||
|
{
|
||||||
|
if size != uniform_bytes.len() {
|
||||||
|
panic!("The number of bytes produced for {} do not match the expected count. Actual: {}. Expected: {}.", field_info.uniform_name, uniform_bytes.len(), size);
|
||||||
|
}
|
||||||
|
|
||||||
|
staging_buffer
|
||||||
|
[staging_buffer_start..(staging_buffer_start + uniform_bytes.len())]
|
||||||
|
.copy_from_slice(&uniform_bytes);
|
||||||
|
} else {
|
||||||
|
panic!(
|
||||||
|
"failed to get data from uniform: {}",
|
||||||
|
field_info.uniform_name
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
uniform_buffer_status
|
||||||
|
.queued_buffer_writes
|
||||||
|
.push(QueuedBufferWrite {
|
||||||
|
buffer: target_buffer,
|
||||||
|
offset: target_offset,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn copy_staging_buffer_to_final_buffers(
|
||||||
|
&mut self,
|
||||||
|
command_queue: &mut CommandQueue,
|
||||||
|
staging_buffer: RenderResource,
|
||||||
|
) {
|
||||||
|
for uniform_buffer_status in self.uniform_arrays.iter_mut() {
|
||||||
|
if let Some((_name, buffer_array_status)) = uniform_buffer_status {
|
||||||
|
let start = buffer_array_status.staging_buffer_offset;
|
||||||
|
for (i, queued_buffer_write) in buffer_array_status
|
||||||
|
.queued_buffer_writes
|
||||||
|
.drain(..)
|
||||||
|
.enumerate()
|
||||||
|
{
|
||||||
|
command_queue.copy_buffer_to_buffer(
|
||||||
|
staging_buffer,
|
||||||
|
(start + (i * buffer_array_status.item_size)) as u64,
|
||||||
|
queued_buffer_write.buffer,
|
||||||
|
queued_buffer_write.offset as u64,
|
||||||
|
buffer_array_status.item_size as u64,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct UniformNode<T>
|
||||||
|
where
|
||||||
|
T: AsUniforms,
|
||||||
|
{
|
||||||
|
command_queue: CommandQueue,
|
||||||
|
dynamic_uniforms: bool,
|
||||||
|
_marker: PhantomData<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> UniformNode<T>
|
||||||
|
where
|
||||||
|
T: AsUniforms,
|
||||||
|
{
|
||||||
|
pub fn new(dynamic_uniforms: bool) -> Self {
|
||||||
|
UniformNode {
|
||||||
|
command_queue: CommandQueue::default(),
|
||||||
|
dynamic_uniforms,
|
||||||
|
_marker: PhantomData::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn initialize_vertex_buffer_descriptor(
|
||||||
|
vertex_buffer_descriptors: &mut VertexBufferDescriptors,
|
||||||
|
) {
|
||||||
|
let vertex_buffer_descriptor = T::get_vertex_buffer_descriptor();
|
||||||
|
if let Some(vertex_buffer_descriptor) = vertex_buffer_descriptor {
|
||||||
|
if let None = vertex_buffer_descriptors.get(&vertex_buffer_descriptor.name) {
|
||||||
|
vertex_buffer_descriptors.set(vertex_buffer_descriptor.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn setup_uniform_texture_resources(
|
||||||
|
uniforms: &T,
|
||||||
|
texture_storage: &AssetStorage<Texture>,
|
||||||
|
render_resource_context: &dyn RenderResourceContext,
|
||||||
|
render_resource_assignments: &mut RenderResourceAssignments,
|
||||||
|
) {
|
||||||
|
for field_info in T::get_field_infos().iter() {
|
||||||
|
let bind_type = uniforms.get_field_bind_type(&field_info.name);
|
||||||
|
match bind_type {
|
||||||
|
Some(FieldBindType::Texture) => {
|
||||||
|
let texture_handle = uniforms
|
||||||
|
.get_uniform_texture(&field_info.texture_name)
|
||||||
|
.unwrap();
|
||||||
|
let (texture_resource, sampler_resource) = match render_resource_context
|
||||||
|
.get_asset_resource(texture_handle, texture::TEXTURE_ASSET_INDEX)
|
||||||
|
{
|
||||||
|
Some(texture_resource) => (
|
||||||
|
texture_resource,
|
||||||
|
render_resource_context
|
||||||
|
.get_asset_resource(texture_handle, texture::SAMPLER_ASSET_INDEX)
|
||||||
|
.unwrap(),
|
||||||
|
),
|
||||||
|
None => {
|
||||||
|
let texture = texture_storage.get(&texture_handle).unwrap();
|
||||||
|
|
||||||
|
let texture_descriptor: TextureDescriptor = texture.into();
|
||||||
|
let texture_resource =
|
||||||
|
render_resource_context.create_texture(&texture_descriptor);
|
||||||
|
// TODO: queue texture copy
|
||||||
|
// .create_texture_with_data(&texture_descriptor, &texture.data);
|
||||||
|
|
||||||
|
let sampler_descriptor: SamplerDescriptor = texture.into();
|
||||||
|
let sampler_resource =
|
||||||
|
render_resource_context.create_sampler(&sampler_descriptor);
|
||||||
|
|
||||||
|
render_resource_context.set_asset_resource(
|
||||||
|
texture_handle,
|
||||||
|
texture_resource,
|
||||||
|
0,
|
||||||
|
);
|
||||||
|
render_resource_context.set_asset_resource(
|
||||||
|
texture_handle,
|
||||||
|
sampler_resource,
|
||||||
|
1,
|
||||||
|
);
|
||||||
|
(texture_resource, sampler_resource)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
render_resource_assignments.set(field_info.texture_name, texture_resource);
|
||||||
|
render_resource_assignments.set(field_info.sampler_name, sampler_resource);
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Node for UniformNode<T>
|
||||||
|
where
|
||||||
|
T: AsUniforms,
|
||||||
|
{
|
||||||
|
fn update(
|
||||||
|
&mut self,
|
||||||
|
_world: &World,
|
||||||
|
_resources: &Resources,
|
||||||
|
render_context: &mut dyn RenderContext,
|
||||||
|
_input: &ResourceSlots,
|
||||||
|
_output: &mut ResourceSlots,
|
||||||
|
) {
|
||||||
|
self.command_queue.execute(render_context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> SystemNode for UniformNode<T>
|
||||||
|
where
|
||||||
|
T: AsUniforms,
|
||||||
|
{
|
||||||
|
fn get_system(&self, resources: &mut Resources) -> Box<dyn Schedulable> {
|
||||||
|
let mut command_queue = self.command_queue.clone();
|
||||||
|
let mut uniform_buffer_arrays = UniformBufferArrays::<T>::new();
|
||||||
|
let mut vertex_buffer_descriptors = resources.get_mut::<VertexBufferDescriptors>().unwrap();
|
||||||
|
let dynamic_uniforms = self.dynamic_uniforms;
|
||||||
|
let mut staging_buffer_resource = None;
|
||||||
|
UniformNode::<T>::initialize_vertex_buffer_descriptor(&mut vertex_buffer_descriptors);
|
||||||
|
// TODO: maybe run "update" here
|
||||||
|
SystemBuilder::new("uniform_resource_provider")
|
||||||
|
.read_resource::<AssetStorage<T>>()
|
||||||
|
.read_resource::<AssetStorage<Texture>>()
|
||||||
|
.read_resource::<GlobalRenderResourceContext>()
|
||||||
|
// TODO: this write on RenderResourceAssignments will prevent this system from running in parallel with other systems that do the same
|
||||||
|
.with_query(<(Read<T>, Read<Renderable>)>::query())
|
||||||
|
.with_query(<(Read<Handle<T>>, Read<Renderable>)>::query())
|
||||||
|
.with_query(<(Read<T>, Write<Renderable>)>::query())
|
||||||
|
.with_query(<(Read<Handle<T>>, Write<Renderable>)>::query())
|
||||||
|
.build(
|
||||||
|
move |_,
|
||||||
|
world,
|
||||||
|
(assets, textures, global_render_resource_context),
|
||||||
|
(
|
||||||
|
read_resource_query,
|
||||||
|
read_handle_query,
|
||||||
|
write_resource_query,
|
||||||
|
write_handle_query,
|
||||||
|
)| {
|
||||||
|
let render_resource_context = &*global_render_resource_context.context;
|
||||||
|
if let Some(staging_buffer_resource) = staging_buffer_resource {
|
||||||
|
render_resource_context.remove_buffer(staging_buffer_resource);
|
||||||
|
}
|
||||||
|
staging_buffer_resource = None;
|
||||||
|
|
||||||
|
uniform_buffer_arrays.reset_new_item_counts();
|
||||||
|
// update uniforms info
|
||||||
|
for (uniforms, renderable) in read_resource_query.iter(world) {
|
||||||
|
if !renderable.is_visible {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if renderable.is_instanced {
|
||||||
|
panic!("instancing not currently supported");
|
||||||
|
} else {
|
||||||
|
uniform_buffer_arrays.increment_uniform_counts(&uniforms);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// update uniform handles info
|
||||||
|
for (handle, renderable) in read_handle_query.iter(world) {
|
||||||
|
if !renderable.is_visible {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if renderable.is_instanced {
|
||||||
|
panic!("instancing not currently supported");
|
||||||
|
} else {
|
||||||
|
let uniforms = assets
|
||||||
|
.get(&handle)
|
||||||
|
.expect("Handle points to a non-existent resource");
|
||||||
|
// TODO: only increment count if we haven't seen this uniform handle before
|
||||||
|
uniform_buffer_arrays.increment_uniform_counts(&uniforms);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uniform_buffer_arrays
|
||||||
|
.setup_buffer_arrays(render_resource_context, dynamic_uniforms);
|
||||||
|
let staging_buffer_size = uniform_buffer_arrays.update_staging_buffer_offsets();
|
||||||
|
|
||||||
|
for (uniforms, mut renderable) in write_resource_query.iter_mut(world) {
|
||||||
|
if !renderable.is_visible {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if renderable.is_instanced {
|
||||||
|
panic!("instancing not currently supported");
|
||||||
|
} else {
|
||||||
|
Self::setup_uniform_texture_resources(
|
||||||
|
&uniforms,
|
||||||
|
textures,
|
||||||
|
render_resource_context,
|
||||||
|
&mut renderable.render_resource_assignments,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (handle, mut renderable) in write_handle_query.iter_mut(world) {
|
||||||
|
if !renderable.is_visible {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if renderable.is_instanced {
|
||||||
|
panic!("instancing not currently supported");
|
||||||
|
} else {
|
||||||
|
let uniforms = assets
|
||||||
|
.get(&handle)
|
||||||
|
.expect("Handle points to a non-existent resource");
|
||||||
|
Self::setup_uniform_texture_resources(
|
||||||
|
&uniforms,
|
||||||
|
textures,
|
||||||
|
render_resource_context,
|
||||||
|
&mut renderable.render_resource_assignments,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if staging_buffer_size == 0 {
|
||||||
|
let mut staging_buffer: [u8; 0] = [];
|
||||||
|
for (uniforms, mut renderable) in write_resource_query.iter_mut(world) {
|
||||||
|
if !renderable.is_visible {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if renderable.is_instanced {
|
||||||
|
panic!("instancing not currently supported");
|
||||||
|
} else {
|
||||||
|
uniform_buffer_arrays.setup_uniform_buffer_resources(
|
||||||
|
&uniforms,
|
||||||
|
dynamic_uniforms,
|
||||||
|
render_resource_context,
|
||||||
|
&mut renderable.render_resource_assignments,
|
||||||
|
&mut staging_buffer,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (handle, mut renderable) in write_handle_query.iter_mut(world) {
|
||||||
|
if !renderable.is_visible {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if renderable.is_instanced {
|
||||||
|
panic!("instancing not currently supported");
|
||||||
|
} else {
|
||||||
|
let uniforms = assets
|
||||||
|
.get(&handle)
|
||||||
|
.expect("Handle points to a non-existent resource");
|
||||||
|
// 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 renderable.render_resource_assignments,
|
||||||
|
&mut staging_buffer,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let staging_buffer = render_resource_context.create_buffer_mapped(
|
||||||
|
BufferInfo {
|
||||||
|
buffer_usage: BufferUsage::COPY_SRC,
|
||||||
|
size: staging_buffer_size,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
&mut |mut staging_buffer, _render_resources| {
|
||||||
|
for (uniforms, mut renderable) in
|
||||||
|
write_resource_query.iter_mut(world)
|
||||||
|
{
|
||||||
|
if !renderable.is_visible {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if renderable.is_instanced {
|
||||||
|
panic!("instancing not currently supported");
|
||||||
|
} else {
|
||||||
|
uniform_buffer_arrays.setup_uniform_buffer_resources(
|
||||||
|
&uniforms,
|
||||||
|
dynamic_uniforms,
|
||||||
|
render_resource_context,
|
||||||
|
&mut renderable.render_resource_assignments,
|
||||||
|
&mut staging_buffer,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (handle, mut renderable) in write_handle_query.iter_mut(world) {
|
||||||
|
if !renderable.is_visible {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if renderable.is_instanced {
|
||||||
|
panic!("instancing not currently supported");
|
||||||
|
} else {
|
||||||
|
let uniforms = assets
|
||||||
|
.get(&handle)
|
||||||
|
.expect("Handle points to a non-existent resource");
|
||||||
|
// 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 renderable.render_resource_assignments,
|
||||||
|
&mut staging_buffer,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
uniform_buffer_arrays.copy_staging_buffer_to_final_buffers(
|
||||||
|
&mut command_queue,
|
||||||
|
staging_buffer,
|
||||||
|
);
|
||||||
|
|
||||||
|
staging_buffer_resource = Some(staging_buffer);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
|
@ -30,6 +30,7 @@ pub trait RenderResourceContext: Downcast + Send + Sync + 'static {
|
||||||
fn create_sampler(&self, sampler_descriptor: &SamplerDescriptor) -> RenderResource;
|
fn create_sampler(&self, sampler_descriptor: &SamplerDescriptor) -> RenderResource;
|
||||||
fn create_texture(&self, texture_descriptor: &TextureDescriptor) -> RenderResource;
|
fn create_texture(&self, texture_descriptor: &TextureDescriptor) -> RenderResource;
|
||||||
fn create_buffer(&self, buffer_info: BufferInfo) -> RenderResource;
|
fn create_buffer(&self, buffer_info: BufferInfo) -> RenderResource;
|
||||||
|
// TODO: remove RenderResourceContext here
|
||||||
fn create_buffer_mapped(
|
fn create_buffer_mapped(
|
||||||
&self,
|
&self,
|
||||||
buffer_info: BufferInfo,
|
buffer_info: BufferInfo,
|
||||||
|
|
|
@ -10,7 +10,7 @@ use bevy_asset::{AssetStorage, Handle};
|
||||||
use bevy_core::bytes::GetBytes;
|
use bevy_core::bytes::GetBytes;
|
||||||
use legion::prelude::*;
|
use legion::prelude::*;
|
||||||
|
|
||||||
pub trait AsUniforms {
|
pub trait AsUniforms: Send + Sync + 'static {
|
||||||
fn get_field_infos() -> &'static [FieldInfo];
|
fn get_field_infos() -> &'static [FieldInfo];
|
||||||
fn get_uniform_bytes(&self, name: &str) -> Option<Vec<u8>>;
|
fn get_uniform_bytes(&self, name: &str) -> Option<Vec<u8>>;
|
||||||
fn get_uniform_texture(&self, name: &str) -> Option<Handle<Texture>>;
|
fn get_uniform_texture(&self, name: &str) -> Option<Handle<Texture>>;
|
||||||
|
|
|
@ -187,19 +187,20 @@ impl WgpuRenderer {
|
||||||
|
|
||||||
pub fn run_graph(&mut self, world: &mut World, resources: &mut Resources) {
|
pub fn run_graph(&mut self, world: &mut World, resources: &mut Resources) {
|
||||||
// run systems
|
// run systems
|
||||||
let mut executor = {
|
let mut system_executor = {
|
||||||
let mut render_graph = resources.get_mut::<RenderGraph2>().unwrap();
|
let mut render_graph = resources.get_mut::<RenderGraph2>().unwrap();
|
||||||
render_graph.take_executor()
|
render_graph.take_executor()
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(executor) = executor.as_mut() {
|
if let Some(executor) = system_executor.as_mut() {
|
||||||
executor.execute(world, resources);
|
executor.execute(world, resources);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
update_shader_assignments(world, resources);
|
||||||
render_resource_sets_system().run(world, resources);
|
render_resource_sets_system().run(world, resources);
|
||||||
|
|
||||||
let mut render_graph = resources.get_mut::<RenderGraph2>().unwrap();
|
let mut render_graph = resources.get_mut::<RenderGraph2>().unwrap();
|
||||||
if let Some(executor) = executor.take() {
|
if let Some(executor) = system_executor.take() {
|
||||||
render_graph.set_executor(executor);
|
render_graph.set_executor(executor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -207,12 +208,12 @@ impl WgpuRenderer {
|
||||||
let mut stager = DependentNodeStager::loose_grouping();
|
let mut stager = DependentNodeStager::loose_grouping();
|
||||||
let stages = stager.get_stages(&render_graph).unwrap();
|
let stages = stager.get_stages(&render_graph).unwrap();
|
||||||
let mut borrowed = stages.borrow(&mut render_graph);
|
let mut borrowed = stages.borrow(&mut render_graph);
|
||||||
|
|
||||||
// execute stages
|
// execute stages
|
||||||
let executor = WgpuRenderGraphExecutor {
|
let graph_executor = WgpuRenderGraphExecutor {
|
||||||
max_thread_count: 2,
|
max_thread_count: 2,
|
||||||
};
|
};
|
||||||
executor.execute(
|
graph_executor.execute(
|
||||||
world,
|
world,
|
||||||
resources,
|
resources,
|
||||||
self.device.clone(),
|
self.device.clone(),
|
||||||
|
@ -244,7 +245,6 @@ impl WgpuRenderer {
|
||||||
|
|
||||||
self.update_resource_providers(world, resources, render_resource_context);
|
self.update_resource_providers(world, resources, render_resource_context);
|
||||||
|
|
||||||
update_shader_assignments(world, resources, &render_context);
|
|
||||||
self.create_queued_textures(resources, &mut render_context.render_resources);
|
self.create_queued_textures(resources, &mut render_context.render_resources);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue