Break up wgpu renderer
This commit is contained in:
parent
85c880e754
commit
cadea8deb0
@ -1,4 +1,4 @@
|
|||||||
use bevy::{asset, prelude::*};
|
use bevy::prelude::*;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
AppBuilder::new().add_defaults().setup_world(setup).run();
|
AppBuilder::new().add_defaults().setup_world(setup).run();
|
||||||
|
|||||||
7
src/render/render_graph/renderers/wgpu_renderer/mod.rs
Normal file
7
src/render/render_graph/renderers/wgpu_renderer/mod.rs
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
mod wgpu_renderer;
|
||||||
|
mod wgpu_resources;
|
||||||
|
mod wgpu_render_pass;
|
||||||
|
|
||||||
|
pub use wgpu_renderer::*;
|
||||||
|
pub use wgpu_resources::*;
|
||||||
|
pub use wgpu_render_pass::*;
|
||||||
@ -0,0 +1,106 @@
|
|||||||
|
use super::{WgpuRenderer, WgpuResources};
|
||||||
|
use crate::render::render_graph::{RenderPass, PipelineDescriptor, Renderer, RenderResource, BindType};
|
||||||
|
use legion::prelude::Entity;
|
||||||
|
|
||||||
|
pub struct WgpuRenderPass<'a, 'b, 'c, 'd> {
|
||||||
|
pub render_pass: &'b mut wgpu::RenderPass<'a>,
|
||||||
|
pub pipeline_descriptor: &'c PipelineDescriptor,
|
||||||
|
pub wgpu_resources: &'a WgpuResources,
|
||||||
|
pub renderer: &'d WgpuRenderer,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, 'b, 'c, 'd> RenderPass for WgpuRenderPass<'a, 'b, 'c, 'd> {
|
||||||
|
fn get_renderer(&mut self) -> &dyn Renderer {
|
||||||
|
self.renderer
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_pipeline_descriptor(&self) -> &PipelineDescriptor {
|
||||||
|
self.pipeline_descriptor
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_vertex_buffer(&mut self, start_slot: u32, resource: RenderResource, offset: u64) {
|
||||||
|
let buffer = self.wgpu_resources.buffers.get(&resource).unwrap();
|
||||||
|
self.render_pass
|
||||||
|
.set_vertex_buffers(start_slot, &[(&buffer, offset)]);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_index_buffer(&mut self, resource: RenderResource, offset: u64) {
|
||||||
|
let buffer = self.wgpu_resources.buffers.get(&resource).unwrap();
|
||||||
|
self.render_pass.set_index_buffer(&buffer, offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn draw_indexed(
|
||||||
|
&mut self,
|
||||||
|
indices: core::ops::Range<u32>,
|
||||||
|
base_vertex: i32,
|
||||||
|
instances: core::ops::Range<u32>,
|
||||||
|
) {
|
||||||
|
self.render_pass
|
||||||
|
.draw_indexed(indices, base_vertex, instances);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn setup_bind_groups(&mut self, entity: Option<&Entity>) {
|
||||||
|
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_hash().unwrap();
|
||||||
|
let bind_group_info = match self.wgpu_resources.bind_groups.get(&bind_group_id) {
|
||||||
|
// if there is a "global" bind group, use that
|
||||||
|
Some(bind_group_info) => bind_group_info,
|
||||||
|
// otherwise try to get an entity-specific bind group
|
||||||
|
None => {
|
||||||
|
if let Some(entity) = entity {
|
||||||
|
if let None = self
|
||||||
|
.wgpu_resources
|
||||||
|
.get_entity_bind_group(*entity, bind_group_id)
|
||||||
|
{
|
||||||
|
// TODO: Uncomment this
|
||||||
|
// self.wgpu_resources.create_entity_bind_group(&self.renderer.device, bind_group, *entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.wgpu_resources
|
||||||
|
.get_entity_bind_group(*entity, bind_group_id)
|
||||||
|
.unwrap()
|
||||||
|
} else {
|
||||||
|
panic!("No bind group exists that matches: {:?}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(resource) = self
|
||||||
|
.wgpu_resources
|
||||||
|
.render_resources
|
||||||
|
.get_named_resource(&binding.name)
|
||||||
|
{
|
||||||
|
// PERF: This hashmap get is pretty expensive (10 fps for 10000 entities)
|
||||||
|
if let Some(dynamic_uniform_buffer_info) = self
|
||||||
|
.wgpu_resources
|
||||||
|
.dynamic_uniform_buffer_info
|
||||||
|
.get(&resource)
|
||||||
|
{
|
||||||
|
let index = dynamic_uniform_buffer_info
|
||||||
|
.offsets
|
||||||
|
.get(entity.unwrap())
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
dynamic_uniform_indices.push(*index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: check to see if bind group is already set
|
||||||
|
self.render_pass.set_bind_group(
|
||||||
|
bind_group.index,
|
||||||
|
&bind_group_info.bind_group,
|
||||||
|
dynamic_uniform_indices.as_slice(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -3,449 +3,19 @@ use crate::{
|
|||||||
legion::prelude::*,
|
legion::prelude::*,
|
||||||
render::{
|
render::{
|
||||||
render_graph::{
|
render_graph::{
|
||||||
resource_name, update_shader_assignments, BindGroup, BindType,
|
resource_name, update_shader_assignments, BindType,
|
||||||
DynamicUniformBufferInfo, PassDescriptor, PipelineDescriptor, PipelineLayout,
|
DynamicUniformBufferInfo, PassDescriptor, PipelineDescriptor, PipelineLayout,
|
||||||
PipelineLayoutType, RenderGraph, RenderPass, RenderPassColorAttachmentDescriptor,
|
PipelineLayoutType, RenderGraph, RenderPassColorAttachmentDescriptor,
|
||||||
RenderPassDepthStencilAttachmentDescriptor, RenderResource, RenderResources, Renderer,
|
RenderPassDepthStencilAttachmentDescriptor, RenderResource, RenderResources, Renderer,
|
||||||
ResourceInfo, SamplerDescriptor, TextureDescriptor,
|
ResourceInfo, SamplerDescriptor, TextureDescriptor,
|
||||||
|
renderers::wgpu_renderer::WgpuResources,
|
||||||
},
|
},
|
||||||
Shader,
|
Shader,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use std::{borrow::Cow, collections::HashMap, ops::Deref};
|
use std::{collections::HashMap, ops::Deref};
|
||||||
|
use super::WgpuRenderPass;
|
||||||
|
|
||||||
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(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
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 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,
|
|
||||||
wgpu::BufferUsage::UNIFORM | wgpu::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),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
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,
|
|
||||||
unset_uniforms,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
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");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => 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,
|
|
||||||
unset_uniforms: Vec::new(),
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn create_buffer(&mut self, device: &wgpu::Device, size: u64, buffer_usage: wgpu::BufferUsage) -> RenderResource {
|
|
||||||
let buffer = device.create_buffer(&wgpu::BufferDescriptor {
|
|
||||||
size,
|
|
||||||
usage: buffer_usage,
|
|
||||||
});
|
|
||||||
|
|
||||||
let resource = self.render_resources.get_next_resource();
|
|
||||||
self.add_resource_info(resource, ResourceInfo::Buffer { buffer_usage, size });
|
|
||||||
|
|
||||||
self.buffers.insert(resource, buffer);
|
|
||||||
resource
|
|
||||||
}
|
|
||||||
|
|
||||||
fn create_buffer_with_data(
|
|
||||||
&mut self,
|
|
||||||
device: &wgpu::Device,
|
|
||||||
data: &[u8],
|
|
||||||
buffer_usage: wgpu::BufferUsage,
|
|
||||||
) -> RenderResource {
|
|
||||||
let resource = self.render_resources.get_next_resource();
|
|
||||||
let buffer = device.create_buffer_with_data(data, buffer_usage);
|
|
||||||
self.add_resource_info(
|
|
||||||
resource,
|
|
||||||
ResourceInfo::Buffer {
|
|
||||||
buffer_usage,
|
|
||||||
size: data.len() as u64,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
self.buffers.insert(resource, buffer);
|
|
||||||
resource
|
|
||||||
}
|
|
||||||
|
|
||||||
fn create_instance_buffer(
|
|
||||||
&mut self,
|
|
||||||
device: &wgpu::Device,
|
|
||||||
mesh_id: usize,
|
|
||||||
size: usize,
|
|
||||||
count: usize,
|
|
||||||
buffer_usage: wgpu::BufferUsage,
|
|
||||||
) -> RenderResource {
|
|
||||||
let buffer = device.create_buffer(&wgpu::BufferDescriptor {
|
|
||||||
size: (size * count) as u64,
|
|
||||||
usage: buffer_usage,
|
|
||||||
});
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
fn create_instance_buffer_with_data(
|
|
||||||
&mut self,
|
|
||||||
device: &wgpu::Device,
|
|
||||||
mesh_id: usize,
|
|
||||||
data: &[u8],
|
|
||||||
size: usize,
|
|
||||||
count: usize,
|
|
||||||
buffer_usage: wgpu::BufferUsage,
|
|
||||||
) -> RenderResource {
|
|
||||||
let buffer = device.create_buffer_with_data(data, buffer_usage);
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_resource_info(&self, resource: RenderResource) -> Option<&ResourceInfo> {
|
|
||||||
self.resource_info.get(&resource)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn remove_buffer(&mut self, resource: RenderResource) {
|
|
||||||
self.buffers.remove(&resource);
|
|
||||||
self.resource_info.remove(&resource);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn create_buffer_mapped(
|
|
||||||
&mut self,
|
|
||||||
device: &wgpu::Device,
|
|
||||||
size: usize,
|
|
||||||
buffer_usage: wgpu::BufferUsage,
|
|
||||||
setup_data: &mut dyn FnMut(&mut [u8]),
|
|
||||||
) -> RenderResource {
|
|
||||||
let mut mapped = device.create_buffer_mapped(size, buffer_usage);
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
fn get_dynamic_uniform_buffer_info(
|
|
||||||
&self,
|
|
||||||
resource: RenderResource,
|
|
||||||
) -> Option<&DynamicUniformBufferInfo> {
|
|
||||||
self.dynamic_uniform_buffer_info.get(&resource)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_dynamic_uniform_buffer_info_mut(
|
|
||||||
&mut self,
|
|
||||||
resource: RenderResource,
|
|
||||||
) -> Option<&mut DynamicUniformBufferInfo> {
|
|
||||||
self.dynamic_uniform_buffer_info.get_mut(&resource)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn add_dynamic_uniform_buffer_info(
|
|
||||||
&mut self,
|
|
||||||
resource: RenderResource,
|
|
||||||
info: DynamicUniformBufferInfo,
|
|
||||||
) {
|
|
||||||
self.dynamic_uniform_buffer_info.insert(resource, info);
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
fn remove_texture(&mut self, resource: RenderResource) {
|
|
||||||
self.textures.remove(&resource);
|
|
||||||
self.resource_info.remove(&resource);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn remove_sampler(&mut self, resource: RenderResource) {
|
|
||||||
self.samplers.remove(&resource);
|
|
||||||
self.resource_info.remove(&resource);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_render_resources(&self) -> &RenderResources {
|
|
||||||
&self.render_resources
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_render_resources_mut(&mut self) -> &mut RenderResources {
|
|
||||||
&mut self.render_resources
|
|
||||||
}
|
|
||||||
|
|
||||||
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,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
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()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct WgpuRenderer {
|
pub struct WgpuRenderer {
|
||||||
pub device: wgpu::Device,
|
pub device: wgpu::Device,
|
||||||
@ -1015,104 +585,6 @@ impl Renderer for WgpuRenderer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct WgpuRenderPass<'a, 'b, 'c, 'd> {
|
|
||||||
pub render_pass: &'b mut wgpu::RenderPass<'a>,
|
|
||||||
pub pipeline_descriptor: &'c PipelineDescriptor,
|
|
||||||
pub wgpu_resources: &'a WgpuResources,
|
|
||||||
pub renderer: &'d WgpuRenderer,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, 'b, 'c, 'd> RenderPass for WgpuRenderPass<'a, 'b, 'c, 'd> {
|
|
||||||
fn get_renderer(&mut self) -> &dyn Renderer {
|
|
||||||
self.renderer
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_pipeline_descriptor(&self) -> &PipelineDescriptor {
|
|
||||||
self.pipeline_descriptor
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_vertex_buffer(&mut self, start_slot: u32, resource: RenderResource, offset: u64) {
|
|
||||||
let buffer = self.wgpu_resources.buffers.get(&resource).unwrap();
|
|
||||||
self.render_pass
|
|
||||||
.set_vertex_buffers(start_slot, &[(&buffer, offset)]);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_index_buffer(&mut self, resource: RenderResource, offset: u64) {
|
|
||||||
let buffer = self.wgpu_resources.buffers.get(&resource).unwrap();
|
|
||||||
self.render_pass.set_index_buffer(&buffer, offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn draw_indexed(
|
|
||||||
&mut self,
|
|
||||||
indices: core::ops::Range<u32>,
|
|
||||||
base_vertex: i32,
|
|
||||||
instances: core::ops::Range<u32>,
|
|
||||||
) {
|
|
||||||
self.render_pass
|
|
||||||
.draw_indexed(indices, base_vertex, instances);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn setup_bind_groups(&mut self, entity: Option<&Entity>) {
|
|
||||||
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_hash().unwrap();
|
|
||||||
let bind_group_info = match self.wgpu_resources.bind_groups.get(&bind_group_id) {
|
|
||||||
// if there is a "global" bind group, use that
|
|
||||||
Some(bind_group_info) => bind_group_info,
|
|
||||||
// otherwise try to get an entity-specific bind group
|
|
||||||
None => {
|
|
||||||
if let Some(entity) = entity {
|
|
||||||
if let None = self.wgpu_resources.get_entity_bind_group(*entity, bind_group_id) {
|
|
||||||
// TODO: Uncomment this
|
|
||||||
// self.wgpu_resources.create_entity_bind_group(&self.renderer.device, bind_group, *entity);
|
|
||||||
}
|
|
||||||
|
|
||||||
self.wgpu_resources
|
|
||||||
.get_entity_bind_group(*entity, bind_group_id)
|
|
||||||
.unwrap()
|
|
||||||
} else {
|
|
||||||
panic!("No bind group exists that matches: {:?}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(resource) = self
|
|
||||||
.wgpu_resources
|
|
||||||
.render_resources
|
|
||||||
.get_named_resource(&binding.name)
|
|
||||||
{
|
|
||||||
// PERF: This hashmap get is pretty expensive (10 fps for 10000 entities)
|
|
||||||
if let Some(dynamic_uniform_buffer_info) =
|
|
||||||
self.wgpu_resources.dynamic_uniform_buffer_info.get(&resource)
|
|
||||||
{
|
|
||||||
let index = dynamic_uniform_buffer_info
|
|
||||||
.offsets
|
|
||||||
.get(entity.unwrap())
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
dynamic_uniform_indices.push(*index);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: check to see if bind group is already set
|
|
||||||
self.render_pass.set_bind_group(
|
|
||||||
bind_group.index,
|
|
||||||
&bind_group_info.bind_group,
|
|
||||||
dynamic_uniform_indices.as_slice(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<&BindType> for wgpu::BindingType {
|
impl From<&BindType> for wgpu::BindingType {
|
||||||
fn from(bind_type: &BindType) -> Self {
|
fn from(bind_type: &BindType) -> Self {
|
||||||
match bind_type {
|
match bind_type {
|
||||||
@ -1138,8 +610,3 @@ impl From<&BindType> for wgpu::BindingType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct BindGroupInfo {
|
|
||||||
pub bind_group: wgpu::BindGroup,
|
|
||||||
pub unset_uniforms: Vec<String>,
|
|
||||||
}
|
|
||||||
@ -0,0 +1,450 @@
|
|||||||
|
use crate::{
|
||||||
|
legion::prelude::*,
|
||||||
|
render::{
|
||||||
|
render_graph::{
|
||||||
|
BindGroup, BindType,
|
||||||
|
DynamicUniformBufferInfo, RenderResource, RenderResources,
|
||||||
|
ResourceInfo, SamplerDescriptor, TextureDescriptor,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
use std::{borrow::Cow, collections::HashMap};
|
||||||
|
|
||||||
|
pub struct BindGroupInfo {
|
||||||
|
pub bind_group: wgpu::BindGroup,
|
||||||
|
pub unset_uniforms: Vec<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
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 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,
|
||||||
|
wgpu::BufferUsage::UNIFORM | wgpu::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),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
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,
|
||||||
|
unset_uniforms,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => 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,
|
||||||
|
unset_uniforms: Vec::new(),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn create_buffer(&mut self, device: &wgpu::Device, size: u64, buffer_usage: wgpu::BufferUsage) -> RenderResource {
|
||||||
|
let buffer = device.create_buffer(&wgpu::BufferDescriptor {
|
||||||
|
size,
|
||||||
|
usage: buffer_usage,
|
||||||
|
});
|
||||||
|
|
||||||
|
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: wgpu::BufferUsage,
|
||||||
|
) -> RenderResource {
|
||||||
|
let resource = self.render_resources.get_next_resource();
|
||||||
|
let buffer = device.create_buffer_with_data(data, buffer_usage);
|
||||||
|
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: wgpu::BufferUsage,
|
||||||
|
) -> RenderResource {
|
||||||
|
let buffer = device.create_buffer(&wgpu::BufferDescriptor {
|
||||||
|
size: (size * count) as u64,
|
||||||
|
usage: buffer_usage,
|
||||||
|
});
|
||||||
|
|
||||||
|
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: wgpu::BufferUsage,
|
||||||
|
) -> RenderResource {
|
||||||
|
let buffer = device.create_buffer_with_data(data, buffer_usage);
|
||||||
|
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: wgpu::BufferUsage,
|
||||||
|
setup_data: &mut dyn FnMut(&mut [u8]),
|
||||||
|
) -> RenderResource {
|
||||||
|
let mut mapped = device.create_buffer_mapped(size, buffer_usage);
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user