begin bind group rework
global and local bind groups are set up the same way (RenderResourceAssignments). bind groups are reused whenever possible
This commit is contained in:
parent
0316efc909
commit
d1db46ef54
@ -18,7 +18,7 @@ pub trait DrawTarget {
|
||||
);
|
||||
fn setup(
|
||||
&mut self,
|
||||
_world: &World,
|
||||
_world: &mut World,
|
||||
_resources: &Resources,
|
||||
_renderer: &mut dyn Renderer,
|
||||
_pipeline_handle: Handle<PipelineDescriptor>,
|
||||
|
||||
@ -66,7 +66,7 @@ impl DrawTarget for AssignedMeshesDrawTarget {
|
||||
}
|
||||
|
||||
// TODO: validate bind group properties against shader uniform properties at least once
|
||||
render_pass.set_render_resource_assignments(Some(&renderable.render_resource_assignments));
|
||||
render_pass.set_render_resources(&renderable.render_resource_assignments);
|
||||
render_pass.draw_indexed(0..current_mesh_index_len, 0, 0..1);
|
||||
}
|
||||
}
|
||||
@ -74,7 +74,7 @@ impl DrawTarget for AssignedMeshesDrawTarget {
|
||||
|
||||
fn setup(
|
||||
&mut self,
|
||||
world: &World,
|
||||
world: &mut World,
|
||||
resources: &Resources,
|
||||
renderer: &mut dyn Renderer,
|
||||
pipeline_handle: Handle<PipelineDescriptor>,
|
||||
@ -93,13 +93,13 @@ impl DrawTarget for AssignedMeshesDrawTarget {
|
||||
let entity = entity_render_resource_assignments
|
||||
.get(*assignment_id)
|
||||
.unwrap();
|
||||
let renderable = world.get_component::<Renderable>(*entity).unwrap();
|
||||
let mut renderable = world.get_component_mut::<Renderable>(*entity).unwrap();
|
||||
if !renderable.is_visible || renderable.is_instanced {
|
||||
continue;
|
||||
}
|
||||
|
||||
renderer.setup_bind_groups(
|
||||
&renderable.render_resource_assignments,
|
||||
&mut renderable.render_resource_assignments,
|
||||
pipeline_descriptor,
|
||||
);
|
||||
}
|
||||
|
||||
@ -52,7 +52,7 @@ impl DrawTarget for MeshesDrawTarget {
|
||||
}
|
||||
|
||||
// TODO: validate bind group properties against shader uniform properties at least once
|
||||
render_pass.set_render_resource_assignments(Some(&renderable.render_resource_assignments));
|
||||
render_pass.set_render_resources(&renderable.render_resource_assignments);
|
||||
render_pass.draw_indexed(0..current_mesh_index_len, 0, 0..1);
|
||||
}
|
||||
}
|
||||
|
||||
@ -26,7 +26,7 @@ impl DrawTarget for UiDrawTarget {
|
||||
fn draw(
|
||||
&self,
|
||||
_world: &World,
|
||||
_resources: &Resources,
|
||||
resources: &Resources,
|
||||
render_pass: &mut dyn RenderPass,
|
||||
_pipeline_handle: Handle<PipelineDescriptor>,
|
||||
) {
|
||||
@ -54,19 +54,21 @@ impl DrawTarget for UiDrawTarget {
|
||||
}
|
||||
};
|
||||
|
||||
render_pass.set_render_resource_assignments(None);
|
||||
render_pass.set_index_buffer(self.mesh_index_buffer.unwrap(), 0);
|
||||
render_pass.set_vertex_buffer(0, self.mesh_vertex_buffer.unwrap(), 0);
|
||||
render_pass.set_vertex_buffer(1, ui_instances_buffer, 0);
|
||||
render_pass.draw_indexed(
|
||||
0..self.mesh_index_length as u32,
|
||||
0,
|
||||
0..(index_count.unwrap() as u32),
|
||||
);
|
||||
// TODO: set global render resources
|
||||
// render_pass.set_render_resources(None);
|
||||
// render_pass.set_index_buffer(self.mesh_index_buffer.unwrap(), 0);
|
||||
// render_pass.set_vertex_buffer(0, self.mesh_vertex_buffer.unwrap(), 0);
|
||||
// render_pass.set_vertex_buffer(1, ui_instances_buffer, 0);
|
||||
// render_pass.draw_indexed(
|
||||
// 0..self.mesh_index_length as u32,
|
||||
// 0,
|
||||
// 0..(index_count.unwrap() as u32),
|
||||
// );
|
||||
}
|
||||
|
||||
fn setup(
|
||||
&mut self,
|
||||
_world: &World,
|
||||
_world: &mut World,
|
||||
_resources: &Resources,
|
||||
renderer: &mut dyn Renderer,
|
||||
_pipeline_handle: Handle<PipelineDescriptor>,
|
||||
|
||||
@ -8,7 +8,7 @@ use std::{
|
||||
pub struct BindGroupDescriptor {
|
||||
pub index: u32,
|
||||
pub bindings: BTreeSet<BindingDescriptor>,
|
||||
hash: Option<BindGroupDescriptorId>,
|
||||
pub id: BindGroupDescriptorId,
|
||||
}
|
||||
|
||||
#[derive(Hash, Copy, Clone, Eq, PartialEq, Debug)]
|
||||
@ -19,7 +19,7 @@ impl BindGroupDescriptor {
|
||||
let mut descriptor = BindGroupDescriptor {
|
||||
index,
|
||||
bindings: bindings.iter().cloned().collect(),
|
||||
hash: None,
|
||||
id: BindGroupDescriptorId(0),
|
||||
};
|
||||
|
||||
// TODO: remove all instances of get_or_update_id
|
||||
@ -27,27 +27,17 @@ impl BindGroupDescriptor {
|
||||
descriptor
|
||||
}
|
||||
|
||||
pub fn get_id(&self) -> Option<BindGroupDescriptorId> {
|
||||
self.hash
|
||||
}
|
||||
|
||||
pub fn get_or_update_id(&mut self) -> BindGroupDescriptorId {
|
||||
if self.hash.is_none() {
|
||||
self.update_id();
|
||||
}
|
||||
|
||||
self.hash.unwrap()
|
||||
}
|
||||
|
||||
pub fn update_id(&mut self) {
|
||||
let mut hasher = DefaultHasher::new();
|
||||
self.hash(&mut hasher);
|
||||
self.hash = Some(BindGroupDescriptorId(hasher.finish()));
|
||||
self.id = BindGroupDescriptorId(hasher.finish());
|
||||
}
|
||||
}
|
||||
|
||||
impl Hash for BindGroupDescriptor {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
// TODO: remove index from hash state (or at least id). index is not considered a part of a bind group on the gpu.
|
||||
// bind groups are bound to indices in pipelines
|
||||
self.index.hash(state);
|
||||
self.bindings.hash(state);
|
||||
}
|
||||
|
||||
@ -24,8 +24,8 @@ pub fn build_entity_render_resource_assignments_system() -> Box<dyn Schedulable>
|
||||
.write_resource::<EntityRenderResourceAssignments>()
|
||||
.with_query(<Write<Renderable>>::query().filter(changed::<Renderable>()))
|
||||
.build(|_, world, entity_assignments, query| {
|
||||
for (entity, mut renderable) in query.iter_entities_mut(world) {
|
||||
entity_assignments.set(renderable.render_resource_assignments.get_id(), entity);
|
||||
for (entity, renderable) in query.iter_entities_mut(world) {
|
||||
entity_assignments.set(renderable.render_resource_assignments.id, entity);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@ -3,6 +3,7 @@ use crate::{
|
||||
render::{mesh::Mesh, texture::Texture},
|
||||
};
|
||||
use std::collections::HashMap;
|
||||
use super::RenderResourceAssignments;
|
||||
|
||||
#[derive(Copy, Clone, Hash, Debug, Eq, PartialEq)]
|
||||
pub struct RenderResource(pub u64);
|
||||
@ -11,7 +12,7 @@ pub struct RenderResource(pub u64);
|
||||
// the overlap could cause accidents.
|
||||
#[derive(Default)]
|
||||
pub struct RenderResources {
|
||||
pub name_to_resource: HashMap<String, RenderResource>,
|
||||
pub global_assignments: RenderResourceAssignments,
|
||||
pub texture_to_resource: HashMap<Handle<Texture>, RenderResource>,
|
||||
pub texture_to_sampler_resource: HashMap<Handle<Texture>, RenderResource>,
|
||||
pub mesh_to_vertices_resource: HashMap<Handle<Mesh>, RenderResource>,
|
||||
@ -21,11 +22,11 @@ pub struct RenderResources {
|
||||
|
||||
impl RenderResources {
|
||||
pub fn set_named_resource(&mut self, name: &str, resource: RenderResource) {
|
||||
self.name_to_resource.insert(name.to_string(), resource);
|
||||
self.global_assignments.set(name, resource);
|
||||
}
|
||||
|
||||
pub fn get_named_resource(&self, name: &str) -> Option<RenderResource> {
|
||||
self.name_to_resource.get(name).cloned()
|
||||
self.global_assignments.get(name).map(|(r, _i)| r)
|
||||
}
|
||||
|
||||
pub fn set_texture_resource(&mut self, texture: Handle<Texture>, resource: RenderResource) {
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
use super::RenderResource;
|
||||
use crate::render::pipeline::BindGroupDescriptor;
|
||||
use crate::render::pipeline::{BindGroupDescriptor, BindGroupDescriptorId};
|
||||
use std::{
|
||||
collections::{hash_map::DefaultHasher, HashMap, HashSet},
|
||||
hash::{Hash, Hasher},
|
||||
@ -9,21 +9,42 @@ use uuid::Uuid;
|
||||
// PERF: if the assignments are scoped to a specific pipeline layout, then names could be replaced with indices here for a perf boost
|
||||
#[derive(Eq, PartialEq, Debug, Default)]
|
||||
pub struct RenderResourceAssignments {
|
||||
id: RenderResourceAssignmentsId,
|
||||
render_resources: HashMap<String, RenderResource>,
|
||||
pub id: RenderResourceAssignmentsId,
|
||||
render_resources: HashMap<String, (RenderResource, Option<u32>)>,
|
||||
vertex_buffers: HashMap<String, (RenderResource, Option<RenderResource>)>,
|
||||
bind_group_resource_sets:
|
||||
HashMap<BindGroupDescriptorId, (RenderResourceSetId, Option<Vec<u32>>)>,
|
||||
dirty_bind_groups: HashSet<BindGroupDescriptorId>,
|
||||
pub(crate) shader_defs: HashSet<String>,
|
||||
// TODO: move offsets here to reduce hashing costs?
|
||||
// render_resource_offsets: HashMap<String, >,
|
||||
}
|
||||
|
||||
impl RenderResourceAssignments {
|
||||
pub fn get(&self, name: &str) -> Option<RenderResource> {
|
||||
pub fn get(&self, name: &str) -> Option<(RenderResource, Option<u32>)> {
|
||||
self.render_resources.get(name).cloned()
|
||||
}
|
||||
|
||||
pub fn set(&mut self, name: &str, resource: RenderResource) {
|
||||
self.render_resources.insert(name.to_string(), resource);
|
||||
self.try_set_dirty(name, resource);
|
||||
self.render_resources
|
||||
.insert(name.to_string(), (resource, None));
|
||||
}
|
||||
|
||||
pub fn set_indexed(&mut self, name: &str, resource: RenderResource, index: u32) {
|
||||
self.try_set_dirty(name, resource);
|
||||
self.render_resources
|
||||
.insert(name.to_string(), (resource, Some(index)));
|
||||
}
|
||||
|
||||
fn try_set_dirty(&mut self, name: &str, resource: RenderResource) {
|
||||
if let Some((render_resource, _)) = self.render_resources.get(name) {
|
||||
if *render_resource != resource {
|
||||
// TODO: this is pretty crude. can we do better?
|
||||
for bind_group_id in self.bind_group_resource_sets.keys() {
|
||||
self.dirty_bind_groups.insert(*bind_group_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_vertex_buffer(
|
||||
@ -43,24 +64,55 @@ impl RenderResourceAssignments {
|
||||
.insert(name.to_string(), (vertices_resource, indices_resource));
|
||||
}
|
||||
|
||||
pub fn get_id(&self) -> RenderResourceAssignmentsId {
|
||||
self.id
|
||||
pub fn get_or_update_render_resource_set_id(
|
||||
&mut self,
|
||||
bind_group_descriptor: &BindGroupDescriptor,
|
||||
) -> Option<RenderResourceSetId> {
|
||||
if !self
|
||||
.bind_group_resource_sets
|
||||
.contains_key(&bind_group_descriptor.id)
|
||||
|| self.dirty_bind_groups.contains(&bind_group_descriptor.id)
|
||||
{
|
||||
let result = self.generate_render_resource_set_id(bind_group_descriptor);
|
||||
if let Some((set_id, indices)) = result {
|
||||
self.bind_group_resource_sets
|
||||
.insert(bind_group_descriptor.id, (set_id, indices));
|
||||
Some(set_id)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
self.bind_group_resource_sets
|
||||
.get(&bind_group_descriptor.id)
|
||||
.map(|(set_id, indices)| *set_id)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_render_resource_set_id(
|
||||
&self,
|
||||
bind_group_descriptor_id: BindGroupDescriptorId,
|
||||
) -> Option<&(RenderResourceSetId, Option<Vec<u32>>)> {
|
||||
self.bind_group_resource_sets.get(&bind_group_descriptor_id)
|
||||
}
|
||||
|
||||
fn generate_render_resource_set_id(
|
||||
&self,
|
||||
bind_group_descriptor: &BindGroupDescriptor,
|
||||
) -> Option<RenderResourceSetId> {
|
||||
) -> Option<(RenderResourceSetId, Option<Vec<u32>>)> {
|
||||
let mut hasher = DefaultHasher::new();
|
||||
let mut indices = Vec::new();
|
||||
for binding_descriptor in bind_group_descriptor.bindings.iter() {
|
||||
if let Some(render_resource) = self.get(&binding_descriptor.name) {
|
||||
if let Some((render_resource, index)) = self.get(&binding_descriptor.name) {
|
||||
render_resource.hash(&mut hasher);
|
||||
if let Some(index) = index {
|
||||
indices.push(index);
|
||||
}
|
||||
} else {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
|
||||
Some(RenderResourceSetId(hasher.finish()))
|
||||
Some((RenderResourceSetId(hasher.finish()), if indices.is_empty() { None } else { Some(indices) }))
|
||||
}
|
||||
}
|
||||
|
||||
@ -95,12 +147,10 @@ mod tests {
|
||||
dynamic: false,
|
||||
properties: vec![UniformProperty {
|
||||
name: "A".to_string(),
|
||||
property_type: UniformPropertyType::Struct(vec![
|
||||
UniformProperty {
|
||||
name: "".to_string(),
|
||||
property_type: UniformPropertyType::Mat4,
|
||||
}
|
||||
]),
|
||||
property_type: UniformPropertyType::Struct(vec![UniformProperty {
|
||||
name: "".to_string(),
|
||||
property_type: UniformPropertyType::Mat4,
|
||||
}]),
|
||||
}],
|
||||
},
|
||||
},
|
||||
@ -111,10 +161,10 @@ mod tests {
|
||||
dynamic: false,
|
||||
properties: vec![UniformProperty {
|
||||
name: "B".to_string(),
|
||||
property_type: UniformPropertyType::Float
|
||||
property_type: UniformPropertyType::Float,
|
||||
}],
|
||||
},
|
||||
}
|
||||
},
|
||||
],
|
||||
);
|
||||
|
||||
@ -130,20 +180,22 @@ mod tests {
|
||||
equal_assignments.set("a", RenderResource(1));
|
||||
equal_assignments.set("b", RenderResource(2));
|
||||
|
||||
let set_id = assignments.get_render_resource_set_id(&bind_group_descriptor);
|
||||
let set_id = assignments.get_or_update_render_resource_set_id(&bind_group_descriptor);
|
||||
assert_ne!(set_id, None);
|
||||
|
||||
let different_set_id = different_assignments.get_render_resource_set_id(&bind_group_descriptor);
|
||||
let different_set_id =
|
||||
different_assignments.get_or_update_render_resource_set_id(&bind_group_descriptor);
|
||||
assert_ne!(different_set_id, None);
|
||||
assert_ne!(different_set_id, set_id);
|
||||
|
||||
let equal_set_id = equal_assignments.get_render_resource_set_id(&bind_group_descriptor);
|
||||
let equal_set_id = equal_assignments.get_or_update_render_resource_set_id(&bind_group_descriptor);
|
||||
assert_ne!(equal_set_id, None);
|
||||
assert_eq!(equal_set_id, set_id);
|
||||
|
||||
let mut unmatched_assignments = RenderResourceAssignments::default();
|
||||
unmatched_assignments.set("a", RenderResource(1));
|
||||
let unmatched_set_id = unmatched_assignments.get_render_resource_set_id(&bind_group_descriptor);
|
||||
let unmatched_set_id =
|
||||
unmatched_assignments.get_or_update_render_resource_set_id(&bind_group_descriptor);
|
||||
assert_eq!(unmatched_set_id, None);
|
||||
}
|
||||
}
|
||||
|
||||
@ -84,4 +84,17 @@ impl ResourceProvider for MeshResourceProvider {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn finish_update(
|
||||
&mut self,
|
||||
_renderer: &mut dyn Renderer,
|
||||
_world: &mut World,
|
||||
resources: &Resources,
|
||||
) {
|
||||
let mesh_storage = resources.get_mut::<AssetStorage<Mesh>>().unwrap();
|
||||
let mut asset_batchers = resources.get_mut::<AssetBatchers>().unwrap();
|
||||
for batch in asset_batchers.get_handle_batches::<Mesh>() {
|
||||
// batch.render_resource_assignments.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -265,8 +265,8 @@ where
|
||||
})) = renderer.get_resource_info_mut(buffer)
|
||||
{
|
||||
let index = array_info
|
||||
.get_or_assign_index(render_resource_assignments.get_id());
|
||||
render_resource_assignments.set(&field_info.uniform_name, buffer);
|
||||
.get_or_assign_index(render_resource_assignments.id);
|
||||
render_resource_assignments.set_indexed(&field_info.uniform_name, buffer, index as u32);
|
||||
(buffer, index * uniform_buffer_status.aligned_size)
|
||||
} else {
|
||||
panic!("Expected a dynamic uniform buffer");
|
||||
@ -275,7 +275,7 @@ where
|
||||
let resource = match render_resource_assignments
|
||||
.get(field_info.uniform_name)
|
||||
{
|
||||
Some(render_resource) => render_resource,
|
||||
Some((render_resource, _index)) => render_resource,
|
||||
None => {
|
||||
let resource = renderer.create_buffer(BufferInfo {
|
||||
size,
|
||||
|
||||
@ -145,7 +145,7 @@ impl CompiledShaderMap {
|
||||
.assignments
|
||||
.get_mut(&final_handle)
|
||||
.unwrap();
|
||||
assignments.push(render_resource_assignments.get_id());
|
||||
assignments.push(render_resource_assignments.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -43,7 +43,7 @@ pub trait Renderer {
|
||||
fn get_render_resources_mut(&mut self) -> &mut RenderResources;
|
||||
fn setup_bind_groups(
|
||||
&mut self,
|
||||
render_resource_assignments: &RenderResourceAssignments,
|
||||
render_resource_assignments: &mut RenderResourceAssignments,
|
||||
pipeline_descriptor: &PipelineDescriptor,
|
||||
);
|
||||
}
|
||||
@ -55,5 +55,5 @@ pub trait RenderPass {
|
||||
fn set_index_buffer(&mut self, resource: RenderResource, offset: u64);
|
||||
fn set_vertex_buffer(&mut self, start_slot: u32, resource: RenderResource, offset: u64);
|
||||
fn draw_indexed(&mut self, indices: Range<u32>, base_vertex: i32, instances: Range<u32>);
|
||||
fn set_render_resource_assignments(&mut self, render_resource_assignments: Option<&RenderResourceAssignments>) -> Option<Range<u32>>;
|
||||
fn set_render_resources(&mut self, render_resource_assignments: &RenderResourceAssignments) -> Option<Range<u32>>;
|
||||
}
|
||||
|
||||
@ -38,66 +38,33 @@ impl<'a, 'b, 'c, 'd> RenderPass for WgpuRenderPass<'a, 'b, 'c, 'd> {
|
||||
.draw_indexed(indices, base_vertex, instances);
|
||||
}
|
||||
|
||||
fn set_render_resource_assignments(
|
||||
fn set_render_resources(
|
||||
&mut self,
|
||||
render_resource_assignments: Option<&RenderResourceAssignments>,
|
||||
render_resource_assignments: &RenderResourceAssignments,
|
||||
) -> Option<Range<u32>> {
|
||||
let pipeline_layout = self.pipeline_descriptor.get_layout().unwrap();
|
||||
for bind_group in pipeline_layout.bind_groups.iter() {
|
||||
let bind_group_id = bind_group.get_id().unwrap();
|
||||
let wgpu_bind_group = match self.wgpu_resources.bind_groups.get(&bind_group_id) {
|
||||
// if there is a "global" bind group, use that
|
||||
Some(wgpu_bind_group) => wgpu_bind_group,
|
||||
// otherwise try to get an entity-specific bind group
|
||||
None => {
|
||||
if let Some(assignments) = render_resource_assignments {
|
||||
self.wgpu_resources
|
||||
.get_assignments_bind_group(assignments.get_id(), bind_group_id)
|
||||
.unwrap()
|
||||
if let Some((render_resource_set_id, dynamic_uniform_indices)) =
|
||||
render_resource_assignments.get_render_resource_set_id(bind_group.id)
|
||||
{
|
||||
if let Some(wgpu_bind_group) = self
|
||||
.wgpu_resources
|
||||
.get_bind_group(bind_group.id, *render_resource_set_id)
|
||||
{
|
||||
// TODO: check to see if bind group is already set
|
||||
let empty = &[];
|
||||
let dynamic_uniform_indices = if let Some(dynamic_uniform_indices) = dynamic_uniform_indices {
|
||||
dynamic_uniform_indices.as_slice()
|
||||
} else {
|
||||
panic!("No bind group exists that matches: {:?}");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 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 {
|
||||
if !dynamic {
|
||||
continue;
|
||||
}
|
||||
|
||||
// PERF: This hashmap get is pretty expensive (10 fps for 10000 entities)
|
||||
if let Some(resource) = self
|
||||
.wgpu_resources
|
||||
.render_resources
|
||||
.get_named_resource(&binding.name)
|
||||
{
|
||||
if let Some(ResourceInfo::Buffer(BufferInfo {
|
||||
array_info: Some(array_info),
|
||||
is_dynamic: true,
|
||||
..
|
||||
})) = self.wgpu_resources.resource_info.get(&resource)
|
||||
{
|
||||
let index = array_info
|
||||
.indices
|
||||
.get(&render_resource_assignments.unwrap().get_id())
|
||||
.unwrap();
|
||||
|
||||
dynamic_uniform_indices.push((*index * array_info.item_size) as u32);
|
||||
}
|
||||
}
|
||||
}
|
||||
empty
|
||||
};
|
||||
self.render_pass.set_bind_group(
|
||||
bind_group.index,
|
||||
&wgpu_bind_group,
|
||||
dynamic_uniform_indices,
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
// TODO: check to see if bind group is already set
|
||||
self.render_pass.set_bind_group(
|
||||
bind_group.index,
|
||||
&wgpu_bind_group,
|
||||
dynamic_uniform_indices.as_slice(),
|
||||
);
|
||||
}
|
||||
|
||||
None
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
use super::{wgpu_type_converter::OwnedWgpuVertexBufferDescriptor, WgpuRenderPass, WgpuResources};
|
||||
use crate::{
|
||||
asset::{AssetStorage, Handle},
|
||||
core::Window,
|
||||
legion::prelude::*,
|
||||
render::{
|
||||
pass::{
|
||||
@ -17,7 +18,7 @@ use crate::{
|
||||
shader::Shader,
|
||||
texture::{SamplerDescriptor, TextureDescriptor},
|
||||
update_shader_assignments,
|
||||
}, core::Window,
|
||||
},
|
||||
};
|
||||
use std::{cell::RefCell, collections::HashMap, ops::Deref, rc::Rc};
|
||||
|
||||
@ -183,8 +184,7 @@ impl WgpuRenderer {
|
||||
|
||||
// setup new bind group layouts
|
||||
for bind_group in layout.bind_groups.iter_mut() {
|
||||
let bind_group_id = bind_group.get_or_update_id();
|
||||
if let None = wgpu_resources.bind_group_layouts.get(&bind_group_id) {
|
||||
if let None = wgpu_resources.bind_group_layouts.get(&bind_group.id) {
|
||||
let bind_group_layout_binding = bind_group
|
||||
.bindings
|
||||
.iter()
|
||||
@ -201,7 +201,7 @@ impl WgpuRenderer {
|
||||
|
||||
wgpu_resources
|
||||
.bind_group_layouts
|
||||
.insert(bind_group_id, bind_group_layout);
|
||||
.insert(bind_group.id, bind_group_layout);
|
||||
}
|
||||
}
|
||||
|
||||
@ -210,10 +210,9 @@ impl WgpuRenderer {
|
||||
.bind_groups
|
||||
.iter()
|
||||
.map(|bind_group| {
|
||||
let bind_group_id = bind_group.get_id().unwrap();
|
||||
wgpu_resources
|
||||
.bind_group_layouts
|
||||
.get(&bind_group_id)
|
||||
.get(&bind_group.id)
|
||||
.unwrap()
|
||||
})
|
||||
.collect::<Vec<&wgpu::BindGroupLayout>>();
|
||||
@ -434,13 +433,7 @@ impl Renderer for WgpuRenderer {
|
||||
resources.insert(swap_chain);
|
||||
let mut render_graph = resources.get_mut::<RenderGraph>().unwrap();
|
||||
for resource_provider in render_graph.resource_providers.iter_mut() {
|
||||
resource_provider.resize(
|
||||
self,
|
||||
world,
|
||||
resources,
|
||||
width,
|
||||
height,
|
||||
);
|
||||
resource_provider.resize(self, world, resources, width, height);
|
||||
}
|
||||
|
||||
// consume current encoder
|
||||
@ -506,13 +499,6 @@ impl Renderer for WgpuRenderer {
|
||||
self.render_pipelines
|
||||
.insert(*pipeline_descriptor_handle, render_pipeline);
|
||||
}
|
||||
|
||||
// create bind groups
|
||||
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.borrow(), bind_group);
|
||||
}
|
||||
}
|
||||
|
||||
// setup draw targets
|
||||
@ -649,19 +635,19 @@ impl Renderer for WgpuRenderer {
|
||||
|
||||
fn setup_bind_groups(
|
||||
&mut self,
|
||||
render_resource_assignments: &RenderResourceAssignments,
|
||||
render_resource_assignments: &mut RenderResourceAssignments,
|
||||
pipeline_descriptor: &PipelineDescriptor,
|
||||
) {
|
||||
let pipeline_layout = pipeline_descriptor.get_layout().unwrap();
|
||||
for bind_group in pipeline_layout.bind_groups.iter() {
|
||||
let bind_group_id = bind_group.get_id().unwrap();
|
||||
// only setup entity bind groups if there isn't already a "global" bind group created
|
||||
if let None = self.wgpu_resources.bind_groups.get(&bind_group_id) {
|
||||
if let Some(render_resource_set_id) =
|
||||
render_resource_assignments.get_or_update_render_resource_set_id(bind_group)
|
||||
{
|
||||
if let None = self
|
||||
.wgpu_resources
|
||||
.get_assignments_bind_group(render_resource_assignments.get_id(), bind_group_id)
|
||||
.get_bind_group(bind_group.id, render_resource_set_id)
|
||||
{
|
||||
self.wgpu_resources.create_assignments_bind_group(
|
||||
self.wgpu_resources.create_bind_group(
|
||||
&self.device.borrow(),
|
||||
bind_group,
|
||||
render_resource_assignments,
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
use super::WgpuRenderer;
|
||||
use crate::render::{
|
||||
pipeline::{BindGroupDescriptor, BindType, BindGroupDescriptorId},
|
||||
pipeline::{BindGroupDescriptor, BindGroupDescriptorId, BindType},
|
||||
render_resource::{
|
||||
BufferInfo, RenderResource, RenderResourceAssignments, RenderResourceAssignmentsId,
|
||||
BufferInfo, RenderResource, RenderResourceAssignments, RenderResourceSetId,
|
||||
RenderResources, ResourceInfo,
|
||||
},
|
||||
renderer::Renderer,
|
||||
@ -10,15 +10,19 @@ use crate::render::{
|
||||
};
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct WgpuBindGroupInfo {
|
||||
pub bind_groups: HashMap<RenderResourceSetId, wgpu::BindGroup>,
|
||||
}
|
||||
|
||||
pub struct WgpuResources {
|
||||
pub render_resources: RenderResources,
|
||||
pub buffers: HashMap<RenderResource, wgpu::Buffer>,
|
||||
pub textures: HashMap<RenderResource, wgpu::TextureView>,
|
||||
pub samplers: HashMap<RenderResource, wgpu::Sampler>,
|
||||
pub resource_info: HashMap<RenderResource, ResourceInfo>,
|
||||
pub bind_groups: HashMap<BindGroupDescriptorId, wgpu::BindGroup>,
|
||||
pub bind_groups: HashMap<BindGroupDescriptorId, WgpuBindGroupInfo>,
|
||||
pub bind_group_layouts: HashMap<BindGroupDescriptorId, wgpu::BindGroupLayout>,
|
||||
pub assignment_bind_groups: HashMap<(RenderResourceAssignmentsId, BindGroupDescriptorId), wgpu::BindGroup>,
|
||||
}
|
||||
|
||||
impl WgpuResources {
|
||||
@ -30,7 +34,6 @@ impl WgpuResources {
|
||||
resource_info: HashMap::new(),
|
||||
bind_groups: HashMap::new(),
|
||||
bind_group_layouts: HashMap::new(),
|
||||
assignment_bind_groups: HashMap::new(),
|
||||
render_resources: RenderResources::default(),
|
||||
}
|
||||
}
|
||||
@ -39,142 +42,98 @@ impl WgpuResources {
|
||||
self.resource_info.insert(resource, resource_info);
|
||||
}
|
||||
|
||||
// TODO: consider moving this to a resource provider
|
||||
pub fn setup_bind_group(&mut self, device: &wgpu::Device, bind_group_descriptor: &BindGroupDescriptor) {
|
||||
let bind_group_descriptor_id = bind_group_descriptor.get_id().unwrap();
|
||||
|
||||
if let None = self.bind_groups.get(&bind_group_descriptor_id) {
|
||||
let mut binding_resources = Vec::new();
|
||||
// if a uniform resource buffer doesn't exist, create a new empty one
|
||||
for binding in bind_group_descriptor.bindings.iter() {
|
||||
let resource = match self.render_resources.get_named_resource(&binding.name) {
|
||||
resource @ Some(_) => resource,
|
||||
None => return,
|
||||
};
|
||||
|
||||
if let Some(resource) = resource {
|
||||
binding_resources.push(resource);
|
||||
}
|
||||
}
|
||||
|
||||
// create wgpu Bindings
|
||||
let bindings = bind_group_descriptor
|
||||
.bindings
|
||||
.iter()
|
||||
.zip(binding_resources)
|
||||
.map(|(binding, resource)| {
|
||||
let resource_info = self.resource_info.get(&resource).unwrap();
|
||||
wgpu::Binding {
|
||||
binding: binding.index,
|
||||
resource: match &binding.bind_type {
|
||||
BindType::Uniform {
|
||||
dynamic: _,
|
||||
properties: _,
|
||||
} => {
|
||||
if let ResourceInfo::Buffer(buffer_info) = resource_info {
|
||||
let buffer = self.buffers.get(&resource).unwrap();
|
||||
wgpu::BindingResource::Buffer {
|
||||
buffer,
|
||||
range: 0..buffer_info.size as u64,
|
||||
}
|
||||
} else {
|
||||
panic!("expected a Buffer resource");
|
||||
}
|
||||
}
|
||||
_ => panic!("unsupported bind type"),
|
||||
},
|
||||
}
|
||||
})
|
||||
.collect::<Vec<wgpu::Binding>>();
|
||||
|
||||
let bind_group_layout = self.bind_group_layouts.get(&bind_group_descriptor_id).unwrap();
|
||||
let bind_group_descriptor = wgpu::BindGroupDescriptor {
|
||||
layout: bind_group_layout,
|
||||
bindings: bindings.as_slice(),
|
||||
};
|
||||
|
||||
let bind_group = device.create_bind_group(&bind_group_descriptor);
|
||||
self.bind_groups
|
||||
.insert(bind_group_descriptor_id, bind_group);
|
||||
pub fn get_bind_group(
|
||||
&self,
|
||||
bind_group_descriptor_id: BindGroupDescriptorId,
|
||||
render_resource_set_id: RenderResourceSetId,
|
||||
) -> Option<&wgpu::BindGroup> {
|
||||
if let Some(bind_group_info) = self.bind_groups.get(&bind_group_descriptor_id) {
|
||||
bind_group_info.bind_groups.get(&render_resource_set_id)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
pub fn get_assignments_bind_group(
|
||||
&self,
|
||||
render_resource_assignment_id: RenderResourceAssignmentsId,
|
||||
bind_group_descriptor_id: BindGroupDescriptorId,
|
||||
) -> Option<&wgpu::BindGroup> {
|
||||
self.assignment_bind_groups
|
||||
.get(&(render_resource_assignment_id, bind_group_descriptor_id))
|
||||
}
|
||||
|
||||
pub fn create_assignments_bind_group(
|
||||
pub fn create_bind_group(
|
||||
&mut self,
|
||||
device: &wgpu::Device,
|
||||
bind_group_descriptor: &BindGroupDescriptor,
|
||||
render_resource_assignments: &RenderResourceAssignments,
|
||||
) {
|
||||
// TODO: don't make this per-entity. bind groups should be re-used across the same resource when possible
|
||||
let bind_group_descriptor_id = bind_group_descriptor.get_id().unwrap();
|
||||
let bindings = bind_group_descriptor
|
||||
.bindings
|
||||
.iter()
|
||||
.map(|binding| {
|
||||
if let Some(resource) = render_resource_assignments.get(&binding.name) {
|
||||
let resource_info = self.resource_info.get(&resource).unwrap();
|
||||
wgpu::Binding {
|
||||
binding: binding.index,
|
||||
resource: match &binding.bind_type {
|
||||
BindType::SampledTexture { .. } => {
|
||||
if let ResourceInfo::Texture = resource_info {
|
||||
let texture = self.textures.get(&resource).unwrap();
|
||||
wgpu::BindingResource::TextureView(texture)
|
||||
} else {
|
||||
panic!("expected a Texture resource");
|
||||
}
|
||||
}
|
||||
BindType::Sampler => {
|
||||
if let ResourceInfo::Sampler = resource_info {
|
||||
let sampler = self.samplers.get(&resource).unwrap();
|
||||
wgpu::BindingResource::Sampler(sampler)
|
||||
} else {
|
||||
panic!("expected a Sampler resource");
|
||||
}
|
||||
}
|
||||
BindType::Uniform { .. } => {
|
||||
if let ResourceInfo::Buffer(buffer_info) = resource_info {
|
||||
let buffer = self.buffers.get(&resource).unwrap();
|
||||
wgpu::BindingResource::Buffer {
|
||||
buffer,
|
||||
range: 0..buffer_info.size as u64,
|
||||
) -> bool {
|
||||
if let Some((render_resource_set_id, _indices)) =
|
||||
render_resource_assignments.get_render_resource_set_id(bind_group_descriptor.id)
|
||||
{
|
||||
let bindings = bind_group_descriptor
|
||||
.bindings
|
||||
.iter()
|
||||
.map(|binding| {
|
||||
if let Some((resource, index)) = render_resource_assignments.get(&binding.name) {
|
||||
let resource_info = self.resource_info.get(&resource).unwrap();
|
||||
wgpu::Binding {
|
||||
binding: binding.index,
|
||||
resource: match &binding.bind_type {
|
||||
BindType::SampledTexture { .. } => {
|
||||
if let ResourceInfo::Texture = resource_info {
|
||||
let texture = self.textures.get(&resource).unwrap();
|
||||
wgpu::BindingResource::TextureView(texture)
|
||||
} else {
|
||||
panic!("expected a Texture resource");
|
||||
}
|
||||
} else {
|
||||
panic!("expected a Buffer resource");
|
||||
}
|
||||
}
|
||||
_ => panic!("unsupported bind type"),
|
||||
},
|
||||
BindType::Sampler => {
|
||||
if let ResourceInfo::Sampler = resource_info {
|
||||
let sampler = self.samplers.get(&resource).unwrap();
|
||||
wgpu::BindingResource::Sampler(sampler)
|
||||
} else {
|
||||
panic!("expected a Sampler resource");
|
||||
}
|
||||
}
|
||||
BindType::Uniform { .. } => {
|
||||
if let ResourceInfo::Buffer(buffer_info) = resource_info {
|
||||
let buffer = self.buffers.get(&resource).unwrap();
|
||||
wgpu::BindingResource::Buffer {
|
||||
buffer,
|
||||
range: 0..buffer_info.size as u64,
|
||||
}
|
||||
} else {
|
||||
panic!("expected a Buffer resource");
|
||||
}
|
||||
}
|
||||
_ => panic!("unsupported bind type"),
|
||||
},
|
||||
}
|
||||
} else {
|
||||
panic!(
|
||||
"No resource assigned to uniform \"{}\" for RenderResourceAssignments {:?}",
|
||||
binding.name,
|
||||
render_resource_assignments.id
|
||||
);
|
||||
}
|
||||
} else {
|
||||
panic!(
|
||||
"No resource assigned to uniform \"{}\" for RenderResourceAssignments {:?}",
|
||||
binding.name,
|
||||
render_resource_assignments.get_id()
|
||||
);
|
||||
}
|
||||
})
|
||||
.collect::<Vec<wgpu::Binding>>();
|
||||
let bind_group_layout = self.bind_group_layouts.get(&bind_group_descriptor_id).unwrap();
|
||||
let bind_group_descriptor = wgpu::BindGroupDescriptor {
|
||||
layout: bind_group_layout,
|
||||
bindings: bindings.as_slice(),
|
||||
};
|
||||
})
|
||||
.collect::<Vec<wgpu::Binding>>();
|
||||
let bind_group_layout = self
|
||||
.bind_group_layouts
|
||||
.get(&bind_group_descriptor.id)
|
||||
.unwrap();
|
||||
let wgpu_bind_group_descriptor = wgpu::BindGroupDescriptor {
|
||||
layout: bind_group_layout,
|
||||
bindings: bindings.as_slice(),
|
||||
};
|
||||
|
||||
let bind_group = device.create_bind_group(&bind_group_descriptor);
|
||||
// TODO: storing a large number entity bind groups might actually be really bad. make sure this is ok
|
||||
self.assignment_bind_groups.insert(
|
||||
(render_resource_assignments.get_id(), bind_group_descriptor_id),
|
||||
bind_group,
|
||||
);
|
||||
let bind_group = device.create_bind_group(&wgpu_bind_group_descriptor);
|
||||
// TODO: storing a large number entity bind groups might actually be really bad. make sure this is ok
|
||||
|
||||
let mut bind_group_info = self
|
||||
.bind_groups
|
||||
.entry(bind_group_descriptor.id)
|
||||
.or_insert_with(|| WgpuBindGroupInfo::default());
|
||||
bind_group_info
|
||||
.bind_groups
|
||||
.insert(*render_resource_set_id, bind_group);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_buffer(
|
||||
|
||||
Loading…
Reference in New Issue
Block a user