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:
Carter Anderson 2020-03-26 01:57:36 -07:00
parent 0316efc909
commit d1db46ef54
15 changed files with 246 additions and 276 deletions

View File

@ -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>,

View File

@ -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,
);
}

View File

@ -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);
}
}

View File

@ -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>,

View File

@ -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);
}

View File

@ -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);
}
})
}

View File

@ -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) {

View File

@ -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);
}
}

View File

@ -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.
}
}
}

View File

@ -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,

View File

@ -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);
}
}
}

View File

@ -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>>;
}

View File

@ -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

View File

@ -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,

View File

@ -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(