bevy/src/render/renderer/renderers/wgpu_renderer/wgpu_resources.rs
Carter Anderson 9881f64715 cargo fmt
2020-03-20 12:47:33 -07:00

436 lines
15 KiB
Rust

use crate::{
legion::prelude::*,
render::{
pipeline::{BindGroup, BindType},
render_resource::{BufferUsage, RenderResource, RenderResources, ResourceInfo},
shader::DynamicUniformBufferInfo,
texture::{SamplerDescriptor, TextureDescriptor},
},
};
use std::{borrow::Cow, collections::HashMap};
pub struct BindGroupInfo {
pub bind_group: wgpu::BindGroup,
}
pub struct WgpuResources {
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<u64, BindGroupInfo>,
pub bind_group_layouts: HashMap<u64, wgpu::BindGroupLayout>,
pub entity_bind_groups: HashMap<(Entity, u64), BindGroupInfo>,
pub entity_uniform_resources:
HashMap<(Cow<'static, Entity>, Cow<'static, str>), RenderResource>,
pub dynamic_uniform_buffer_info: HashMap<RenderResource, DynamicUniformBufferInfo>,
pub render_resources: RenderResources,
}
impl WgpuResources {
pub fn new() -> Self {
WgpuResources {
buffers: HashMap::new(),
textures: HashMap::new(),
samplers: HashMap::new(),
resource_info: HashMap::new(),
bind_groups: HashMap::new(),
bind_group_layouts: HashMap::new(),
dynamic_uniform_buffer_info: HashMap::new(),
entity_bind_groups: HashMap::new(),
entity_uniform_resources: HashMap::new(),
render_resources: RenderResources::default(),
}
}
pub fn add_resource_info(&mut self, resource: RenderResource, resource_info: ResourceInfo) {
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: &BindGroup) {
let bind_group_id = bind_group.get_hash().unwrap();
if let None = self.bind_groups.get(&bind_group_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.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
.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 {
size,
buffer_usage: _,
} = 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"),
},
}
})
.collect::<Vec<wgpu::Binding>>();
let bind_group_layout = self.bind_group_layouts.get(&bind_group_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_id, BindGroupInfo { bind_group });
}
}
pub fn get_entity_bind_group(
&self,
entity: Entity,
bind_group_id: u64,
) -> Option<&BindGroupInfo> {
self.entity_bind_groups.get(&(entity, bind_group_id))
}
pub fn create_entity_bind_group(
&mut self,
device: &wgpu::Device,
bind_group: &BindGroup,
entity: Entity,
) {
// TODO: don't make this per-entity. bind groups should be re-used across the same resource when possible
let bind_group_id = bind_group.get_hash().unwrap();
let bindings = bind_group
.bindings
.iter()
.map(|binding| {
if let Some(resource) = self.get_entity_uniform_resource(entity, &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 { 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"),
},
}
} else {
panic!(
"No resource assigned to uniform \"{}\" for entity {}",
binding.name, entity
);
}
})
.collect::<Vec<wgpu::Binding>>();
let bind_group_layout = self.bind_group_layouts.get(&bind_group_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);
// TODO: storing a large number entity bind groups might actually be really bad. make sure this is ok
self.entity_bind_groups
.insert((entity, bind_group_id), BindGroupInfo { bind_group });
}
pub fn create_buffer(
&mut self,
device: &wgpu::Device,
size: u64,
buffer_usage: BufferUsage,
) -> RenderResource {
let buffer = device.create_buffer(&wgpu::BufferDescriptor {
size,
usage: buffer_usage.into(),
});
let resource = self.render_resources.get_next_resource();
self.add_resource_info(resource, ResourceInfo::Buffer { buffer_usage, size });
self.buffers.insert(resource, buffer);
resource
}
pub fn create_buffer_with_data(
&mut self,
device: &wgpu::Device,
data: &[u8],
buffer_usage: BufferUsage,
) -> RenderResource {
let resource = self.render_resources.get_next_resource();
let buffer = device.create_buffer_with_data(data, buffer_usage.into());
self.add_resource_info(
resource,
ResourceInfo::Buffer {
buffer_usage,
size: data.len() as u64,
},
);
self.buffers.insert(resource, buffer);
resource
}
pub fn create_instance_buffer(
&mut self,
device: &wgpu::Device,
mesh_id: usize,
size: usize,
count: usize,
buffer_usage: BufferUsage,
) -> RenderResource {
let buffer = device.create_buffer(&wgpu::BufferDescriptor {
size: (size * count) as u64,
usage: buffer_usage.into(),
});
let resource = self.render_resources.get_next_resource();
self.add_resource_info(
resource,
ResourceInfo::InstanceBuffer {
buffer_usage,
size,
count,
mesh_id,
},
);
self.buffers.insert(resource, buffer);
resource
}
pub fn create_instance_buffer_with_data(
&mut self,
device: &wgpu::Device,
mesh_id: usize,
data: &[u8],
size: usize,
count: usize,
buffer_usage: BufferUsage,
) -> RenderResource {
let buffer = device.create_buffer_with_data(data, buffer_usage.into());
let resource = self.render_resources.get_next_resource();
self.add_resource_info(
resource,
ResourceInfo::InstanceBuffer {
buffer_usage,
size,
count,
mesh_id,
},
);
self.buffers.insert(resource, buffer);
resource
}
pub fn get_resource_info(&self, resource: RenderResource) -> Option<&ResourceInfo> {
self.resource_info.get(&resource)
}
pub fn remove_buffer(&mut self, resource: RenderResource) {
self.buffers.remove(&resource);
self.resource_info.remove(&resource);
}
pub fn create_buffer_mapped(
&mut self,
device: &wgpu::Device,
size: usize,
buffer_usage: BufferUsage,
setup_data: &mut dyn FnMut(&mut [u8]),
) -> RenderResource {
let mut mapped = device.create_buffer_mapped(size, buffer_usage.into());
setup_data(&mut mapped.data);
let buffer = mapped.finish();
let resource = self.render_resources.get_next_resource();
self.add_resource_info(
resource,
ResourceInfo::Buffer {
buffer_usage,
size: size as u64,
},
);
self.buffers.insert(resource, buffer);
resource
}
pub fn copy_buffer_to_buffer(
&mut self,
encoder: &mut wgpu::CommandEncoder,
source_buffer: RenderResource,
source_offset: u64,
destination_buffer: RenderResource,
destination_offset: u64,
size: u64,
) {
let source = self.buffers.get(&source_buffer).unwrap();
let destination = self.buffers.get(&destination_buffer).unwrap();
encoder.copy_buffer_to_buffer(source, source_offset, destination, destination_offset, size);
}
pub fn get_dynamic_uniform_buffer_info(
&self,
resource: RenderResource,
) -> Option<&DynamicUniformBufferInfo> {
self.dynamic_uniform_buffer_info.get(&resource)
}
pub fn get_dynamic_uniform_buffer_info_mut(
&mut self,
resource: RenderResource,
) -> Option<&mut DynamicUniformBufferInfo> {
self.dynamic_uniform_buffer_info.get_mut(&resource)
}
pub fn add_dynamic_uniform_buffer_info(
&mut self,
resource: RenderResource,
info: DynamicUniformBufferInfo,
) {
self.dynamic_uniform_buffer_info.insert(resource, info);
}
pub fn create_sampler(
&mut self,
device: &wgpu::Device,
sampler_descriptor: &SamplerDescriptor,
) -> RenderResource {
let descriptor: wgpu::SamplerDescriptor = (*sampler_descriptor).into();
let sampler = device.create_sampler(&descriptor);
let resource = self.render_resources.get_next_resource();
self.samplers.insert(resource, sampler);
self.add_resource_info(resource, ResourceInfo::Sampler);
resource
}
pub fn create_texture(
&mut self,
device: &wgpu::Device,
encoder: &mut wgpu::CommandEncoder,
texture_descriptor: &TextureDescriptor,
bytes: Option<&[u8]>,
) -> RenderResource {
let descriptor: wgpu::TextureDescriptor = (*texture_descriptor).into();
let texture = device.create_texture(&descriptor);
let texture_view = texture.create_default_view();
if let Some(bytes) = bytes {
let temp_buf = device.create_buffer_with_data(bytes, wgpu::BufferUsage::COPY_SRC);
encoder.copy_buffer_to_texture(
wgpu::BufferCopyView {
buffer: &temp_buf,
offset: 0,
row_pitch: 4 * descriptor.size.width,
image_height: descriptor.size.height,
},
wgpu::TextureCopyView {
texture: &texture,
mip_level: 0,
array_layer: 0,
origin: wgpu::Origin3d { x: 0, y: 0, z: 0 },
},
descriptor.size,
);
}
let resource = self.render_resources.get_next_resource();
self.add_resource_info(resource, ResourceInfo::Texture);
self.textures.insert(resource, texture_view);
resource
}
pub fn remove_texture(&mut self, resource: RenderResource) {
self.textures.remove(&resource);
self.resource_info.remove(&resource);
}
pub fn remove_sampler(&mut self, resource: RenderResource) {
self.samplers.remove(&resource);
self.resource_info.remove(&resource);
}
pub fn get_render_resources(&self) -> &RenderResources {
&self.render_resources
}
pub fn get_render_resources_mut(&mut self) -> &mut RenderResources {
&mut self.render_resources
}
pub fn set_entity_uniform_resource(
&mut self,
entity: Entity,
uniform_name: &str,
resource: RenderResource,
) {
self.entity_uniform_resources.insert(
(Cow::Owned(entity), Cow::Owned(uniform_name.to_string())),
resource,
);
}
pub fn get_entity_uniform_resource(
&self,
entity: Entity,
uniform_name: &str,
) -> Option<RenderResource> {
self.entity_uniform_resources
.get(&(Cow::Owned(entity), Cow::Borrowed(uniform_name)))
.cloned()
}
}