diff --git a/bevy_render/src/lib.rs b/bevy_render/src/lib.rs index 77cde927f7..460a04c1e6 100644 --- a/bevy_render/src/lib.rs +++ b/bevy_render/src/lib.rs @@ -3,6 +3,8 @@ mod camera; pub mod entity; pub mod mesh; pub mod render_graph; +pub mod render_graph_2; +pub mod renderer_2; pub mod shader; mod color; diff --git a/bevy_render/src/render_graph_2/mod.rs b/bevy_render/src/render_graph_2/mod.rs new file mode 100644 index 0000000000..e69de29bb2 diff --git a/bevy_render/src/render_resource/render_resource.rs b/bevy_render/src/render_resource/render_resource.rs index 1ac21f2bcb..e29eb2910b 100644 --- a/bevy_render/src/render_resource/render_resource.rs +++ b/bevy_render/src/render_resource/render_resource.rs @@ -1,9 +1,17 @@ use crate::{mesh::Mesh, texture::Texture}; use bevy_asset::Handle; use std::collections::HashMap; +use uuid::Uuid; +// TODO: Rename to RenderResourceId #[derive(Copy, Clone, Hash, Debug, Eq, PartialEq)] -pub struct RenderResource(pub u64); +pub struct RenderResource(Uuid); + +impl RenderResource { + pub fn new() -> Self { + RenderResource(Uuid::new_v4()) + } +} // TODO: consider scoping breaking these mappings up by type: Texture, Sampler, etc // the overlap could cause accidents. @@ -13,7 +21,6 @@ pub struct RenderResources { pub texture_to_sampler_resource: HashMap, RenderResource>, pub mesh_to_vertices_resource: HashMap, RenderResource>, pub mesh_to_indices_resource: HashMap, RenderResource>, - pub resource_index: u64, } impl RenderResources { @@ -52,11 +59,4 @@ impl RenderResources { pub fn get_texture_sampler_resource(&self, texture: Handle) -> Option { self.texture_to_sampler_resource.get(&texture).cloned() } - - pub fn get_next_resource(&mut self) -> RenderResource { - let resource = self.resource_index; - self.resource_index += 1; - - RenderResource(resource) - } } diff --git a/bevy_render/src/renderer_2/mod.rs b/bevy_render/src/renderer_2/mod.rs new file mode 100644 index 0000000000..c757304f6e --- /dev/null +++ b/bevy_render/src/renderer_2/mod.rs @@ -0,0 +1,3 @@ +mod render_context; + +pub use render_context::*; \ No newline at end of file diff --git a/bevy_render/src/renderer_2/render_context.rs b/bevy_render/src/renderer_2/render_context.rs new file mode 100644 index 0000000000..0cb3e34044 --- /dev/null +++ b/bevy_render/src/renderer_2/render_context.rs @@ -0,0 +1,61 @@ +use crate::{ + render_resource::{ + BufferInfo, RenderResource, RenderResources, ResourceInfo, + }, + texture::{SamplerDescriptor, TextureDescriptor}, +}; + +pub trait RenderContext { + fn create_sampler(&mut self, sampler_descriptor: &SamplerDescriptor) -> RenderResource; + fn create_texture( + &mut self, + texture_descriptor: &TextureDescriptor, + ) -> RenderResource; + fn create_buffer(&mut self, buffer_info: BufferInfo) -> RenderResource; + fn create_buffer_mapped( + &mut self, + buffer_info: BufferInfo, + setup_data: &mut dyn FnMut(&mut [u8], &mut dyn RenderContext), + ) -> RenderResource; + fn create_buffer_with_data(&mut self, buffer_info: BufferInfo, data: &[u8]) -> RenderResource; + fn remove_buffer(&mut self, resource: RenderResource); + fn remove_texture(&mut self, resource: RenderResource); + fn remove_sampler(&mut self, resource: RenderResource); + fn get_resource_info(&self, resource: RenderResource) -> Option<&ResourceInfo>; + fn get_resource_info_mut(&mut self, resource: RenderResource) -> Option<&mut ResourceInfo>; + fn render_resources(&self) -> &RenderResources; + fn render_resources_mut(&mut self) -> &mut RenderResources; + // fn setup_render_pipeline( + // &mut self, + // pipeline_handle: Handle, + // pipeline_descriptor: &mut PipelineDescriptor, + // shader_storage: &AssetStorage, + // ); + // fn setup_bind_groups( + // &mut self, + // render_resource_assignments: &mut RenderResourceAssignments, + // pipeline_descriptor: &PipelineDescriptor, + // ); + + fn create_texture_with_data( + &mut self, + texture_descriptor: &TextureDescriptor, + bytes: Option<&[u8]>, + ) -> RenderResource; + fn copy_buffer_to_buffer( + &mut self, + source_buffer: RenderResource, + source_offset: u64, + destination_buffer: RenderResource, + destination_offset: u64, + size: u64, + ); + // fn copy_buffer_to_texture( + // &mut self, + // source_buffer: RenderResource, + // source_offset: u64, + // destination_buffer: RenderResource, + // destination_offset: u64, + // size: u64, + // ); +} diff --git a/bevy_wgpu/Cargo.toml b/bevy_wgpu/Cargo.toml index 3b5e43b7f2..ffbad8bcbe 100644 --- a/bevy_wgpu/Cargo.toml +++ b/bevy_wgpu/Cargo.toml @@ -22,4 +22,5 @@ legion = { path = "../bevy_legion" } wgpu = { version = "0.5.0" } futures = "0.3" -log = { version = "0.4", features = ["release_max_level_info"] } \ No newline at end of file +log = { version = "0.4", features = ["release_max_level_info"] } +crossbeam-channel = "0.4.2" \ No newline at end of file diff --git a/bevy_wgpu/src/lib.rs b/bevy_wgpu/src/lib.rs index ebe79c0e7d..794ead7329 100644 --- a/bevy_wgpu/src/lib.rs +++ b/bevy_wgpu/src/lib.rs @@ -2,6 +2,7 @@ mod wgpu_render_pass; mod wgpu_renderer; mod wgpu_resources; mod wgpu_type_converter; +pub mod renderer_2; pub use wgpu_render_pass::*; pub use wgpu_renderer::*; diff --git a/bevy_wgpu/src/renderer_2/mod.rs b/bevy_wgpu/src/renderer_2/mod.rs new file mode 100644 index 0000000000..04757d0794 --- /dev/null +++ b/bevy_wgpu/src/renderer_2/mod.rs @@ -0,0 +1,3 @@ +mod wgpu_render_context; + +pub use wgpu_render_context::*; \ No newline at end of file diff --git a/bevy_wgpu/src/renderer_2/wgpu_render_context.rs b/bevy_wgpu/src/renderer_2/wgpu_render_context.rs new file mode 100644 index 0000000000..b70058c87e --- /dev/null +++ b/bevy_wgpu/src/renderer_2/wgpu_render_context.rs @@ -0,0 +1,133 @@ +use crate::WgpuResources; + +use bevy_render::{ + render_resource::{BufferInfo, RenderResource, RenderResources, ResourceInfo}, + renderer_2::RenderContext, + texture::{SamplerDescriptor, TextureDescriptor}, +}; +use std::sync::Arc; + +#[derive(Default)] +struct LazyCommandEncoder { + command_encoder: Option, +} + +impl LazyCommandEncoder { + pub fn get_or_create(&mut self, device: &wgpu::Device) -> &mut wgpu::CommandEncoder { + match self.command_encoder { + Some(ref mut command_encoder) => command_encoder, + None => { + let command_encoder = + device.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None }); + self.command_encoder = Some(command_encoder); + self.command_encoder.as_mut().unwrap() + } + } + } + + pub fn take(&mut self) -> Option { + self.command_encoder.take() + } +} + +pub struct WgpuRenderContext { + pub device: Arc, + command_encoder: LazyCommandEncoder, + wgpu_resources: WgpuResources, +} + +impl WgpuRenderContext { + pub fn new(device: Arc) -> Self { + WgpuRenderContext { + device, + command_encoder: LazyCommandEncoder::default(), + wgpu_resources: WgpuResources::default(), + } + } + + pub fn finish(&mut self) -> Option { + self.command_encoder.take().map(|encoder| encoder.finish()) + } +} + +impl RenderContext for WgpuRenderContext { + fn create_sampler(&mut self, sampler_descriptor: &SamplerDescriptor) -> RenderResource { + self.wgpu_resources + .create_sampler(&self.device, sampler_descriptor) + } + fn create_texture(&mut self, texture_descriptor: &TextureDescriptor) -> RenderResource { + self.wgpu_resources + .create_texture(&self.device, texture_descriptor) + } + fn create_buffer(&mut self, buffer_info: BufferInfo) -> RenderResource { + self.wgpu_resources.create_buffer(&self.device, buffer_info) + } + + // TODO: clean this up + fn create_buffer_mapped( + &mut self, + buffer_info: BufferInfo, + setup_data: &mut dyn FnMut(&mut [u8], &mut dyn RenderContext), + ) -> RenderResource { + let buffer = WgpuResources::begin_create_buffer_mapped_render_context( + &buffer_info, + self, + setup_data, + ); + self.wgpu_resources.assign_buffer(buffer, buffer_info) + } + fn create_texture_with_data( + &mut self, + texture_descriptor: &TextureDescriptor, + bytes: Option<&[u8]>, + ) -> RenderResource { + self.wgpu_resources.create_texture_with_data( + &self.device, + self.command_encoder.get_or_create(&self.device), + texture_descriptor, + bytes, + ) + } + fn remove_buffer(&mut self, resource: RenderResource) { + self.wgpu_resources.remove_buffer(resource); + } + fn remove_texture(&mut self, resource: RenderResource) { + self.wgpu_resources.remove_texture(resource); + } + fn remove_sampler(&mut self, resource: RenderResource) { + self.wgpu_resources.remove_sampler(resource); + } + fn get_resource_info(&self, resource: RenderResource) -> Option<&ResourceInfo> { + self.wgpu_resources.resource_info.get(&resource) + } + fn get_resource_info_mut(&mut self, resource: RenderResource) -> Option<&mut ResourceInfo> { + self.wgpu_resources.resource_info.get_mut(&resource) + } + fn render_resources(&self) -> &RenderResources { + &self.wgpu_resources.render_resources + } + fn render_resources_mut(&mut self) -> &mut RenderResources { + &mut self.wgpu_resources.render_resources + } + fn copy_buffer_to_buffer( + &mut self, + source_buffer: RenderResource, + source_offset: u64, + destination_buffer: RenderResource, + destination_offset: u64, + size: u64, + ) { + self.wgpu_resources.copy_buffer_to_buffer( + self.command_encoder.get_or_create(&self.device), + source_buffer, + source_offset, + destination_buffer, + destination_offset, + size, + ); + } + fn create_buffer_with_data(&mut self, buffer_info: BufferInfo, data: &[u8]) -> RenderResource { + self.wgpu_resources + .create_buffer_with_data(&self.device, buffer_info, data) + } +} diff --git a/bevy_wgpu/src/wgpu_renderer.rs b/bevy_wgpu/src/wgpu_renderer.rs index b0e7709a42..4c8a14e6cd 100644 --- a/bevy_wgpu/src/wgpu_renderer.rs +++ b/bevy_wgpu/src/wgpu_renderer.rs @@ -2,6 +2,7 @@ use super::{ wgpu_type_converter::{OwnedWgpuVertexBufferDescriptor, WgpuInto}, WgpuRenderPass, WgpuResources, }; +use crate::renderer_2::WgpuRenderContext; use bevy_app::{EventReader, Events}; use bevy_asset::{AssetStorage, Handle}; use bevy_render::{ @@ -12,8 +13,8 @@ use bevy_render::{ pipeline::{update_shader_assignments, PipelineCompiler, PipelineDescriptor}, render_graph::RenderGraph, render_resource::{ - resource_name, BufferInfo, RenderResource, RenderResourceAssignments, RenderResources, - ResourceInfo, + resource_name, BufferInfo, BufferUsage, RenderResource, RenderResourceAssignments, + RenderResources, ResourceInfo, }, renderer::Renderer, shader::Shader, @@ -359,6 +360,43 @@ impl Renderer for WgpuRenderer { .create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None }), ); + // use bevy_render::renderer_2::RenderContext; + // let thread_count = 5; + // let (sender, receiver) = crossbeam_channel::bounded(thread_count); + // for i in 0..thread_count { + // let device = self.device.clone(); + // let sender = sender.clone(); + // std::thread::spawn(move || { + // let mut context = WgpuRenderContext::new(device); + // let data: Vec:: = vec![1, 2, 3,4 ]; + // let data2: Vec:: = vec![4, 2, 3,4 ]; + // let buffer = context.create_buffer_with_data(BufferInfo { + // buffer_usage: BufferUsage::COPY_SRC, + // ..Default::default() + // }, &data); + + // let buffer2 = context.create_buffer_with_data(BufferInfo { + // buffer_usage: BufferUsage::UNIFORM |BufferUsage::COPY_DST, + // ..Default::default() + // }, &data2); + + // context.copy_buffer_to_buffer(buffer, 0, buffer2, 0, data.len() as u64); + + // sender.send(context.finish()).unwrap(); + // }); + // } + + // let mut command_buffers = Vec::new(); + // for i in 0..thread_count { + // if let Some(command_buffer) = receiver.recv().unwrap() { + // command_buffers.push(command_buffer); + // } + + // println!("got {}", i); + // } + + // self.queue.submit(&command_buffers); + self.update_resource_providers(world, resources); update_shader_assignments(world, resources, self); self.create_queued_textures(resources); @@ -434,8 +472,7 @@ impl Renderer for WgpuRenderer { } fn create_buffer(&mut self, buffer_info: BufferInfo) -> RenderResource { - self.wgpu_resources - .create_buffer(&self.device, buffer_info) + self.wgpu_resources.create_buffer(&self.device, buffer_info) } fn get_resource_info(&self, resource: RenderResource) -> Option<&ResourceInfo> { @@ -487,7 +524,7 @@ impl Renderer for WgpuRenderer { texture_descriptor: &TextureDescriptor, bytes: Option<&[u8]>, ) -> RenderResource { - self.wgpu_resources.create_texture( + self.wgpu_resources.create_texture_with_data( &self.device, self.encoder.as_mut().unwrap(), texture_descriptor, @@ -564,10 +601,11 @@ impl Renderer for WgpuRenderer { }) .collect::>(); let wgpu_bind_group_layout = - self.device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { - bindings: bind_group_layout_binding.as_slice(), - label: None, - }); + self.device + .create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { + bindings: bind_group_layout_binding.as_slice(), + label: None, + }); self.wgpu_resources .bind_group_layouts @@ -587,9 +625,11 @@ impl Renderer for WgpuRenderer { }) .collect::>(); - let pipeline_layout = self.device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { - bind_group_layouts: bind_group_layouts.as_slice(), - }); + let pipeline_layout = self + .device + .create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { + bind_group_layouts: bind_group_layouts.as_slice(), + }); let owned_vertex_buffer_descriptors = layout .vertex_buffer_descriptors @@ -617,8 +657,11 @@ impl Renderer for WgpuRenderer { if let Some(fragment_handle) = pipeline_descriptor.shader_stages.fragment { if let None = self.wgpu_resources.shader_modules.get(&fragment_handle) { - self.wgpu_resources - .create_shader_module(&self.device, fragment_handle, shader_storage); + self.wgpu_resources.create_shader_module( + &self.device, + fragment_handle, + shader_storage, + ); } }; @@ -673,7 +716,9 @@ impl Renderer for WgpuRenderer { alpha_to_coverage_enabled: pipeline_descriptor.alpha_to_coverage_enabled, }; - let render_pipeline = self.device.create_render_pipeline(&mut render_pipeline_descriptor); + let render_pipeline = self + .device + .create_render_pipeline(&mut render_pipeline_descriptor); self.render_pipelines .insert(pipeline_handle, render_pipeline); } diff --git a/bevy_wgpu/src/wgpu_resources.rs b/bevy_wgpu/src/wgpu_resources.rs index 0bf1b7e320..f1f0558c42 100644 --- a/bevy_wgpu/src/wgpu_resources.rs +++ b/bevy_wgpu/src/wgpu_resources.rs @@ -1,5 +1,5 @@ use super::WgpuRenderer; -use crate::wgpu_type_converter::WgpuInto; +use crate::{renderer_2::WgpuRenderContext, wgpu_type_converter::WgpuInto}; use bevy_asset::{AssetStorage, Handle}; use bevy_render::{ pipeline::{BindGroupDescriptor, BindGroupDescriptorId, BindType}, @@ -9,7 +9,7 @@ use bevy_render::{ }, renderer::Renderer, shader::Shader, - texture::{SamplerDescriptor, TextureDescriptor}, + texture::{SamplerDescriptor, TextureDescriptor}, renderer_2::RenderContext, }; use bevy_window::WindowId; use std::collections::HashMap; @@ -154,7 +154,7 @@ impl WgpuResources { usage: buffer_info.buffer_usage.wgpu_into(), }); - let resource = self.render_resources.get_next_resource(); + let resource = RenderResource::new(); self.add_resource_info(resource, ResourceInfo::Buffer(buffer_info)); self.buffers.insert(resource, buffer); @@ -186,7 +186,7 @@ impl WgpuResources { buffer: wgpu::Buffer, buffer_info: BufferInfo, ) -> RenderResource { - let resource = self.render_resources.get_next_resource(); + let resource = RenderResource::new(); self.add_resource_info(resource, ResourceInfo::Buffer(buffer_info)); self.buffers.insert(resource, buffer); resource @@ -209,6 +209,24 @@ impl WgpuResources { mapped.finish() } + // TODO: clean this up + pub fn begin_create_buffer_mapped_render_context( + buffer_info: &BufferInfo, + render_context: &mut WgpuRenderContext, + setup_data: &mut dyn FnMut(&mut [u8], &mut dyn RenderContext), + ) -> wgpu::Buffer { + let device = render_context.device.clone(); + let mut mapped = device.create_buffer_mapped( + &wgpu::BufferDescriptor { + size: buffer_info.size as u64, + usage: buffer_info.buffer_usage.wgpu_into(), + label: None, + } + ); + setup_data(&mut mapped.data, render_context); + mapped.finish() + } + pub fn copy_buffer_to_buffer( &mut self, encoder: &mut wgpu::CommandEncoder, @@ -242,13 +260,27 @@ impl WgpuResources { ) -> RenderResource { let descriptor: wgpu::SamplerDescriptor = (*sampler_descriptor).wgpu_into(); let sampler = device.create_sampler(&descriptor); - let resource = self.render_resources.get_next_resource(); + let resource = RenderResource::new(); self.samplers.insert(resource, sampler); self.add_resource_info(resource, ResourceInfo::Sampler); resource } pub fn create_texture( + &mut self, + device: &wgpu::Device, + texture_descriptor: &TextureDescriptor, + ) -> RenderResource { + let descriptor: wgpu::TextureDescriptor = (*texture_descriptor).wgpu_into(); + let texture = device.create_texture(&descriptor); + let texture_view = texture.create_default_view(); + let resource = RenderResource::new(); + self.add_resource_info(resource, ResourceInfo::Texture); + self.textures.insert(resource, texture_view); + resource + } + + pub fn create_texture_with_data( &mut self, device: &wgpu::Device, encoder: &mut wgpu::CommandEncoder, @@ -277,7 +309,7 @@ impl WgpuResources { ); } - let resource = self.render_resources.get_next_resource(); + let resource = RenderResource::new(); self.add_resource_info(resource, ResourceInfo::Texture); self.textures.insert(resource, texture_view); resource