mirror of
https://github.com/bevyengine/bevy
synced 2024-11-10 07:04:33 +00:00
Add Handle<T> support to uniform resource provider. Use Handle<StandardMaterial> instead of StandardMaterial
This commit is contained in:
parent
c1e66089cc
commit
5d99f3a7e8
14 changed files with 418 additions and 243 deletions
10
.vscode/settings.json
vendored
Normal file
10
.vscode/settings.json
vendored
Normal file
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"cSpell.words": [
|
||||
"Wgpu",
|
||||
"bools",
|
||||
"chunkset",
|
||||
"chunksets",
|
||||
"multizip",
|
||||
"passthrough"
|
||||
]
|
||||
}
|
|
@ -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>);
|
||||
|
||||
|
|
|
@ -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,
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
})
|
||||
|
|
|
@ -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()
|
||||
})
|
||||
|
|
|
@ -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 {
|
||||
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: 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(),
|
||||
},
|
||||
material: spawned_material_handle,
|
||||
translation: Translation::new(
|
||||
rng.gen_range(-50.0, 50.0),
|
||||
rng.gen_range(-50.0, 50.0),
|
||||
|
|
|
@ -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()
|
||||
})
|
||||
|
|
|
@ -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()
|
||||
})
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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()));
|
||||
}
|
||||
|
||||
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
|
||||
),
|
||||
}
|
||||
}
|
||||
self.setup_entity_uniform_resources(entity, &uniforms, renderer, resources, true, None);
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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(),
|
||||
},
|
||||
);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue