mirror of
https://github.com/bevyengine/bevy
synced 2024-11-10 15:14:50 +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 pipeline::pipelines::build_forward_pipeline;
|
||||
use render_graph_2::{
|
||||
nodes::{Camera2dNode, CameraNode, PassNode, WindowSwapChainNode, WindowTextureNode},
|
||||
nodes::{Camera2dNode, CameraNode, PassNode, WindowSwapChainNode, WindowTextureNode, UniformNode},
|
||||
RenderGraph2,
|
||||
};
|
||||
use render_resource::resource_providers::mesh_resource_provider_system;
|
||||
|
@ -78,7 +78,6 @@ impl RenderPlugin {
|
|||
render_graph
|
||||
.build(&mut pipelines, &mut shaders)
|
||||
.add_resource_provider(LightResourceProvider::new(10))
|
||||
.add_resource_provider(UniformResourceProvider::<StandardMaterial>::new(true))
|
||||
.add_resource_provider(UniformResourceProvider::<LocalToWorld>::new(true));
|
||||
}
|
||||
}
|
||||
|
@ -124,6 +123,7 @@ impl AppPlugin for RenderPlugin {
|
|||
let resources = app.resources_mut();
|
||||
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("standard_material", UniformNode::<StandardMaterial>::new(true), resources);
|
||||
render_graph.add_node_named(
|
||||
"swapchain",
|
||||
WindowSwapChainNode::new(
|
||||
|
@ -185,6 +185,7 @@ impl AppPlugin for RenderPlugin {
|
|||
// TODO: replace these with "autowire" groups
|
||||
render_graph.add_node_edge("camera", "main_pass").unwrap();
|
||||
render_graph.add_node_edge("camera2d", "main_pass").unwrap();
|
||||
render_graph.add_node_edge("standard_material", "main_pass").unwrap();
|
||||
render_graph
|
||||
.add_slot_edge(
|
||||
"swapchain",
|
||||
|
|
|
@ -6,7 +6,7 @@ use crate::{
|
|||
render_resource::{
|
||||
BufferInfo, RenderResourceAssignments, RenderResourceAssignmentsId, ResourceInfo,
|
||||
},
|
||||
renderer_2::RenderContext,
|
||||
renderer_2::{RenderResourceContext, GlobalRenderResourceContext},
|
||||
shader::{Shader, ShaderSource},
|
||||
Renderable,
|
||||
};
|
||||
|
@ -48,7 +48,7 @@ impl PipelineCompiler {
|
|||
shader_storage: &AssetStorage<Shader>,
|
||||
vertex_buffer_descriptors: &VertexBufferDescriptors,
|
||||
pipeline_descriptor: &mut PipelineDescriptor,
|
||||
render_context: &dyn RenderContext,
|
||||
render_resource_context: &dyn RenderResourceContext,
|
||||
render_resource_assignments: &RenderResourceAssignments,
|
||||
) {
|
||||
let vertex_spirv = shader_storage
|
||||
|
@ -75,7 +75,7 @@ impl PipelineCompiler {
|
|||
for bind_group in layout.bind_groups.iter_mut() {
|
||||
for binding in bind_group.bindings.iter_mut() {
|
||||
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,
|
||||
&mut |resource_info| {
|
||||
if let Some(ResourceInfo::Buffer(BufferInfo { is_dynamic, .. })) =
|
||||
|
@ -142,7 +142,7 @@ impl PipelineCompiler {
|
|||
&mut self,
|
||||
vertex_buffer_descriptors: &VertexBufferDescriptors,
|
||||
shader_storage: &mut AssetStorage<Shader>,
|
||||
render_context: &dyn RenderContext,
|
||||
render_resource_context: &dyn RenderResourceContext,
|
||||
pipeline_descriptor: &PipelineDescriptor,
|
||||
render_resource_assignments: &RenderResourceAssignments,
|
||||
) -> PipelineDescriptor {
|
||||
|
@ -173,7 +173,7 @@ impl PipelineCompiler {
|
|||
shader_storage,
|
||||
vertex_buffer_descriptors,
|
||||
&mut compiled_pipeline_descriptor,
|
||||
render_context,
|
||||
render_resource_context,
|
||||
render_resource_assignments,
|
||||
);
|
||||
|
||||
|
@ -187,7 +187,7 @@ impl PipelineCompiler {
|
|||
&mut self,
|
||||
vertex_buffer_descriptors: &VertexBufferDescriptors,
|
||||
shader_pipeline_assignments: &mut PipelineAssignments,
|
||||
render_context: &dyn RenderContext,
|
||||
render_resource_context: &dyn RenderResourceContext,
|
||||
pipeline_storage: &mut AssetStorage<PipelineDescriptor>,
|
||||
shader_storage: &mut AssetStorage<Shader>,
|
||||
pipelines: &[Handle<PipelineDescriptor>],
|
||||
|
@ -213,7 +213,7 @@ impl PipelineCompiler {
|
|||
let compiled_pipeline = self.compile_pipeline(
|
||||
vertex_buffer_descriptors,
|
||||
shader_storage,
|
||||
render_context,
|
||||
render_resource_context,
|
||||
pipeline_descriptor,
|
||||
render_resource_assignments,
|
||||
);
|
||||
|
@ -286,7 +286,6 @@ impl PipelineAssignments {
|
|||
pub fn update_shader_assignments(
|
||||
world: &mut World,
|
||||
resources: &Resources,
|
||||
render_context: &dyn RenderContext,
|
||||
) {
|
||||
// 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
|
||||
|
@ -295,6 +294,7 @@ pub fn update_shader_assignments(
|
|||
let mut pipeline_compiler = resources.get_mut::<PipelineCompiler>().unwrap();
|
||||
let mut shader_storage = resources.get_mut::<AssetStorage<Shader>>().unwrap();
|
||||
let vertex_buffer_descriptors = resources.get::<VertexBufferDescriptors>().unwrap();
|
||||
let global_render_resource_context = resources.get::<GlobalRenderResourceContext>().unwrap();
|
||||
let mut pipeline_descriptor_storage = resources
|
||||
.get_mut::<AssetStorage<PipelineDescriptor>>()
|
||||
.unwrap();
|
||||
|
@ -312,7 +312,7 @@ pub fn update_shader_assignments(
|
|||
pipeline_compiler.update_shader_assignments(
|
||||
&vertex_buffer_descriptors,
|
||||
&mut shader_pipeline_assignments,
|
||||
render_context,
|
||||
&*global_render_resource_context.context,
|
||||
&mut pipeline_descriptor_storage,
|
||||
&mut shader_storage,
|
||||
&renderable.pipelines,
|
||||
|
|
|
@ -3,9 +3,11 @@ mod camera2d_node;
|
|||
mod window_texture_node;
|
||||
mod window_swapchain_node;
|
||||
mod pass_node;
|
||||
mod uniform_node;
|
||||
|
||||
pub use camera_node::*;
|
||||
pub use camera2d_node::*;
|
||||
pub use window_texture_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_texture(&self, texture_descriptor: &TextureDescriptor) -> RenderResource;
|
||||
fn create_buffer(&self, buffer_info: BufferInfo) -> RenderResource;
|
||||
// TODO: remove RenderResourceContext here
|
||||
fn create_buffer_mapped(
|
||||
&self,
|
||||
buffer_info: BufferInfo,
|
||||
|
|
|
@ -10,7 +10,7 @@ use bevy_asset::{AssetStorage, Handle};
|
|||
use bevy_core::bytes::GetBytes;
|
||||
use legion::prelude::*;
|
||||
|
||||
pub trait AsUniforms {
|
||||
pub trait AsUniforms: Send + Sync + 'static {
|
||||
fn get_field_infos() -> &'static [FieldInfo];
|
||||
fn get_uniform_bytes(&self, name: &str) -> Option<Vec<u8>>;
|
||||
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) {
|
||||
// run systems
|
||||
let mut executor = {
|
||||
let mut system_executor = {
|
||||
let mut render_graph = resources.get_mut::<RenderGraph2>().unwrap();
|
||||
render_graph.take_executor()
|
||||
};
|
||||
|
||||
if let Some(executor) = executor.as_mut() {
|
||||
if let Some(executor) = system_executor.as_mut() {
|
||||
executor.execute(world, resources);
|
||||
}
|
||||
|
||||
update_shader_assignments(world, resources);
|
||||
render_resource_sets_system().run(world, resources);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -207,12 +208,12 @@ impl WgpuRenderer {
|
|||
let mut stager = DependentNodeStager::loose_grouping();
|
||||
let stages = stager.get_stages(&render_graph).unwrap();
|
||||
let mut borrowed = stages.borrow(&mut render_graph);
|
||||
|
||||
|
||||
// execute stages
|
||||
let executor = WgpuRenderGraphExecutor {
|
||||
let graph_executor = WgpuRenderGraphExecutor {
|
||||
max_thread_count: 2,
|
||||
};
|
||||
executor.execute(
|
||||
graph_executor.execute(
|
||||
world,
|
||||
resources,
|
||||
self.device.clone(),
|
||||
|
@ -244,7 +245,6 @@ impl WgpuRenderer {
|
|||
|
||||
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);
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in a new issue