diff --git a/bevy_render/src/pipeline/pipeline_compiler.rs b/bevy_render/src/pipeline/pipeline_compiler.rs index 59169a893a..8da991f322 100644 --- a/bevy_render/src/pipeline/pipeline_compiler.rs +++ b/bevy_render/src/pipeline/pipeline_compiler.rs @@ -239,7 +239,7 @@ impl PipelineAssignments { // TODO: make this a system pub fn update_shader_assignments( world: &mut World, - resources: &mut Resources, + resources: &Resources, render_context: &dyn RenderContext, ) { // PERF: this seems like a lot of work for things that don't change that often. diff --git a/bevy_render/src/render_resource/render_resource.rs b/bevy_render/src/render_resource/render_resource.rs index 8145540f59..56eb265d58 100644 --- a/bevy_render/src/render_resource/render_resource.rs +++ b/bevy_render/src/render_resource/render_resource.rs @@ -17,25 +17,13 @@ impl RenderResource { // the overlap could cause accidents. #[derive(Default)] pub struct AssetResources { - pub texture_to_resource: HashMap, RenderResource>, - pub texture_to_sampler_resource: HashMap, RenderResource>, - pub mesh_to_vertices_resource: HashMap, RenderResource>, - pub mesh_to_indices_resource: HashMap, RenderResource>, + texture_to_resource: HashMap, RenderResource>, + texture_to_sampler_resource: HashMap, RenderResource>, + mesh_to_vertices_resource: HashMap, RenderResource>, + mesh_to_indices_resource: HashMap, RenderResource>, } impl AssetResources { - pub fn consume(&mut self, render_resources: AssetResources) { - // TODO: this is brittle. consider a single change-stream-based approach instead? - self.texture_to_resource - .extend(render_resources.texture_to_resource); - self.texture_to_sampler_resource - .extend(render_resources.texture_to_sampler_resource); - self.mesh_to_vertices_resource - .extend(render_resources.mesh_to_vertices_resource); - self.mesh_to_indices_resource - .extend(render_resources.mesh_to_indices_resource); - } - pub fn set_texture_resource(&mut self, texture: Handle, resource: RenderResource) { self.texture_to_resource.insert(texture, resource); } diff --git a/bevy_render/src/renderer_2/render_resource_context.rs b/bevy_render/src/renderer_2/render_resource_context.rs index 62b13a81d7..03b3b46375 100644 --- a/bevy_render/src/renderer_2/render_resource_context.rs +++ b/bevy_render/src/renderer_2/render_resource_context.rs @@ -6,13 +6,33 @@ use crate::{ }; use bevy_asset::{AssetStorage, Handle}; use bevy_window::{Window, WindowId}; +use std::any::Any; pub struct GlobalRenderResourceContext { pub context: Box, } +impl GlobalRenderResourceContext { + pub fn new(context: T) -> GlobalRenderResourceContext + where + T: RenderResourceContext + Send + Sync + 'static, + { + GlobalRenderResourceContext { + context: Box::new(context), + } + } + + // pub fn render_resources_mut(&mut self) -> &dyn RenderResourceContext { + // (&mut self.context).downcast_mut::() + // } + + // pub fn downcast_mut(&self) -> &dyn RenderResourceContext { + // self.context.downcast_ref::() + // } +} + // TODO: Rename to RenderResources after cleaning up AssetResources rename -pub trait RenderResourceContext { +pub trait RenderResourceContext: Any { fn create_swap_chain(&mut self, window: &Window); fn next_swap_chain_texture(&mut self, window_id: WindowId); fn drop_swap_chain_texture(&mut self, window_id: WindowId); diff --git a/bevy_wgpu/src/renderer_2/mod.rs b/bevy_wgpu/src/renderer_2/mod.rs index 2653f43421..77d2886c98 100644 --- a/bevy_wgpu/src/renderer_2/mod.rs +++ b/bevy_wgpu/src/renderer_2/mod.rs @@ -1,9 +1,7 @@ mod systems; mod wgpu_render_context; mod wgpu_render_resource_context; -mod wgpu_transactional_render_resource_context; pub use systems::*; pub use wgpu_render_context::*; pub use wgpu_render_resource_context::*; -pub use wgpu_transactional_render_resource_context::*; diff --git a/bevy_wgpu/src/renderer_2/wgpu_render_context.rs b/bevy_wgpu/src/renderer_2/wgpu_render_context.rs index 6882eb7fc0..7873c7a676 100644 --- a/bevy_wgpu/src/renderer_2/wgpu_render_context.rs +++ b/bevy_wgpu/src/renderer_2/wgpu_render_context.rs @@ -1,4 +1,4 @@ -use super::WgpuRenderResourceContextTrait; +use super::WgpuRenderResourceContext; use crate::{ wgpu_type_converter::{OwnedWgpuVertexBufferDescriptor, WgpuInto}, WgpuRenderPass, @@ -21,7 +21,7 @@ use bevy_window::WindowId; use std::{collections::HashMap, sync::Arc}; #[derive(Default)] -struct LazyCommandEncoder { +pub struct LazyCommandEncoder { command_encoder: Option, } @@ -55,22 +55,16 @@ impl LazyCommandEncoder { } } -pub struct WgpuRenderContext -where - T: RenderResourceContext, -{ +pub struct WgpuRenderContext { pub device: Arc, // TODO: remove this pub primary_window: Option, - command_encoder: LazyCommandEncoder, - pub render_resources: T, + pub command_encoder: LazyCommandEncoder, + pub render_resources: WgpuRenderResourceContext, } -impl WgpuRenderContext -where - T: RenderResourceContext, -{ - pub fn new(device: Arc, resources: T) -> Self { +impl WgpuRenderContext { + pub fn new(device: Arc, resources: WgpuRenderResourceContext) -> Self { WgpuRenderContext { device, primary_window: None, @@ -81,34 +75,25 @@ where /// Consume this context, finalize the current CommandEncoder (if it exists), and take the current WgpuResources. /// This is intended to be called from a worker thread right before synchronizing with the main thread. - pub fn finish(mut self) -> (Option, T) { - ( - self.command_encoder.take().map(|encoder| encoder.finish()), - self.render_resources, - ) - } - - /// Consume this context, finalize the current CommandEncoder (if it exists), and take the current WgpuResources. - /// This is intended to be called from a worker thread right before synchronizing with the main thread. - pub fn finish_encoder(&mut self) -> Option { + pub fn finish(&mut self) -> Option { self.command_encoder.take().map(|encoder| encoder.finish()) } } -impl RenderContext for WgpuRenderContext -where - T: RenderResourceContext + WgpuRenderResourceContextTrait, -{ +impl RenderContext for WgpuRenderContext { fn create_texture_with_data( &mut self, texture_descriptor: &TextureDescriptor, bytes: &[u8], ) -> RenderResource { - self.render_resources.create_texture_with_data( - self.command_encoder.get_or_create(&self.device), - texture_descriptor, - bytes, - ) + self.render_resources + .wgpu_resources + .create_texture_with_data( + &self.device, + self.command_encoder.get_or_create(&self.device), + texture_descriptor, + bytes, + ) } fn copy_buffer_to_buffer( &mut self, @@ -119,15 +104,11 @@ where size: u64, ) { let command_encoder = self.command_encoder.get_or_create(&self.device); - let source = self.render_resources.get_buffer(source_buffer).unwrap(); - let destination = self - .render_resources - .get_buffer(destination_buffer) - .unwrap(); - command_encoder.copy_buffer_to_buffer( - source, + self.render_resources.wgpu_resources.copy_buffer_to_buffer( + command_encoder, + source_buffer, source_offset, - destination, + destination_buffer, destination_offset, size, ); @@ -148,6 +129,7 @@ where { if let None = self .render_resources + .wgpu_resources .get_bind_group(bind_group_descriptor.id, *render_resource_set_id) { log::trace!( @@ -155,6 +137,19 @@ where render_resource_set_id ); let wgpu_bind_group = { + let textures = self + .render_resources + .wgpu_resources + .textures + .read() + .unwrap(); + let samplers = self + .render_resources + .wgpu_resources + .samplers + .read() + .unwrap(); + let buffers = self.render_resources.wgpu_resources.buffers.read().unwrap(); let bindings = bind_group_descriptor .bindings .iter() @@ -174,10 +169,7 @@ where resource: match &binding.bind_type { BindType::SampledTexture { .. } => { if let ResourceInfo::Texture = resource_info { - let texture = self - .render_resources - .get_texture(resource) - .unwrap(); + let texture = textures.get(&resource).unwrap(); wgpu::BindingResource::TextureView(texture) } else { panic!("expected a Texture resource"); @@ -185,10 +177,7 @@ where } BindType::Sampler { .. } => { if let ResourceInfo::Sampler = resource_info { - let sampler = self - .render_resources - .get_sampler(resource) - .unwrap(); + let sampler = samplers.get(&resource).unwrap(); wgpu::BindingResource::Sampler(sampler) } else { panic!("expected a Sampler resource"); @@ -197,10 +186,7 @@ where BindType::Uniform { .. } => { if let ResourceInfo::Buffer(buffer_info) = resource_info { - let buffer = self - .render_resources - .get_buffer(resource) - .unwrap(); + let buffer = buffers.get(&resource).unwrap(); wgpu::BindingResource::Buffer { buffer, range: 0..buffer_info.size as u64, @@ -221,19 +207,26 @@ where } }) .collect::>(); - let bind_group_layout = self + let bind_group_layouts = self .render_resources - .get_bind_group_layout(bind_group_descriptor.id) + .wgpu_resources + .bind_group_layouts + .read() .unwrap(); + let bind_group_layout = + bind_group_layouts.get(&bind_group_descriptor.id).unwrap(); let wgpu_bind_group_descriptor = wgpu::BindGroupDescriptor { label: None, layout: bind_group_layout, bindings: bindings.as_slice(), }; - self.render_resources - .create_bind_group(*render_resource_set_id, &wgpu_bind_group_descriptor) + self.render_resources.wgpu_resources.create_bind_group( + &self.device, + *render_resource_set_id, + &wgpu_bind_group_descriptor, + ) }; - self.render_resources.set_bind_group( + self.render_resources.wgpu_resources.set_bind_group( bind_group_descriptor.id, *render_resource_set_id, wgpu_bind_group, @@ -250,13 +243,27 @@ where pipeline_descriptor: &mut PipelineDescriptor, shader_storage: &AssetStorage, ) { - if let Some(_) = self.render_resources.get_pipeline(pipeline_handle) { + if let Some(_) = self + .render_resources + .wgpu_resources + .render_pipelines + .read() + .unwrap() + .get(&pipeline_handle) + { return; } let layout = pipeline_descriptor.get_layout().unwrap(); for bind_group in layout.bind_groups.iter() { - if let None = self.render_resources.get_bind_group_layout(bind_group.id) { + if let None = self + .render_resources + .wgpu_resources + .bind_group_layouts + .read() + .unwrap() + .get(&bind_group.id) + { let bind_group_layout_binding = bind_group .bindings .iter() @@ -266,32 +273,37 @@ where ty: (&binding.bind_type).wgpu_into(), }) .collect::>(); - self.render_resources.create_bind_group_layout( - bind_group.id, - &wgpu::BindGroupLayoutDescriptor { - bindings: bind_group_layout_binding.as_slice(), - label: None, - }, - ); + self.render_resources + .wgpu_resources + .create_bind_group_layout( + &self.device, + bind_group.id, + &wgpu::BindGroupLayoutDescriptor { + bindings: bind_group_layout_binding.as_slice(), + label: None, + }, + ); } } - // setup and collect bind group layouts - let bind_group_layouts = layout - .bind_groups - .iter() - .map(|bind_group| { - self.render_resources - .get_bind_group_layout(bind_group.id) - .unwrap() - }) - .collect::>(); - - let pipeline_layout = self - .device - .create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { - bind_group_layouts: bind_group_layouts.as_slice(), - }); + let pipeline_layout = { + let bind_group_layouts = self + .render_resources + .wgpu_resources + .bind_group_layouts + .read() + .unwrap(); + // setup and collect bind group layouts + let bind_group_layouts = layout + .bind_groups + .iter() + .map(|bind_group| bind_group_layouts.get(&bind_group.id).unwrap()) + .collect::>(); + self.device + .create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { + bind_group_layouts: bind_group_layouts.as_slice(), + }) + }; let owned_vertex_buffer_descriptors = layout .vertex_buffer_descriptors @@ -305,32 +317,46 @@ where .map(|c| c.wgpu_into()) .collect::>(); - if let None = self + if self .render_resources - .get_shader_module(pipeline_descriptor.shader_stages.vertex) + .wgpu_resources + .shader_modules + .read() + .unwrap() + .get(&pipeline_descriptor.shader_stages.vertex) + .is_none() { self.render_resources .create_shader_module(pipeline_descriptor.shader_stages.vertex, shader_storage); } if let Some(fragment_handle) = pipeline_descriptor.shader_stages.fragment { - if let None = self.render_resources.get_shader_module(fragment_handle) { + if self + .render_resources + .wgpu_resources + .shader_modules + .read() + .unwrap() + .get(&fragment_handle) + .is_none() + { self.render_resources .create_shader_module(fragment_handle, shader_storage); } }; let wgpu_pipeline = { - let vertex_shader_module = self + let shader_modules = self .render_resources - .get_shader_module(pipeline_descriptor.shader_stages.vertex) + .wgpu_resources + .shader_modules + .read() + .unwrap(); + let vertex_shader_module = shader_modules + .get(&pipeline_descriptor.shader_stages.vertex) .unwrap(); let fragment_shader_module = match pipeline_descriptor.shader_stages.fragment { - Some(fragment_handle) => Some( - self.render_resources - .get_shader_module(fragment_handle) - .unwrap(), - ), + Some(fragment_handle) => Some(shader_modules.get(&fragment_handle).unwrap()), None => None, }; @@ -370,9 +396,11 @@ where }; self.render_resources - .create_render_pipeline(&render_pipeline_descriptor) + .wgpu_resources + .create_render_pipeline(&self.device, &render_pipeline_descriptor) }; self.render_resources + .wgpu_resources .set_render_pipeline(pipeline_handle, wgpu_pipeline); } fn begin_pass( @@ -406,15 +434,12 @@ where } } -pub fn create_render_pass<'a, 'b, T>( - render_context: &'a WgpuRenderContext, +pub fn create_render_pass<'a, 'b>( + render_context: &'a WgpuRenderContext, pass_descriptor: &PassDescriptor, global_render_resource_assignments: &'b RenderResourceAssignments, encoder: &'a mut wgpu::CommandEncoder, -) -> wgpu::RenderPass<'a> -where - T: WgpuRenderResourceContextTrait + RenderResourceContext, -{ +) -> wgpu::RenderPass<'a> { encoder.begin_render_pass(&wgpu::RenderPassDescriptor { color_attachments: &pass_descriptor .color_attachments @@ -437,19 +462,20 @@ where }) } -fn get_texture_view<'a, T>( - render_context: &'a WgpuRenderContext, +fn get_texture_view<'a>( + render_context: &'a WgpuRenderContext, global_render_resource_assignments: &RenderResourceAssignments, name: &str, -) -> &'a wgpu::TextureView -where - T: WgpuRenderResourceContextTrait + RenderResourceContext, -{ +) -> &'a wgpu::TextureView { match name { resource_name::texture::SWAP_CHAIN => { if let Some(primary_swap_chain) = render_context .render_resources - .get_swap_chain_output(render_context.primary_window.as_ref().unwrap()) + .wgpu_resources + .swap_chain_outputs + .read() + .unwrap() + .get(render_context.primary_window.as_ref().unwrap()) .map(|output| &output.view) { primary_swap_chain @@ -460,7 +486,11 @@ where _ => match global_render_resource_assignments.get(name) { Some(resource) => render_context .render_resources - .get_texture(resource) + .wgpu_resources + .textures + .read() + .unwrap() + .get(&resource) .unwrap(), None => { // if let Some(swap_chain_output) = swap_chain_outputs.get(name) { @@ -473,14 +503,11 @@ where } } -fn create_wgpu_color_attachment_descriptor<'a, T>( - render_context: &'a WgpuRenderContext, +fn create_wgpu_color_attachment_descriptor<'a>( + render_context: &'a WgpuRenderContext, global_render_resource_assignments: &RenderResourceAssignments, color_attachment_descriptor: &RenderPassColorAttachmentDescriptor, -) -> wgpu::RenderPassColorAttachmentDescriptor<'a> -where - T: WgpuRenderResourceContextTrait + RenderResourceContext, -{ +) -> wgpu::RenderPassColorAttachmentDescriptor<'a> { let attachment = get_texture_view( render_context, global_render_resource_assignments, @@ -507,14 +534,11 @@ where } } -fn create_wgpu_depth_stencil_attachment_descriptor<'a, T>( - render_context: &'a WgpuRenderContext, +fn create_wgpu_depth_stencil_attachment_descriptor<'a>( + render_context: &'a WgpuRenderContext, global_render_resource_assignments: &RenderResourceAssignments, depth_stencil_attachment_descriptor: &RenderPassDepthStencilAttachmentDescriptor, -) -> wgpu::RenderPassDepthStencilAttachmentDescriptor<'a> -where - T: WgpuRenderResourceContextTrait + RenderResourceContext, -{ +) -> wgpu::RenderPassDepthStencilAttachmentDescriptor<'a> { let attachment = get_texture_view( render_context, global_render_resource_assignments, diff --git a/bevy_wgpu/src/renderer_2/wgpu_render_resource_context.rs b/bevy_wgpu/src/renderer_2/wgpu_render_resource_context.rs index ffcd3c8131..68f6b73512 100644 --- a/bevy_wgpu/src/renderer_2/wgpu_render_resource_context.rs +++ b/bevy_wgpu/src/renderer_2/wgpu_render_resource_context.rs @@ -3,9 +3,8 @@ use crate::WgpuResources; use bevy_asset::{AssetStorage, Handle}; use bevy_render::{ mesh::Mesh, - pipeline::{BindGroupDescriptorId, PipelineDescriptor}, render_resource::{ - AssetResources, BufferInfo, RenderResource, RenderResourceSetId, ResourceInfo, + AssetResources, BufferInfo, RenderResource, ResourceInfo, }, renderer_2::RenderResourceContext, shader::Shader, @@ -14,158 +13,18 @@ use bevy_render::{ use std::sync::Arc; use bevy_window::{WindowId, Window}; +#[derive(Clone)] pub struct WgpuRenderResourceContext { pub device: Arc, - pub wgpu_resources: WgpuResources, + pub wgpu_resources: Arc, } -// TODO: make this name not terrible -pub trait WgpuRenderResourceContextTrait { - fn create_texture_with_data( - &mut self, - command_encoder: &mut wgpu::CommandEncoder, - texture_descriptor: &TextureDescriptor, - bytes: &[u8], - ) -> RenderResource; - - fn create_bind_group( - &self, - render_resource_set_id: RenderResourceSetId, - descriptor: &wgpu::BindGroupDescriptor, - ) -> wgpu::BindGroup; - fn set_bind_group( - &mut self, - bind_group_descriptor_id: BindGroupDescriptorId, - render_resource_set_id: RenderResourceSetId, - bind_group: wgpu::BindGroup, - ); - fn create_bind_group_layout( - &mut self, - bind_group_id: BindGroupDescriptorId, - descriptor: &wgpu::BindGroupLayoutDescriptor, - ); - fn create_render_pipeline( - &self, - descriptor: &wgpu::RenderPipelineDescriptor, - ) -> wgpu::RenderPipeline; - fn set_render_pipeline( - &mut self, - pipeline_handle: Handle, - pipeline: wgpu::RenderPipeline, - ); - fn get_bind_group( - &self, - bind_group_id: BindGroupDescriptorId, - render_resource_set_id: RenderResourceSetId, - ) -> Option<&wgpu::BindGroup>; - fn get_bind_group_layout( - &self, - bind_group_id: BindGroupDescriptorId, - ) -> Option<&wgpu::BindGroupLayout>; - fn get_buffer(&self, render_resource: RenderResource) -> Option<&wgpu::Buffer>; - fn get_swap_chain_output(&self, window_id: &WindowId) -> Option<&wgpu::SwapChainOutput>; - fn get_texture(&self, render_resource: RenderResource) -> Option<&wgpu::TextureView>; - fn get_sampler(&self, render_resource: RenderResource) -> Option<&wgpu::Sampler>; - fn get_pipeline(&self, pipeline: Handle) -> Option<&wgpu::RenderPipeline>; - fn get_shader_module(&self, shader: Handle) -> Option<&wgpu::ShaderModule>; -} - -impl WgpuRenderResourceContextTrait for WgpuRenderResourceContext { - fn get_buffer(&self, render_resource: RenderResource) -> Option<&wgpu::Buffer> { - self.wgpu_resources.buffers.get(&render_resource) - } - fn create_texture_with_data( - &mut self, - command_encoder: &mut wgpu::CommandEncoder, - texture_descriptor: &TextureDescriptor, - bytes: &[u8], - ) -> RenderResource { - self.wgpu_resources.create_texture_with_data( - &self.device, - command_encoder, - texture_descriptor, - bytes, - ) - } - fn create_bind_group( - &self, - render_resource_set_id: RenderResourceSetId, - descriptor: &wgpu::BindGroupDescriptor, - ) -> wgpu::BindGroup { - self.wgpu_resources - .create_bind_group(&self.device, render_resource_set_id, descriptor) - } - fn create_bind_group_layout( - &mut self, - bind_group_id: BindGroupDescriptorId, - descriptor: &wgpu::BindGroupLayoutDescriptor, - ) { - self.wgpu_resources - .create_bind_group_layout(&self.device, bind_group_id, descriptor); - } - fn create_render_pipeline( - &self, - descriptor: &wgpu::RenderPipelineDescriptor, - ) -> wgpu::RenderPipeline { - self.wgpu_resources - .create_render_pipeline(&self.device, descriptor) - } - fn get_bind_group( - &self, - bind_group_descriptor_id: BindGroupDescriptorId, - render_resource_set_id: RenderResourceSetId, - ) -> Option<&wgpu::BindGroup> { - self.wgpu_resources - .get_bind_group(bind_group_descriptor_id, render_resource_set_id) - } - fn get_bind_group_layout( - &self, - bind_group_id: BindGroupDescriptorId, - ) -> Option<&wgpu::BindGroupLayout> { - self.wgpu_resources.bind_group_layouts.get(&bind_group_id) - } - fn get_texture(&self, render_resource: RenderResource) -> Option<&wgpu::TextureView> { - self.wgpu_resources.textures.get(&render_resource) - } - fn get_sampler(&self, render_resource: RenderResource) -> Option<&wgpu::Sampler> { - self.wgpu_resources.samplers.get(&render_resource) - } - fn get_pipeline(&self, pipeline: Handle) -> Option<&wgpu::RenderPipeline> { - self.wgpu_resources.render_pipelines.get(&pipeline) - } - fn get_shader_module(&self, shader: Handle) -> Option<&wgpu::ShaderModule> { - self.wgpu_resources.shader_modules.get(&shader) - } - fn set_bind_group( - &mut self, - bind_group_descriptor_id: BindGroupDescriptorId, - render_resource_set_id: RenderResourceSetId, - bind_group: wgpu::BindGroup, - ) { - self.wgpu_resources.set_bind_group( - bind_group_descriptor_id, - render_resource_set_id, - bind_group, - ); - } - fn set_render_pipeline( - &mut self, - pipeline_handle: Handle, - pipeline: wgpu::RenderPipeline, - ) { - self.wgpu_resources - .set_render_pipeline(pipeline_handle, pipeline); - } - fn get_swap_chain_output(&self, window_id: &WindowId) -> Option<&wgpu::SwapChainOutput> { - self.wgpu_resources.swap_chain_outputs.get(window_id) - } -} impl WgpuRenderResourceContext { pub fn new(device: Arc) -> Self { WgpuRenderResourceContext { device, - wgpu_resources: WgpuResources::default(), + wgpu_resources: Arc::new(WgpuResources::default()), } } } @@ -251,7 +110,7 @@ impl RenderResourceContext for WgpuRenderResourceContext { shader_handle: Handle, shader_storage: &AssetStorage, ) { - if self.get_shader_module(shader_handle).is_some() { + if self.wgpu_resources.shader_modules.read().unwrap().get(&shader_handle).is_some() { return; } diff --git a/bevy_wgpu/src/renderer_2/wgpu_transactional_render_resource_context.rs b/bevy_wgpu/src/renderer_2/wgpu_transactional_render_resource_context.rs deleted file mode 100644 index 10e63549a0..0000000000 --- a/bevy_wgpu/src/renderer_2/wgpu_transactional_render_resource_context.rs +++ /dev/null @@ -1,307 +0,0 @@ -use crate::WgpuResources; - -use super::WgpuRenderResourceContextTrait; -use bevy_asset::Handle; -use bevy_render::{ - mesh::Mesh, - pipeline::{BindGroupDescriptorId, PipelineDescriptor}, - render_resource::{ - AssetResources, BufferInfo, RenderResource, RenderResourceSetId, ResourceInfo, - }, - renderer_2::RenderResourceContext, - shader::Shader, - texture::{SamplerDescriptor, Texture, TextureDescriptor}, -}; -use bevy_window::{WindowId, Window}; -use std::sync::Arc; - -pub struct WgpuTransactionalRenderResourceContext<'a> { - pub device: Arc, - pub local_resources: WgpuResources, - pub parent_resources: &'a WgpuResources, - removed_resources: Vec, -} - -impl<'a> WgpuRenderResourceContextTrait for WgpuTransactionalRenderResourceContext<'a> { - fn get_buffer(&self, render_resource: RenderResource) -> Option<&wgpu::Buffer> { - let local = self.local_resources.buffers.get(&render_resource); - if local.is_some() { - return local; - } - - self.parent_resources.buffers.get(&render_resource) - } - - fn create_texture_with_data( - &mut self, - command_encoder: &mut wgpu::CommandEncoder, - texture_descriptor: &TextureDescriptor, - bytes: &[u8], - ) -> RenderResource { - self.local_resources.create_texture_with_data( - &self.device, - command_encoder, - texture_descriptor, - bytes, - ) - } - fn create_bind_group( - &self, - render_resource_set_id: RenderResourceSetId, - descriptor: &wgpu::BindGroupDescriptor, - ) -> wgpu::BindGroup { - self.local_resources - .create_bind_group(&self.device, render_resource_set_id, descriptor) - } - fn create_bind_group_layout( - &mut self, - bind_group_id: BindGroupDescriptorId, - descriptor: &wgpu::BindGroupLayoutDescriptor, - ) { - self.local_resources - .create_bind_group_layout(&self.device, bind_group_id, descriptor); - } - fn create_render_pipeline( - &self, - descriptor: &wgpu::RenderPipelineDescriptor, - ) -> wgpu::RenderPipeline { - self.local_resources - .create_render_pipeline(&self.device, descriptor) - } - fn get_bind_group( - &self, - bind_group_descriptor_id: BindGroupDescriptorId, - render_resource_set_id: RenderResourceSetId, - ) -> Option<&wgpu::BindGroup> { - let local = self - .local_resources - .get_bind_group(bind_group_descriptor_id, render_resource_set_id); - if local.is_some() { - return local; - } - self.parent_resources - .get_bind_group(bind_group_descriptor_id, render_resource_set_id) - } - fn get_bind_group_layout( - &self, - bind_group_id: BindGroupDescriptorId, - ) -> Option<&wgpu::BindGroupLayout> { - let local = self.local_resources.bind_group_layouts.get(&bind_group_id); - if local.is_some() { - return local; - } - self.parent_resources.bind_group_layouts.get(&bind_group_id) - } - fn get_texture(&self, render_resource: RenderResource) -> Option<&wgpu::TextureView> { - let local = self.local_resources.textures.get(&render_resource); - if local.is_some() { - return local; - } - self.parent_resources.textures.get(&render_resource) - } - fn get_sampler(&self, render_resource: RenderResource) -> Option<&wgpu::Sampler> { - let local = self.local_resources.samplers.get(&render_resource); - if local.is_some() { - return local; - } - self.parent_resources.samplers.get(&render_resource) - } - fn get_pipeline(&self, pipeline: Handle) -> Option<&wgpu::RenderPipeline> { - let local = self.local_resources.render_pipelines.get(&pipeline); - if local.is_some() { - return local; - } - self.parent_resources.render_pipelines.get(&pipeline) - } - fn get_shader_module(&self, shader: Handle) -> Option<&wgpu::ShaderModule> { - let local = self.local_resources.shader_modules.get(&shader); - if local.is_some() { - return local; - } - self.parent_resources.shader_modules.get(&shader) - } - fn set_bind_group( - &mut self, - bind_group_descriptor_id: BindGroupDescriptorId, - render_resource_set_id: RenderResourceSetId, - bind_group: wgpu::BindGroup, - ) { - self.local_resources.set_bind_group( - bind_group_descriptor_id, - render_resource_set_id, - bind_group, - ); - } - fn set_render_pipeline( - &mut self, - pipeline_handle: Handle, - pipeline: wgpu::RenderPipeline, - ) { - self.local_resources - .set_render_pipeline(pipeline_handle, pipeline); - } - fn get_swap_chain_output( - &self, - window_id: &bevy_window::WindowId, - ) -> Option<&wgpu::SwapChainOutput> { - let local = self.local_resources.swap_chain_outputs.get(window_id); - if local.is_some() { - return local; - } - self.parent_resources.swap_chain_outputs.get(window_id) - } -} - -impl<'a> WgpuTransactionalRenderResourceContext<'a> { - pub fn new(device: Arc, parent_resources: &'a WgpuResources) -> Self { - WgpuTransactionalRenderResourceContext { - device, - local_resources: WgpuResources::default(), - parent_resources, - removed_resources: Vec::new(), - } - } -} - -impl<'a> RenderResourceContext for WgpuTransactionalRenderResourceContext<'a> { - fn create_sampler(&mut self, sampler_descriptor: &SamplerDescriptor) -> RenderResource { - self.local_resources - .create_sampler(&self.device, sampler_descriptor) - } - fn create_texture(&mut self, texture_descriptor: &TextureDescriptor) -> RenderResource { - self.local_resources - .create_texture(&self.device, texture_descriptor) - } - fn create_buffer(&mut self, buffer_info: BufferInfo) -> RenderResource { - self.local_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 RenderResourceContext), - ) -> RenderResource { - let buffer = WgpuResources::begin_create_buffer_mapped_transactional_render_context( - &buffer_info, - self, - setup_data, - ); - self.local_resources.assign_buffer(buffer, buffer_info) - } - - fn create_buffer_with_data(&mut self, buffer_info: BufferInfo, data: &[u8]) -> RenderResource { - self.local_resources - .create_buffer_with_data(&self.device, buffer_info, data) - } - - fn remove_buffer(&mut self, resource: RenderResource) { - self.local_resources.remove_buffer(resource); - self.removed_resources.push(resource); - } - fn remove_texture(&mut self, resource: RenderResource) { - self.local_resources.remove_texture(resource); - self.removed_resources.push(resource); - } - fn remove_sampler(&mut self, resource: RenderResource) { - self.local_resources.remove_sampler(resource); - self.removed_resources.push(resource); - } - - fn get_texture_resource(&self, texture: Handle) -> Option { - let local = self - .local_resources - .asset_resources - .get_texture_resource(texture); - if local.is_some() { - return local; - } - - self.parent_resources - .asset_resources - .get_texture_resource(texture) - } - - fn get_texture_sampler_resource(&self, texture: Handle) -> Option { - let local = self - .local_resources - .asset_resources - .get_texture_sampler_resource(texture); - - if local.is_some() { - return local; - } - - self.parent_resources - .asset_resources - .get_texture_sampler_resource(texture) - } - - fn get_mesh_vertices_resource(&self, mesh: Handle) -> Option { - let local = self - .local_resources - .asset_resources - .get_mesh_vertices_resource(mesh); - if local.is_some() { - return local; - } - - self.parent_resources - .asset_resources - .get_mesh_vertices_resource(mesh) - } - - fn get_mesh_indices_resource(&self, mesh: Handle) -> Option { - let local = self - .local_resources - .asset_resources - .get_mesh_indices_resource(mesh); - if local.is_some() { - return local; - } - - self.parent_resources - .asset_resources - .get_mesh_indices_resource(mesh) - } - - fn get_resource_info(&self, resource: RenderResource) -> Option<&ResourceInfo> { - let local = self.local_resources.get_resource_info(resource); - if local.is_some() { - return local; - } - - self.parent_resources.get_resource_info(resource) - } - - fn asset_resources(&self) -> &AssetResources { - &self.local_resources.asset_resources - } - fn asset_resources_mut(&mut self) -> &mut AssetResources { - &mut self.local_resources.asset_resources - } - fn create_shader_module( - &mut self, - shader_handle: Handle, - shader_storage: &bevy_asset::AssetStorage, - ) { - if self.get_shader_module(shader_handle).is_some() { - return; - } - - let shader = shader_storage.get(&shader_handle).unwrap(); - self.local_resources - .create_shader_module(&self.device, shader_handle, shader); - } - fn create_swap_chain(&mut self, window: &Window) { - self.local_resources - .create_window_swap_chain(&self.device, window) - } - fn next_swap_chain_texture(&mut self, window_id: bevy_window::WindowId) { - self.local_resources.next_swap_chain_texture(window_id); - } - fn drop_swap_chain_texture(&mut self, window_id: WindowId) { - self.local_resources.remove_swap_chain_texture(window_id); - } -} diff --git a/bevy_wgpu/src/wgpu_render_pass.rs b/bevy_wgpu/src/wgpu_render_pass.rs index b46dd534e2..fb8d4fbed8 100644 --- a/bevy_wgpu/src/wgpu_render_pass.rs +++ b/bevy_wgpu/src/wgpu_render_pass.rs @@ -1,47 +1,48 @@ -use crate::renderer_2::{WgpuRenderContext, WgpuRenderResourceContextTrait}; +use crate::renderer_2::WgpuRenderContext; +use bevy_asset::Handle; use bevy_render::{ pass::RenderPass, pipeline::PipelineDescriptor, render_resource::{ RenderResource, RenderResourceAssignments, RenderResourceSetId, ResourceInfo, }, - renderer_2::{RenderContext, RenderResourceContext}, + renderer_2::RenderContext, }; use std::{collections::HashMap, ops::Range}; -pub struct WgpuRenderPass<'a, T> -where - T: RenderResourceContext + WgpuRenderResourceContextTrait, -{ +pub struct WgpuRenderPass<'a> { pub render_pass: wgpu::RenderPass<'a>, - pub render_context: &'a WgpuRenderContext, + pub render_context: &'a WgpuRenderContext, pub bound_bind_groups: HashMap, } -impl<'a, T> RenderPass for WgpuRenderPass<'a, T> -where - T: RenderResourceContext + WgpuRenderResourceContextTrait, -{ +impl<'a> RenderPass for WgpuRenderPass<'a> { fn get_render_context(&self) -> &dyn RenderContext { self.render_context } fn set_vertex_buffer(&mut self, start_slot: u32, resource: RenderResource, offset: u64) { - let buffer = self + let buffers = self .render_context .render_resources - .get_buffer(resource) + .wgpu_resources + .buffers + .read() .unwrap(); + let buffer = buffers.get(&resource).unwrap(); self.render_pass .set_vertex_buffer(start_slot, &buffer, offset, 0); } fn set_index_buffer(&mut self, resource: RenderResource, offset: u64) { - let buffer = self + let buffers = self .render_context .render_resources - .get_buffer(resource) + .wgpu_resources + .buffers + .read() .unwrap(); + let buffer = buffers.get(&resource).unwrap(); self.render_pass.set_index_buffer(&buffer, offset, 0); } @@ -55,8 +56,7 @@ where pipeline_descriptor: &PipelineDescriptor, render_resource_assignments: &RenderResourceAssignments, ) -> Option> { - let pipeline_layout = pipeline_descriptor.get_layout() - .unwrap(); + let pipeline_layout = pipeline_descriptor.get_layout().unwrap(); // PERF: vertex buffer lookup comes at a cost when vertex buffers aren't in render_resource_assignments. iterating over render_resource_assignment vertex buffers // would likely be faster let mut indices = None; @@ -102,6 +102,7 @@ where if let Some(wgpu_bind_group) = self .render_context .render_resources + .wgpu_resources .get_bind_group(bind_group.id, *render_resource_set_id) { const EMPTY: &'static [u32] = &[]; @@ -148,8 +149,17 @@ where indices } - fn set_pipeline(&mut self, pipeline_handle: bevy_asset::Handle) { - let pipeline = self.render_context.render_resources.get_pipeline(pipeline_handle).expect("Attempted to use a pipeline that does not exist in this RenderPass's RenderContext"); + fn set_pipeline(&mut self, pipeline_handle: Handle) { + let render_pipelines = self + .render_context + .render_resources + .wgpu_resources + .render_pipelines + .read() + .unwrap(); + let pipeline = render_pipelines.get(&pipeline_handle).expect( + "Attempted to use a pipeline that does not exist in this RenderPass's RenderContext", + ); self.render_pass.set_pipeline(pipeline); } } diff --git a/bevy_wgpu/src/wgpu_renderer.rs b/bevy_wgpu/src/wgpu_renderer.rs index b96af8e594..2a53c8d7be 100644 --- a/bevy_wgpu/src/wgpu_renderer.rs +++ b/bevy_wgpu/src/wgpu_renderer.rs @@ -1,7 +1,5 @@ -use super::WgpuResources; use crate::renderer_2::{ render_resource_sets_system, WgpuRenderContext, WgpuRenderResourceContext, - WgpuTransactionalRenderResourceContext, }; use bevy_app::{EventReader, Events}; use bevy_asset::AssetStorage; @@ -9,14 +7,14 @@ use bevy_render::{ pipeline::{update_shader_assignments, PipelineCompiler, PipelineDescriptor}, render_graph::RenderGraph, render_resource::RenderResourceAssignments, - renderer_2::{RenderContext, RenderResourceContext}, + renderer_2::{GlobalRenderResourceContext, RenderContext, RenderResourceContext}, }; use bevy_window::{WindowCreated, WindowResized, Windows}; use legion::prelude::*; -use std::{collections::HashSet, ops::Deref, sync::Arc}; +use std::{any::Any, collections::HashSet, ops::Deref, sync::Arc}; pub struct WgpuRenderer { - pub global_context: WgpuRenderContext, + pub device: Arc, pub queue: wgpu::Queue, pub window_resized_event_reader: EventReader, pub window_created_event_reader: EventReader, @@ -48,10 +46,7 @@ impl WgpuRenderer { .await; let device = Arc::new(device); WgpuRenderer { - global_context: WgpuRenderContext::new( - device.clone(), - WgpuRenderResourceContext::new(device), - ), + device, queue, window_resized_event_reader, window_created_event_reader, @@ -61,8 +56,8 @@ impl WgpuRenderer { pub fn initialize_resource_providers( world: &mut World, - resources: &mut Resources, - render_context: &mut WgpuRenderContext, + resources: &Resources, + render_context: &mut WgpuRenderContext, ) { let mut render_graph = resources.get_mut::().unwrap(); for resource_provider in render_graph.resource_providers.iter_mut() { @@ -74,8 +69,8 @@ impl WgpuRenderer { world: &World, resources: &Resources, device: Arc, - global_wgpu_resources: &WgpuResources, - ) -> (Vec, Vec) { + render_resource_context: &WgpuRenderResourceContext, + ) -> Vec { let max_thread_count = 8; let (sender, receiver) = crossbeam_channel::bounded(max_thread_count); let mut render_graph = resources.get_mut::().unwrap(); @@ -86,21 +81,15 @@ impl WgpuRenderer { crossbeam_utils::thread::scope(|s| { for resource_provider_chunk in render_graph.resource_providers.chunks_mut(chunk_size) { let device = device.clone(); - let resource_device = device.clone(); let sender = sender.clone(); - let global_wgpu_resources = &*global_wgpu_resources; let world = &*world; let resources = &*resources; actual_thread_count += 1; // println!("spawn {}", resource_provider_chunk.len()); + let render_resource_context = render_resource_context.clone(); s.spawn(move |_| { - let mut render_context = WgpuRenderContext::new( - device, - WgpuTransactionalRenderResourceContext::new( - resource_device, - global_wgpu_resources, - ), - ); + let mut render_context = + WgpuRenderContext::new(device, render_resource_context); for resource_provider in resource_provider_chunk.iter_mut() { resource_provider.update(&mut render_context, world, resources); } @@ -111,37 +100,28 @@ impl WgpuRenderer { .unwrap(); let mut command_buffers = Vec::new(); - let mut local_resources = Vec::new(); for _i in 0..actual_thread_count { - let (command_buffer, render_resources) = receiver.recv().unwrap(); + let command_buffer = receiver.recv().unwrap(); if let Some(command_buffer) = command_buffer { command_buffers.push(command_buffer); } - - local_resources.push(render_resources.local_resources); - - // println!("got {}", i); } - (command_buffers, local_resources) + command_buffers } pub fn update_resource_providers( + &mut self, world: &mut World, - resources: &mut Resources, - queue: &mut wgpu::Queue, - device: Arc, - global_wgpu_resources: &mut WgpuResources, + resources: &Resources, + render_resource_context: &WgpuRenderResourceContext, ) { - let (mut command_buffers, local_resources) = Self::parallel_resource_provider_update( + let mut command_buffers = Self::parallel_resource_provider_update( world, resources, - device.clone(), - global_wgpu_resources, + self.device.clone(), + render_resource_context, ); - for local_resource in local_resources { - global_wgpu_resources.consume(local_resource); - } let mut render_graph = resources.get_mut::().unwrap(); let mut results = Vec::new(); @@ -150,15 +130,13 @@ impl WgpuRenderer { // crossbeam_utils::thread::scope(|s| { for resource_provider_chunk in render_graph.resource_providers.chunks_mut(chunk_size) { // TODO: try to unify this Device usage - let device = device.clone(); + let device = self.device.clone(); let resource_device = device.clone(); // let sender = sender.clone(); // s.spawn(|_| { // TODO: replace WgpuResources with Global+Local resources - let mut render_context = WgpuRenderContext::new( - device, - WgpuTransactionalRenderResourceContext::new(resource_device, global_wgpu_resources), - ); + let mut render_context = + WgpuRenderContext::new(device, render_resource_context.clone()); for resource_provider in resource_provider_chunk.iter_mut() { resource_provider.finish_update(&mut render_context, world, resources); } @@ -168,42 +146,37 @@ impl WgpuRenderer { } // }); - let mut local_resources = Vec::new(); - for (command_buffer, render_resources) in results { + for command_buffer in results { // for i in 0..thread_count { // let (command_buffer, wgpu_resources) = receiver.recv().unwrap(); if let Some(command_buffer) = command_buffer { command_buffers.push(command_buffer); } - local_resources.push(render_resources.local_resources); // println!("got {}", i); } - for local_resource in local_resources { - global_wgpu_resources.consume(local_resource); - } - queue.submit(&command_buffers); + self.queue.submit(&command_buffers); } - pub fn create_queued_textures(&mut self, resources: &mut Resources) { + pub fn create_queued_textures( + &mut self, + resources: &Resources, + global_render_resources: &mut WgpuRenderResourceContext, + ) { let mut render_graph = resources.get_mut::().unwrap(); let mut render_resource_assignments = resources.get_mut::().unwrap(); for (name, texture_descriptor) in render_graph.queued_textures.drain(..) { - let resource = self - .global_context - .resources_mut() - .create_texture(&texture_descriptor); + let resource = global_render_resources.create_texture(&texture_descriptor); render_resource_assignments.set(&name, resource); } } pub fn handle_window_resized_events( - resources: &mut Resources, - device: &wgpu::Device, - wgpu_resources: &mut WgpuResources, - window_resized_event_reader: &mut EventReader, + &mut self, + resources: &Resources, + global_render_resources: &mut WgpuRenderResourceContext, ) { let windows = resources.get::().unwrap(); let window_resized_events = resources.get::>().unwrap(); @@ -211,7 +184,7 @@ impl WgpuRenderer { // iterate in reverse order so we can handle the latest window resize event first for each window. // we skip earlier events for the same window because it results in redundant work for window_resized_event in window_resized_events - .iter(window_resized_event_reader) + .iter(&mut self.window_resized_event_reader) .rev() { if handled_windows.contains(&window_resized_event.id) { @@ -223,21 +196,22 @@ impl WgpuRenderer { .expect("Received window resized event for non-existent window"); // TODO: consider making this a WgpuRenderContext method - wgpu_resources.create_window_swap_chain(device, window); + global_render_resources.create_swap_chain(window); handled_windows.insert(window_resized_event.id); } } pub fn handle_window_created_events( - resources: &mut Resources, - device: &wgpu::Device, - wgpu_resources: &mut WgpuResources, - window_created_event_reader: &mut EventReader, + &mut self, + resources: &Resources, + global_render_resource_context: &mut WgpuRenderResourceContext, ) { let windows = resources.get::().unwrap(); let window_created_events = resources.get::>().unwrap(); - for window_created_event in window_created_events.iter(window_created_event_reader) { + for window_created_event in + window_created_events.iter(&mut self.window_created_event_reader) + { let window = windows .get(window_created_event.id) .expect("Received window created event for non-existent window"); @@ -246,49 +220,81 @@ impl WgpuRenderer { let winit_windows = resources.get::().unwrap(); let primary_winit_window = winit_windows.get_window(window.id).unwrap(); let surface = wgpu::Surface::create(primary_winit_window.deref()); - wgpu_resources.set_window_surface(window.id, surface); - wgpu_resources.create_window_swap_chain(device, window); + global_render_resource_context + .wgpu_resources + .set_window_surface(window.id, surface); + global_render_resource_context.create_swap_chain(window); } } } + pub fn create_global_render_resource_context(&self, resources: &mut Resources) { + resources.insert(GlobalRenderResourceContext::new( + WgpuRenderResourceContext::new(self.device.clone()), + )) + } + pub fn update(&mut self, world: &mut World, resources: &mut Resources) { - Self::handle_window_created_events( - resources, - &self.global_context.device, - &mut self.global_context.render_resources.wgpu_resources, - &mut self.window_created_event_reader, - ); - Self::handle_window_resized_events( - resources, - &self.global_context.device, - &mut self.global_context.render_resources.wgpu_resources, - &mut self.window_resized_event_reader, - ); if !self.intialized { - Self::initialize_resource_providers(world, resources, &mut self.global_context); - let buffer = self.global_context.finish_encoder(); - if let Some(buffer) = buffer { - self.queue.submit(&[buffer]); - } - self.intialized = true; + self.create_global_render_resource_context(resources); } - Self::update_resource_providers( - world, - resources, - &mut self.queue, - self.global_context.device.clone(), - &mut self.global_context.render_resources.wgpu_resources, - ); + let mut encoder = { + let mut global_context = resources.get_mut::().unwrap(); + let mut any_context = (&mut global_context.context) as &mut dyn Any; + // let mut any_context = (&mut global_context.context); + // println!("{}", std::any::type_name_of_val(any_context)); + let mut render_resource_context = any_context + .downcast_mut::() + .unwrap(); + panic!("ahh"); - update_shader_assignments(world, resources, &self.global_context); - self.create_queued_textures(resources); + // let mut render_resource_context = any_context + // .downcast_mut::() + // .unwrap(); + self.handle_window_created_events(resources, render_resource_context); + self.handle_window_resized_events(resources, render_resource_context); + let mut render_context = + WgpuRenderContext::new(self.device.clone(), render_resource_context.clone()); + if !self.intialized { + Self::initialize_resource_providers(world, resources, &mut render_context); + let buffer = render_context.finish(); + if let Some(buffer) = buffer { + self.queue.submit(&[buffer]); + } + self.intialized = true; + } + + self.update_resource_providers( + world, + resources, + render_resource_context, + ); + + update_shader_assignments(world, resources, &render_context); + self.create_queued_textures(resources, &mut render_context.render_resources); + render_context.command_encoder.take() + }; + + // TODO: add to POST_UPDATE and remove redundant global_context render_resource_sets_system().run(world, resources); + let mut global_context = resources.get_mut::().unwrap(); + let mut any_context = (&mut global_context.context) as &mut dyn Any; + // let mut any_context = (&mut global_context.context); + // println!("{}", std::any::type_name_of_val(any_context)); + let mut render_resource_context = any_context + .downcast_mut::() + .unwrap(); + let mut render_context = + WgpuRenderContext::new(self.device.clone(), render_resource_context.clone()); + if let Some(command_encoder) = encoder.take() { + render_context.command_encoder.set(command_encoder); + } + // setup draw targets let mut render_graph = resources.get_mut::().unwrap(); - render_graph.setup_pipeline_draw_targets(world, resources, &mut self.global_context); + render_graph.setup_pipeline_draw_targets(world, resources, &mut render_context); // get next swap chain texture on primary window let primary_window_id = resources @@ -297,10 +303,10 @@ impl WgpuRenderer { .get_primary() .map(|window| window.id); if let Some(primary_window_id) = primary_window_id { - self.global_context + render_context .render_resources .next_swap_chain_texture(primary_window_id); - self.global_context.primary_window = Some(primary_window_id); + render_context.primary_window = Some(primary_window_id); } // begin render passes @@ -310,7 +316,7 @@ impl WgpuRenderer { for (pass_name, pass_descriptor) in render_graph.pass_descriptors.iter() { let global_render_resource_assignments = resources.get::().unwrap(); - self.global_context.begin_pass( + render_context.begin_pass( pass_descriptor, &global_render_resource_assignments, &mut |render_pass| { @@ -346,14 +352,14 @@ impl WgpuRenderer { ); } - let command_buffer = self.global_context.finish_encoder(); + let command_buffer = render_context.finish(); if let Some(command_buffer) = command_buffer { self.queue.submit(&[command_buffer]); } // clear primary swap chain texture if let Some(primary_window_id) = primary_window_id { - self.global_context + render_context .render_resources .drop_swap_chain_texture(primary_window_id); } diff --git a/bevy_wgpu/src/wgpu_resources.rs b/bevy_wgpu/src/wgpu_resources.rs index c1d8022062..0baa974cdc 100644 --- a/bevy_wgpu/src/wgpu_resources.rs +++ b/bevy_wgpu/src/wgpu_resources.rs @@ -1,7 +1,4 @@ -use crate::{ - renderer_2::{WgpuRenderResourceContext, WgpuTransactionalRenderResourceContext}, - wgpu_type_converter::WgpuInto, -}; +use crate::{renderer_2::WgpuRenderResourceContext, wgpu_type_converter::WgpuInto}; use bevy_asset::Handle; use bevy_render::{ pipeline::{BindGroupDescriptorId, PipelineDescriptor}, @@ -13,85 +10,94 @@ use bevy_render::{ texture::{SamplerDescriptor, TextureDescriptor}, }; use bevy_window::{Window, WindowId}; -use std::collections::HashMap; +use std::{ + collections::HashMap, + sync::{Arc, RwLock, RwLockReadGuard}, +}; #[derive(Default)] pub struct WgpuBindGroupInfo { pub bind_groups: HashMap, } +pub struct WgpuResourcesReadLock<'a> { + pub buffers: RwLockReadGuard<'a, HashMap>, + pub textures: RwLockReadGuard<'a, HashMap>, +} + #[derive(Default)] pub struct WgpuResources { // TODO: remove this from WgpuResources. it doesn't need to be here pub asset_resources: AssetResources, - pub window_surfaces: HashMap, - pub window_swap_chains: HashMap, - pub swap_chain_outputs: HashMap, - pub buffers: HashMap, - pub textures: HashMap, - pub samplers: HashMap, - pub resource_info: HashMap, - pub shader_modules: HashMap, wgpu::ShaderModule>, - pub render_pipelines: HashMap, wgpu::RenderPipeline>, - pub bind_groups: HashMap, - pub bind_group_layouts: HashMap, + pub window_surfaces: Arc>>, + pub window_swap_chains: Arc>>, + pub swap_chain_outputs: Arc>>, + pub buffers: Arc>>, + pub textures: Arc>>, + pub samplers: Arc>>, + pub resource_info: Arc>>, + pub shader_modules: Arc, wgpu::ShaderModule>>>, + pub render_pipelines: Arc, wgpu::RenderPipeline>>>, + pub bind_groups: Arc>>, + pub bind_group_layouts: Arc>>, } impl WgpuResources { - pub fn consume(&mut self, wgpu_resources: WgpuResources) { - // TODO: this is brittle. consider a single change-stream-based approach instead? - self.asset_resources.consume(wgpu_resources.asset_resources); - self.window_surfaces.extend(wgpu_resources.window_surfaces); - self.window_swap_chains - .extend(wgpu_resources.window_swap_chains); - self.swap_chain_outputs - .extend(wgpu_resources.swap_chain_outputs); - self.buffers.extend(wgpu_resources.buffers); - self.textures.extend(wgpu_resources.textures); - self.samplers.extend(wgpu_resources.samplers); - self.resource_info.extend(wgpu_resources.resource_info); - self.shader_modules.extend(wgpu_resources.shader_modules); - self.render_pipelines.extend(wgpu_resources.render_pipelines); - self.bind_groups.extend(wgpu_resources.bind_groups); - self.bind_group_layouts - .extend(wgpu_resources.bind_group_layouts); + pub fn read(&self) -> WgpuResourcesReadLock { + WgpuResourcesReadLock { + buffers: self.buffers.read().unwrap(), + textures: self.textures.read().unwrap(), + } + } + + pub fn set_window_surface(&self, window_id: WindowId, surface: wgpu::Surface) { + self.window_surfaces + .write() + .unwrap() + .insert(window_id, surface); } - pub fn set_window_surface(&mut self, window_id: WindowId, surface: wgpu::Surface) { - self.window_surfaces.insert(window_id, surface); - } - - pub fn get_window_surface(&mut self, window_id: WindowId) -> Option<&wgpu::Surface> { - self.window_surfaces.get(&window_id) - } - - pub fn next_swap_chain_texture(&mut self, window_id: WindowId) -> Option<&wgpu::SwapChainOutput> { - let swap_chain_output = self.window_swap_chains.get_mut(&window_id).unwrap(); + pub fn next_swap_chain_texture(&self, window_id: WindowId) { + let mut swap_chain_outputs = self + .window_swap_chains + .write() + .unwrap(); + let swap_chain_output = swap_chain_outputs + .get_mut(&window_id) + .unwrap(); let next_texture = swap_chain_output.get_next_texture().unwrap(); - self.swap_chain_outputs.insert(window_id, next_texture); - self.swap_chain_outputs.get(&window_id) + self.swap_chain_outputs + .write() + .unwrap() + .insert(window_id, next_texture); } - pub fn remove_swap_chain_texture(&mut self, window_id: WindowId) { - self.swap_chain_outputs.remove(&window_id); + pub fn remove_swap_chain_texture(&self, window_id: WindowId) { + self.swap_chain_outputs.write().unwrap().remove(&window_id); } - pub fn remove_all_swap_chain_textures(&mut self) { - self.swap_chain_outputs.clear(); + pub fn remove_all_swap_chain_textures(&self) { + self.swap_chain_outputs.write().unwrap().clear(); } - pub fn create_window_swap_chain(&mut self, device: &wgpu::Device, window: &Window) { + pub fn create_window_swap_chain(&self, device: &wgpu::Device, window: &Window) { let swap_chain_descriptor: wgpu::SwapChainDescriptor = window.wgpu_into(); - let surface = self - .window_surfaces + let surfaces = self.window_surfaces.read().unwrap(); + let surface = surfaces .get(&window.id) .expect("No surface found for window"); let swap_chain = device.create_swap_chain(surface, &swap_chain_descriptor); - self.window_swap_chains.insert(window.id, swap_chain); + self.window_swap_chains + .write() + .unwrap() + .insert(window.id, swap_chain); } - pub fn add_resource_info(&mut self, resource: RenderResource, resource_info: ResourceInfo) { - self.resource_info.insert(resource, resource_info); + pub fn add_resource_info(&self, resource: RenderResource, resource_info: ResourceInfo) { + self.resource_info + .write() + .unwrap() + .insert(resource, resource_info); } pub fn get_bind_group( @@ -99,7 +105,12 @@ impl WgpuResources { bind_group_descriptor_id: BindGroupDescriptorId, render_resource_set_id: RenderResourceSetId, ) -> Option<&wgpu::BindGroup> { - if let Some(bind_group_info) = self.bind_groups.get(&bind_group_descriptor_id) { + if let Some(bind_group_info) = self + .bind_groups + .read() + .unwrap() + .get(&bind_group_descriptor_id) + { bind_group_info.bind_groups.get(&render_resource_set_id) } else { None @@ -121,13 +132,16 @@ impl WgpuResources { } pub fn set_bind_group( - &mut self, + &self, bind_group_descriptor_id: BindGroupDescriptorId, render_resource_set_id: RenderResourceSetId, bind_group: wgpu::BindGroup, ) { - let bind_group_info = self + let mut bind_groups = self .bind_groups + .write() + .unwrap(); + let bind_group_info = bind_groups .entry(bind_group_descriptor_id) .or_insert_with(|| WgpuBindGroupInfo::default()); bind_group_info @@ -135,11 +149,7 @@ impl WgpuResources { .insert(render_resource_set_id, bind_group); } - pub fn create_buffer( - &mut self, - device: &wgpu::Device, - buffer_info: BufferInfo, - ) -> RenderResource { + pub fn create_buffer(&self, device: &wgpu::Device, buffer_info: BufferInfo) -> RenderResource { let buffer = device.create_buffer(&wgpu::BufferDescriptor { label: None, size: buffer_info.size as u64, @@ -149,12 +159,12 @@ impl WgpuResources { let resource = RenderResource::new(); self.add_resource_info(resource, ResourceInfo::Buffer(buffer_info)); - self.buffers.insert(resource, buffer); + self.buffers.write().unwrap().insert(resource, buffer); resource } pub fn create_buffer_with_data( - &mut self, + &self, device: &wgpu::Device, mut buffer_info: BufferInfo, data: &[u8], @@ -165,22 +175,18 @@ impl WgpuResources { } pub fn get_resource_info(&self, resource: RenderResource) -> Option<&ResourceInfo> { - self.resource_info.get(&resource) + self.resource_info.read().unwrap().get(&resource) } - pub fn remove_buffer(&mut self, resource: RenderResource) { - self.buffers.remove(&resource); - self.resource_info.remove(&resource); + pub fn remove_buffer(&self, resource: RenderResource) { + self.buffers.write().unwrap().remove(&resource); + self.resource_info.write().unwrap().remove(&resource); } - pub fn assign_buffer( - &mut self, - buffer: wgpu::Buffer, - buffer_info: BufferInfo, - ) -> RenderResource { + pub fn assign_buffer(&self, buffer: wgpu::Buffer, buffer_info: BufferInfo) -> RenderResource { let resource = RenderResource::new(); self.add_resource_info(resource, ResourceInfo::Buffer(buffer_info)); - self.buffers.insert(resource, buffer); + self.buffers.write().unwrap().insert(resource, buffer); resource } @@ -200,23 +206,8 @@ impl WgpuResources { mapped.finish() } - pub fn begin_create_buffer_mapped_transactional_render_context( - buffer_info: &BufferInfo, - render_resources: &mut WgpuTransactionalRenderResourceContext, - setup_data: &mut dyn FnMut(&mut [u8], &mut dyn RenderResourceContext), - ) -> wgpu::Buffer { - let device = render_resources.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_resources); - mapped.finish() - } - pub fn copy_buffer_to_buffer( - &mut self, + &self, encoder: &mut wgpu::CommandEncoder, source_buffer: RenderResource, source_offset: u64, @@ -224,36 +215,40 @@ impl WgpuResources { destination_offset: u64, size: u64, ) { - let source = self.buffers.get(&source_buffer).unwrap(); - let destination = self.buffers.get(&destination_buffer).unwrap(); + let buffers = self.buffers.read().unwrap(); + let source = buffers.get(&source_buffer).unwrap(); + let destination = buffers.get(&destination_buffer).unwrap(); encoder.copy_buffer_to_buffer(source, source_offset, destination, destination_offset, size); } pub fn create_shader_module( - &mut self, + &self, device: &wgpu::Device, shader_handle: Handle, shader: &Shader, ) { let shader_module = device.create_shader_module(&shader.get_spirv(None)); - self.shader_modules.insert(shader_handle, shader_module); + self.shader_modules + .write() + .unwrap() + .insert(shader_handle, shader_module); } pub fn create_sampler( - &mut self, + &self, device: &wgpu::Device, sampler_descriptor: &SamplerDescriptor, ) -> RenderResource { let descriptor: wgpu::SamplerDescriptor = (*sampler_descriptor).wgpu_into(); let sampler = device.create_sampler(&descriptor); let resource = RenderResource::new(); - self.samplers.insert(resource, sampler); + self.samplers.write().unwrap().insert(resource, sampler); self.add_resource_info(resource, ResourceInfo::Sampler); resource } pub fn create_texture( - &mut self, + &self, device: &wgpu::Device, texture_descriptor: &TextureDescriptor, ) -> RenderResource { @@ -262,12 +257,15 @@ impl WgpuResources { let texture_view = texture.create_default_view(); let resource = RenderResource::new(); self.add_resource_info(resource, ResourceInfo::Texture); - self.textures.insert(resource, texture_view); + self.textures + .write() + .unwrap() + .insert(resource, texture_view); resource } pub fn create_texture_with_data( - &mut self, + &self, device: &wgpu::Device, encoder: &mut wgpu::CommandEncoder, texture_descriptor: &TextureDescriptor, @@ -295,18 +293,21 @@ impl WgpuResources { let resource = RenderResource::new(); self.add_resource_info(resource, ResourceInfo::Texture); - self.textures.insert(resource, texture_view); + self.textures + .write() + .unwrap() + .insert(resource, texture_view); resource } - pub fn remove_texture(&mut self, resource: RenderResource) { - self.textures.remove(&resource); - self.resource_info.remove(&resource); + pub fn remove_texture(&self, resource: RenderResource) { + self.textures.write().unwrap().remove(&resource); + self.resource_info.write().unwrap().remove(&resource); } - pub fn remove_sampler(&mut self, resource: RenderResource) { - self.samplers.remove(&resource); - self.resource_info.remove(&resource); + pub fn remove_sampler(&self, resource: RenderResource) { + self.samplers.write().unwrap().remove(&resource); + self.resource_info.write().unwrap().remove(&resource); } pub fn get_render_resources(&self) -> &AssetResources { @@ -318,13 +319,15 @@ impl WgpuResources { } pub fn create_bind_group_layout( - &mut self, + &self, device: &wgpu::Device, bind_group_id: BindGroupDescriptorId, descriptor: &wgpu::BindGroupLayoutDescriptor, ) { let wgpu_bind_group_layout = device.create_bind_group_layout(descriptor); self.bind_group_layouts + .write() + .unwrap() .insert(bind_group_id, wgpu_bind_group_layout); } @@ -337,11 +340,13 @@ impl WgpuResources { } pub fn set_render_pipeline( - &mut self, + &self, pipeline_handle: Handle, render_pipeline: wgpu::RenderPipeline, ) { self.render_pipelines + .write() + .unwrap() .insert(pipeline_handle, render_pipeline); } }