RenderResource ids

This commit is contained in:
Carter Anderson 2020-02-23 21:13:03 -08:00
parent f84e71d051
commit 79c900bc2d
16 changed files with 503 additions and 241 deletions

View file

@ -146,8 +146,8 @@ impl AppBuilder {
assigned_meshes_draw_target,
)
.add_draw_target(resource_name::draw_target::UI, ui_draw_target)
.add_resource_provider(Box::new(CameraResourceProvider))
.add_resource_provider(Box::new(Camera2dResourceProvider))
.add_resource_provider(Box::new(CameraResourceProvider::default()))
.add_resource_provider(Box::new(Camera2dResourceProvider::default()))
.add_resource_provider(Box::new(LightResourceProvider::new(10)))
.add_resource_provider(Box::new(UiResourceProvider::new()))
.add_resource_provider(Box::new(UniformResourceProvider::<StandardMaterial>::new()))

View file

@ -1,9 +1,7 @@
use crate::{
asset::{AssetStorage, Handle, Mesh},
legion::prelude::*,
render::render_graph::{
resource_name, PipelineDescriptor, RenderPass, Renderable, ShaderPipelineAssignments,
},
render::render_graph::{PipelineDescriptor, RenderPass, Renderable, ShaderPipelineAssignments},
};
use zerocopy::AsBytes;
@ -19,6 +17,8 @@ pub fn assigned_meshes_draw_target(
.get_mut::<ShaderPipelineAssignments>()
.unwrap();
let mut current_mesh_id = None;
let mut current_mesh_vertex_buffer = None;
let mut current_mesh_index_buffer = None;
let mut current_mesh_index_length = 0;
let assigned_entities = shader_pipeline_assignments
@ -42,25 +42,25 @@ pub fn assigned_meshes_draw_target(
if should_load_mesh {
if let Some(mesh_asset) = mesh_storage.get_id(mesh.id) {
let renderer = render_pass.get_renderer();
renderer.create_buffer_with_data(
resource_name::buffer::TEMP_MESH_VERTEX_BUFFER_NAME,
if let Some(buffer) = current_mesh_vertex_buffer {
renderer.remove_buffer(buffer);
}
if let Some(buffer) = current_mesh_index_buffer {
renderer.remove_buffer(buffer);
}
current_mesh_vertex_buffer = Some(renderer.create_buffer_with_data(
mesh_asset.vertices.as_bytes(),
wgpu::BufferUsage::VERTEX,
);
renderer.create_buffer_with_data(
resource_name::buffer::TEMP_MESH_INDEX_BUFFER_NAME,
));
current_mesh_index_buffer = Some(renderer.create_buffer_with_data(
mesh_asset.indices.as_bytes(),
wgpu::BufferUsage::INDEX,
);
));
// TODO: Verify buffer format matches render pass
render_pass
.set_index_buffer(resource_name::buffer::TEMP_MESH_INDEX_BUFFER_NAME, 0);
render_pass.set_vertex_buffer(
0,
resource_name::buffer::TEMP_MESH_VERTEX_BUFFER_NAME,
0,
);
render_pass.set_index_buffer(current_mesh_index_buffer.unwrap(), 0);
render_pass.set_vertex_buffer(0, current_mesh_vertex_buffer.unwrap(), 0);
current_mesh_id = Some(mesh.id);
current_mesh_index_length = mesh_asset.indices.len() as u32;
};
@ -73,7 +73,12 @@ pub fn assigned_meshes_draw_target(
// cleanup buffers
let renderer = render_pass.get_renderer();
renderer.remove_buffer(resource_name::buffer::TEMP_MESH_VERTEX_BUFFER_NAME);
renderer.remove_buffer(resource_name::buffer::TEMP_MESH_INDEX_BUFFER_NAME);
if let Some(buffer) = current_mesh_vertex_buffer {
renderer.remove_buffer(buffer);
}
if let Some(buffer) = current_mesh_index_buffer {
renderer.remove_buffer(buffer);
}
}
}

View file

@ -2,7 +2,7 @@ use crate::{
asset::{AssetStorage, Handle, Mesh},
legion::prelude::*,
render::{
render_graph::{resource_name, PipelineDescriptor, RenderPass, Renderable},
render_graph::{PipelineDescriptor, RenderPass, Renderable},
Instanced,
},
};
@ -16,9 +16,12 @@ pub fn meshes_draw_target(
) {
let mesh_storage = world.resources.get_mut::<AssetStorage<Mesh>>().unwrap();
let mut current_mesh_id = None;
let mut current_mesh_vertex_buffer = None;
let mut current_mesh_index_buffer = None;
let mut current_mesh_index_length = 0;
let mesh_query =
<(Read<Handle<Mesh>>, Read<Renderable>)>::query().filter(!component::<Instanced>());
for (entity, (mesh, renderable)) in mesh_query.iter_entities(world) {
if !renderable.is_visible {
continue;
@ -32,24 +35,25 @@ pub fn meshes_draw_target(
if should_load_mesh {
if let Some(mesh_asset) = mesh_storage.get_id(mesh.id) {
let renderer = render_pass.get_renderer();
renderer.create_buffer_with_data(
resource_name::buffer::TEMP_MESH_VERTEX_BUFFER_NAME,
if let Some(buffer) = current_mesh_vertex_buffer {
renderer.remove_buffer(buffer);
}
if let Some(buffer) = current_mesh_index_buffer {
renderer.remove_buffer(buffer);
}
current_mesh_vertex_buffer = Some(renderer.create_buffer_with_data(
mesh_asset.vertices.as_bytes(),
wgpu::BufferUsage::VERTEX,
);
renderer.create_buffer_with_data(
resource_name::buffer::TEMP_MESH_INDEX_BUFFER_NAME,
));
current_mesh_index_buffer = Some(renderer.create_buffer_with_data(
mesh_asset.indices.as_bytes(),
wgpu::BufferUsage::INDEX,
);
));
// TODO: Verify buffer format matches render pass
render_pass.set_index_buffer(resource_name::buffer::TEMP_MESH_INDEX_BUFFER_NAME, 0);
render_pass.set_vertex_buffer(
0,
resource_name::buffer::TEMP_MESH_VERTEX_BUFFER_NAME,
0,
);
render_pass.set_index_buffer(current_mesh_index_buffer.unwrap(), 0);
render_pass.set_vertex_buffer(0, current_mesh_vertex_buffer.unwrap(), 0);
current_mesh_id = Some(mesh.id);
current_mesh_index_length = mesh_asset.indices.len() as u32;
};
@ -62,6 +66,12 @@ pub fn meshes_draw_target(
// cleanup buffers
let renderer = render_pass.get_renderer();
renderer.remove_buffer(resource_name::buffer::TEMP_MESH_VERTEX_BUFFER_NAME);
renderer.remove_buffer(resource_name::buffer::TEMP_MESH_INDEX_BUFFER_NAME);
if let Some(buffer) = current_mesh_vertex_buffer {
renderer.remove_buffer(buffer);
}
if let Some(buffer) = current_mesh_index_buffer {
renderer.remove_buffer(buffer);
}
}

View file

@ -12,11 +12,20 @@ pub fn ui_draw_target(
_pipeline_handle: Handle<PipelineDescriptor>,
) {
let mesh_storage = world.resources.get_mut::<AssetStorage<Mesh>>().unwrap();
let mut current_mesh_vertex_buffer = None;
let mut current_mesh_index_buffer = None;
let ui_instances_buffer = {
let renderer = render_pass.get_renderer();
match renderer.get_named_resource(resource_name::buffer::UI_INSTANCES) {
Some(buffer) => buffer,
None => return,
}
};
// NOTE: this is ugly and borrowing is stupid
let result = {
let renderer = render_pass.get_renderer();
let result = if let Some(ResourceInfo::InstanceBuffer { count, mesh_id, .. }) =
renderer.get_resource_info(resource_name::buffer::UI_INSTANCES)
renderer.get_resource_info(ui_instances_buffer)
{
Some((*count, *mesh_id))
} else {
@ -25,16 +34,21 @@ pub fn ui_draw_target(
if let Some((instance_count, mesh_id)) = result {
if let Some(mesh_asset) = mesh_storage.get_id(mesh_id) {
renderer.create_buffer_with_data(
resource_name::buffer::TEMP_MESH_VERTEX_BUFFER_NAME,
if let Some(buffer) = current_mesh_vertex_buffer {
renderer.remove_buffer(buffer);
}
if let Some(buffer) = current_mesh_index_buffer {
renderer.remove_buffer(buffer);
}
current_mesh_vertex_buffer = Some(renderer.create_buffer_with_data(
mesh_asset.vertices.as_bytes(),
wgpu::BufferUsage::VERTEX,
);
renderer.create_buffer_with_data(
resource_name::buffer::TEMP_MESH_INDEX_BUFFER_NAME,
));
current_mesh_index_buffer = Some(renderer.create_buffer_with_data(
mesh_asset.indices.as_bytes(),
wgpu::BufferUsage::INDEX,
);
));
Some((instance_count, mesh_asset.indices.len()))
} else {
None
@ -45,9 +59,18 @@ pub fn ui_draw_target(
};
if let Some((instance_count, indices_length)) = result {
render_pass.setup_bind_groups(None);
render_pass.set_index_buffer(resource_name::buffer::TEMP_MESH_INDEX_BUFFER_NAME, 0);
render_pass.set_vertex_buffer(0, resource_name::buffer::TEMP_MESH_VERTEX_BUFFER_NAME, 0);
render_pass.set_vertex_buffer(1, resource_name::buffer::UI_INSTANCES, 0);
render_pass.set_index_buffer(current_mesh_index_buffer.unwrap(), 0);
render_pass.set_vertex_buffer(0, current_mesh_vertex_buffer.unwrap(), 0);
render_pass.set_vertex_buffer(1, ui_instances_buffer, 0);
render_pass.draw_indexed(0..indices_length as u32, 0, 0..(instance_count as u32));
}
let renderer = render_pass.get_renderer();
if let Some(buffer) = current_mesh_vertex_buffer {
renderer.remove_buffer(buffer);
}
if let Some(buffer) = current_mesh_index_buffer {
renderer.remove_buffer(buffer);
}
}

View file

@ -6,6 +6,7 @@ mod pipeline;
mod pipeline_layout;
pub mod pipelines;
mod render_graph;
mod render_resource;
mod renderable;
mod renderer;
pub mod renderers;
@ -21,6 +22,7 @@ pub use pass::*;
pub use pipeline::*;
pub use pipeline_layout::*;
pub use render_graph::*;
pub use render_resource::*;
pub use renderable::*;
pub use renderer::*;
pub use resource::*;

View file

@ -16,10 +16,6 @@ layout(set = 1, binding = 0) uniform Object {
mat4 Model;
};
layout(set = 1, binding = 1) uniform StandardMaterial_albedo {
vec4 Albedo;
};
void main() {
v_Normal = mat3(Model) * vec3(a_Normal.xyz);
v_Position = Model * vec4(a_Pos);

View file

@ -0,0 +1,37 @@
use crate::asset::{Handle, Texture};
use std::collections::HashMap;
#[derive(Copy, Clone, Hash, Debug, Eq, PartialEq)]
pub struct RenderResource(pub u64);
#[derive(Default)]
pub struct RenderResources {
pub name_to_resource: HashMap<String, RenderResource>,
pub texture_to_resource: HashMap<Handle<Texture>, RenderResource>,
pub resource_index: u64,
}
impl RenderResources {
pub fn set_named_resource(&mut self, name: &str, resource: RenderResource) {
self.name_to_resource.insert(name.to_string(), resource);
}
pub fn get_named_resource(&self, name: &str) -> Option<RenderResource> {
self.name_to_resource.get(name).cloned()
}
pub fn set_texture_resource(&mut self, texture: Handle<Texture>, resource: RenderResource) {
self.texture_to_resource.insert(texture, resource);
}
pub fn get_texture_resource(&self, texture: Handle<Texture>) -> Option<RenderResource> {
self.texture_to_resource.get(&texture).cloned()
}
pub fn get_next_resource(&mut self) -> RenderResource {
let resource = self.resource_index;
self.resource_index += 1;
RenderResource(resource)
}
}

View file

@ -1,7 +1,8 @@
use crate::{
legion::prelude::*,
render::render_graph::{
DynamicUniformBufferInfo, PipelineDescriptor, RenderGraph, ResourceInfo, TextureDescriptor,
render_resource::RenderResource, DynamicUniformBufferInfo, PipelineDescriptor, RenderGraph,
ResourceInfo, TextureDescriptor,
},
};
use std::ops::Range;
@ -17,57 +18,74 @@ pub trait Renderer {
);
fn process_render_graph(&mut self, render_graph: &mut RenderGraph, world: &mut World);
// TODO: swap out wgpu::BufferUsage for non-wgpu type
fn create_buffer_with_data(&mut self, name: &str, data: &[u8], buffer_usage: wgpu::BufferUsage);
fn create_texture(&mut self, name: &str, texture_descriptor: &TextureDescriptor);
fn get_dynamic_uniform_buffer_info(&self, name: &str) -> Option<&DynamicUniformBufferInfo>;
fn create_buffer_with_data(
&mut self,
data: &[u8],
buffer_usage: wgpu::BufferUsage,
) -> RenderResource;
fn create_texture(&mut self, texture_descriptor: &TextureDescriptor) -> RenderResource;
fn create_texture_with_data(
&mut self,
texture_descriptor: &TextureDescriptor,
bytes: Option<&[u8]>,
) -> RenderResource;
// TODO: remove this and replace it with ResourceInfo
fn get_dynamic_uniform_buffer_info(
&self,
resource: RenderResource,
) -> Option<&DynamicUniformBufferInfo>;
fn get_dynamic_uniform_buffer_info_mut(
&mut self,
name: &str,
resource: RenderResource,
) -> Option<&mut DynamicUniformBufferInfo>;
fn add_dynamic_uniform_buffer_info(&mut self, name: &str, info: DynamicUniformBufferInfo);
fn create_buffer(&mut self, name: &str, size: u64, buffer_usage: wgpu::BufferUsage);
fn add_dynamic_uniform_buffer_info(
&mut self,
resource: RenderResource,
info: DynamicUniformBufferInfo,
);
fn create_buffer(&mut self, size: u64, buffer_usage: wgpu::BufferUsage) -> RenderResource;
fn create_instance_buffer(
&mut self,
name: &str,
mesh_id: usize,
size: usize,
count: usize,
buffer_usage: wgpu::BufferUsage,
);
) -> RenderResource;
fn create_instance_buffer_with_data(
&mut self,
name: &str,
mesh_id: usize,
data: &[u8],
size: usize,
count: usize,
buffer_usage: wgpu::BufferUsage,
);
) -> RenderResource;
fn create_buffer_mapped(
&mut self,
name: &str,
size: usize,
buffer_usage: wgpu::BufferUsage,
func: &mut dyn FnMut(&mut [u8]),
);
fn remove_buffer(&mut self, name: &str);
fn get_resource_info(&self, name: &str) -> Option<&ResourceInfo>;
) -> RenderResource;
fn remove_buffer(&mut self, resource: RenderResource);
fn remove_texture(&mut self, resource: RenderResource);
fn get_resource_info(&self, resource: RenderResource) -> Option<&ResourceInfo>;
fn copy_buffer_to_buffer(
&mut self,
source_buffer: &str,
source_buffer: RenderResource,
source_offset: u64,
destination_buffer: &str,
destination_buffer: RenderResource,
destination_offset: u64,
size: u64,
);
fn get_named_resource(&self, name: &str) -> Option<RenderResource>;
fn set_named_resource(&mut self, name: &str, resource: RenderResource);
}
pub trait RenderPass {
// TODO: consider using static dispatch for the renderer: Renderer<WgpuBackend>. compare compile times
fn get_renderer(&mut self) -> &mut dyn Renderer;
fn get_pipeline_descriptor(&self) -> &PipelineDescriptor;
fn set_index_buffer(&mut self, name: &str, offset: u64);
fn set_vertex_buffer(&mut self, start_slot: u32, name: &str, offset: u64);
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 setup_bind_groups(&mut self, entity: Option<&Entity>);
}

View file

@ -6,7 +6,8 @@ use crate::{
resource_name, update_shader_assignments, BindGroup, BindType,
DynamicUniformBufferInfo, PassDescriptor, PipelineDescriptor, PipelineLayout,
PipelineLayoutType, RenderGraph, RenderPass, RenderPassColorAttachmentDescriptor,
RenderPassDepthStencilAttachmentDescriptor, Renderer, ResourceInfo, TextureDescriptor,
RenderPassDepthStencilAttachmentDescriptor, RenderResource, RenderResources, Renderer,
ResourceInfo, TextureDescriptor,
},
Shader,
},
@ -20,12 +21,13 @@ pub struct WgpuRenderer {
pub encoder: Option<wgpu::CommandEncoder>,
pub swap_chain_descriptor: wgpu::SwapChainDescriptor,
pub render_pipelines: HashMap<Handle<PipelineDescriptor>, wgpu::RenderPipeline>,
pub buffers: HashMap<String, wgpu::Buffer>,
pub textures: HashMap<String, wgpu::TextureView>,
pub resource_info: HashMap<String, ResourceInfo>,
pub buffers: HashMap<RenderResource, wgpu::Buffer>,
pub textures: HashMap<RenderResource, wgpu::TextureView>,
pub resource_info: HashMap<RenderResource, ResourceInfo>,
pub bind_groups: HashMap<u64, BindGroupInfo>,
pub bind_group_layouts: HashMap<u64, wgpu::BindGroupLayout>,
pub dynamic_uniform_buffer_info: HashMap<String, DynamicUniformBufferInfo>,
pub dynamic_uniform_buffer_info: HashMap<RenderResource, DynamicUniformBufferInfo>,
pub render_resources: RenderResources,
}
impl WgpuRenderer {
@ -66,11 +68,13 @@ impl WgpuRenderer {
bind_groups: HashMap::new(),
bind_group_layouts: HashMap::new(),
dynamic_uniform_buffer_info: HashMap::new(),
render_resources: RenderResources::default(),
}
}
pub fn create_render_pipeline(
dynamic_uniform_buffer_info: &HashMap<String, DynamicUniformBufferInfo>,
render_resources: &RenderResources,
dynamic_uniform_buffer_info: &HashMap<RenderResource, DynamicUniformBufferInfo>,
pipeline_descriptor: &mut PipelineDescriptor,
bind_group_layouts: &mut HashMap<u64, wgpu::BindGroupLayout>,
device: &wgpu::Device,
@ -106,8 +110,12 @@ impl WgpuRenderer {
ref mut dynamic, ..
} = binding.bind_type
{
if dynamic_uniform_buffer_info.contains_key(&binding.name) {
*dynamic = true;
if let Some(resource) =
render_resources.get_named_resource(&binding.name)
{
if dynamic_uniform_buffer_info.contains_key(&resource) {
*dynamic = true;
}
}
}
@ -216,16 +224,30 @@ impl WgpuRenderer {
) -> wgpu::RenderPassColorAttachmentDescriptor<'a> {
let attachment = match color_attachment_descriptor.attachment.as_str() {
resource_name::texture::SWAP_CHAIN => &frame.view,
_ => self
.textures
.get(&color_attachment_descriptor.attachment)
.unwrap(),
_ => {
match self
.render_resources
.get_named_resource(&color_attachment_descriptor.attachment)
{
Some(resource) => self.textures.get(&resource).unwrap(),
None => panic!(
"Color attachment {} does not exist",
&color_attachment_descriptor.attachment
),
}
}
};
let resolve_target = match color_attachment_descriptor.resolve_target {
Some(ref target) => match target.as_str() {
resource_name::texture::SWAP_CHAIN => Some(&frame.view),
_ => Some(&frame.view),
_ => match self.render_resources.get_named_resource(target.as_str()) {
Some(resource) => Some(self.textures.get(&resource).unwrap()),
None => panic!(
"Color attachment {} does not exist",
&color_attachment_descriptor.attachment
),
},
},
None => None,
};
@ -246,10 +268,18 @@ impl WgpuRenderer {
) -> wgpu::RenderPassDepthStencilAttachmentDescriptor<&'a wgpu::TextureView> {
let attachment = match depth_stencil_attachment_descriptor.attachment.as_str() {
resource_name::texture::SWAP_CHAIN => &frame.view,
_ => self
.textures
.get(&depth_stencil_attachment_descriptor.attachment)
.unwrap(),
_ => {
match self
.render_resources
.get_named_resource(&depth_stencil_attachment_descriptor.attachment)
{
Some(ref resource) => self.textures.get(&resource).unwrap(),
None => panic!(
"Depth stencil attachment {} does not exist",
&depth_stencil_attachment_descriptor.attachment
),
}
}
};
wgpu::RenderPassDepthStencilAttachmentDescriptor {
@ -263,8 +293,8 @@ impl WgpuRenderer {
}
}
fn add_resource_info(&mut self, name: &str, resource_info: ResourceInfo) {
self.resource_info.insert(name.to_string(), resource_info);
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
@ -273,31 +303,45 @@ impl WgpuRenderer {
if let None = self.bind_groups.get(&bind_group_id) {
let mut unset_uniforms = Vec::new();
let mut binding_resources = Vec::with_capacity(bind_group.bindings.len());
// if a uniform resource buffer doesn't exist, create a new empty one
for binding in bind_group.bindings.iter() {
if let None = self.resource_info.get(&binding.name) {
println!(
"Warning: creating new empty buffer for binding {}",
binding.name
);
unset_uniforms.push(binding.name.to_string());
if let BindType::Uniform { .. } = &binding.bind_type {
let size = binding.bind_type.get_uniform_size().unwrap();
self.create_buffer(
&binding.name,
size,
wgpu::BufferUsage::UNIFORM | wgpu::BufferUsage::COPY_DST,
)
let resource = match self.render_resources.get_named_resource(&binding.name) {
Some(resource) => resource,
None => {
println!(
"Warning: creating new empty buffer for binding {} {:?}",
binding.name, binding
);
unset_uniforms.push(binding.name.to_string());
match binding.bind_type {
BindType::Uniform { .. } => {
let size = binding.bind_type.get_uniform_size().unwrap();
let resource = self.create_buffer(
size,
wgpu::BufferUsage::UNIFORM | wgpu::BufferUsage::COPY_DST,
);
self.render_resources
.set_named_resource(&binding.name, resource);
resource
}
_ => panic!("unsupported bind type: {:?}", binding),
}
}
}
};
binding_resources.push(resource);
}
// create wgpu Bindings
let bindings = bind_group
.bindings
.iter()
.map(|binding| {
let resource_info = self.resource_info.get(&binding.name).unwrap();
.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 {
@ -310,7 +354,7 @@ impl WgpuRenderer {
buffer_usage: _,
} = resource_info
{
let buffer = self.buffers.get(&binding.name).unwrap();
let buffer = self.buffers.get(&resource).unwrap();
wgpu::BindingResource::Buffer {
buffer,
range: 0..*size,
@ -430,7 +474,8 @@ impl Renderer for WgpuRenderer {
update_shader_assignments(world, render_graph);
for (name, texture_descriptor) in render_graph.queued_textures.drain(..) {
self.create_texture(&name, &texture_descriptor);
let resource = self.create_texture(&texture_descriptor);
self.render_resources.set_named_resource(&name, resource);
}
let mut encoder = self.encoder.take().unwrap();
@ -467,6 +512,7 @@ impl Renderer for WgpuRenderer {
.as_ref()
.map(|handle| &*shader_storage.get(&handle).unwrap());
let render_pipeline = WgpuRenderer::create_render_pipeline(
&self.render_resources,
&self.dynamic_uniform_buffer_info,
pipeline_descriptor,
&mut self.bind_group_layouts,
@ -514,48 +560,51 @@ impl Renderer for WgpuRenderer {
fn create_buffer_with_data(
&mut self,
name: &str,
data: &[u8],
buffer_usage: wgpu::BufferUsage,
) {
) -> RenderResource {
let resource = self.render_resources.get_next_resource();
let buffer = self.device.create_buffer_with_data(data, buffer_usage);
self.add_resource_info(
name,
resource,
ResourceInfo::Buffer {
buffer_usage,
size: data.len() as u64,
},
);
self.buffers.insert(name.to_string(), buffer);
self.buffers.insert(resource, buffer);
resource
}
fn create_buffer(&mut self, name: &str, size: u64, buffer_usage: wgpu::BufferUsage) {
fn create_buffer(&mut self, size: u64, buffer_usage: wgpu::BufferUsage) -> RenderResource {
let buffer = self.device.create_buffer(&wgpu::BufferDescriptor {
size,
usage: buffer_usage,
});
self.add_resource_info(name, ResourceInfo::Buffer { buffer_usage, size });
let resource = self.render_resources.get_next_resource();
self.add_resource_info(resource, ResourceInfo::Buffer { buffer_usage, size });
self.buffers.insert(name.to_string(), buffer);
self.buffers.insert(resource, buffer);
resource
}
fn create_instance_buffer(
&mut self,
name: &str,
mesh_id: usize,
size: usize,
count: usize,
buffer_usage: wgpu::BufferUsage,
) {
) -> RenderResource {
let buffer = self.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(
name,
resource,
ResourceInfo::InstanceBuffer {
buffer_usage,
size,
@ -564,22 +613,23 @@ impl Renderer for WgpuRenderer {
},
);
self.buffers.insert(name.to_string(), buffer);
self.buffers.insert(resource, buffer);
resource
}
fn create_instance_buffer_with_data(
&mut self,
name: &str,
mesh_id: usize,
data: &[u8],
size: usize,
count: usize,
buffer_usage: wgpu::BufferUsage,
) {
) -> RenderResource {
let buffer = self.device.create_buffer_with_data(data, buffer_usage);
let resource = self.render_resources.get_next_resource();
self.add_resource_info(
name,
resource,
ResourceInfo::InstanceBuffer {
buffer_usage,
size,
@ -588,73 +638,131 @@ impl Renderer for WgpuRenderer {
},
);
self.buffers.insert(name.to_string(), buffer);
self.buffers.insert(resource, buffer);
resource
}
fn get_resource_info(&self, name: &str) -> Option<&ResourceInfo> {
self.resource_info.get(name)
fn get_resource_info(&self, resource: RenderResource) -> Option<&ResourceInfo> {
self.resource_info.get(&resource)
}
fn remove_buffer(&mut self, name: &str) {
self.buffers.remove(name);
fn remove_buffer(&mut self, resource: RenderResource) {
self.buffers.remove(&resource);
self.resource_info.remove(&resource);
}
fn create_buffer_mapped(
&mut self,
name: &str,
size: usize,
buffer_usage: wgpu::BufferUsage,
setup_data: &mut dyn FnMut(&mut [u8]),
) {
) -> RenderResource {
let mut mapped = self.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(
name,
resource,
ResourceInfo::Buffer {
buffer_usage,
size: size as u64,
},
);
self.buffers.insert(name.to_string(), buffer);
self.buffers.insert(resource, buffer);
resource
}
fn copy_buffer_to_buffer(
&mut self,
source_buffer: &str,
source_buffer: RenderResource,
source_offset: u64,
destination_buffer: &str,
destination_buffer: RenderResource,
destination_offset: u64,
size: u64,
) {
let source = self.buffers.get(source_buffer).unwrap();
let destination = self.buffers.get(destination_buffer).unwrap();
let source = self.buffers.get(&source_buffer).unwrap();
let destination = self.buffers.get(&destination_buffer).unwrap();
let encoder = self.encoder.as_mut().unwrap();
encoder.copy_buffer_to_buffer(source, source_offset, destination, destination_offset, size);
}
fn get_dynamic_uniform_buffer_info(&self, name: &str) -> Option<&DynamicUniformBufferInfo> {
self.dynamic_uniform_buffer_info.get(name)
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,
name: &str,
resource: RenderResource,
) -> Option<&mut DynamicUniformBufferInfo> {
self.dynamic_uniform_buffer_info.get_mut(name)
self.dynamic_uniform_buffer_info.get_mut(&resource)
}
fn add_dynamic_uniform_buffer_info(&mut self, name: &str, info: DynamicUniformBufferInfo) {
self.dynamic_uniform_buffer_info
.insert(name.to_string(), info);
fn add_dynamic_uniform_buffer_info(
&mut self,
resource: RenderResource,
info: DynamicUniformBufferInfo,
) {
self.dynamic_uniform_buffer_info.insert(resource, info);
}
fn create_texture(&mut self, name: &str, texture_descriptor: &TextureDescriptor) {
fn create_texture(&mut self, texture_descriptor: &TextureDescriptor) -> RenderResource {
let descriptor: wgpu::TextureDescriptor = (*texture_descriptor).into();
let texture = self.device.create_texture(&descriptor);
let resource = self.render_resources.get_next_resource();
self.textures
.insert(name.to_string(), texture.create_default_view());
.insert(resource, texture.create_default_view());
resource
}
fn create_texture_with_data(
&mut self,
texture_descriptor: &TextureDescriptor,
bytes: Option<&[u8]>,
) -> RenderResource {
let descriptor: wgpu::TextureDescriptor = (*texture_descriptor).into();
let texture = self.device.create_texture(&descriptor);
let texture_view = texture.create_default_view();
if let Some(bytes) = bytes {
let temp_buf = self
.device
.create_buffer_with_data(bytes, wgpu::BufferUsage::COPY_SRC);
self.encoder.as_mut().unwrap().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);
resource
}
fn get_named_resource(&self, name: &str) -> Option<RenderResource> {
self.render_resources.get_named_resource(name)
}
fn set_named_resource(&mut self, name: &str, resource: RenderResource) {
self.render_resources.set_named_resource(name, resource);
}
fn remove_texture(&mut self, resource: RenderResource) {
self.textures.remove(&resource);
self.resource_info.remove(&resource);
}
}
@ -673,14 +781,14 @@ impl<'a, 'b, 'c, 'd> RenderPass for WgpuRenderPass<'a, 'b, 'c, 'd> {
self.pipeline_descriptor
}
fn set_vertex_buffer(&mut self, start_slot: u32, name: &str, offset: u64) {
let buffer = self.renderer.buffers.get(name).unwrap();
fn set_vertex_buffer(&mut self, start_slot: u32, resource: RenderResource, offset: u64) {
let buffer = self.renderer.buffers.get(&resource).unwrap();
self.render_pass
.set_vertex_buffers(start_slot, &[(&buffer, offset)]);
}
fn set_index_buffer(&mut self, name: &str, offset: u64) {
let buffer = self.renderer.buffers.get(name).unwrap();
fn set_index_buffer(&mut self, resource: RenderResource, offset: u64) {
let buffer = self.renderer.buffers.get(&resource).unwrap();
self.render_pass.set_index_buffer(&buffer, offset);
}
@ -707,16 +815,22 @@ impl<'a, 'b, 'c, 'd> RenderPass for WgpuRenderPass<'a, 'b, 'c, 'd> {
continue;
}
// PERF: This hashmap get is pretty expensive (10 fps for 10000 entities)
if let Some(dynamic_uniform_buffer_info) =
self.renderer.dynamic_uniform_buffer_info.get(&binding.name)
if let Some(resource) = self
.renderer
.render_resources
.get_named_resource(&binding.name)
{
let index = dynamic_uniform_buffer_info
.offsets
.get(entity.unwrap())
.unwrap();
// PERF: This hashmap get is pretty expensive (10 fps for 10000 entities)
if let Some(dynamic_uniform_buffer_info) =
self.renderer.dynamic_uniform_buffer_info.get(&resource)
{
let index = dynamic_uniform_buffer_info
.offsets
.get(entity.unwrap())
.unwrap();
dynamic_uniform_indices.push(*index);
dynamic_uniform_indices.push(*index);
}
}
}
}

View file

@ -15,4 +15,5 @@ pub enum ResourceInfo {
mesh_id: usize,
// pub layout: Option<
},
Texture,
}

View file

@ -1,19 +1,25 @@
use crate::render::{
render_graph::{resource_name, Renderer, ResourceProvider},
render_graph::{resource_name, RenderResource, Renderer, ResourceProvider},
ActiveCamera2d, Camera,
};
use legion::prelude::*;
use zerocopy::AsBytes;
pub struct Camera2dResourceProvider;
#[derive(Default)]
pub struct Camera2dResourceProvider {
pub camera_buffer: Option<RenderResource>,
pub tmp_buffer: Option<RenderResource>,
}
impl ResourceProvider for Camera2dResourceProvider {
fn initialize(&mut self, renderer: &mut dyn Renderer, _world: &mut World) {
renderer.create_buffer(
resource_name::uniform::CAMERA2D,
let buffer = renderer.create_buffer(
std::mem::size_of::<[[f32; 4]; 4]>() as u64,
wgpu::BufferUsage::COPY_DST | wgpu::BufferUsage::UNIFORM,
);
renderer.set_named_resource(resource_name::uniform::CAMERA2D, buffer);
self.camera_buffer = Some(buffer);
}
fn update(&mut self, _renderer: &mut dyn Renderer, _world: &mut World) {}
@ -23,19 +29,22 @@ impl ResourceProvider for Camera2dResourceProvider {
camera.update(width, height);
let camera_matrix: [[f32; 4]; 4] = camera.view_matrix.to_cols_array_2d();
renderer.create_buffer_mapped(
"camera2d_tmp",
if let Some(old_tmp_buffer) = self.tmp_buffer {
renderer.remove_buffer(old_tmp_buffer);
}
self.tmp_buffer = Some(renderer.create_buffer_mapped(
matrix_size,
wgpu::BufferUsage::COPY_SRC,
&mut |data| {
data[0..matrix_size].copy_from_slice(camera_matrix.as_bytes());
},
);
));
renderer.copy_buffer_to_buffer(
"camera2d_tmp",
self.tmp_buffer.unwrap(),
0,
resource_name::uniform::CAMERA2D,
self.camera_buffer.unwrap(),
0,
matrix_size as u64,
);

View file

@ -1,20 +1,26 @@
use crate::render::{
render_graph::{resource_name, Renderer, ResourceProvider},
render_graph::{resource_name, RenderResource, Renderer, ResourceProvider},
ActiveCamera, Camera,
};
use bevy_transform::prelude::LocalToWorld;
use legion::prelude::*;
use zerocopy::AsBytes;
pub struct CameraResourceProvider;
#[derive(Default)]
pub struct CameraResourceProvider {
pub camera_buffer: Option<RenderResource>,
pub tmp_buffer: Option<RenderResource>,
}
impl ResourceProvider for CameraResourceProvider {
fn initialize(&mut self, renderer: &mut dyn Renderer, _world: &mut World) {
renderer.create_buffer(
resource_name::uniform::CAMERA,
let buffer = renderer.create_buffer(
std::mem::size_of::<[[f32; 4]; 4]>() as u64,
wgpu::BufferUsage::COPY_DST | wgpu::BufferUsage::UNIFORM,
);
renderer.set_named_resource(resource_name::uniform::CAMERA, buffer);
self.camera_buffer = Some(buffer);
}
fn update(&mut self, _renderer: &mut dyn Renderer, _world: &mut World) {}
@ -27,19 +33,22 @@ impl ResourceProvider for CameraResourceProvider {
let camera_matrix: [[f32; 4]; 4] =
(camera.view_matrix * local_to_world.0).to_cols_array_2d();
renderer.create_buffer_mapped(
"camera_tmp",
if let Some(old_tmp_buffer) = self.tmp_buffer {
renderer.remove_buffer(old_tmp_buffer);
}
self.tmp_buffer = Some(renderer.create_buffer_mapped(
matrix_size,
wgpu::BufferUsage::COPY_SRC,
&mut |data| {
data[0..matrix_size].copy_from_slice(camera_matrix.as_bytes());
},
);
));
renderer.copy_buffer_to_buffer(
"camera_tmp",
self.tmp_buffer.unwrap(),
0,
resource_name::uniform::CAMERA,
self.camera_buffer.unwrap(),
0,
matrix_size as u64,
);

View file

@ -21,7 +21,13 @@ impl FrameTextureResourceProvider {
let window_size = window.inner_size();
self.descriptor.size.width = window_size.width;
self.descriptor.size.height = window_size.height;
renderer.create_texture(&self.name, &self.descriptor);
if let Some(old_resource) = renderer.get_named_resource(&self.name) {
renderer.remove_texture(old_resource);
}
let texture_resource = renderer.create_texture(&self.descriptor);
renderer.set_named_resource(&self.name, texture_resource);
}
}

View file

@ -1,5 +1,5 @@
use crate::render::{
render_graph::{resource_name, Renderer, ResourceProvider},
render_graph::{resource_name, RenderResource, Renderer, ResourceProvider},
Light, LightRaw,
};
use bevy_transform::prelude::{LocalToWorld, Translation};
@ -9,6 +9,9 @@ use zerocopy::AsBytes;
pub struct LightResourceProvider {
pub lights_are_dirty: bool,
pub max_lights: usize,
pub light_buffer: Option<RenderResource>,
pub tmp_light_buffer: Option<RenderResource>,
pub tmp_count_buffer: Option<RenderResource>,
}
#[repr(C)]
@ -22,6 +25,9 @@ impl LightResourceProvider {
LightResourceProvider {
lights_are_dirty: true,
max_lights,
light_buffer: None,
tmp_light_buffer: None,
tmp_count_buffer: None,
}
}
}
@ -32,11 +38,12 @@ impl ResourceProvider for LightResourceProvider {
+ self.max_lights * std::mem::size_of::<LightRaw>())
as wgpu::BufferAddress;
renderer.create_buffer(
resource_name::uniform::LIGHTS,
let buffer = renderer.create_buffer(
light_uniform_size,
wgpu::BufferUsage::UNIFORM | wgpu::BufferUsage::COPY_SRC | wgpu::BufferUsage::COPY_DST,
);
renderer.set_named_resource(resource_name::uniform::LIGHTS, buffer);
self.light_buffer = Some(buffer);
}
fn update(&mut self, renderer: &mut dyn Renderer, world: &mut World) {
@ -52,8 +59,16 @@ impl ResourceProvider for LightResourceProvider {
let size = std::mem::size_of::<LightRaw>();
let total_size = size * light_count;
let light_count_size = std::mem::size_of::<LightCount>();
renderer.create_buffer_mapped(
"LIGHT_TMP",
if let Some(old_tmp_light_buffer) = self.tmp_light_buffer {
renderer.remove_buffer(old_tmp_light_buffer);
}
if let Some(old_tmp_count_buffer) = self.tmp_count_buffer {
renderer.remove_buffer(old_tmp_count_buffer);
}
self.tmp_light_buffer = Some(renderer.create_buffer_mapped(
total_size,
wgpu::BufferUsage::COPY_SRC,
&mut |data| {
@ -65,28 +80,27 @@ impl ResourceProvider for LightResourceProvider {
);
}
},
);
renderer.create_buffer_mapped(
"LIGHT_COUNT_TMP",
));
self.tmp_count_buffer = Some(renderer.create_buffer_mapped(
light_count_size,
wgpu::BufferUsage::COPY_SRC,
&mut |data| {
data.copy_from_slice([light_count as u32, 0, 0, 0].as_bytes());
},
);
));
renderer.copy_buffer_to_buffer(
"LIGHT_COUNT_TMP",
self.tmp_count_buffer.unwrap(),
0,
resource_name::uniform::LIGHTS,
self.light_buffer.unwrap(),
0,
light_count_size as wgpu::BufferAddress,
);
renderer.copy_buffer_to_buffer(
"LIGHT_TMP",
self.tmp_light_buffer.unwrap(),
0,
resource_name::uniform::LIGHTS,
self.light_buffer.unwrap(),
light_count_size as u64,
total_size as wgpu::BufferAddress,
);

View file

@ -2,7 +2,7 @@ use crate::{
asset::{Asset, AssetStorage, Handle, Mesh, MeshType},
ecs, math,
prelude::Node,
render::render_graph::{resource_name, Renderer, ResourceProvider},
render::render_graph::{resource_name, RenderResource, Renderer, ResourceProvider},
};
use bevy_transform::prelude::Parent;
use legion::prelude::*;
@ -19,11 +19,15 @@ pub struct RectData {
pub struct UiResourceProvider {
pub quad: Option<Handle<Mesh>>,
pub instance_buffer: Option<RenderResource>,
}
impl UiResourceProvider {
pub fn new() -> Self {
UiResourceProvider { quad: None }
UiResourceProvider {
quad: None,
instance_buffer: None,
}
}
pub fn update(&mut self, renderer: &mut dyn Renderer, world: &World) {
@ -66,14 +70,20 @@ impl UiResourceProvider {
let mesh_id = self.quad.as_ref().unwrap().id;
renderer.create_instance_buffer_with_data(
resource_name::buffer::UI_INSTANCES,
if let Some(old_instance_buffer) = self.instance_buffer {
renderer.remove_buffer(old_instance_buffer);
}
let buffer = renderer.create_instance_buffer_with_data(
mesh_id,
data.as_bytes(),
size,
data.len(),
wgpu::BufferUsage::COPY_SRC | wgpu::BufferUsage::VERTEX,
);
renderer.set_named_resource(resource_name::buffer::UI_INSTANCES, buffer);
self.instance_buffer = Some(buffer);
}
}

View file

@ -1,6 +1,6 @@
use crate::render::render_graph::{
AsUniforms, BindType, DynamicUniformBufferInfo, Renderable, Renderer, ResourceProvider,
UniformInfoIter,
render_resource::RenderResource, AsUniforms, BindType, DynamicUniformBufferInfo, Renderable,
Renderer, ResourceProvider, UniformInfoIter,
};
use legion::prelude::*;
use std::{marker::PhantomData, ops::Deref};
@ -10,7 +10,7 @@ where
T: AsUniforms + Send + Sync,
{
_marker: PhantomData<T>,
uniform_buffer_info_names: Vec<String>,
uniform_buffer_info_resources: Vec<(String, Option<RenderResource>)>,
}
impl<T> UniformResourceProvider<T>
@ -19,7 +19,7 @@ where
{
pub fn new() -> Self {
UniformResourceProvider {
uniform_buffer_info_names: Vec::new(),
uniform_buffer_info_resources: Vec::new(),
_marker: PhantomData,
}
}
@ -40,80 +40,86 @@ where
// (2) if we create new buffers, the old bind groups will be invalid
// reset all uniform buffer info counts
for name in self.uniform_buffer_info_names.iter() {
for (_name, resource) in self.uniform_buffer_info_resources.iter() {
renderer
.get_dynamic_uniform_buffer_info_mut(name)
.get_dynamic_uniform_buffer_info_mut(resource.unwrap())
.unwrap()
.count = 0;
}
let mut counts = Vec::new();
for (uniforms, _renderable) in query.iter(world) {
let mut uniform_index = 0;
let field_uniform_names = uniforms.get_field_uniform_names();
for (i, uniform_info) in UniformInfoIter::new(field_uniform_names, uniforms.deref())
.filter(|u| {
if let BindType::Uniform { .. } = u.bind_type {
true
} else {
false
for uniform_info in UniformInfoIter::new(field_uniform_names, uniforms.deref()) {
match uniform_info.bind_type {
BindType::Uniform { .. } => {
// only add the first time a uniform info is processed
if self.uniform_buffer_info_resources.len() <= uniform_index {
self.uniform_buffer_info_resources
.push((uniform_info.name.to_string(), None));
}
if counts.len() <= uniform_index {
counts.push(0);
}
counts[uniform_index] += 1;
uniform_index += 1;
}
})
.enumerate()
{
// only add the first time a uniform info is processed
if self.uniform_buffer_info_names.len() <= i {
self.uniform_buffer_info_names
.push(uniform_info.name.to_string());
BindType::SampledTexture { .. } => {
// TODO: look up Handle and load
}
BindType::Sampler { .. } => {
// TODO: look up Handle and load
}
_ => panic!(
"encountered unsupported bind_type {:?}",
uniform_info.bind_type
),
}
if counts.len() <= i {
counts.push(0);
}
counts[i] += 1;
}
}
// create and update uniform buffer info. this is separate from the last block to avoid
// the expense of hashing for large numbers of entities
for (i, name) in self.uniform_buffer_info_names.iter().enumerate() {
if let None = renderer.get_dynamic_uniform_buffer_info(name) {
let info = DynamicUniformBufferInfo::new();
renderer.add_dynamic_uniform_buffer_info(name, info);
}
let info = renderer.get_dynamic_uniform_buffer_info_mut(name).unwrap();
info.count = counts[i];
}
// allocate uniform buffers
for name in self.uniform_buffer_info_names.iter() {
if let Some(_) = renderer.get_resource_info(name) {
for (i, (name, resource)) in self.uniform_buffer_info_resources.iter_mut().enumerate() {
if let Some(resource) = resource {
let mut info = renderer
.get_dynamic_uniform_buffer_info_mut(*resource)
.unwrap();
info.count = counts[i];
continue;
}
let info = renderer.get_dynamic_uniform_buffer_info_mut(name).unwrap();
// allocate enough space for twice as many entities as there are currently;
info.capacity = info.count * 2;
let size = wgpu::BIND_BUFFER_ALIGNMENT * info.capacity;
renderer.create_buffer(
name,
let capacity = counts[i] * 2;
let size = wgpu::BIND_BUFFER_ALIGNMENT * capacity;
let created_resource = renderer.create_buffer(
size,
wgpu::BufferUsage::COPY_DST | wgpu::BufferUsage::UNIFORM,
);
let mut info = DynamicUniformBufferInfo::new();
info.count = counts[i];
info.capacity = capacity;
renderer.add_dynamic_uniform_buffer_info(created_resource, info);
*resource = Some(created_resource);
renderer.set_named_resource(name, created_resource);
}
// copy entity uniform data to buffers
for name in self.uniform_buffer_info_names.iter() {
for (name, resource) in self.uniform_buffer_info_resources.iter() {
let resource = resource.unwrap();
let size = {
let info = renderer.get_dynamic_uniform_buffer_info(name).unwrap();
let info = renderer.get_dynamic_uniform_buffer_info(resource).unwrap();
wgpu::BIND_BUFFER_ALIGNMENT * info.count
};
let alignment = wgpu::BIND_BUFFER_ALIGNMENT as usize;
let mut offset = 0usize;
let info = renderer.get_dynamic_uniform_buffer_info_mut(name).unwrap();
let info = renderer
.get_dynamic_uniform_buffer_info_mut(resource)
.unwrap();
for (i, (entity, _)) in query.iter_entities(world).enumerate() {
// TODO: check if index has changed. if it has, then entity should be updated
// TODO: only mem-map entities if their data has changed
@ -125,8 +131,7 @@ where
}
// let mut data = vec![Default::default(); size as usize];
renderer.create_buffer_mapped(
"tmp_uniform_mapped",
let mapped_buffer_resource = renderer.create_buffer_mapped(
size as usize,
wgpu::BufferUsage::COPY_SRC,
&mut |mapped| {
@ -136,7 +141,7 @@ where
// TODO: check if index has changed. if it has, then entity should be updated
// TODO: only mem-map entities if their data has changed
// TODO: try getting bytes ref first
if let Some(uniform_bytes) = uniforms.get_uniform_bytes(name) {
if let Some(uniform_bytes) = uniforms.get_uniform_bytes(&name) {
mapped[offset..(offset + uniform_bytes.len())]
.copy_from_slice(uniform_bytes.as_slice());
offset += alignment;
@ -145,7 +150,10 @@ where
},
);
renderer.copy_buffer_to_buffer("tmp_uniform_mapped", 0, name, 0, size);
renderer.copy_buffer_to_buffer(mapped_buffer_resource, 0, resource, 0, size);
// TODO: uncomment this to free resource?
renderer.remove_buffer(mapped_buffer_resource);
}
// update shader assignments based on current macro defs