mirror of
https://github.com/bevyengine/bevy
synced 2025-02-17 22:48:38 +00:00
fix uniform providers with different field sets
This commit is contained in:
parent
5154320f70
commit
ca563ea1b3
5 changed files with 41 additions and 27 deletions
|
@ -1,4 +1,4 @@
|
||||||
use bevy::prelude::*;
|
use bevy::{asset, prelude::*};
|
||||||
use rand::{rngs::StdRng, Rng, SeedableRng};
|
use rand::{rngs::StdRng, Rng, SeedableRng};
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
|
|
||||||
|
@ -69,6 +69,11 @@ fn setup(world: &mut World) {
|
||||||
let mut mesh_storage = world.resources.get_mut::<AssetStorage<Mesh>>().unwrap();
|
let mut mesh_storage = world.resources.get_mut::<AssetStorage<Mesh>>().unwrap();
|
||||||
(mesh_storage.add(cube), mesh_storage.add(plane))
|
(mesh_storage.add(cube), mesh_storage.add(plane))
|
||||||
};
|
};
|
||||||
|
// let texture_handle = {
|
||||||
|
// let mut texture_storage = world.resources.get_mut::<AssetStorage<Texture>>().unwrap();
|
||||||
|
// let texture = Texture::load(TextureType::Data(asset::create_texels(256), 256, 256));
|
||||||
|
// texture_storage.add(texture)
|
||||||
|
// };
|
||||||
|
|
||||||
let mut builder = world
|
let mut builder = world
|
||||||
.build()
|
.build()
|
||||||
|
@ -123,6 +128,7 @@ fn setup(world: &mut World) {
|
||||||
builder = builder.add_archetype(MeshEntity {
|
builder = builder.add_archetype(MeshEntity {
|
||||||
mesh: cube_handle,
|
mesh: cube_handle,
|
||||||
material: StandardMaterial {
|
material: StandardMaterial {
|
||||||
|
// albedo: texture_handle.into(),
|
||||||
albedo: math::vec4(
|
albedo: math::vec4(
|
||||||
rng.gen_range(0.0, 1.0),
|
rng.gen_range(0.0, 1.0),
|
||||||
rng.gen_range(0.0, 1.0),
|
rng.gen_range(0.0, 1.0),
|
||||||
|
|
|
@ -24,9 +24,17 @@ fn setup(world: &mut World) {
|
||||||
material: StandardMaterial {
|
material: StandardMaterial {
|
||||||
albedo: texture_handle.into(),
|
albedo: texture_handle.into(),
|
||||||
},
|
},
|
||||||
translation: Translation::new(0.0, 0.0, 1.0),
|
translation: Translation::new(0.0, 0.0, 0.0),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
})
|
})
|
||||||
|
// .add_archetype(MeshEntity {
|
||||||
|
// mesh: cube_handle,
|
||||||
|
// material: StandardMaterial {
|
||||||
|
// albedo: Vec4::new(1.0, 0.0, 0.0, 1.0).into(),
|
||||||
|
// },
|
||||||
|
// translation: Translation::new(2.0, 0.0, 0.0),
|
||||||
|
// ..Default::default()
|
||||||
|
// })
|
||||||
// light
|
// light
|
||||||
.add_archetype(LightEntity {
|
.add_archetype(LightEntity {
|
||||||
translation: Translation::new(4.0, -4.0, 5.0),
|
translation: Translation::new(4.0, -4.0, 5.0),
|
||||||
|
|
|
@ -429,6 +429,7 @@ impl WgpuRenderer {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_entity_bind_group(&mut self, bind_group: &BindGroup, entity: Entity) {
|
pub fn create_entity_bind_group(&mut self, bind_group: &BindGroup, entity: Entity) {
|
||||||
|
// TODO: don't make this per-entity. bind groups should be re-used across the same resource when possible
|
||||||
let bind_group_id = bind_group.get_hash().unwrap();
|
let bind_group_id = bind_group.get_hash().unwrap();
|
||||||
let bindings = bind_group.bindings.iter().map(|binding| {
|
let bindings = bind_group.bindings.iter().map(|binding| {
|
||||||
if let Some(resource) = self.get_entity_uniform_resource(entity, &binding.name) {
|
if let Some(resource) = self.get_entity_uniform_resource(entity, &binding.name) {
|
||||||
|
|
|
@ -6,14 +6,15 @@ use crate::{
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use legion::prelude::*;
|
use legion::prelude::*;
|
||||||
use std::{marker::PhantomData, ops::Deref};
|
use std::{marker::PhantomData, ops::Deref, collections::{HashSet, HashMap}};
|
||||||
|
|
||||||
pub struct UniformResourceProvider<T>
|
pub struct UniformResourceProvider<T>
|
||||||
where
|
where
|
||||||
T: AsUniforms + Send + Sync,
|
T: AsUniforms + Send + Sync,
|
||||||
{
|
{
|
||||||
_marker: PhantomData<T>,
|
_marker: PhantomData<T>,
|
||||||
uniform_buffer_info_resources: Vec<(String, Option<RenderResource>)>,
|
// PERF: somehow remove this HashSet
|
||||||
|
uniform_buffer_info_resources: HashMap<String, (Option<RenderResource>, usize, HashSet<Entity>)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> UniformResourceProvider<T>
|
impl<T> UniformResourceProvider<T>
|
||||||
|
@ -22,7 +23,7 @@ where
|
||||||
{
|
{
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
UniformResourceProvider {
|
UniformResourceProvider {
|
||||||
uniform_buffer_info_resources: Vec::new(),
|
uniform_buffer_info_resources: HashMap::new(),
|
||||||
_marker: PhantomData,
|
_marker: PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -43,32 +44,27 @@ where
|
||||||
// (2) if we create new buffers, the old bind groups will be invalid
|
// (2) if we create new buffers, the old bind groups will be invalid
|
||||||
|
|
||||||
// reset all uniform buffer info counts
|
// reset all uniform buffer info counts
|
||||||
for (_name, resource) in self.uniform_buffer_info_resources.iter() {
|
for (_name, (resource, _count, entities)) in self.uniform_buffer_info_resources.iter() {
|
||||||
renderer
|
renderer
|
||||||
.get_dynamic_uniform_buffer_info_mut(resource.unwrap())
|
.get_dynamic_uniform_buffer_info_mut(resource.unwrap())
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.count = 0;
|
.count = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut counts = Vec::new();
|
|
||||||
for (entity, (uniforms, _renderable)) in query.iter_entities(world) {
|
for (entity, (uniforms, _renderable)) in query.iter_entities(world) {
|
||||||
let mut uniform_index = 0;
|
|
||||||
let field_uniform_names = uniforms.get_field_uniform_names();
|
let field_uniform_names = uniforms.get_field_uniform_names();
|
||||||
for uniform_info in UniformInfoIter::new(field_uniform_names, uniforms.deref()) {
|
for uniform_info in UniformInfoIter::new(field_uniform_names, uniforms.deref()) {
|
||||||
match uniform_info.bind_type {
|
match uniform_info.bind_type {
|
||||||
BindType::Uniform { .. } => {
|
BindType::Uniform { .. } => {
|
||||||
// only add the first time a uniform info is processed
|
// only add the first time a uniform info is processed
|
||||||
if self.uniform_buffer_info_resources.len() <= uniform_index {
|
if let None = self.uniform_buffer_info_resources.get(uniform_info.name) {
|
||||||
self.uniform_buffer_info_resources
|
self.uniform_buffer_info_resources
|
||||||
.push((uniform_info.name.to_string(), None));
|
.insert(uniform_info.name.to_string(), (None, 0, HashSet::new()));
|
||||||
}
|
}
|
||||||
|
|
||||||
if counts.len() <= uniform_index {
|
let (resource, counts, entities) = self.uniform_buffer_info_resources.get_mut(uniform_info.name).unwrap();
|
||||||
counts.push(0);
|
entities.insert(entity);
|
||||||
}
|
*counts += 1;
|
||||||
|
|
||||||
counts[uniform_index] += 1;
|
|
||||||
uniform_index += 1;
|
|
||||||
}
|
}
|
||||||
BindType::SampledTexture { .. } => {
|
BindType::SampledTexture { .. } => {
|
||||||
let texture_handle =
|
let texture_handle =
|
||||||
|
@ -115,17 +111,18 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
// allocate uniform buffers
|
// allocate uniform buffers
|
||||||
for (i, (name, resource)) in self.uniform_buffer_info_resources.iter_mut().enumerate() {
|
for (name, (resource, count, entities)) in self.uniform_buffer_info_resources.iter_mut() {
|
||||||
|
let count = *count as u64;
|
||||||
if let Some(resource) = resource {
|
if let Some(resource) = resource {
|
||||||
let mut info = renderer
|
let mut info = renderer
|
||||||
.get_dynamic_uniform_buffer_info_mut(*resource)
|
.get_dynamic_uniform_buffer_info_mut(*resource)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
info.count = counts[i];
|
info.count = count;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// allocate enough space for twice as many entities as there are currently;
|
// allocate enough space for twice as many entities as there are currently;
|
||||||
let capacity = counts[i] * 2;
|
let capacity = count * 2;
|
||||||
let size = wgpu::BIND_BUFFER_ALIGNMENT * capacity;
|
let size = wgpu::BIND_BUFFER_ALIGNMENT * capacity;
|
||||||
let created_resource = renderer.create_buffer(
|
let created_resource = renderer.create_buffer(
|
||||||
size,
|
size,
|
||||||
|
@ -133,7 +130,7 @@ where
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut info = DynamicUniformBufferInfo::new();
|
let mut info = DynamicUniformBufferInfo::new();
|
||||||
info.count = counts[i];
|
info.count = count;
|
||||||
info.capacity = capacity;
|
info.capacity = capacity;
|
||||||
renderer.add_dynamic_uniform_buffer_info(created_resource, info);
|
renderer.add_dynamic_uniform_buffer_info(created_resource, info);
|
||||||
*resource = Some(created_resource);
|
*resource = Some(created_resource);
|
||||||
|
@ -141,7 +138,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
// copy entity uniform data to buffers
|
// copy entity uniform data to buffers
|
||||||
for (name, resource) in self.uniform_buffer_info_resources.iter() {
|
for (name, (resource, _count, entities)) in self.uniform_buffer_info_resources.iter() {
|
||||||
let resource = resource.unwrap();
|
let resource = resource.unwrap();
|
||||||
let size = {
|
let size = {
|
||||||
let info = renderer.get_dynamic_uniform_buffer_info(resource).unwrap();
|
let info = renderer.get_dynamic_uniform_buffer_info(resource).unwrap();
|
||||||
|
@ -153,24 +150,28 @@ where
|
||||||
let info = renderer
|
let info = renderer
|
||||||
.get_dynamic_uniform_buffer_info_mut(resource)
|
.get_dynamic_uniform_buffer_info_mut(resource)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
for (i, (entity, _)) in query.iter_entities(world).enumerate() {
|
for (entity, _) in query.iter_entities(world) {
|
||||||
|
if !entities.contains(&entity) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
// TODO: check if index has changed. if it has, then entity should be updated
|
// TODO: check if index has changed. if it has, then entity should be updated
|
||||||
// TODO: only mem-map entities if their data has changed
|
// TODO: only mem-map entities if their data has changed
|
||||||
// PERF: These hashmap inserts are pretty expensive (10 fps for 10000 entities)
|
// PERF: These hashmap inserts are pretty expensive (10 fps for 10000 entities)
|
||||||
info.offsets.insert(entity, offset as u64);
|
info.offsets.insert(entity, offset as u64);
|
||||||
info.indices.insert(i, entity);
|
|
||||||
// TODO: try getting ref first
|
// TODO: try getting ref first
|
||||||
offset += alignment;
|
offset += alignment;
|
||||||
}
|
}
|
||||||
|
|
||||||
// let mut data = vec![Default::default(); size as usize];
|
|
||||||
let mapped_buffer_resource = renderer.create_buffer_mapped(
|
let mapped_buffer_resource = renderer.create_buffer_mapped(
|
||||||
size as usize,
|
size as usize,
|
||||||
wgpu::BufferUsage::COPY_SRC,
|
wgpu::BufferUsage::COPY_SRC,
|
||||||
&mut |mapped| {
|
&mut |mapped| {
|
||||||
let alignment = wgpu::BIND_BUFFER_ALIGNMENT as usize;
|
let alignment = wgpu::BIND_BUFFER_ALIGNMENT as usize;
|
||||||
let mut offset = 0usize;
|
let mut offset = 0usize;
|
||||||
for (uniforms, _renderable) in query.iter(world) {
|
for (entity, (uniforms, _renderable)) in query.iter_entities(world) {
|
||||||
|
if !entities.contains(&entity) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
// TODO: check if index has changed. if it has, then entity should be updated
|
// TODO: check if index has changed. if it has, then entity should be updated
|
||||||
// TODO: only mem-map entities if their data has changed
|
// TODO: only mem-map entities if their data has changed
|
||||||
// TODO: try getting bytes ref first
|
// TODO: try getting bytes ref first
|
||||||
|
|
|
@ -171,7 +171,6 @@ pub struct UniformInfo<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct DynamicUniformBufferInfo {
|
pub struct DynamicUniformBufferInfo {
|
||||||
pub indices: HashMap<usize, Entity>,
|
|
||||||
pub offsets: HashMap<Entity, u64>,
|
pub offsets: HashMap<Entity, u64>,
|
||||||
pub capacity: u64,
|
pub capacity: u64,
|
||||||
pub count: u64,
|
pub count: u64,
|
||||||
|
@ -182,7 +181,6 @@ impl DynamicUniformBufferInfo {
|
||||||
DynamicUniformBufferInfo {
|
DynamicUniformBufferInfo {
|
||||||
capacity: 0,
|
capacity: 0,
|
||||||
count: 0,
|
count: 0,
|
||||||
indices: HashMap::new(),
|
|
||||||
offsets: HashMap::new(),
|
offsets: HashMap::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue