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, assigned_meshes_draw_target,
) )
.add_draw_target(resource_name::draw_target::UI, ui_draw_target) .add_draw_target(resource_name::draw_target::UI, ui_draw_target)
.add_resource_provider(Box::new(CameraResourceProvider)) .add_resource_provider(Box::new(CameraResourceProvider::default()))
.add_resource_provider(Box::new(Camera2dResourceProvider)) .add_resource_provider(Box::new(Camera2dResourceProvider::default()))
.add_resource_provider(Box::new(LightResourceProvider::new(10))) .add_resource_provider(Box::new(LightResourceProvider::new(10)))
.add_resource_provider(Box::new(UiResourceProvider::new())) .add_resource_provider(Box::new(UiResourceProvider::new()))
.add_resource_provider(Box::new(UniformResourceProvider::<StandardMaterial>::new())) .add_resource_provider(Box::new(UniformResourceProvider::<StandardMaterial>::new()))

View File

@ -1,9 +1,7 @@
use crate::{ use crate::{
asset::{AssetStorage, Handle, Mesh}, asset::{AssetStorage, Handle, Mesh},
legion::prelude::*, legion::prelude::*,
render::render_graph::{ render::render_graph::{PipelineDescriptor, RenderPass, Renderable, ShaderPipelineAssignments},
resource_name, PipelineDescriptor, RenderPass, Renderable, ShaderPipelineAssignments,
},
}; };
use zerocopy::AsBytes; use zerocopy::AsBytes;
@ -19,6 +17,8 @@ pub fn assigned_meshes_draw_target(
.get_mut::<ShaderPipelineAssignments>() .get_mut::<ShaderPipelineAssignments>()
.unwrap(); .unwrap();
let mut current_mesh_id = None; 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 mut current_mesh_index_length = 0;
let assigned_entities = shader_pipeline_assignments let assigned_entities = shader_pipeline_assignments
@ -42,25 +42,25 @@ pub fn assigned_meshes_draw_target(
if should_load_mesh { if should_load_mesh {
if let Some(mesh_asset) = mesh_storage.get_id(mesh.id) { if let Some(mesh_asset) = mesh_storage.get_id(mesh.id) {
let renderer = render_pass.get_renderer(); let renderer = render_pass.get_renderer();
renderer.create_buffer_with_data( if let Some(buffer) = current_mesh_vertex_buffer {
resource_name::buffer::TEMP_MESH_VERTEX_BUFFER_NAME, 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(), mesh_asset.vertices.as_bytes(),
wgpu::BufferUsage::VERTEX, wgpu::BufferUsage::VERTEX,
); ));
renderer.create_buffer_with_data( current_mesh_index_buffer = Some(renderer.create_buffer_with_data(
resource_name::buffer::TEMP_MESH_INDEX_BUFFER_NAME,
mesh_asset.indices.as_bytes(), mesh_asset.indices.as_bytes(),
wgpu::BufferUsage::INDEX, wgpu::BufferUsage::INDEX,
); ));
// TODO: Verify buffer format matches render pass // TODO: Verify buffer format matches render pass
render_pass render_pass.set_index_buffer(current_mesh_index_buffer.unwrap(), 0);
.set_index_buffer(resource_name::buffer::TEMP_MESH_INDEX_BUFFER_NAME, 0); render_pass.set_vertex_buffer(0, current_mesh_vertex_buffer.unwrap(), 0);
render_pass.set_vertex_buffer(
0,
resource_name::buffer::TEMP_MESH_VERTEX_BUFFER_NAME,
0,
);
current_mesh_id = Some(mesh.id); current_mesh_id = Some(mesh.id);
current_mesh_index_length = mesh_asset.indices.len() as u32; current_mesh_index_length = mesh_asset.indices.len() as u32;
}; };
@ -73,7 +73,12 @@ pub fn assigned_meshes_draw_target(
// cleanup buffers // cleanup buffers
let renderer = render_pass.get_renderer(); let renderer = render_pass.get_renderer();
renderer.remove_buffer(resource_name::buffer::TEMP_MESH_VERTEX_BUFFER_NAME); if let Some(buffer) = current_mesh_vertex_buffer {
renderer.remove_buffer(resource_name::buffer::TEMP_MESH_INDEX_BUFFER_NAME); 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}, asset::{AssetStorage, Handle, Mesh},
legion::prelude::*, legion::prelude::*,
render::{ render::{
render_graph::{resource_name, PipelineDescriptor, RenderPass, Renderable}, render_graph::{PipelineDescriptor, RenderPass, Renderable},
Instanced, Instanced,
}, },
}; };
@ -16,9 +16,12 @@ pub fn meshes_draw_target(
) { ) {
let mesh_storage = world.resources.get_mut::<AssetStorage<Mesh>>().unwrap(); let mesh_storage = world.resources.get_mut::<AssetStorage<Mesh>>().unwrap();
let mut current_mesh_id = None; 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 mut current_mesh_index_length = 0;
let mesh_query = let mesh_query =
<(Read<Handle<Mesh>>, Read<Renderable>)>::query().filter(!component::<Instanced>()); <(Read<Handle<Mesh>>, Read<Renderable>)>::query().filter(!component::<Instanced>());
for (entity, (mesh, renderable)) in mesh_query.iter_entities(world) { for (entity, (mesh, renderable)) in mesh_query.iter_entities(world) {
if !renderable.is_visible { if !renderable.is_visible {
continue; continue;
@ -32,24 +35,25 @@ pub fn meshes_draw_target(
if should_load_mesh { if should_load_mesh {
if let Some(mesh_asset) = mesh_storage.get_id(mesh.id) { if let Some(mesh_asset) = mesh_storage.get_id(mesh.id) {
let renderer = render_pass.get_renderer(); let renderer = render_pass.get_renderer();
renderer.create_buffer_with_data( if let Some(buffer) = current_mesh_vertex_buffer {
resource_name::buffer::TEMP_MESH_VERTEX_BUFFER_NAME, 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(), mesh_asset.vertices.as_bytes(),
wgpu::BufferUsage::VERTEX, wgpu::BufferUsage::VERTEX,
); ));
renderer.create_buffer_with_data( current_mesh_index_buffer = Some(renderer.create_buffer_with_data(
resource_name::buffer::TEMP_MESH_INDEX_BUFFER_NAME,
mesh_asset.indices.as_bytes(), mesh_asset.indices.as_bytes(),
wgpu::BufferUsage::INDEX, wgpu::BufferUsage::INDEX,
); ));
// TODO: Verify buffer format matches render pass // TODO: Verify buffer format matches render pass
render_pass.set_index_buffer(resource_name::buffer::TEMP_MESH_INDEX_BUFFER_NAME, 0); render_pass.set_index_buffer(current_mesh_index_buffer.unwrap(), 0);
render_pass.set_vertex_buffer( render_pass.set_vertex_buffer(0, current_mesh_vertex_buffer.unwrap(), 0);
0,
resource_name::buffer::TEMP_MESH_VERTEX_BUFFER_NAME,
0,
);
current_mesh_id = Some(mesh.id); current_mesh_id = Some(mesh.id);
current_mesh_index_length = mesh_asset.indices.len() as u32; current_mesh_index_length = mesh_asset.indices.len() as u32;
}; };
@ -62,6 +66,12 @@ pub fn meshes_draw_target(
// cleanup buffers // cleanup buffers
let renderer = render_pass.get_renderer(); 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>, _pipeline_handle: Handle<PipelineDescriptor>,
) { ) {
let mesh_storage = world.resources.get_mut::<AssetStorage<Mesh>>().unwrap(); 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 // NOTE: this is ugly and borrowing is stupid
let result = { let result = {
let renderer = render_pass.get_renderer(); let renderer = render_pass.get_renderer();
let result = if let Some(ResourceInfo::InstanceBuffer { count, mesh_id, .. }) = 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)) Some((*count, *mesh_id))
} else { } else {
@ -25,16 +34,21 @@ pub fn ui_draw_target(
if let Some((instance_count, mesh_id)) = result { if let Some((instance_count, mesh_id)) = result {
if let Some(mesh_asset) = mesh_storage.get_id(mesh_id) { if let Some(mesh_asset) = mesh_storage.get_id(mesh_id) {
renderer.create_buffer_with_data( if let Some(buffer) = current_mesh_vertex_buffer {
resource_name::buffer::TEMP_MESH_VERTEX_BUFFER_NAME, 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(), mesh_asset.vertices.as_bytes(),
wgpu::BufferUsage::VERTEX, wgpu::BufferUsage::VERTEX,
); ));
renderer.create_buffer_with_data( current_mesh_index_buffer = Some(renderer.create_buffer_with_data(
resource_name::buffer::TEMP_MESH_INDEX_BUFFER_NAME,
mesh_asset.indices.as_bytes(), mesh_asset.indices.as_bytes(),
wgpu::BufferUsage::INDEX, wgpu::BufferUsage::INDEX,
); ));
Some((instance_count, mesh_asset.indices.len())) Some((instance_count, mesh_asset.indices.len()))
} else { } else {
None None
@ -45,9 +59,18 @@ pub fn ui_draw_target(
}; };
if let Some((instance_count, indices_length)) = result { if let Some((instance_count, indices_length)) = result {
render_pass.setup_bind_groups(None); render_pass.setup_bind_groups(None);
render_pass.set_index_buffer(resource_name::buffer::TEMP_MESH_INDEX_BUFFER_NAME, 0); render_pass.set_index_buffer(current_mesh_index_buffer.unwrap(), 0);
render_pass.set_vertex_buffer(0, resource_name::buffer::TEMP_MESH_VERTEX_BUFFER_NAME, 0); render_pass.set_vertex_buffer(0, current_mesh_vertex_buffer.unwrap(), 0);
render_pass.set_vertex_buffer(1, resource_name::buffer::UI_INSTANCES, 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)); 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; mod pipeline_layout;
pub mod pipelines; pub mod pipelines;
mod render_graph; mod render_graph;
mod render_resource;
mod renderable; mod renderable;
mod renderer; mod renderer;
pub mod renderers; pub mod renderers;
@ -21,6 +22,7 @@ pub use pass::*;
pub use pipeline::*; pub use pipeline::*;
pub use pipeline_layout::*; pub use pipeline_layout::*;
pub use render_graph::*; pub use render_graph::*;
pub use render_resource::*;
pub use renderable::*; pub use renderable::*;
pub use renderer::*; pub use renderer::*;
pub use resource::*; pub use resource::*;

View File

@ -16,10 +16,6 @@ layout(set = 1, binding = 0) uniform Object {
mat4 Model; mat4 Model;
}; };
layout(set = 1, binding = 1) uniform StandardMaterial_albedo {
vec4 Albedo;
};
void main() { void main() {
v_Normal = mat3(Model) * vec3(a_Normal.xyz); v_Normal = mat3(Model) * vec3(a_Normal.xyz);
v_Position = Model * vec4(a_Pos); 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::{ use crate::{
legion::prelude::*, legion::prelude::*,
render::render_graph::{ render::render_graph::{
DynamicUniformBufferInfo, PipelineDescriptor, RenderGraph, ResourceInfo, TextureDescriptor, render_resource::RenderResource, DynamicUniformBufferInfo, PipelineDescriptor, RenderGraph,
ResourceInfo, TextureDescriptor,
}, },
}; };
use std::ops::Range; use std::ops::Range;
@ -17,57 +18,74 @@ pub trait Renderer {
); );
fn process_render_graph(&mut self, render_graph: &mut RenderGraph, world: &mut World); fn process_render_graph(&mut self, render_graph: &mut RenderGraph, world: &mut World);
// TODO: swap out wgpu::BufferUsage for non-wgpu type // 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_buffer_with_data(
fn create_texture(&mut self, name: &str, texture_descriptor: &TextureDescriptor); &mut self,
fn get_dynamic_uniform_buffer_info(&self, name: &str) -> Option<&DynamicUniformBufferInfo>; 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( fn get_dynamic_uniform_buffer_info_mut(
&mut self, &mut self,
name: &str, resource: RenderResource,
) -> Option<&mut DynamicUniformBufferInfo>; ) -> Option<&mut DynamicUniformBufferInfo>;
fn add_dynamic_uniform_buffer_info(&mut self, name: &str, info: DynamicUniformBufferInfo); fn add_dynamic_uniform_buffer_info(
fn create_buffer(&mut self, name: &str, size: u64, buffer_usage: wgpu::BufferUsage); &mut self,
resource: RenderResource,
info: DynamicUniformBufferInfo,
);
fn create_buffer(&mut self, size: u64, buffer_usage: wgpu::BufferUsage) -> RenderResource;
fn create_instance_buffer( fn create_instance_buffer(
&mut self, &mut self,
name: &str,
mesh_id: usize, mesh_id: usize,
size: usize, size: usize,
count: usize, count: usize,
buffer_usage: wgpu::BufferUsage, buffer_usage: wgpu::BufferUsage,
); ) -> RenderResource;
fn create_instance_buffer_with_data( fn create_instance_buffer_with_data(
&mut self, &mut self,
name: &str,
mesh_id: usize, mesh_id: usize,
data: &[u8], data: &[u8],
size: usize, size: usize,
count: usize, count: usize,
buffer_usage: wgpu::BufferUsage, buffer_usage: wgpu::BufferUsage,
); ) -> RenderResource;
fn create_buffer_mapped( fn create_buffer_mapped(
&mut self, &mut self,
name: &str,
size: usize, size: usize,
buffer_usage: wgpu::BufferUsage, buffer_usage: wgpu::BufferUsage,
func: &mut dyn FnMut(&mut [u8]), func: &mut dyn FnMut(&mut [u8]),
); ) -> RenderResource;
fn remove_buffer(&mut self, name: &str); fn remove_buffer(&mut self, resource: RenderResource);
fn get_resource_info(&self, name: &str) -> Option<&ResourceInfo>; fn remove_texture(&mut self, resource: RenderResource);
fn get_resource_info(&self, resource: RenderResource) -> Option<&ResourceInfo>;
fn copy_buffer_to_buffer( fn copy_buffer_to_buffer(
&mut self, &mut self,
source_buffer: &str, source_buffer: RenderResource,
source_offset: u64, source_offset: u64,
destination_buffer: &str, destination_buffer: RenderResource,
destination_offset: u64, destination_offset: u64,
size: 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 { pub trait RenderPass {
// TODO: consider using static dispatch for the renderer: Renderer<WgpuBackend>. compare compile times // TODO: consider using static dispatch for the renderer: Renderer<WgpuBackend>. compare compile times
fn get_renderer(&mut self) -> &mut dyn Renderer; fn get_renderer(&mut self) -> &mut dyn Renderer;
fn get_pipeline_descriptor(&self) -> &PipelineDescriptor; fn get_pipeline_descriptor(&self) -> &PipelineDescriptor;
fn set_index_buffer(&mut self, name: &str, offset: u64); fn set_index_buffer(&mut self, resource: RenderResource, offset: u64);
fn set_vertex_buffer(&mut self, start_slot: u32, name: &str, 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 draw_indexed(&mut self, indices: Range<u32>, base_vertex: i32, instances: Range<u32>);
fn setup_bind_groups(&mut self, entity: Option<&Entity>); fn setup_bind_groups(&mut self, entity: Option<&Entity>);
} }

View File

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

View File

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

View File

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

View File

@ -21,7 +21,13 @@ impl FrameTextureResourceProvider {
let window_size = window.inner_size(); let window_size = window.inner_size();
self.descriptor.size.width = window_size.width; self.descriptor.size.width = window_size.width;
self.descriptor.size.height = window_size.height; 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::{ use crate::render::{
render_graph::{resource_name, Renderer, ResourceProvider}, render_graph::{resource_name, RenderResource, Renderer, ResourceProvider},
Light, LightRaw, Light, LightRaw,
}; };
use bevy_transform::prelude::{LocalToWorld, Translation}; use bevy_transform::prelude::{LocalToWorld, Translation};
@ -9,6 +9,9 @@ use zerocopy::AsBytes;
pub struct LightResourceProvider { pub struct LightResourceProvider {
pub lights_are_dirty: bool, pub lights_are_dirty: bool,
pub max_lights: usize, pub max_lights: usize,
pub light_buffer: Option<RenderResource>,
pub tmp_light_buffer: Option<RenderResource>,
pub tmp_count_buffer: Option<RenderResource>,
} }
#[repr(C)] #[repr(C)]
@ -22,6 +25,9 @@ impl LightResourceProvider {
LightResourceProvider { LightResourceProvider {
lights_are_dirty: true, lights_are_dirty: true,
max_lights, 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>()) + self.max_lights * std::mem::size_of::<LightRaw>())
as wgpu::BufferAddress; as wgpu::BufferAddress;
renderer.create_buffer( let buffer = renderer.create_buffer(
resource_name::uniform::LIGHTS,
light_uniform_size, light_uniform_size,
wgpu::BufferUsage::UNIFORM | wgpu::BufferUsage::COPY_SRC | wgpu::BufferUsage::COPY_DST, 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) { 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 size = std::mem::size_of::<LightRaw>();
let total_size = size * light_count; let total_size = size * light_count;
let light_count_size = std::mem::size_of::<LightCount>(); 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, total_size,
wgpu::BufferUsage::COPY_SRC, wgpu::BufferUsage::COPY_SRC,
&mut |data| { &mut |data| {
@ -65,28 +80,27 @@ impl ResourceProvider for LightResourceProvider {
); );
} }
}, },
); ));
renderer.create_buffer_mapped( self.tmp_count_buffer = Some(renderer.create_buffer_mapped(
"LIGHT_COUNT_TMP",
light_count_size, light_count_size,
wgpu::BufferUsage::COPY_SRC, wgpu::BufferUsage::COPY_SRC,
&mut |data| { &mut |data| {
data.copy_from_slice([light_count as u32, 0, 0, 0].as_bytes()); data.copy_from_slice([light_count as u32, 0, 0, 0].as_bytes());
}, },
); ));
renderer.copy_buffer_to_buffer( renderer.copy_buffer_to_buffer(
"LIGHT_COUNT_TMP", self.tmp_count_buffer.unwrap(),
0, 0,
resource_name::uniform::LIGHTS, self.light_buffer.unwrap(),
0, 0,
light_count_size as wgpu::BufferAddress, light_count_size as wgpu::BufferAddress,
); );
renderer.copy_buffer_to_buffer( renderer.copy_buffer_to_buffer(
"LIGHT_TMP", self.tmp_light_buffer.unwrap(),
0, 0,
resource_name::uniform::LIGHTS, self.light_buffer.unwrap(),
light_count_size as u64, light_count_size as u64,
total_size as wgpu::BufferAddress, total_size as wgpu::BufferAddress,
); );

View File

@ -2,7 +2,7 @@ use crate::{
asset::{Asset, AssetStorage, Handle, Mesh, MeshType}, asset::{Asset, AssetStorage, Handle, Mesh, MeshType},
ecs, math, ecs, math,
prelude::Node, prelude::Node,
render::render_graph::{resource_name, Renderer, ResourceProvider}, render::render_graph::{resource_name, RenderResource, Renderer, ResourceProvider},
}; };
use bevy_transform::prelude::Parent; use bevy_transform::prelude::Parent;
use legion::prelude::*; use legion::prelude::*;
@ -19,11 +19,15 @@ pub struct RectData {
pub struct UiResourceProvider { pub struct UiResourceProvider {
pub quad: Option<Handle<Mesh>>, pub quad: Option<Handle<Mesh>>,
pub instance_buffer: Option<RenderResource>,
} }
impl UiResourceProvider { impl UiResourceProvider {
pub fn new() -> Self { pub fn new() -> Self {
UiResourceProvider { quad: None } UiResourceProvider {
quad: None,
instance_buffer: None,
}
} }
pub fn update(&mut self, renderer: &mut dyn Renderer, world: &World) { 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; let mesh_id = self.quad.as_ref().unwrap().id;
renderer.create_instance_buffer_with_data( if let Some(old_instance_buffer) = self.instance_buffer {
resource_name::buffer::UI_INSTANCES, renderer.remove_buffer(old_instance_buffer);
}
let buffer = renderer.create_instance_buffer_with_data(
mesh_id, mesh_id,
data.as_bytes(), data.as_bytes(),
size, size,
data.len(), data.len(),
wgpu::BufferUsage::COPY_SRC | wgpu::BufferUsage::VERTEX, 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::{ use crate::render::render_graph::{
AsUniforms, BindType, DynamicUniformBufferInfo, Renderable, Renderer, ResourceProvider, render_resource::RenderResource, AsUniforms, BindType, DynamicUniformBufferInfo, Renderable,
UniformInfoIter, Renderer, ResourceProvider, UniformInfoIter,
}; };
use legion::prelude::*; use legion::prelude::*;
use std::{marker::PhantomData, ops::Deref}; use std::{marker::PhantomData, ops::Deref};
@ -10,7 +10,7 @@ where
T: AsUniforms + Send + Sync, T: AsUniforms + Send + Sync,
{ {
_marker: PhantomData<T>, _marker: PhantomData<T>,
uniform_buffer_info_names: Vec<String>, uniform_buffer_info_resources: Vec<(String, Option<RenderResource>)>,
} }
impl<T> UniformResourceProvider<T> impl<T> UniformResourceProvider<T>
@ -19,7 +19,7 @@ where
{ {
pub fn new() -> Self { pub fn new() -> Self {
UniformResourceProvider { UniformResourceProvider {
uniform_buffer_info_names: Vec::new(), uniform_buffer_info_resources: Vec::new(),
_marker: PhantomData, _marker: PhantomData,
} }
} }
@ -40,80 +40,86 @@ where
// (2) if we create new buffers, the old bind groups will be invalid // (2) if we create new buffers, the old bind groups will be invalid
// reset all uniform buffer info counts // 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 renderer
.get_dynamic_uniform_buffer_info_mut(name) .get_dynamic_uniform_buffer_info_mut(resource.unwrap())
.unwrap() .unwrap()
.count = 0; .count = 0;
} }
let mut counts = Vec::new(); let mut counts = Vec::new();
for (uniforms, _renderable) in query.iter(world) { for (uniforms, _renderable) in query.iter(world) {
let mut uniform_index = 0;
let field_uniform_names = uniforms.get_field_uniform_names(); let field_uniform_names = uniforms.get_field_uniform_names();
for (i, uniform_info) in UniformInfoIter::new(field_uniform_names, uniforms.deref()) for uniform_info in UniformInfoIter::new(field_uniform_names, uniforms.deref()) {
.filter(|u| { match uniform_info.bind_type {
if let BindType::Uniform { .. } = u.bind_type { BindType::Uniform { .. } => {
true // only add the first time a uniform info is processed
} else { if self.uniform_buffer_info_resources.len() <= uniform_index {
false 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;
} }
}) BindType::SampledTexture { .. } => {
.enumerate() // TODO: look up Handle and load
{ }
// only add the first time a uniform info is processed BindType::Sampler { .. } => {
if self.uniform_buffer_info_names.len() <= i { // TODO: look up Handle and load
self.uniform_buffer_info_names }
.push(uniform_info.name.to_string()); _ => 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 // allocate uniform buffers
for name in self.uniform_buffer_info_names.iter() { for (i, (name, resource)) in self.uniform_buffer_info_resources.iter_mut().enumerate() {
if let Some(_) = renderer.get_resource_info(name) { if let Some(resource) = resource {
let mut info = renderer
.get_dynamic_uniform_buffer_info_mut(*resource)
.unwrap();
info.count = counts[i];
continue; continue;
} }
let info = renderer.get_dynamic_uniform_buffer_info_mut(name).unwrap();
// allocate enough space for twice as many entities as there are currently; // allocate enough space for twice as many entities as there are currently;
info.capacity = info.count * 2; let capacity = counts[i] * 2;
let size = wgpu::BIND_BUFFER_ALIGNMENT * info.capacity; let size = wgpu::BIND_BUFFER_ALIGNMENT * capacity;
renderer.create_buffer( let created_resource = renderer.create_buffer(
name,
size, size,
wgpu::BufferUsage::COPY_DST | wgpu::BufferUsage::UNIFORM, 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 // 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 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 wgpu::BIND_BUFFER_ALIGNMENT * info.count
}; };
let alignment = wgpu::BIND_BUFFER_ALIGNMENT as usize; let alignment = wgpu::BIND_BUFFER_ALIGNMENT as usize;
let mut offset = 0usize; 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() { for (i, (entity, _)) in query.iter_entities(world).enumerate() {
// TODO: check if index has changed. if it has, then entity should be updated // 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: only mem-map entities if their data has changed
@ -125,8 +131,7 @@ where
} }
// let mut data = vec![Default::default(); size as usize]; // let mut data = vec![Default::default(); size as usize];
renderer.create_buffer_mapped( let mapped_buffer_resource = renderer.create_buffer_mapped(
"tmp_uniform_mapped",
size as usize, size as usize,
wgpu::BufferUsage::COPY_SRC, wgpu::BufferUsage::COPY_SRC,
&mut |mapped| { &mut |mapped| {
@ -136,7 +141,7 @@ where
// TODO: check if index has changed. if it has, then entity should be updated // 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: only mem-map entities if their data has changed
// TODO: try getting bytes ref first // 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())] mapped[offset..(offset + uniform_bytes.len())]
.copy_from_slice(uniform_bytes.as_slice()); .copy_from_slice(uniform_bytes.as_slice());
offset += alignment; 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 // update shader assignments based on current macro defs