mirror of
https://github.com/bevyengine/bevy
synced 2024-11-10 15:14:50 +00:00
finish new uniform resource provider staging buffer. dynamic uniforms work again. both dynamic and non-dynamic uniforms perform better than the previous implementation.
This commit is contained in:
parent
c71b886165
commit
4d17763c85
15 changed files with 620 additions and 1094 deletions
|
@ -199,8 +199,8 @@ impl AppBuilder {
|
|||
.add_resource_provider(LightResourceProvider::new(10))
|
||||
.add_resource_provider(UiResourceProvider::new())
|
||||
.add_resource_provider(MeshResourceProvider::new())
|
||||
.add_resource_provider(UniformResourceProviderNew::<StandardMaterial>::new(false))
|
||||
.add_resource_provider(UniformResourceProviderNew::<LocalToWorld>::new(false))
|
||||
.add_resource_provider(UniformResourceProvider::<StandardMaterial>::new(true))
|
||||
.add_resource_provider(UniformResourceProvider::<LocalToWorld>::new(true))
|
||||
.add_forward_pass()
|
||||
.add_forward_pipeline()
|
||||
.add_ui_pipeline();
|
||||
|
|
|
@ -4,21 +4,39 @@ use std::collections::HashMap;
|
|||
|
||||
#[derive(Default)]
|
||||
pub struct BufferArrayInfo {
|
||||
pub item_count: u64,
|
||||
pub item_size: u64,
|
||||
pub item_capacity: u64,
|
||||
pub item_count: usize,
|
||||
pub item_size: usize,
|
||||
pub item_capacity: usize,
|
||||
pub indices: HashMap<RenderResourceAssignmentsId, usize>,
|
||||
pub current_index: usize,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct BufferDynamicUniformInfo {
|
||||
pub offsets: HashMap<RenderResourceAssignmentsId, u32>,
|
||||
impl BufferArrayInfo {
|
||||
pub fn get_index(&self, id: RenderResourceAssignmentsId) -> Option<usize> {
|
||||
self.indices.get(&id).map(|offset| *offset)
|
||||
}
|
||||
|
||||
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.item_capacity {
|
||||
panic!("no empty slots available in array");
|
||||
}
|
||||
|
||||
let index = self.current_index;
|
||||
self.indices.insert(id, index);
|
||||
self.current_index += 1;
|
||||
index
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct BufferInfo {
|
||||
pub size: u64,
|
||||
pub size: usize,
|
||||
pub buffer_usage: BufferUsage,
|
||||
pub array_info: Option<BufferArrayInfo>,
|
||||
pub dynamic_uniform_info: Option<BufferDynamicUniformInfo>,
|
||||
pub is_dynamic: bool,
|
||||
}
|
||||
|
||||
impl Default for BufferInfo {
|
||||
|
@ -27,7 +45,7 @@ impl Default for BufferInfo {
|
|||
size: 0,
|
||||
buffer_usage: BufferUsage::NONE,
|
||||
array_info: None,
|
||||
dynamic_uniform_info: None,
|
||||
is_dynamic: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@ impl ResourceProvider for Camera2dResourceProvider {
|
|||
_resources: &Resources,
|
||||
) {
|
||||
let buffer = renderer.create_buffer(BufferInfo {
|
||||
size: std::mem::size_of::<[[f32; 4]; 4]>() as u64,
|
||||
size: std::mem::size_of::<[[f32; 4]; 4]>(),
|
||||
buffer_usage: BufferUsage::COPY_DST | BufferUsage::UNIFORM,
|
||||
..Default::default()
|
||||
});
|
||||
|
@ -50,11 +50,11 @@ impl ResourceProvider for Camera2dResourceProvider {
|
|||
|
||||
self.tmp_buffer = Some(renderer.create_buffer_mapped(
|
||||
BufferInfo {
|
||||
size: matrix_size as u64,
|
||||
size: matrix_size,
|
||||
buffer_usage: BufferUsage::COPY_SRC,
|
||||
..Default::default()
|
||||
},
|
||||
&mut |data| {
|
||||
&mut |data, _renderer| {
|
||||
data[0..matrix_size].copy_from_slice(camera_matrix.as_bytes());
|
||||
},
|
||||
));
|
||||
|
|
|
@ -21,7 +21,7 @@ impl ResourceProvider for CameraResourceProvider {
|
|||
_resources: &Resources,
|
||||
) {
|
||||
let buffer = renderer.create_buffer(BufferInfo {
|
||||
size: std::mem::size_of::<[[f32; 4]; 4]>() as u64,
|
||||
size: std::mem::size_of::<[[f32; 4]; 4]>(),
|
||||
buffer_usage: BufferUsage::COPY_DST | BufferUsage::UNIFORM,
|
||||
..Default::default()
|
||||
});
|
||||
|
@ -54,11 +54,11 @@ impl ResourceProvider for CameraResourceProvider {
|
|||
|
||||
self.tmp_buffer = Some(renderer.create_buffer_mapped(
|
||||
BufferInfo {
|
||||
size: matrix_size as u64,
|
||||
size: matrix_size,
|
||||
buffer_usage: BufferUsage::COPY_SRC,
|
||||
..Default::default()
|
||||
},
|
||||
&mut |data| {
|
||||
&mut |data, _renderer| {
|
||||
data[0..matrix_size].copy_from_slice(camera_matrix.as_bytes());
|
||||
},
|
||||
));
|
||||
|
|
|
@ -40,9 +40,8 @@ impl ResourceProvider for LightResourceProvider {
|
|||
_world: &mut World,
|
||||
_resources: &Resources,
|
||||
) {
|
||||
let light_uniform_size = (std::mem::size_of::<LightCount>()
|
||||
+ self.max_lights * std::mem::size_of::<LightRaw>())
|
||||
as u64;
|
||||
let light_uniform_size =
|
||||
std::mem::size_of::<LightCount>() + self.max_lights * std::mem::size_of::<LightRaw>();
|
||||
|
||||
let buffer = renderer.create_buffer(BufferInfo {
|
||||
size: light_uniform_size,
|
||||
|
@ -79,11 +78,11 @@ impl ResourceProvider for LightResourceProvider {
|
|||
|
||||
self.tmp_light_buffer = Some(renderer.create_buffer_mapped(
|
||||
BufferInfo {
|
||||
size: total_size as u64,
|
||||
size: total_size,
|
||||
buffer_usage: BufferUsage::COPY_SRC,
|
||||
..Default::default()
|
||||
},
|
||||
&mut |data| {
|
||||
&mut |data, _renderer| {
|
||||
for ((light, local_to_world, translation), slot) in
|
||||
light_query.iter(world).zip(data.chunks_exact_mut(size))
|
||||
{
|
||||
|
@ -95,11 +94,11 @@ impl ResourceProvider for LightResourceProvider {
|
|||
));
|
||||
self.tmp_count_buffer = Some(renderer.create_buffer_mapped(
|
||||
BufferInfo {
|
||||
size: light_count_size as u64,
|
||||
size: light_count_size,
|
||||
buffer_usage: BufferUsage::COPY_SRC,
|
||||
..Default::default()
|
||||
},
|
||||
&mut |data| {
|
||||
&mut |data, _renderer| {
|
||||
data.copy_from_slice([light_count as u32, 0, 0, 0].as_bytes());
|
||||
},
|
||||
));
|
||||
|
|
|
@ -5,7 +5,6 @@ mod light_resource_provider;
|
|||
mod mesh_resource_provider;
|
||||
mod ui_resource_provider;
|
||||
mod uniform_resource_provider;
|
||||
mod uniform_resource_provider_new;
|
||||
|
||||
pub use camera2d_resource_provider::*;
|
||||
pub use camera_resource_provider::*;
|
||||
|
@ -14,4 +13,3 @@ pub use light_resource_provider::*;
|
|||
pub use mesh_resource_provider::*;
|
||||
pub use ui_resource_provider::*;
|
||||
pub use uniform_resource_provider::*;
|
||||
pub use uniform_resource_provider_new::*;
|
||||
|
|
|
@ -77,8 +77,8 @@ impl UiResourceProvider {
|
|||
return;
|
||||
}
|
||||
|
||||
let size = std::mem::size_of::<Rect>() as u64;
|
||||
let data_len = data.len() as u64;
|
||||
let size = std::mem::size_of::<Rect>();
|
||||
let data_len = data.len();
|
||||
|
||||
if let Some(old_instance_buffer) = self.instance_buffer {
|
||||
renderer.remove_buffer(old_instance_buffer);
|
||||
|
@ -92,6 +92,7 @@ impl UiResourceProvider {
|
|||
item_capacity: data_len,
|
||||
item_count: data_len,
|
||||
item_size: size,
|
||||
..Default::default()
|
||||
}),
|
||||
..Default::default()
|
||||
},
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,589 +0,0 @@
|
|||
use crate::{
|
||||
asset::{AssetStorage, Handle},
|
||||
render::{
|
||||
render_graph::RenderGraph,
|
||||
render_resource::{
|
||||
AssetBatchers, BufferArrayInfo, BufferDynamicUniformInfo, BufferInfo, BufferUsage,
|
||||
RenderResource, RenderResourceAssignments, RenderResourceAssignmentsProvider,
|
||||
ResourceInfo, ResourceProvider,
|
||||
},
|
||||
renderer::Renderer,
|
||||
shader::{AsUniforms, FieldBindType},
|
||||
texture::{SamplerDescriptor, Texture, TextureDescriptor},
|
||||
Renderable,
|
||||
},
|
||||
};
|
||||
use legion::{filter::*, prelude::*};
|
||||
use std::marker::PhantomData;
|
||||
pub const BIND_BUFFER_ALIGNMENT: u64 = 256;
|
||||
|
||||
#[derive(Debug)]
|
||||
struct BufferArrayStatus {
|
||||
new_item_count: usize,
|
||||
item_size: usize,
|
||||
staging_buffer_offset: usize,
|
||||
buffer: Option<RenderResource>,
|
||||
}
|
||||
|
||||
pub struct UniformResourceProviderNew<T>
|
||||
where
|
||||
T: AsUniforms + Send + Sync + 'static,
|
||||
{
|
||||
_marker: PhantomData<T>,
|
||||
use_dynamic_uniforms: bool,
|
||||
is_instanceable: bool,
|
||||
// PERF: somehow remove this HashSet
|
||||
dynamic_uniform_buffer_status: Vec<Option<(String, BufferArrayStatus)>>,
|
||||
instance_buffer_status: Option<BufferArrayStatus>,
|
||||
query: Option<
|
||||
Query<
|
||||
(Read<T>, Write<Renderable>),
|
||||
EntityFilterTuple<
|
||||
And<(ComponentFilter<T>, ComponentFilter<Renderable>)>,
|
||||
And<(Passthrough, Passthrough)>,
|
||||
And<(Passthrough, Passthrough)>,
|
||||
>,
|
||||
>,
|
||||
>,
|
||||
query_finish: Option<
|
||||
Query<
|
||||
(Read<T>, Write<Renderable>),
|
||||
EntityFilterTuple<
|
||||
And<(ComponentFilter<T>, ComponentFilter<Renderable>)>,
|
||||
And<(Passthrough, Passthrough)>,
|
||||
And<(Passthrough, Passthrough)>,
|
||||
>,
|
||||
>,
|
||||
>,
|
||||
handle_query: Option<
|
||||
Query<
|
||||
(Read<Handle<T>>, Write<Renderable>),
|
||||
EntityFilterTuple<
|
||||
And<(ComponentFilter<Handle<T>>, ComponentFilter<Renderable>)>,
|
||||
And<(Passthrough, Passthrough)>,
|
||||
And<(Passthrough, Passthrough)>,
|
||||
>,
|
||||
>,
|
||||
>,
|
||||
handle_query_finish: Option<
|
||||
Query<
|
||||
(Read<Handle<T>>, Write<Renderable>),
|
||||
EntityFilterTuple<
|
||||
And<(ComponentFilter<Handle<T>>, ComponentFilter<Renderable>)>,
|
||||
And<(Passthrough, Passthrough)>,
|
||||
And<(Passthrough, Passthrough)>,
|
||||
>,
|
||||
>,
|
||||
>,
|
||||
}
|
||||
|
||||
impl<T> UniformResourceProviderNew<T>
|
||||
where
|
||||
T: AsUniforms + Send + Sync + 'static,
|
||||
{
|
||||
pub fn new(use_dynamic_uniforms: bool) -> Self {
|
||||
let mut dynamic_uniform_buffer_status = Vec::new();
|
||||
let field_infos = T::get_field_infos();
|
||||
dynamic_uniform_buffer_status.resize_with(field_infos.len(), || None);
|
||||
let is_instanceable = field_infos.iter().find(|f| f.is_instanceable).is_some();
|
||||
UniformResourceProviderNew {
|
||||
dynamic_uniform_buffer_status,
|
||||
use_dynamic_uniforms,
|
||||
instance_buffer_status: None,
|
||||
is_instanceable,
|
||||
query: Some(<(Read<T>, Write<Renderable>)>::query()),
|
||||
query_finish: Some(<(Read<T>, Write<Renderable>)>::query()),
|
||||
handle_query: Some(<(Read<Handle<T>>, Write<Renderable>)>::query()),
|
||||
handle_query_finish: Some(<(Read<Handle<T>>, Write<Renderable>)>::query()),
|
||||
_marker: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
fn reset_buffer_array_status_counts(&mut self) {
|
||||
for buffer_status in self.dynamic_uniform_buffer_status.iter_mut() {
|
||||
if let Some((_name, buffer_status)) = buffer_status {
|
||||
buffer_status.new_item_count = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(ref mut buffer_status) = self.instance_buffer_status {
|
||||
buffer_status.new_item_count = 0;
|
||||
}
|
||||
}
|
||||
|
||||
fn update_uniforms_info(&mut self, world: &mut World) {
|
||||
if !self.use_dynamic_uniforms {
|
||||
return;
|
||||
}
|
||||
|
||||
let query = self.query.take().unwrap();
|
||||
for (uniforms, mut renderable) in query.iter_mut(world) {
|
||||
if !renderable.is_visible {
|
||||
return;
|
||||
}
|
||||
|
||||
if renderable.is_instanced {
|
||||
if self.is_instanceable {
|
||||
self.increment_instance_count(|| Self::get_instance_size(&uniforms));
|
||||
} else {
|
||||
panic!(
|
||||
"Cannot instance uniforms of type {}",
|
||||
std::any::type_name::<T>()
|
||||
);
|
||||
}
|
||||
} else if self.use_dynamic_uniforms {
|
||||
self.increment_dynamic_uniform_counts(&uniforms);
|
||||
}
|
||||
|
||||
Self::update_shader_defs(
|
||||
&uniforms,
|
||||
renderable.render_resource_assignments.as_mut().unwrap(),
|
||||
);
|
||||
}
|
||||
|
||||
self.query = Some(query);
|
||||
}
|
||||
|
||||
fn update_handles_info(&mut self, world: &mut World, resources: &Resources) {
|
||||
let handle_query = self.handle_query.take().unwrap();
|
||||
let assets = resources.get::<AssetStorage<T>>();
|
||||
let mut asset_batchers = resources.get_mut::<AssetBatchers>().unwrap();
|
||||
if let Some(assets) = assets {
|
||||
for (entity, (handle, mut renderable)) in handle_query.iter_entities_mut(world) {
|
||||
if !renderable.is_visible {
|
||||
return;
|
||||
}
|
||||
|
||||
if renderable.is_instanced {
|
||||
if self.is_instanceable {
|
||||
asset_batchers.set_entity_handle(entity, *handle);
|
||||
self.increment_instance_count(|| {
|
||||
let uniforms = assets.get(&handle).unwrap();
|
||||
Self::get_instance_size(uniforms)
|
||||
});
|
||||
} else {
|
||||
panic!(
|
||||
"Cannot instance uniforms of type Handle<{}>",
|
||||
std::any::type_name::<T>()
|
||||
);
|
||||
}
|
||||
} else {
|
||||
let uniforms = assets
|
||||
.get(&handle)
|
||||
.expect("Handle points to a non-existent resource");
|
||||
Self::update_shader_defs(
|
||||
uniforms,
|
||||
renderable.render_resource_assignments.as_mut().unwrap(),
|
||||
);
|
||||
if self.use_dynamic_uniforms {
|
||||
self.increment_dynamic_uniform_counts(&uniforms);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.handle_query = Some(handle_query);
|
||||
}
|
||||
|
||||
fn increment_instance_count(&mut self, f: impl Fn() -> usize) {
|
||||
if let Some(ref mut buffer_array_status) = self.instance_buffer_status {
|
||||
buffer_array_status.new_item_count += 1;
|
||||
} else {
|
||||
self.instance_buffer_status = Some(BufferArrayStatus {
|
||||
new_item_count: 1,
|
||||
item_size: f(),
|
||||
staging_buffer_offset: 0,
|
||||
buffer: None,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn get_instance_size(uniforms: &T) -> usize {
|
||||
let mut instance_buffer_size = 0;
|
||||
for field_info in T::get_field_infos().iter() {
|
||||
if field_info.is_instanceable {
|
||||
if let Some(FieldBindType::Uniform { size }) =
|
||||
uniforms.get_field_bind_type(field_info.name)
|
||||
{
|
||||
instance_buffer_size += size;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
instance_buffer_size
|
||||
}
|
||||
|
||||
fn increment_dynamic_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.dynamic_uniform_buffer_status[i]
|
||||
{
|
||||
buffer_array_status.new_item_count += 1;
|
||||
} else {
|
||||
self.dynamic_uniform_buffer_status[i] = Some((
|
||||
field_info.uniform_name.to_string(),
|
||||
BufferArrayStatus {
|
||||
new_item_count: 1,
|
||||
item_size: size,
|
||||
staging_buffer_offset: 0,
|
||||
buffer: None,
|
||||
},
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn update_shader_defs(
|
||||
uniforms: &T,
|
||||
render_resource_assignments: &mut RenderResourceAssignments,
|
||||
) {
|
||||
if let Some(shader_defs) = uniforms.get_shader_defs() {
|
||||
for shader_def in shader_defs {
|
||||
render_resource_assignments.shader_defs.insert(shader_def);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn setup_uniform_resources(
|
||||
&mut self,
|
||||
uniforms: &T,
|
||||
renderer: &mut dyn Renderer,
|
||||
resources: &Resources,
|
||||
render_resource_assignments: &mut RenderResourceAssignments,
|
||||
) {
|
||||
for field_info in T::get_field_infos() {
|
||||
let bind_type = uniforms.get_field_bind_type(&field_info.name);
|
||||
match bind_type {
|
||||
Some(FieldBindType::Uniform { size }) => {
|
||||
if self.use_dynamic_uniforms {
|
||||
} else {
|
||||
let buffer_resource = match render_resource_assignments
|
||||
.get(field_info.uniform_name)
|
||||
{
|
||||
Some(render_resource) => render_resource,
|
||||
None => {
|
||||
let resource = renderer.create_buffer(BufferInfo {
|
||||
size: size as u64,
|
||||
buffer_usage: BufferUsage::COPY_DST | BufferUsage::UNIFORM,
|
||||
..Default::default()
|
||||
});
|
||||
render_resource_assignments.set(&field_info.uniform_name, resource);
|
||||
resource
|
||||
}
|
||||
};
|
||||
|
||||
let (tmp_buffer, tmp_buffer_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);
|
||||
}
|
||||
|
||||
(
|
||||
renderer.create_buffer_mapped(
|
||||
BufferInfo {
|
||||
size: uniform_bytes.len() as u64,
|
||||
buffer_usage: BufferUsage::COPY_SRC,
|
||||
..Default::default()
|
||||
},
|
||||
&mut |mapped| {
|
||||
mapped.copy_from_slice(uniform_bytes);
|
||||
},
|
||||
),
|
||||
uniform_bytes.len(),
|
||||
)
|
||||
} 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);
|
||||
}
|
||||
|
||||
(
|
||||
renderer.create_buffer_mapped(
|
||||
BufferInfo {
|
||||
size: uniform_bytes.len() as u64,
|
||||
buffer_usage: BufferUsage::COPY_SRC,
|
||||
..Default::default()
|
||||
},
|
||||
&mut |mapped| {
|
||||
mapped.copy_from_slice(&uniform_bytes);
|
||||
},
|
||||
),
|
||||
uniform_bytes.len(),
|
||||
)
|
||||
} else {
|
||||
panic!(
|
||||
"failed to get data from uniform: {}",
|
||||
field_info.uniform_name
|
||||
);
|
||||
};
|
||||
|
||||
renderer.copy_buffer_to_buffer(
|
||||
tmp_buffer,
|
||||
0,
|
||||
buffer_resource,
|
||||
0,
|
||||
tmp_buffer_size as u64,
|
||||
);
|
||||
|
||||
renderer.remove_buffer(tmp_buffer);
|
||||
}
|
||||
}
|
||||
Some(FieldBindType::Texture) => {
|
||||
let texture_handle = uniforms
|
||||
.get_uniform_texture(&field_info.texture_name)
|
||||
.unwrap();
|
||||
let (texture_resource, sampler_resource) = match renderer
|
||||
.get_render_resources()
|
||||
.get_texture_resource(texture_handle)
|
||||
{
|
||||
Some(texture_resource) => (
|
||||
texture_resource,
|
||||
renderer
|
||||
.get_render_resources()
|
||||
.get_texture_sampler_resource(texture_handle)
|
||||
.unwrap(),
|
||||
),
|
||||
None => {
|
||||
let storage = resources.get::<AssetStorage<Texture>>().unwrap();
|
||||
let texture = storage.get(&texture_handle).unwrap();
|
||||
|
||||
let texture_descriptor: TextureDescriptor = texture.into();
|
||||
let texture_resource =
|
||||
renderer.create_texture(&texture_descriptor, Some(&texture.data));
|
||||
|
||||
let sampler_descriptor: SamplerDescriptor = texture.into();
|
||||
let sampler_resource = renderer.create_sampler(&sampler_descriptor);
|
||||
|
||||
let render_resources = renderer.get_render_resources_mut();
|
||||
render_resources.set_texture_resource(texture_handle, texture_resource);
|
||||
render_resources
|
||||
.set_texture_sampler_resource(texture_handle, sampler_resource);
|
||||
(texture_resource, sampler_resource)
|
||||
}
|
||||
};
|
||||
|
||||
render_resource_assignments.set(field_info.texture_name, texture_resource);
|
||||
render_resource_assignments.set(field_info.sampler_name, sampler_resource);
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn setup_uniforms_resources(
|
||||
&mut self,
|
||||
world: &mut World,
|
||||
resources: &Resources,
|
||||
renderer: &mut dyn Renderer,
|
||||
) {
|
||||
let query_finish = self.query_finish.take().unwrap();
|
||||
for (uniforms, mut renderable) in query_finish.iter_mut(world) {
|
||||
if !renderable.is_visible {
|
||||
return;
|
||||
}
|
||||
|
||||
if renderable.is_instanced {
|
||||
panic!(
|
||||
"Cannot instance uniforms of type {0}. Only Handle<{0}> can be instanced.",
|
||||
std::any::type_name::<T>()
|
||||
);
|
||||
} else {
|
||||
self.setup_uniform_resources(
|
||||
&uniforms,
|
||||
renderer,
|
||||
resources,
|
||||
renderable.render_resource_assignments.as_mut().unwrap(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
self.query_finish = Some(query_finish);
|
||||
}
|
||||
|
||||
fn setup_handles_resources(
|
||||
&mut self,
|
||||
world: &mut World,
|
||||
resources: &Resources,
|
||||
renderer: &mut dyn Renderer,
|
||||
) {
|
||||
let assets = resources.get::<AssetStorage<T>>();
|
||||
if let Some(assets) = assets {
|
||||
let handle_query_finish = self.handle_query_finish.take().unwrap();
|
||||
for (handle, mut renderable) in handle_query_finish.iter_mut(world) {
|
||||
if !renderable.is_visible || renderable.is_instanced {
|
||||
return;
|
||||
}
|
||||
|
||||
let uniforms = assets
|
||||
.get(&handle)
|
||||
.expect("Handle points to a non-existent resource");
|
||||
self.setup_uniform_resources(
|
||||
&uniforms,
|
||||
renderer,
|
||||
resources,
|
||||
renderable.render_resource_assignments.as_mut().unwrap(),
|
||||
)
|
||||
}
|
||||
|
||||
self.handle_query_finish = Some(handle_query_finish);
|
||||
}
|
||||
}
|
||||
|
||||
fn setup_batched_resources(
|
||||
&mut self,
|
||||
world: &mut World,
|
||||
resources: &Resources,
|
||||
renderer: &mut dyn Renderer,
|
||||
) {
|
||||
// update batch resources. this needs to run in "finish_update" because batches aren't finalized across
|
||||
// all members of the batch until "UniformResourceProvider.update" has run for all members of the batch
|
||||
if let Some(asset_storage) = resources.get::<AssetStorage<T>>() {
|
||||
let mut asset_batchers = resources.get_mut::<AssetBatchers>().unwrap();
|
||||
let mut render_resource_assignments_provider = resources
|
||||
.get_mut::<RenderResourceAssignmentsProvider>()
|
||||
.unwrap();
|
||||
let handle_type = std::any::TypeId::of::<T>();
|
||||
for batch in asset_batchers.get_handle_batches_mut::<T>().unwrap() {
|
||||
let handle: Handle<T> = batch
|
||||
.handles
|
||||
.iter()
|
||||
.find(|h| h.type_id == handle_type)
|
||||
.map(|h| (*h).into())
|
||||
.unwrap();
|
||||
|
||||
let render_resource_assignments = batch
|
||||
.render_resource_assignments
|
||||
.get_or_insert_with(|| render_resource_assignments_provider.next());
|
||||
if let Some(uniforms) = asset_storage.get(&handle) {
|
||||
self.setup_uniform_resources(
|
||||
uniforms,
|
||||
renderer,
|
||||
resources,
|
||||
render_resource_assignments,
|
||||
);
|
||||
|
||||
Self::update_shader_defs(&uniforms, render_resource_assignments);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn setup_buffer_arrays(&mut self, renderer: &mut dyn Renderer) {
|
||||
for buffer_array_status in self.dynamic_uniform_buffer_status.iter_mut() {
|
||||
if let Some((name, buffer_array_status)) = buffer_array_status {
|
||||
println!("dynamic {} {:?}", name, buffer_array_status);
|
||||
Self::setup_buffer_array(buffer_array_status, renderer);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(ref mut buffer_array_status) = self.instance_buffer_status {
|
||||
println!("instance {}", std::any::type_name::<T>());
|
||||
Self::setup_buffer_array(buffer_array_status, renderer);
|
||||
}
|
||||
}
|
||||
|
||||
fn setup_buffer_array(
|
||||
buffer_array_status: &mut BufferArrayStatus,
|
||||
renderer: &mut dyn Renderer,
|
||||
) {
|
||||
let new_capacity = if let Some(buffer) = buffer_array_status.buffer {
|
||||
if let Some(ResourceInfo::Buffer(BufferInfo {
|
||||
array_info: Some(array_info),
|
||||
..
|
||||
})) = renderer.get_resource_info_mut(buffer)
|
||||
{
|
||||
if array_info.item_capacity < buffer_array_status.new_item_count as u64 {
|
||||
Some(
|
||||
buffer_array_status.new_item_count + buffer_array_status.new_item_count / 2,
|
||||
)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
Some(buffer_array_status.new_item_count)
|
||||
}
|
||||
} else {
|
||||
Some(buffer_array_status.new_item_count)
|
||||
};
|
||||
|
||||
if let Some(new_capacity) = new_capacity {
|
||||
println!("creating buffer {}", new_capacity);
|
||||
let buffer = renderer.create_buffer(BufferInfo {
|
||||
array_info: Some(BufferArrayInfo {
|
||||
item_capacity: new_capacity as u64,
|
||||
item_count: buffer_array_status.new_item_count as u64,
|
||||
item_size: buffer_array_status.item_size as u64,
|
||||
}),
|
||||
size: (buffer_array_status.item_size * new_capacity) as u64,
|
||||
buffer_usage: BufferUsage::COPY_DST | BufferUsage::UNIFORM,
|
||||
dynamic_uniform_info: Some(BufferDynamicUniformInfo::default()),
|
||||
});
|
||||
|
||||
buffer_array_status.buffer = Some(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
fn initialize_vertex_buffer_descriptor(&self, render_graph: &mut RenderGraph) {
|
||||
let vertex_buffer_descriptor = T::get_vertex_buffer_descriptor();
|
||||
if let Some(vertex_buffer_descriptor) = vertex_buffer_descriptor {
|
||||
if let None = render_graph.get_vertex_buffer_descriptor(&vertex_buffer_descriptor.name)
|
||||
{
|
||||
render_graph.set_vertex_buffer_descriptor(vertex_buffer_descriptor.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn update_staging_buffer_offsets(&mut self) -> usize {
|
||||
let mut size = 0;
|
||||
for dynamic_buffer_array_status in self.dynamic_uniform_buffer_status.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
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> ResourceProvider for UniformResourceProviderNew<T>
|
||||
where
|
||||
T: AsUniforms + Send + Sync + 'static,
|
||||
{
|
||||
fn initialize(
|
||||
&mut self,
|
||||
renderer: &mut dyn Renderer,
|
||||
world: &mut World,
|
||||
resources: &Resources,
|
||||
) {
|
||||
let mut render_graph = resources.get_mut::<RenderGraph>().unwrap();
|
||||
self.initialize_vertex_buffer_descriptor(&mut render_graph);
|
||||
self.update(renderer, world, resources);
|
||||
}
|
||||
|
||||
fn update(&mut self, renderer: &mut dyn Renderer, world: &mut World, resources: &Resources) {
|
||||
self.reset_buffer_array_status_counts();
|
||||
self.update_uniforms_info(world);
|
||||
self.update_handles_info(world, resources);
|
||||
}
|
||||
|
||||
fn finish_update(
|
||||
&mut self,
|
||||
renderer: &mut dyn Renderer,
|
||||
world: &mut World,
|
||||
resources: &Resources,
|
||||
) {
|
||||
let staging_buffer_size = self.update_staging_buffer_offsets();
|
||||
// TODO: when setting batch shader_defs, add INSTANCING
|
||||
self.setup_buffer_arrays(renderer);
|
||||
self.setup_uniforms_resources(world, resources, renderer);
|
||||
self.setup_handles_resources(world, resources, renderer);
|
||||
self.setup_batched_resources(world, resources, renderer);
|
||||
}
|
||||
}
|
|
@ -24,7 +24,7 @@ pub trait Renderer {
|
|||
fn create_buffer_mapped(
|
||||
&mut self,
|
||||
buffer_info: BufferInfo,
|
||||
func: &mut dyn FnMut(&mut [u8]),
|
||||
func: &mut dyn FnMut(&mut [u8], &mut dyn Renderer),
|
||||
) -> RenderResource;
|
||||
fn remove_buffer(&mut self, resource: RenderResource);
|
||||
fn remove_texture(&mut self, resource: RenderResource);
|
||||
|
|
|
@ -58,6 +58,7 @@ impl<'a, 'b, 'c, 'd> RenderPass for WgpuRenderPass<'a, 'b, 'c, 'd> {
|
|||
};
|
||||
|
||||
// setup dynamic uniform instances
|
||||
// TODO: these indices could be stored in RenderResourceAssignments so they dont need to be collected on each draw
|
||||
let mut dynamic_uniform_indices = Vec::new();
|
||||
for binding in bind_group.bindings.iter() {
|
||||
if let BindType::Uniform { dynamic, .. } = binding.bind_type {
|
||||
|
@ -72,16 +73,17 @@ impl<'a, 'b, 'c, 'd> RenderPass for WgpuRenderPass<'a, 'b, 'c, 'd> {
|
|||
.get_named_resource(&binding.name)
|
||||
{
|
||||
if let Some(ResourceInfo::Buffer(BufferInfo {
|
||||
dynamic_uniform_info: Some(dynamic_uniform_info),
|
||||
array_info: Some(array_info),
|
||||
is_dynamic: true,
|
||||
..
|
||||
})) = self.wgpu_resources.resource_info.get(&resource)
|
||||
{
|
||||
let index = dynamic_uniform_info
|
||||
.offsets
|
||||
let index = array_info
|
||||
.indices
|
||||
.get(&render_resource_assignments.unwrap().get_id())
|
||||
.unwrap();
|
||||
|
||||
dynamic_uniform_indices.push(*index);
|
||||
dynamic_uniform_indices.push((*index * array_info.item_size) as u32);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,10 +19,10 @@ use crate::{
|
|||
update_shader_assignments,
|
||||
},
|
||||
};
|
||||
use std::{collections::HashMap, ops::Deref};
|
||||
use std::{cell::RefCell, collections::HashMap, ops::Deref, rc::Rc};
|
||||
|
||||
pub struct WgpuRenderer {
|
||||
pub device: wgpu::Device,
|
||||
pub device: Rc<RefCell<wgpu::Device>>,
|
||||
pub queue: wgpu::Queue,
|
||||
pub surface: Option<wgpu::Surface>,
|
||||
pub encoder: Option<wgpu::CommandEncoder>,
|
||||
|
@ -58,7 +58,7 @@ impl WgpuRenderer {
|
|||
};
|
||||
|
||||
WgpuRenderer {
|
||||
device,
|
||||
device: Rc::new(RefCell::new(device)),
|
||||
queue,
|
||||
surface: None,
|
||||
encoder: None,
|
||||
|
@ -160,7 +160,7 @@ impl WgpuRenderer {
|
|||
if let Some(ResourceInfo::Buffer(buffer_info)) =
|
||||
wgpu_resources.resource_info.get(&resource)
|
||||
{
|
||||
*dynamic = buffer_info.dynamic_uniform_info.is_some();
|
||||
*dynamic = buffer_info.is_dynamic;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -370,6 +370,7 @@ impl WgpuRenderer {
|
|||
let mut render_graph = resources.get_mut::<RenderGraph>().unwrap();
|
||||
self.encoder = Some(
|
||||
self.device
|
||||
.borrow()
|
||||
.create_command_encoder(&wgpu::CommandEncoderDescriptor { todo: 0 }),
|
||||
);
|
||||
for resource_provider in render_graph.resource_providers.iter_mut() {
|
||||
|
@ -417,12 +418,14 @@ impl Renderer for WgpuRenderer {
|
|||
};
|
||||
self.encoder = Some(
|
||||
self.device
|
||||
.borrow()
|
||||
.create_command_encoder(&wgpu::CommandEncoderDescriptor { todo: 0 }),
|
||||
);
|
||||
self.swap_chain_descriptor.width = window_size.width;
|
||||
self.swap_chain_descriptor.height = window_size.height;
|
||||
let swap_chain = self
|
||||
.device
|
||||
.borrow()
|
||||
.create_swap_chain(self.surface.as_ref().unwrap(), &self.swap_chain_descriptor);
|
||||
|
||||
// WgpuRenderer can't own swap_chain without creating lifetime ergonomics issues, so lets just store it in World.
|
||||
|
@ -449,6 +452,7 @@ impl Renderer for WgpuRenderer {
|
|||
// exposing the wgpu renderer internals to ResourceProvider traits. if this can be made cleaner that would be pretty cool.
|
||||
self.encoder = Some(
|
||||
self.device
|
||||
.borrow()
|
||||
.create_command_encoder(&wgpu::CommandEncoderDescriptor { todo: 0 }),
|
||||
);
|
||||
|
||||
|
@ -492,7 +496,7 @@ impl Renderer for WgpuRenderer {
|
|||
let render_pipeline = WgpuRenderer::create_render_pipeline(
|
||||
&mut self.wgpu_resources,
|
||||
pipeline_descriptor,
|
||||
&self.device,
|
||||
&self.device.borrow(),
|
||||
&render_graph,
|
||||
vertex_shader,
|
||||
fragment_shader,
|
||||
|
@ -505,7 +509,7 @@ impl Renderer for WgpuRenderer {
|
|||
let pipeline_layout = pipeline_descriptor.get_layout().unwrap();
|
||||
for bind_group in pipeline_layout.bind_groups.iter() {
|
||||
self.wgpu_resources
|
||||
.setup_bind_group(&self.device, bind_group);
|
||||
.setup_bind_group(&self.device.borrow(), bind_group);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -560,11 +564,12 @@ impl Renderer for WgpuRenderer {
|
|||
|
||||
fn create_buffer_with_data(&mut self, buffer_info: BufferInfo, data: &[u8]) -> RenderResource {
|
||||
self.wgpu_resources
|
||||
.create_buffer_with_data(&self.device, buffer_info, data)
|
||||
.create_buffer_with_data(&self.device.borrow(), buffer_info, data)
|
||||
}
|
||||
|
||||
fn create_buffer(&mut self, buffer_info: BufferInfo) -> RenderResource {
|
||||
self.wgpu_resources.create_buffer(&self.device, buffer_info)
|
||||
self.wgpu_resources
|
||||
.create_buffer(&self.device.borrow(), buffer_info)
|
||||
}
|
||||
|
||||
fn get_resource_info(&self, resource: RenderResource) -> Option<&ResourceInfo> {
|
||||
|
@ -582,10 +587,10 @@ impl Renderer for WgpuRenderer {
|
|||
fn create_buffer_mapped(
|
||||
&mut self,
|
||||
buffer_info: BufferInfo,
|
||||
setup_data: &mut dyn FnMut(&mut [u8]),
|
||||
setup_data: &mut dyn FnMut(&mut [u8], &mut dyn Renderer),
|
||||
) -> RenderResource {
|
||||
self.wgpu_resources
|
||||
.create_buffer_mapped(&self.device, buffer_info, setup_data)
|
||||
let buffer = WgpuResources::begin_create_buffer_mapped(&buffer_info, self, setup_data);
|
||||
self.wgpu_resources.assign_buffer(buffer, buffer_info)
|
||||
}
|
||||
|
||||
fn copy_buffer_to_buffer(
|
||||
|
@ -608,7 +613,7 @@ impl Renderer for WgpuRenderer {
|
|||
|
||||
fn create_sampler(&mut self, sampler_descriptor: &SamplerDescriptor) -> RenderResource {
|
||||
self.wgpu_resources
|
||||
.create_sampler(&self.device, sampler_descriptor)
|
||||
.create_sampler(&self.device.borrow(), sampler_descriptor)
|
||||
}
|
||||
|
||||
fn create_texture(
|
||||
|
@ -617,7 +622,7 @@ impl Renderer for WgpuRenderer {
|
|||
bytes: Option<&[u8]>,
|
||||
) -> RenderResource {
|
||||
self.wgpu_resources.create_texture(
|
||||
&self.device,
|
||||
&self.device.borrow(),
|
||||
self.encoder.as_mut().unwrap(),
|
||||
texture_descriptor,
|
||||
bytes,
|
||||
|
@ -655,7 +660,7 @@ impl Renderer for WgpuRenderer {
|
|||
.get_assignments_bind_group(render_resource_assignments.get_id(), bind_group_id)
|
||||
{
|
||||
self.wgpu_resources.create_assignments_bind_group(
|
||||
&self.device,
|
||||
&self.device.borrow(),
|
||||
bind_group,
|
||||
render_resource_assignments,
|
||||
);
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
use super::WgpuRenderer;
|
||||
use crate::render::{
|
||||
pipeline::{BindGroup, BindType},
|
||||
render_resource::{
|
||||
BufferInfo, RenderResource, RenderResourceAssignments, RenderResourceAssignmentsId,
|
||||
RenderResources, ResourceInfo,
|
||||
},
|
||||
renderer::Renderer,
|
||||
texture::{SamplerDescriptor, TextureDescriptor},
|
||||
};
|
||||
use std::collections::HashMap;
|
||||
|
@ -77,7 +79,7 @@ impl WgpuResources {
|
|||
let buffer = self.buffers.get(&resource).unwrap();
|
||||
wgpu::BindingResource::Buffer {
|
||||
buffer,
|
||||
range: 0..buffer_info.size,
|
||||
range: 0..buffer_info.size as u64,
|
||||
}
|
||||
} else {
|
||||
panic!("expected a Buffer resource");
|
||||
|
@ -147,7 +149,7 @@ impl WgpuResources {
|
|||
let buffer = self.buffers.get(&resource).unwrap();
|
||||
wgpu::BindingResource::Buffer {
|
||||
buffer,
|
||||
range: 0..buffer_info.size,
|
||||
range: 0..buffer_info.size as u64,
|
||||
}
|
||||
} else {
|
||||
panic!("expected a Buffer resource");
|
||||
|
@ -185,7 +187,7 @@ impl WgpuResources {
|
|||
buffer_info: BufferInfo,
|
||||
) -> RenderResource {
|
||||
let buffer = device.create_buffer(&wgpu::BufferDescriptor {
|
||||
size: buffer_info.size,
|
||||
size: buffer_info.size as u64,
|
||||
usage: buffer_info.buffer_usage.into(),
|
||||
});
|
||||
|
||||
|
@ -202,13 +204,9 @@ impl WgpuResources {
|
|||
mut buffer_info: BufferInfo,
|
||||
data: &[u8],
|
||||
) -> RenderResource {
|
||||
buffer_info.size = data.len() as u64;
|
||||
let resource = self.render_resources.get_next_resource();
|
||||
buffer_info.size = data.len();
|
||||
let buffer = device.create_buffer_with_data(data, buffer_info.buffer_usage.into());
|
||||
self.add_resource_info(resource, ResourceInfo::Buffer(buffer_info));
|
||||
|
||||
self.buffers.insert(resource, buffer);
|
||||
resource
|
||||
self.assign_buffer(buffer, buffer_info)
|
||||
}
|
||||
|
||||
pub fn get_resource_info(&self, resource: RenderResource) -> Option<&ResourceInfo> {
|
||||
|
@ -220,24 +218,31 @@ impl WgpuResources {
|
|||
self.resource_info.remove(&resource);
|
||||
}
|
||||
|
||||
pub fn create_buffer_mapped(
|
||||
pub fn assign_buffer(
|
||||
&mut self,
|
||||
device: &wgpu::Device,
|
||||
buffer: wgpu::Buffer,
|
||||
buffer_info: BufferInfo,
|
||||
setup_data: &mut dyn FnMut(&mut [u8]),
|
||||
) -> RenderResource {
|
||||
let mut mapped =
|
||||
device.create_buffer_mapped(buffer_info.size as usize, buffer_info.buffer_usage.into());
|
||||
setup_data(&mut mapped.data);
|
||||
let buffer = mapped.finish();
|
||||
|
||||
let resource = self.render_resources.get_next_resource();
|
||||
self.add_resource_info(resource, ResourceInfo::Buffer(buffer_info));
|
||||
|
||||
self.buffers.insert(resource, buffer);
|
||||
resource
|
||||
}
|
||||
|
||||
pub fn begin_create_buffer_mapped(
|
||||
buffer_info: &BufferInfo,
|
||||
renderer: &mut WgpuRenderer,
|
||||
setup_data: &mut dyn FnMut(&mut [u8], &mut dyn Renderer),
|
||||
) -> wgpu::Buffer {
|
||||
let device_rc = renderer.device.clone();
|
||||
let device = device_rc.borrow();
|
||||
|
||||
let mut mapped =
|
||||
device.create_buffer_mapped(buffer_info.size as usize, buffer_info.buffer_usage.into());
|
||||
setup_data(&mut mapped.data, renderer);
|
||||
mapped.finish()
|
||||
}
|
||||
|
||||
pub fn copy_buffer_to_buffer(
|
||||
&mut self,
|
||||
encoder: &mut wgpu::CommandEncoder,
|
||||
|
|
|
@ -5,7 +5,7 @@ use crate::{
|
|||
color::ColorSource,
|
||||
pipeline::{BindType, VertexBufferDescriptor},
|
||||
texture::{Texture, TextureViewDimension},
|
||||
}, prelude::Color,
|
||||
},
|
||||
};
|
||||
|
||||
pub trait AsUniforms {
|
||||
|
@ -79,7 +79,7 @@ where
|
|||
let bind_type = self.uniforms.get_field_bind_type(field_info.name);
|
||||
if let Some(bind_type) = bind_type {
|
||||
Some(match bind_type {
|
||||
FieldBindType::Uniform { .. }=> UniformInfo {
|
||||
FieldBindType::Uniform { .. } => UniformInfo {
|
||||
bind_type: BindType::Uniform {
|
||||
dynamic: false,
|
||||
properties: Vec::new(),
|
||||
|
@ -147,7 +147,9 @@ where
|
|||
{
|
||||
// TODO: this breaks if get_bytes_ref() isn't supported for a datatype
|
||||
default fn get_field_bind_type(&self) -> Option<FieldBindType> {
|
||||
Some(FieldBindType::Uniform { size: self.get_bytes_ref().unwrap().len() })
|
||||
Some(FieldBindType::Uniform {
|
||||
size: self.get_bytes_ref().unwrap().len(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ use crate::{
|
|||
pipeline::{
|
||||
InputStepMode, VertexAttributeDescriptor, VertexBufferDescriptor, VertexFormat,
|
||||
},
|
||||
shader::{AsUniforms, FieldBindType, FieldInfo, AsFieldBindType},
|
||||
shader::{AsFieldBindType, AsUniforms, FieldBindType, FieldInfo},
|
||||
texture::Texture,
|
||||
},
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue