Add Handle<T> support to uniform resource provider. Use Handle<StandardMaterial> instead of StandardMaterial

This commit is contained in:
Carter Anderson 2020-03-16 00:45:28 -07:00
parent c1e66089cc
commit 5d99f3a7e8
14 changed files with 418 additions and 243 deletions

10
.vscode/settings.json vendored Normal file
View file

@ -0,0 +1,10 @@
{
"cSpell.words": [
"Wgpu",
"bools",
"chunkset",
"chunksets",
"multizip",
"passthrough"
]
}

View file

@ -380,7 +380,7 @@ impl<'a, 'b, F: Filter<ArchetypeFilterData<'a>>> Iterator for FilterArchIter<'a,
}
}
/// An iterator which yields the index of chuinks that match a filter.
/// An iterator which yields the index of chunks that match a filter.
pub struct FilterChunkIter<'a, 'b, F: Filter<ChunksetFilterData<'a>>> {
filter: &'b F,
chunks: Enumerate<F::Iter>,
@ -905,7 +905,7 @@ impl_or_filter!(A => a, B => b, C => c, D => d, E => e, F => f, G => g, H => h,
impl_or_filter!(A => a, B => b, C => c, D => d, E => e, F => f, G => g, H => h, I => i, J => j, K => k);
impl_or_filter!(A => a, B => b, C => c, D => d, E => e, F => f, G => g, H => h, I => i, J => j, K => k, L => l);
/// A filter qhich requires that all chunks contain entity data components of type `T`.
/// A filter which requires that all chunks contain entity data components of type `T`.
#[derive(Debug)]
pub struct ComponentFilter<T>(PhantomData<T>);

View file

@ -117,24 +117,22 @@ fn create_entities_builder_add_component(
fn create_entities_builder_archetype(
world: &mut World,
plane_handle: Handle<Mesh>,
plane_material_handle: Handle<StandardMaterial>,
cube_handle: Handle<Mesh>,
cube_material_handle: Handle<StandardMaterial>,
) {
world
.build()
// plane
.add_entity(MeshEntity {
mesh: plane_handle,
material: StandardMaterial {
albedo: Color::rgb(0.1, 0.2, 0.1).into(),
},
material: plane_material_handle,
..Default::default()
})
// cube
.add_entity(MeshEntity {
mesh: cube_handle,
material: StandardMaterial {
albedo: Color::rgb(0.5, 0.3, 0.3).into(),
},
material: cube_material_handle,
..Default::default()
})
// light
@ -162,9 +160,19 @@ fn create_entities_builder_archetype(
fn setup(world: &mut World, resources: &mut Resources) {
let mut mesh_storage = resources.get_mut::<AssetStorage<Mesh>>().unwrap();
let mut material_storage = resources
.get_mut::<AssetStorage<StandardMaterial>>()
.unwrap();
let cube_handle = mesh_storage.add(Mesh::load(MeshType::Cube));
let plane_handle = mesh_storage.add(Mesh::load(MeshType::Plane { size: 10.0 }));
let cube_material_handle = material_storage.add(StandardMaterial {
albedo: Color::rgb(0.5, 0.3, 0.3).into(),
});
let plane_material_handle = material_storage.add(StandardMaterial {
albedo: Color::rgb(0.1, 0.2, 0.1).into(),
});
// no-archetype precompile: 1.24 sec
// archetype precompile: 1.07 sec
// create_entities_insert_vec(world, plane_handle, cube_handle);
@ -174,5 +182,11 @@ fn setup(world: &mut World, resources: &mut Resources) {
// create_entities_builder_add_component(world, plane_handle, cube_handle);
// archetype precompile: 0.65
create_entities_builder_archetype(world, plane_handle, cube_handle);
create_entities_builder_archetype(
world,
plane_handle,
plane_material_handle,
cube_handle,
cube_material_handle,
);
}

View file

@ -24,16 +24,21 @@ fn build_rotator_system() -> Box<dyn Schedulable> {
fn setup(world: &mut World, resources: &mut Resources) {
let mut mesh_storage = resources.get_mut::<AssetStorage<Mesh>>().unwrap();
let mut material_storage = resources
.get_mut::<AssetStorage<StandardMaterial>>()
.unwrap();
let cube_handle = mesh_storage.add(Mesh::load(MeshType::Cube));
let cube_material_handle = material_storage.add(StandardMaterial {
albedo: Color::rgb(0.5, 0.4, 0.3).into(),
});
world
.build()
// parent cube
.add_entity(MeshEntity {
mesh: cube_handle,
material: StandardMaterial {
albedo: Color::rgb(0.5, 0.4, 0.3).into(),
},
material: cube_material_handle,
translation: Translation::new(0.0, 0.0, 1.0),
..Default::default()
})
@ -42,9 +47,7 @@ fn setup(world: &mut World, resources: &mut Resources) {
// cube
builder.add_entity(MeshEntity {
mesh: cube_handle,
material: StandardMaterial {
albedo: Color::rgb(0.5, 0.4, 0.3).into(),
},
material: cube_material_handle,
translation: Translation::new(0.0, 0.0, 3.0),
..Default::default()
})

View file

@ -6,25 +6,30 @@ fn main() {
fn setup(world: &mut World, resources: &mut Resources) {
let mut mesh_storage = resources.get_mut::<AssetStorage<Mesh>>().unwrap();
let mut material_storage = resources
.get_mut::<AssetStorage<StandardMaterial>>()
.unwrap();
let cube_handle = mesh_storage.add(Mesh::load(MeshType::Cube));
let plane_handle = mesh_storage.add(Mesh::load(MeshType::Plane { size: 10.0 }));
let cube_material_handle = material_storage.add(StandardMaterial {
albedo: Color::rgb(0.5, 0.4, 0.3).into(),
});
let plane_material_handle = material_storage.add(StandardMaterial {
albedo: Color::rgb(0.1, 0.2, 0.1).into(),
});
world
.build()
// plane
.add_entity(MeshEntity {
mesh: plane_handle,
material: StandardMaterial {
albedo: Color::rgb(0.1, 0.2, 0.1).into(),
},
material: plane_material_handle,
..Default::default()
})
// cube
.add_entity(MeshEntity {
mesh: cube_handle,
material: StandardMaterial {
albedo: Color::rgb(0.5, 0.4, 0.3).into(),
},
material: cube_material_handle,
translation: Translation::new(0.0, 0.0, 1.0),
..Default::default()
})

View file

@ -13,14 +13,15 @@ fn main() {
fn build_move_system() -> Box<dyn Schedulable> {
SystemBuilder::new("Move")
.read_resource::<Time>()
.with_query(<(Write<Translation>, Write<StandardMaterial>)>::query())
.build(move |_, world, time, person_query| {
for (mut translation, mut material) in person_query.iter_mut(world) {
.write_resource::<AssetStorage<StandardMaterial>>()
.with_query(<(Write<Translation>, Read<Handle<StandardMaterial>>)>::query())
.build(move |_, world, (time, material_storage), person_query| {
for (mut translation, material_handle) in person_query.iter_mut(world) {
let material = material_storage.get_mut(&material_handle).unwrap();
translation.0 += math::vec3(1.0, 0.0, 0.0) * time.delta_seconds;
if let ColorSource::Color(color) = material.albedo {
material.albedo = (color
+ Color::rgb(-time.delta_seconds, -time.delta_seconds, time.delta_seconds))
.into();
if let ColorSource::Color(ref mut color) = material.albedo {
*color = *color
+ Color::rgb(-time.delta_seconds, -time.delta_seconds, time.delta_seconds);
}
}
})
@ -28,36 +29,33 @@ fn build_move_system() -> Box<dyn Schedulable> {
fn setup(world: &mut World, resources: &mut Resources) {
let mut mesh_storage = resources.get_mut::<AssetStorage<Mesh>>().unwrap();
let mut material_storage = resources
.get_mut::<AssetStorage<StandardMaterial>>()
.unwrap();
let cube_handle = mesh_storage.add(Mesh::load(MeshType::Cube));
let plane_handle = mesh_storage.add(Mesh::load(MeshType::Plane { size: 10.0 }));
let cube_material_handle = material_storage.add(StandardMaterial {
albedo: Color::rgb(0.5, 0.4, 0.3).into(),
});
let plane_material_handle = material_storage.add(StandardMaterial {
albedo: Color::rgb(0.1, 0.2, 0.1).into(),
});
let mut builder = world
.build()
// plane
.add_entity(MeshEntity {
mesh: plane_handle,
material: StandardMaterial {
albedo: Color::rgb(0.1, 0.2, 0.1).into(),
},
material: plane_material_handle,
..Default::default()
})
// cube
.add_entity(MeshEntity {
mesh: cube_handle,
material: StandardMaterial {
albedo: Color::rgb(1.0, 1.0, 1.0).into(),
},
material: cube_material_handle,
translation: Translation::new(0.0, 0.0, 1.0),
..Default::default()
})
.add_entity(MeshEntity {
mesh: cube_handle,
material: StandardMaterial {
albedo: Color::rgb(0.0, 1.0, 0.0).into(),
},
translation: Translation::new(-2.0, 0.0, 1.0),
..Default::default()
})
// light
.add_entity(LightEntity {
translation: Translation::new(4.0, -4.0, 5.0),
@ -81,16 +79,17 @@ fn setup(world: &mut World, resources: &mut Resources) {
let mut rng = StdRng::from_entropy();
for _ in 0..10000 {
builder = builder.add_entity(MeshEntity {
mesh: cube_handle,
material: StandardMaterial {
let spawned_material_handle = material_storage.add(StandardMaterial {
albedo: Color::rgb(
rng.gen_range(0.0, 1.0),
rng.gen_range(0.0, 1.0),
rng.gen_range(0.0, 1.0),
)
.into(),
},
});
builder = builder.add_entity(MeshEntity {
mesh: cube_handle,
material: spawned_material_handle,
translation: Translation::new(
rng.gen_range(-50.0, 50.0),
rng.gen_range(-50.0, 50.0),

View file

@ -14,14 +14,20 @@ fn setup(world: &mut World, resources: &mut Resources) {
));
let texture_handle = texture_storage.add(texture);
let mut material_storage = resources
.get_mut::<AssetStorage<StandardMaterial>>()
.unwrap();
let cube_material_handle = material_storage.add(StandardMaterial {
albedo: texture_handle.into(),
});
world
.build()
// cube
.add_entity(MeshEntity {
mesh: cube_handle,
material: StandardMaterial {
albedo: texture_handle.into(),
},
material: cube_material_handle,
translation: Translation::new(0.0, 0.0, 0.0),
..Default::default()
})

View file

@ -6,16 +6,20 @@ fn main() {
fn setup(world: &mut World, resources: &mut Resources) {
let mut mesh_storage = resources.get_mut::<AssetStorage<Mesh>>().unwrap();
let mut material_storage = resources
.get_mut::<AssetStorage<StandardMaterial>>()
.unwrap();
let cube_handle = mesh_storage.add(Mesh::load(MeshType::Cube));
let cube_material_handle = material_storage.add(StandardMaterial {
albedo: Color::rgb(0.5, 0.3, 0.3).into(),
});
world
.build()
// cube
.add_entity(MeshEntity {
mesh: cube_handle,
material: StandardMaterial {
albedo: Color::rgb(0.5, 0.3, 0.3).into(),
},
material: cube_material_handle,
translation: Translation::new(0.0, 0.0, 1.0),
..Default::default()
})

View file

@ -14,7 +14,7 @@ fn build_move_system() -> Box<dyn Schedulable> {
.read_resource::<Time>()
.with_query(<Write<Node>>::query())
.build(move |_, world, time, query| {
for (i, mut node) in query.iter_mut(world).enumerate() {
for (_i, mut node) in query.iter_mut(world).enumerate() {
if node.color.r > 0.2 {
node.position += Vec2::new(0.1 * time.delta_seconds, 0.0);
// println!("{}", node.position.x());

View file

@ -125,6 +125,8 @@ impl AppBuilder {
self.resources.insert(AssetStorage::<Mesh>::new());
self.resources.insert(AssetStorage::<Texture>::new());
self.resources.insert(AssetStorage::<Shader>::new());
self.resources
.insert(AssetStorage::<StandardMaterial>::new());
self.resources
.insert(AssetStorage::<PipelineDescriptor>::new());
self.resources.insert(ShaderPipelineAssignments::new());

View file

@ -6,7 +6,7 @@ use bevy_derive::EntityArchetype;
#[derive(EntityArchetype, Default)]
pub struct MeshEntity {
pub mesh: Handle<Mesh>,
pub material: StandardMaterial,
pub material: Handle<StandardMaterial>,
pub renderable: Renderable,
pub local_to_world: LocalToWorld,
pub translation: Translation,

View file

@ -1,5 +1,5 @@
use crate::{
asset::AssetStorage,
asset::{AssetStorage, Handle},
render::{
pipeline::BindType,
render_resource::{BufferUsage, RenderResource, ResourceProvider},
@ -9,31 +9,313 @@ use crate::{
Renderable,
},
};
use legion::prelude::*;
use legion::{filter::*, prelude::*};
use std::{
collections::{HashMap, HashSet},
marker::PhantomData,
ops::Deref,
};
pub const BIND_BUFFER_ALIGNMENT: u64 = 256;
pub struct UniformResourceProvider<T>
where
T: AsUniforms + Send + Sync,
T: AsUniforms + Send + Sync + 'static,
{
_marker: PhantomData<T>,
// PERF: somehow remove this HashSet
uniform_buffer_info_resources:
HashMap<String, (Option<RenderResource>, usize, HashSet<Entity>)>,
asset_resources: HashMap<Handle<T>, HashMap<String, RenderResource>>,
resource_query: Query<
(Read<T>, Read<Renderable>),
EntityFilterTuple<
And<(ComponentFilter<T>, ComponentFilter<Renderable>)>,
And<(Passthrough, Passthrough)>,
And<(Passthrough, Passthrough)>,
>,
>,
handle_query: Option<
Query<
(Read<Handle<T>>, Read<Renderable>),
EntityFilterTuple<
And<(ComponentFilter<Handle<T>>, ComponentFilter<Renderable>)>,
And<(Passthrough, Passthrough)>,
And<(Passthrough, Passthrough)>,
>,
>,
>,
}
impl<T> UniformResourceProvider<T>
where
T: AsUniforms + Send + Sync,
T: AsUniforms + Send + Sync + 'static,
{
pub fn new() -> Self {
UniformResourceProvider {
uniform_buffer_info_resources: HashMap::new(),
uniform_buffer_info_resources: Default::default(),
asset_resources: Default::default(),
_marker: PhantomData,
resource_query: <(Read<T>, Read<Renderable>)>::query(),
handle_query: Some(<(Read<Handle<T>>, Read<Renderable>)>::query()),
}
}
fn update_asset_uniforms(
&mut self,
renderer: &mut dyn Renderer,
world: &World,
resources: &Resources,
) {
let handle_query = self.handle_query.take().unwrap();
// TODO: only update handle values when Asset value has changed
if let Some(asset_storage) = resources.get::<AssetStorage<T>>() {
for (entity, (handle, _renderable)) in handle_query.iter_entities(world) {
if let Some(uniforms) = asset_storage.get(&handle) {
self.setup_entity_uniform_resources(
entity,
uniforms,
renderer,
resources,
false,
Some(*handle),
)
}
}
}
self.handle_query = Some(handle_query);
}
fn setup_entity_uniform_resources(
&mut self,
entity: Entity,
uniforms: &T,
renderer: &mut dyn Renderer,
resources: &Resources,
dynamic_unforms: bool,
asset_handle: Option<Handle<T>>,
) {
let field_infos = uniforms.get_field_infos();
for uniform_info in UniformInfoIter::new(field_infos, uniforms.deref()) {
match uniform_info.bind_type {
BindType::Uniform { .. } => {
if dynamic_unforms {
if let None = self.uniform_buffer_info_resources.get(uniform_info.name) {
self.uniform_buffer_info_resources
.insert(uniform_info.name.to_string(), (None, 0, HashSet::new()));
}
let (_resource, counts, entities) = self
.uniform_buffer_info_resources
.get_mut(uniform_info.name)
.unwrap();
entities.insert(entity);
*counts += 1;
} else {
let handle = asset_handle.unwrap();
if let None = self.asset_resources.get(&handle) {
self.asset_resources.insert(handle, HashMap::new());
}
let resources = self.asset_resources.get_mut(&handle).unwrap();
let render_resource = match resources.get(uniform_info.name) {
Some(render_resource) => *render_resource,
None => {
// let size = uniform_info.bind_type.get_uniform_size().unwrap();
let size = BIND_BUFFER_ALIGNMENT;
let resource = renderer.create_buffer(
size,
BufferUsage::COPY_DST | BufferUsage::UNIFORM,
);
resources.insert(uniform_info.name.to_string(), resource);
resource
}
};
renderer.set_entity_uniform_resource(
entity,
uniform_info.name,
render_resource,
);
let (tmp_buffer, tmp_buffer_size) = if let Some(uniform_bytes) =
uniforms.get_uniform_bytes_ref(uniform_info.name)
{
(
renderer.create_buffer_mapped(
uniform_bytes.len(),
BufferUsage::COPY_SRC,
&mut |mapped| {
mapped.copy_from_slice(uniform_bytes);
},
),
uniform_bytes.len(),
)
} else if let Some(uniform_bytes) =
uniforms.get_uniform_bytes(uniform_info.name)
{
(
renderer.create_buffer_mapped(
uniform_bytes.len(),
BufferUsage::COPY_SRC,
&mut |mapped| {
mapped.copy_from_slice(&uniform_bytes);
},
),
uniform_bytes.len(),
)
} else {
panic!("failed to get data from uniform: {}", uniform_info.name);
};
renderer.copy_buffer_to_buffer(
tmp_buffer,
0,
render_resource,
0,
tmp_buffer_size as u64,
);
renderer.remove_buffer(tmp_buffer);
}
}
BindType::SampledTexture { .. } => {
let texture_handle = uniforms.get_uniform_texture(&uniform_info.name).unwrap();
let resource = match renderer
.get_render_resources()
.get_texture_resource(texture_handle)
{
Some(resource) => resource,
None => {
let storage = resources.get::<AssetStorage<Texture>>().unwrap();
let texture = storage.get(&texture_handle).unwrap();
let descriptor: TextureDescriptor = texture.into();
let resource =
renderer.create_texture(&descriptor, Some(&texture.data));
renderer
.get_render_resources_mut()
.set_texture_resource(texture_handle, resource);
resource
}
};
renderer.set_entity_uniform_resource(entity, uniform_info.name, resource);
}
BindType::Sampler { .. } => {
let texture_handle = uniforms.get_uniform_texture(&uniform_info.name).unwrap();
let resource = match renderer
.get_render_resources()
.get_texture_sampler_resource(texture_handle)
{
Some(resource) => resource,
None => {
let storage = resources.get::<AssetStorage<Texture>>().unwrap();
let texture = storage.get(&texture_handle).unwrap();
let descriptor: SamplerDescriptor = texture.into();
let resource = renderer.create_sampler(&descriptor);
renderer
.get_render_resources_mut()
.set_texture_sampler_resource(texture_handle, resource);
resource
}
};
renderer.set_entity_uniform_resource(entity, uniform_info.name, resource);
}
_ => panic!(
"encountered unsupported bind_type {:?}",
uniform_info.bind_type
),
}
}
}
fn setup_dynamic_uniform_buffers(&mut self, renderer: &mut dyn Renderer, world: &World) {
// allocate uniform buffers
for (name, (resource, count, _entities)) in self.uniform_buffer_info_resources.iter_mut() {
let count = *count as u64;
if let Some(resource) = resource {
let mut info = renderer
.get_dynamic_uniform_buffer_info_mut(*resource)
.unwrap();
info.count = count;
continue;
}
// allocate enough space for twice as many entities as there are currently;
let capacity = count * 2;
let size = BIND_BUFFER_ALIGNMENT * capacity;
let created_resource =
renderer.create_buffer(size, BufferUsage::COPY_DST | BufferUsage::UNIFORM);
let mut info = DynamicUniformBufferInfo::new();
info.count = count;
info.capacity = capacity;
renderer.add_dynamic_uniform_buffer_info(created_resource, info);
*resource = Some(created_resource);
renderer
.get_render_resources_mut()
.set_named_resource(name, created_resource);
}
// copy entity uniform data to buffers
for (name, (resource, _count, entities)) in self.uniform_buffer_info_resources.iter() {
let resource = resource.unwrap();
let size = {
// TODO: this lookup isn't needed anymore?
let info = renderer.get_dynamic_uniform_buffer_info(resource).unwrap();
BIND_BUFFER_ALIGNMENT * info.count
};
let alignment = BIND_BUFFER_ALIGNMENT as usize;
let mut offset = 0usize;
let info = renderer
.get_dynamic_uniform_buffer_info_mut(resource)
.unwrap();
for (entity, _) in self.resource_query.iter_entities(world) {
if !entities.contains(&entity) {
continue;
}
// TODO: check if index has changed. if it has, then entity should be updated
// TODO: only mem-map entities if their data has changed
// PERF: These hashmap inserts are pretty expensive (10 fps for 10000 entities)
info.offsets.insert(entity, offset as u32);
// TODO: try getting ref first
offset += alignment;
}
let mapped_buffer_resource = renderer.create_buffer_mapped(
size as usize,
BufferUsage::COPY_SRC,
&mut |mapped| {
let alignment = BIND_BUFFER_ALIGNMENT as usize;
let mut offset = 0usize;
for (entity, (uniforms, _renderable)) in
self.resource_query.iter_entities(world)
{
if !entities.contains(&entity) {
continue;
}
// TODO: check if index has changed. if it has, then entity should be updated
// TODO: only mem-map entities if their data has changed
if let Some(uniform_bytes) = uniforms.get_uniform_bytes_ref(&name) {
mapped[offset..(offset + uniform_bytes.len())]
.copy_from_slice(uniform_bytes);
offset += alignment;
} else if let Some(uniform_bytes) = uniforms.get_uniform_bytes(&name) {
mapped[offset..(offset + uniform_bytes.len())]
.copy_from_slice(uniform_bytes.as_slice());
offset += alignment;
}
}
},
);
renderer.copy_buffer_to_buffer(mapped_buffer_resource, 0, resource, 0, size);
// TODO: uncomment this to free resource?
renderer.remove_buffer(mapped_buffer_resource);
}
}
}
@ -66,160 +348,13 @@ where
*count = 0;
}
self.update_asset_uniforms(renderer, world, resources);
for (entity, (uniforms, _renderable)) in query.iter_entities(world) {
let field_infos = uniforms.get_field_infos();
for uniform_info in UniformInfoIter::new(field_infos, uniforms.deref()) {
match uniform_info.bind_type {
BindType::Uniform { .. } => {
// only add the first time a uniform info is processed
if let None = self.uniform_buffer_info_resources.get(uniform_info.name) {
self.uniform_buffer_info_resources
.insert(uniform_info.name.to_string(), (None, 0, HashSet::new()));
self.setup_entity_uniform_resources(entity, &uniforms, renderer, resources, true, None);
}
let (_resource, counts, entities) = self
.uniform_buffer_info_resources
.get_mut(uniform_info.name)
.unwrap();
entities.insert(entity);
*counts += 1;
}
BindType::SampledTexture { .. } => {
let texture_handle =
uniforms.get_uniform_texture(&uniform_info.name).unwrap();
let storage = resources.get::<AssetStorage<Texture>>().unwrap();
let texture = storage.get(&texture_handle).unwrap();
let resource = match renderer
.get_render_resources()
.get_texture_resource(texture_handle)
{
Some(resource) => resource,
None => {
let descriptor: TextureDescriptor = texture.into();
let resource =
renderer.create_texture(&descriptor, Some(&texture.data));
renderer
.get_render_resources_mut()
.set_texture_resource(texture_handle, resource);
resource
}
};
renderer.set_entity_uniform_resource(entity, uniform_info.name, resource);
}
BindType::Sampler { .. } => {
let texture_handle =
uniforms.get_uniform_texture(&uniform_info.name).unwrap();
let storage = resources.get::<AssetStorage<Texture>>().unwrap();
let texture = storage.get(&texture_handle).unwrap();
let resource = match renderer
.get_render_resources()
.get_texture_sampler_resource(texture_handle)
{
Some(resource) => resource,
None => {
let descriptor: SamplerDescriptor = texture.into();
let resource = renderer.create_sampler(&descriptor);
renderer
.get_render_resources_mut()
.set_texture_sampler_resource(texture_handle, resource);
resource
}
};
renderer.set_entity_uniform_resource(entity, uniform_info.name, resource);
}
_ => panic!(
"encountered unsupported bind_type {:?}",
uniform_info.bind_type
),
}
}
}
// allocate uniform buffers
for (name, (resource, count, _entities)) in self.uniform_buffer_info_resources.iter_mut() {
let count = *count as u64;
if let Some(resource) = resource {
let mut info = renderer
.get_dynamic_uniform_buffer_info_mut(*resource)
.unwrap();
info.count = count;
continue;
}
// allocate enough space for twice as many entities as there are currently;
let capacity = count * 2;
let size = BIND_BUFFER_ALIGNMENT * capacity;
let created_resource =
renderer.create_buffer(size, BufferUsage::COPY_DST | BufferUsage::UNIFORM);
let mut info = DynamicUniformBufferInfo::new();
info.count = count;
info.capacity = capacity;
renderer.add_dynamic_uniform_buffer_info(created_resource, info);
*resource = Some(created_resource);
renderer
.get_render_resources_mut()
.set_named_resource(name, created_resource);
}
// copy entity uniform data to buffers
for (name, (resource, _count, entities)) in self.uniform_buffer_info_resources.iter() {
let resource = resource.unwrap();
let size = {
let info = renderer.get_dynamic_uniform_buffer_info(resource).unwrap();
BIND_BUFFER_ALIGNMENT * info.count
};
let alignment = BIND_BUFFER_ALIGNMENT as usize;
let mut offset = 0usize;
let info = renderer
.get_dynamic_uniform_buffer_info_mut(resource)
.unwrap();
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: only mem-map entities if their data has changed
// PERF: These hashmap inserts are pretty expensive (10 fps for 10000 entities)
info.offsets.insert(entity, offset as u32);
// TODO: try getting ref first
offset += alignment;
}
let mapped_buffer_resource = renderer.create_buffer_mapped(
size as usize,
BufferUsage::COPY_SRC,
&mut |mapped| {
let alignment = BIND_BUFFER_ALIGNMENT as usize;
let mut offset = 0usize;
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: only mem-map entities if their data has changed
if let Some(uniform_bytes) = uniforms.get_uniform_bytes_ref(&name) {
mapped[offset..(offset + uniform_bytes.len())]
.copy_from_slice(uniform_bytes);
offset += alignment;
}
else if let Some(uniform_bytes) = uniforms.get_uniform_bytes(&name) {
mapped[offset..(offset + uniform_bytes.len())]
.copy_from_slice(uniform_bytes.as_slice());
offset += alignment;
}
}
},
);
renderer.copy_buffer_to_buffer(mapped_buffer_resource, 0, resource, 0, size);
// TODO: uncomment this to free resource?
renderer.remove_buffer(mapped_buffer_resource);
}
self.setup_dynamic_uniform_buffers(renderer, world);
// update shader assignments based on current macro defs
for (uniforms, mut renderable) in <(Read<T>, Write<Renderable>)>::query().iter_mut(world) {
@ -229,5 +364,18 @@ where
}
}
}
if let Some(asset_storage) = resources.get::<AssetStorage<T>>() {
for (handle, mut renderable) in
<(Read<Handle<T>>, Write<Renderable>)>::query().iter_mut(world)
{
let uniforms = asset_storage.get(&handle).unwrap();
if let Some(shader_defs) = uniforms.get_shader_defs() {
for shader_def in shader_defs {
renderable.shader_defs.insert(shader_def);
}
}
}
}
}
}

View file

@ -62,6 +62,7 @@ impl<'a, 'b, 'c, 'd> RenderPass for WgpuRenderPass<'a, 'b, 'c, 'd> {
}
};
// setup dynamic uniform instances
let mut dynamic_uniform_indices = Vec::new();
for binding in bind_group.bindings.iter() {
if let BindType::Uniform { dynamic, .. } = binding.bind_type {

View file

@ -11,7 +11,6 @@ use std::{borrow::Cow, collections::HashMap};
pub struct BindGroupInfo {
pub bind_group: wgpu::BindGroup,
pub unset_uniforms: Vec<String>,
}
pub struct WgpuResources {
@ -53,38 +52,13 @@ impl WgpuResources {
let bind_group_id = bind_group.get_hash().unwrap();
if let None = self.bind_groups.get(&bind_group_id) {
let mut unset_uniforms = Vec::new();
let mut binding_resources = Vec::new();
// if a uniform resource buffer doesn't exist, create a new empty one
for binding in bind_group.bindings.iter() {
let resource = match self.render_resources.get_named_resource(&binding.name) {
resource @ Some(_) => resource,
None => {
match binding.bind_type {
BindType::Uniform { .. } => {
// println!(
// "Warning: creating new empty buffer for uniform binding {} {:?}",
// binding.name, binding
// );
unset_uniforms.push(binding.name.to_string());
let size = binding.bind_type.get_uniform_size().unwrap();
let resource = self.create_buffer(
device,
size,
BufferUsage::UNIFORM | BufferUsage::COPY_DST,
);
self.render_resources
.set_named_resource(&binding.name, resource);
Some(resource)
}
BindType::Sampler | BindType::SampledTexture { .. } => {
// textures and samplers are handled per-entity
return;
}
_ => panic!("unsupported bind type: {:?}", binding),
}
return
}
};
@ -138,7 +112,6 @@ impl WgpuResources {
bind_group_id,
BindGroupInfo {
bind_group,
unset_uniforms,
},
);
}
@ -184,6 +157,17 @@ impl WgpuResources {
panic!("expected a Sampler resource");
}
}
BindType::Uniform { .. } => {
if let ResourceInfo::Buffer { size, .. } = resource_info {
let buffer = self.buffers.get(&resource).unwrap();
wgpu::BindingResource::Buffer {
buffer,
range: 0..*size,
}
} else {
panic!("expected a Buffer resource");
}
}
_ => panic!("unsupported bind type"),
},
}
@ -207,7 +191,6 @@ impl WgpuResources {
(entity, bind_group_id),
BindGroupInfo {
bind_group,
unset_uniforms: Vec::new(),
},
);
}