From a99b5600bc9653baf3ea018f979ba4fd1cb41c1b Mon Sep 17 00:00:00 2001 From: Carter Anderson Date: Mon, 13 Apr 2020 13:04:31 -0700 Subject: [PATCH] Refactor render passes --- bevy_render/src/draw_target/draw_target.rs | 1 + .../assigned_batches_draw_target.rs | 7 +- .../assigned_meshes_draw_target.rs | 5 +- .../draw_targets/meshes_draw_target.rs | 3 +- .../draw_targets/ui_draw_target.rs | 3 +- bevy_render/src/pass/render_pass.rs | 5 +- bevy_render/src/renderer_2/render_context.rs | 27 +- .../src/renderer_2/render_resource_context.rs | 4 + .../src/renderer_2/wgpu_render_context.rs | 211 +++++++++++-- .../wgpu_render_resource_context.rs | 14 + ...u_transactional_render_resource_context.rs | 21 ++ bevy_wgpu/src/wgpu_render_pass.rs | 19 +- bevy_wgpu/src/wgpu_renderer.rs | 293 ++++-------------- bevy_wgpu/src/wgpu_resources.rs | 19 ++ 14 files changed, 343 insertions(+), 289 deletions(-) diff --git a/bevy_render/src/draw_target/draw_target.rs b/bevy_render/src/draw_target/draw_target.rs index 7e203a1c2a..c83f98f2ec 100644 --- a/bevy_render/src/draw_target/draw_target.rs +++ b/bevy_render/src/draw_target/draw_target.rs @@ -10,6 +10,7 @@ pub trait DrawTarget { resources: &Resources, render_pass: &mut dyn RenderPass, pipeline_handle: Handle, + pipeline_descriptor: &PipelineDescriptor, ); fn setup( &mut self, diff --git a/bevy_render/src/draw_target/draw_targets/assigned_batches_draw_target.rs b/bevy_render/src/draw_target/draw_targets/assigned_batches_draw_target.rs index 8ea4f83309..1d01a7b022 100644 --- a/bevy_render/src/draw_target/draw_targets/assigned_batches_draw_target.rs +++ b/bevy_render/src/draw_target/draw_targets/assigned_batches_draw_target.rs @@ -19,14 +19,15 @@ impl DrawTarget for AssignedBatchesDrawTarget { resources: &Resources, render_pass: &mut dyn RenderPass, pipeline_handle: Handle, + pipeline_descriptor: &PipelineDescriptor, ) { log::trace!("drawing batches for pipeline {:?}", pipeline_handle); let asset_batches = resources.get::().unwrap(); let global_render_resource_assignments = resources.get::().unwrap(); - render_pass.set_render_resources(&global_render_resource_assignments); + render_pass.set_render_resources(pipeline_descriptor, &global_render_resource_assignments); for batch in asset_batches.get_batches() { - let indices = render_pass.set_render_resources(&batch.render_resource_assignments); + let indices = render_pass.set_render_resources(pipeline_descriptor, &batch.render_resource_assignments); log::trace!("drawing batch {:?}", batch.render_resource_assignments.id); log::trace!("{:#?}", batch); for batched_entity in batch.entities.iter() { @@ -38,7 +39,7 @@ impl DrawTarget for AssignedBatchesDrawTarget { log::trace!("start drawing batched entity: {:?}", batched_entity); log::trace!("{:#?}", renderable.render_resource_assignments); let entity_indices = - render_pass.set_render_resources(&renderable.render_resource_assignments); + render_pass.set_render_resources(pipeline_descriptor, &renderable.render_resource_assignments); let mut draw_indices = &indices; if entity_indices.is_some() { if indices.is_some() { diff --git a/bevy_render/src/draw_target/draw_targets/assigned_meshes_draw_target.rs b/bevy_render/src/draw_target/draw_targets/assigned_meshes_draw_target.rs index 2cef0252f6..6f6cf5c604 100644 --- a/bevy_render/src/draw_target/draw_targets/assigned_meshes_draw_target.rs +++ b/bevy_render/src/draw_target/draw_targets/assigned_meshes_draw_target.rs @@ -23,6 +23,7 @@ impl DrawTarget for AssignedMeshesDrawTarget { resources: &Resources, render_pass: &mut dyn RenderPass, pipeline_handle: Handle, + pipeline_descriptor: &PipelineDescriptor, ) { let shader_pipeline_assignments = resources.get::().unwrap(); let entity_render_resource_assignments = @@ -31,7 +32,7 @@ impl DrawTarget for AssignedMeshesDrawTarget { let mut current_mesh_index_len = 0; let global_render_resource_assignments = resources.get::().unwrap(); - render_pass.set_render_resources(&global_render_resource_assignments); + render_pass.set_render_resources(pipeline_descriptor, &global_render_resource_assignments); let assigned_render_resource_assignments = shader_pipeline_assignments .assignments @@ -74,7 +75,7 @@ impl DrawTarget for AssignedMeshesDrawTarget { } // TODO: validate bind group properties against shader uniform properties at least once - render_pass.set_render_resources(&renderable.render_resource_assignments); + render_pass.set_render_resources(pipeline_descriptor, &renderable.render_resource_assignments); render_pass.draw_indexed(0..current_mesh_index_len, 0, 0..1); } } diff --git a/bevy_render/src/draw_target/draw_targets/meshes_draw_target.rs b/bevy_render/src/draw_target/draw_targets/meshes_draw_target.rs index 60fe4db01a..d27440914d 100644 --- a/bevy_render/src/draw_target/draw_targets/meshes_draw_target.rs +++ b/bevy_render/src/draw_target/draw_targets/meshes_draw_target.rs @@ -19,6 +19,7 @@ impl DrawTarget for MeshesDrawTarget { _resources: &Resources, render_pass: &mut dyn RenderPass, _pipeline_handle: Handle, + pipeline_descriptor: &PipelineDescriptor, ) { let mut current_mesh_handle = None; let mut current_mesh_index_len = 0; @@ -53,7 +54,7 @@ impl DrawTarget for MeshesDrawTarget { } // TODO: validate bind group properties against shader uniform properties at least once - render_pass.set_render_resources(&renderable.render_resource_assignments); + render_pass.set_render_resources(pipeline_descriptor, &renderable.render_resource_assignments); render_pass.draw_indexed(0..current_mesh_index_len, 0, 0..1); } } diff --git a/bevy_render/src/draw_target/draw_targets/ui_draw_target.rs b/bevy_render/src/draw_target/draw_targets/ui_draw_target.rs index 5a6bddd6c4..4547ac9bf8 100644 --- a/bevy_render/src/draw_target/draw_targets/ui_draw_target.rs +++ b/bevy_render/src/draw_target/draw_targets/ui_draw_target.rs @@ -29,6 +29,7 @@ impl DrawTarget for UiDrawTarget { resources: &Resources, render_pass: &mut dyn RenderPass, _pipeline_handle: Handle, + pipeline_descriptor: &PipelineDescriptor, ) { let render_resource_assignments = resources.get::().unwrap(); let ui_instances_buffer = { @@ -55,7 +56,7 @@ impl DrawTarget for UiDrawTarget { let global_render_resource_assignments = resources.get::().unwrap(); - render_pass.set_render_resources(&global_render_resource_assignments); + render_pass.set_render_resources(pipeline_descriptor, &global_render_resource_assignments); render_pass.set_index_buffer(self.mesh_index_buffer.unwrap(), 0); render_pass.set_vertex_buffer(0, self.mesh_vertex_buffer.unwrap(), 0); render_pass.set_vertex_buffer(1, ui_instances_buffer, 0); diff --git a/bevy_render/src/pass/render_pass.rs b/bevy_render/src/pass/render_pass.rs index a1da619e21..00728b013b 100644 --- a/bevy_render/src/pass/render_pass.rs +++ b/bevy_render/src/pass/render_pass.rs @@ -4,15 +4,18 @@ use crate::{ renderer_2::RenderContext, }; use std::ops::Range; +use bevy_asset::Handle; pub trait RenderPass { fn get_render_context(&self) -> &dyn RenderContext; - fn get_pipeline_descriptor(&self) -> &PipelineDescriptor; fn set_index_buffer(&mut self, resource: RenderResource, offset: u64); fn set_vertex_buffer(&mut self, start_slot: u32, resource: RenderResource, offset: u64); + fn set_pipeline(&mut self, pipeline_handle: Handle); fn draw_indexed(&mut self, indices: Range, base_vertex: i32, instances: Range); + // TODO: try to somehow take into account the "set" pipeline instead of passing it in here fn set_render_resources( &mut self, + pipeline_descriptor: &PipelineDescriptor, render_resource_assignments: &RenderResourceAssignments, ) -> Option>; } diff --git a/bevy_render/src/renderer_2/render_context.rs b/bevy_render/src/renderer_2/render_context.rs index 3e4768f0ee..d150dde44e 100644 --- a/bevy_render/src/renderer_2/render_context.rs +++ b/bevy_render/src/renderer_2/render_context.rs @@ -1,5 +1,6 @@ use super::RenderResourceContext; use crate::{ + pass::{PassDescriptor, RenderPass}, pipeline::{BindGroupDescriptor, PipelineDescriptor}, render_resource::{RenderResource, RenderResourceAssignments, RenderResourceSetId}, shader::Shader, @@ -8,18 +9,6 @@ use crate::{ use bevy_asset::{AssetStorage, Handle}; pub trait RenderContext { - // 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 resources(&self) -> &dyn RenderResourceContext; fn resources_mut(&mut self) -> &mut dyn RenderResourceContext; @@ -36,14 +25,6 @@ pub trait RenderContext { 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, - // ); fn create_bind_group( &mut self, bind_group_descriptor: &BindGroupDescriptor, @@ -65,4 +46,10 @@ pub trait RenderContext { self.create_bind_group(bind_group, render_resource_assignments); } } + fn begin_pass( + &mut self, + pass_descriptor: &PassDescriptor, + render_resource_assignments: &RenderResourceAssignments, + run_pass: &mut dyn Fn(&mut dyn RenderPass) + ); } diff --git a/bevy_render/src/renderer_2/render_resource_context.rs b/bevy_render/src/renderer_2/render_resource_context.rs index ac5d323576..62b13a81d7 100644 --- a/bevy_render/src/renderer_2/render_resource_context.rs +++ b/bevy_render/src/renderer_2/render_resource_context.rs @@ -5,6 +5,7 @@ use crate::{ texture::{SamplerDescriptor, Texture, TextureDescriptor}, }; use bevy_asset::{AssetStorage, Handle}; +use bevy_window::{Window, WindowId}; pub struct GlobalRenderResourceContext { pub context: Box, @@ -12,6 +13,9 @@ pub struct GlobalRenderResourceContext { // TODO: Rename to RenderResources after cleaning up AssetResources rename pub trait RenderResourceContext { + 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); 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; diff --git a/bevy_wgpu/src/renderer_2/wgpu_render_context.rs b/bevy_wgpu/src/renderer_2/wgpu_render_context.rs index 78e3c930fc..6882eb7fc0 100644 --- a/bevy_wgpu/src/renderer_2/wgpu_render_context.rs +++ b/bevy_wgpu/src/renderer_2/wgpu_render_context.rs @@ -1,16 +1,24 @@ use super::WgpuRenderResourceContextTrait; -use crate::wgpu_type_converter::{OwnedWgpuVertexBufferDescriptor, WgpuInto}; +use crate::{ + wgpu_type_converter::{OwnedWgpuVertexBufferDescriptor, WgpuInto}, + WgpuRenderPass, +}; use bevy_asset::{AssetStorage, Handle}; use bevy_render::{ + pass::{ + PassDescriptor, RenderPass, RenderPassColorAttachmentDescriptor, + RenderPassDepthStencilAttachmentDescriptor, + }, pipeline::{BindGroupDescriptor, BindType, PipelineDescriptor}, render_resource::{ - RenderResource, RenderResourceAssignments, RenderResourceSetId, ResourceInfo, + resource_name, RenderResource, RenderResourceAssignments, RenderResourceSetId, ResourceInfo, }, renderer_2::{RenderContext, RenderResourceContext}, shader::Shader, texture::TextureDescriptor, }; -use std::sync::Arc; +use bevy_window::WindowId; +use std::{collections::HashMap, sync::Arc}; #[derive(Default)] struct LazyCommandEncoder { @@ -22,17 +30,29 @@ impl LazyCommandEncoder { 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.create(device); self.command_encoder.as_mut().unwrap() } } } + pub fn is_some(&self) -> bool { + self.command_encoder.is_some() + } + + pub fn create(&mut self, device: &wgpu::Device) { + let command_encoder = + device.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None }); + self.command_encoder = Some(command_encoder); + } + pub fn take(&mut self) -> Option { self.command_encoder.take() } + + pub fn set(&mut self, command_encoder: wgpu::CommandEncoder) { + self.command_encoder = Some(command_encoder); + } } pub struct WgpuRenderContext @@ -40,6 +60,8 @@ where T: RenderResourceContext, { pub device: Arc, + // TODO: remove this + pub primary_window: Option, command_encoder: LazyCommandEncoder, pub render_resources: T, } @@ -51,6 +73,7 @@ where pub fn new(device: Arc, resources: T) -> Self { WgpuRenderContext { device, + primary_window: None, render_resources: resources, command_encoder: LazyCommandEncoder::default(), } @@ -70,19 +93,6 @@ where pub fn finish_encoder(&mut self) -> Option { self.command_encoder.take().map(|encoder| encoder.finish()) } - - // fn get_buffer<'b>( - // render_resource: RenderResource, - // local_resources: &'b WgpuResources, - // global_resources: &'b WgpuResources, - // ) -> Option<&'b wgpu::Buffer> { - // let buffer = local_resources.buffers.get(&render_resource); - // if buffer.is_some() { - // return buffer; - // } - - // global_resources.buffers.get(&render_resource) - // } } impl RenderContext for WgpuRenderContext @@ -365,4 +375,167 @@ where self.render_resources .set_render_pipeline(pipeline_handle, wgpu_pipeline); } + fn begin_pass( + &mut self, + pass_descriptor: &PassDescriptor, + render_resource_assignments: &RenderResourceAssignments, + run_pass: &mut dyn Fn(&mut dyn RenderPass), + ) { + if !self.command_encoder.is_some() { + self.command_encoder.create(&self.device); + } + + let mut encoder = self.command_encoder.take().unwrap(); + { + let render_pass = create_render_pass( + self, + pass_descriptor, + render_resource_assignments, + &mut encoder, + ); + let mut wgpu_render_pass = WgpuRenderPass { + render_context: self, + render_pass, + bound_bind_groups: HashMap::default(), + }; + + run_pass(&mut wgpu_render_pass); + } + + self.command_encoder.set(encoder); + } +} + +pub fn create_render_pass<'a, 'b, T>( + 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, +{ + encoder.begin_render_pass(&wgpu::RenderPassDescriptor { + color_attachments: &pass_descriptor + .color_attachments + .iter() + .map(|c| { + create_wgpu_color_attachment_descriptor( + render_context, + global_render_resource_assignments, + c, + ) + }) + .collect::>(), + depth_stencil_attachment: pass_descriptor.depth_stencil_attachment.as_ref().map(|d| { + create_wgpu_depth_stencil_attachment_descriptor( + render_context, + global_render_resource_assignments, + d, + ) + }), + }) +} + +fn get_texture_view<'a, T>( + render_context: &'a WgpuRenderContext, + global_render_resource_assignments: &RenderResourceAssignments, + name: &str, +) -> &'a wgpu::TextureView +where + T: WgpuRenderResourceContextTrait + RenderResourceContext, +{ + 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()) + .map(|output| &output.view) + { + primary_swap_chain + } else { + panic!("No primary swap chain found for color attachment"); + } + } + _ => match global_render_resource_assignments.get(name) { + Some(resource) => render_context + .render_resources + .get_texture(resource) + .unwrap(), + None => { + // if let Some(swap_chain_output) = swap_chain_outputs.get(name) { + // &swap_chain_output.view + // } else { + panic!("Color attachment {} does not exist", name); + // } + } + }, + } +} + +fn create_wgpu_color_attachment_descriptor<'a, T>( + render_context: &'a WgpuRenderContext, + global_render_resource_assignments: &RenderResourceAssignments, + color_attachment_descriptor: &RenderPassColorAttachmentDescriptor, +) -> wgpu::RenderPassColorAttachmentDescriptor<'a> +where + T: WgpuRenderResourceContextTrait + RenderResourceContext, +{ + let attachment = get_texture_view( + render_context, + global_render_resource_assignments, + color_attachment_descriptor.attachment.as_str(), + ); + + let resolve_target = color_attachment_descriptor + .resolve_target + .as_ref() + .map(|target| { + get_texture_view( + render_context, + global_render_resource_assignments, + target.as_str(), + ) + }); + + wgpu::RenderPassColorAttachmentDescriptor { + store_op: color_attachment_descriptor.store_op.wgpu_into(), + load_op: color_attachment_descriptor.load_op.wgpu_into(), + clear_color: color_attachment_descriptor.clear_color.wgpu_into(), + attachment, + resolve_target, + } +} + +fn create_wgpu_depth_stencil_attachment_descriptor<'a, T>( + render_context: &'a WgpuRenderContext, + global_render_resource_assignments: &RenderResourceAssignments, + depth_stencil_attachment_descriptor: &RenderPassDepthStencilAttachmentDescriptor, +) -> wgpu::RenderPassDepthStencilAttachmentDescriptor<'a> +where + T: WgpuRenderResourceContextTrait + RenderResourceContext, +{ + let attachment = get_texture_view( + render_context, + global_render_resource_assignments, + depth_stencil_attachment_descriptor.attachment.as_str(), + ); + + wgpu::RenderPassDepthStencilAttachmentDescriptor { + attachment, + clear_depth: depth_stencil_attachment_descriptor.clear_depth, + clear_stencil: depth_stencil_attachment_descriptor.clear_stencil, + depth_load_op: depth_stencil_attachment_descriptor + .depth_load_op + .wgpu_into(), + depth_store_op: depth_stencil_attachment_descriptor + .depth_store_op + .wgpu_into(), + stencil_load_op: depth_stencil_attachment_descriptor + .stencil_load_op + .wgpu_into(), + stencil_store_op: depth_stencil_attachment_descriptor + .stencil_store_op + .wgpu_into(), + } } 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 78e0e09337..ffcd3c8131 100644 --- a/bevy_wgpu/src/renderer_2/wgpu_render_resource_context.rs +++ b/bevy_wgpu/src/renderer_2/wgpu_render_resource_context.rs @@ -12,6 +12,7 @@ use bevy_render::{ texture::{SamplerDescriptor, Texture, TextureDescriptor}, }; use std::sync::Arc; +use bevy_window::{WindowId, Window}; pub struct WgpuRenderResourceContext { pub device: Arc, @@ -62,6 +63,7 @@ pub trait WgpuRenderResourceContextTrait { 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>; @@ -154,6 +156,9 @@ impl WgpuRenderResourceContextTrait for WgpuRenderResourceContext { 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 { @@ -254,4 +259,13 @@ impl RenderResourceContext for WgpuRenderResourceContext { self.wgpu_resources .create_shader_module(&self.device, shader_handle, shader); } + fn create_swap_chain(&mut self, window: &Window) { + self.wgpu_resources.create_window_swap_chain(&self.device, window) + } + fn next_swap_chain_texture(&mut self, window_id: bevy_window::WindowId) { + self.wgpu_resources.next_swap_chain_texture(window_id); + } + fn drop_swap_chain_texture(&mut self, window_id: WindowId) { + self.wgpu_resources.remove_swap_chain_texture(window_id); + } } 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 index aff1350f4b..10e63549a0 100644 --- a/bevy_wgpu/src/renderer_2/wgpu_transactional_render_resource_context.rs +++ b/bevy_wgpu/src/renderer_2/wgpu_transactional_render_resource_context.rs @@ -12,6 +12,7 @@ use bevy_render::{ shader::Shader, texture::{SamplerDescriptor, Texture, TextureDescriptor}, }; +use bevy_window::{WindowId, Window}; use std::sync::Arc; pub struct WgpuTransactionalRenderResourceContext<'a> { @@ -139,6 +140,16 @@ impl<'a> WgpuRenderResourceContextTrait for WgpuTransactionalRenderResourceConte 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> { @@ -283,4 +294,14 @@ impl<'a> RenderResourceContext for WgpuTransactionalRenderResourceContext<'a> { 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 c81172ca1c..b46dd534e2 100644 --- a/bevy_wgpu/src/wgpu_render_pass.rs +++ b/bevy_wgpu/src/wgpu_render_pass.rs @@ -9,17 +9,16 @@ use bevy_render::{ }; use std::{collections::HashMap, ops::Range}; -pub struct WgpuRenderPass<'a, 'b, 'c, T> +pub struct WgpuRenderPass<'a, T> where T: RenderResourceContext + WgpuRenderResourceContextTrait, { - pub render_pass: &'b mut wgpu::RenderPass<'a>, - pub pipeline_descriptor: &'c PipelineDescriptor, + pub render_pass: wgpu::RenderPass<'a>, pub render_context: &'a WgpuRenderContext, pub bound_bind_groups: HashMap, } -impl<'a, 'b, 'c, T> RenderPass for WgpuRenderPass<'a, 'b, 'c, T> +impl<'a, T> RenderPass for WgpuRenderPass<'a, T> where T: RenderResourceContext + WgpuRenderResourceContextTrait, { @@ -27,10 +26,6 @@ where self.render_context } - fn get_pipeline_descriptor(&self) -> &PipelineDescriptor { - self.pipeline_descriptor - } - fn set_vertex_buffer(&mut self, start_slot: u32, resource: RenderResource, offset: u64) { let buffer = self .render_context @@ -57,9 +52,11 @@ where fn set_render_resources( &mut self, + pipeline_descriptor: &PipelineDescriptor, render_resource_assignments: &RenderResourceAssignments, ) -> Option> { - let pipeline_layout = self.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; @@ -151,4 +148,8 @@ 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"); + self.render_pass.set_pipeline(pipeline); + } } diff --git a/bevy_wgpu/src/wgpu_renderer.rs b/bevy_wgpu/src/wgpu_renderer.rs index 9e41f9d741..b96af8e594 100644 --- a/bevy_wgpu/src/wgpu_renderer.rs +++ b/bevy_wgpu/src/wgpu_renderer.rs @@ -1,32 +1,23 @@ -use super::{wgpu_type_converter::WgpuInto, WgpuRenderPass, WgpuResources}; +use super::WgpuResources; use crate::renderer_2::{ render_resource_sets_system, WgpuRenderContext, WgpuRenderResourceContext, - WgpuRenderResourceContextTrait, WgpuTransactionalRenderResourceContext, + WgpuTransactionalRenderResourceContext, }; use bevy_app::{EventReader, Events}; use bevy_asset::AssetStorage; use bevy_render::{ - pass::{ - PassDescriptor, RenderPassColorAttachmentDescriptor, - RenderPassDepthStencilAttachmentDescriptor, - }, pipeline::{update_shader_assignments, PipelineCompiler, PipelineDescriptor}, render_graph::RenderGraph, - render_resource::{resource_name, RenderResourceAssignments}, - renderer_2::RenderContext, + render_resource::RenderResourceAssignments, + renderer_2::{RenderContext, RenderResourceContext}, }; use bevy_window::{WindowCreated, WindowResized, Windows}; use legion::prelude::*; -use std::{ - collections::{HashMap, HashSet}, - ops::Deref, - sync::Arc, -}; +use std::{collections::HashSet, ops::Deref, sync::Arc}; pub struct WgpuRenderer { pub global_context: WgpuRenderContext, pub queue: wgpu::Queue, - pub encoder: Option, pub window_resized_event_reader: EventReader, pub window_created_event_reader: EventReader, pub intialized: bool, @@ -62,149 +53,12 @@ impl WgpuRenderer { WgpuRenderResourceContext::new(device), ), queue, - encoder: None, window_resized_event_reader, window_created_event_reader, intialized: false, } } - pub fn create_render_pass<'a, 'b>( - wgpu_resources: &'a WgpuResources, - pass_descriptor: &PassDescriptor, - global_render_resource_assignments: &'b RenderResourceAssignments, - encoder: &'a mut wgpu::CommandEncoder, - primary_swap_chain: &Option, - swap_chain_outputs: &'a HashMap, - ) -> wgpu::RenderPass<'a> { - encoder.begin_render_pass(&wgpu::RenderPassDescriptor { - color_attachments: &pass_descriptor - .color_attachments - .iter() - .map(|c| { - Self::create_wgpu_color_attachment_descriptor( - wgpu_resources, - global_render_resource_assignments, - c, - primary_swap_chain, - swap_chain_outputs, - ) - }) - .collect::>(), - depth_stencil_attachment: pass_descriptor.depth_stencil_attachment.as_ref().map(|d| { - Self::create_wgpu_depth_stencil_attachment_descriptor( - wgpu_resources, - global_render_resource_assignments, - d, - primary_swap_chain, - swap_chain_outputs, - ) - }), - }) - } - - fn get_texture_view<'a>( - wgpu_resources: &'a WgpuResources, - global_render_resource_assignments: &RenderResourceAssignments, - primary_swap_chain: &Option, - swap_chain_outputs: &'a HashMap, - name: &str, - ) -> &'a wgpu::TextureView { - match name { - resource_name::texture::SWAP_CHAIN => { - if let Some(primary_swap_chain) = primary_swap_chain { - swap_chain_outputs - .get(primary_swap_chain) - .map(|output| &output.view) - .unwrap() - } else { - panic!("No primary swap chain found for color attachment"); - } - } - _ => match global_render_resource_assignments.get(name) { - Some(resource) => wgpu_resources.textures.get(&resource).unwrap(), - None => { - if let Some(swap_chain_output) = swap_chain_outputs.get(name) { - &swap_chain_output.view - } else { - panic!("Color attachment {} does not exist", name); - } - } - }, - } - } - - fn create_wgpu_color_attachment_descriptor<'a>( - wgpu_resources: &'a WgpuResources, - global_render_resource_assignments: &RenderResourceAssignments, - color_attachment_descriptor: &RenderPassColorAttachmentDescriptor, - primary_swap_chain: &Option, - swap_chain_outputs: &'a HashMap, - ) -> wgpu::RenderPassColorAttachmentDescriptor<'a> { - let attachment = Self::get_texture_view( - wgpu_resources, - global_render_resource_assignments, - primary_swap_chain, - swap_chain_outputs, - color_attachment_descriptor.attachment.as_str(), - ); - - let resolve_target = color_attachment_descriptor - .resolve_target - .as_ref() - .map(|target| { - Self::get_texture_view( - wgpu_resources, - global_render_resource_assignments, - primary_swap_chain, - swap_chain_outputs, - target.as_str(), - ) - }); - - wgpu::RenderPassColorAttachmentDescriptor { - store_op: color_attachment_descriptor.store_op.wgpu_into(), - load_op: color_attachment_descriptor.load_op.wgpu_into(), - clear_color: color_attachment_descriptor.clear_color.wgpu_into(), - attachment, - resolve_target, - } - } - - fn create_wgpu_depth_stencil_attachment_descriptor<'a>( - wgpu_resources: &'a WgpuResources, - global_render_resource_assignments: &RenderResourceAssignments, - depth_stencil_attachment_descriptor: &RenderPassDepthStencilAttachmentDescriptor, - primary_swap_chain: &Option, - swap_chain_outputs: &'a HashMap, - ) -> wgpu::RenderPassDepthStencilAttachmentDescriptor<'a> { - let attachment = Self::get_texture_view( - wgpu_resources, - global_render_resource_assignments, - primary_swap_chain, - swap_chain_outputs, - depth_stencil_attachment_descriptor.attachment.as_str(), - ); - - wgpu::RenderPassDepthStencilAttachmentDescriptor { - attachment, - clear_depth: depth_stencil_attachment_descriptor.clear_depth, - clear_stencil: depth_stencil_attachment_descriptor.clear_stencil, - depth_load_op: depth_stencil_attachment_descriptor - .depth_load_op - .wgpu_into(), - depth_store_op: depth_stencil_attachment_descriptor - .depth_store_op - .wgpu_into(), - stencil_load_op: depth_stencil_attachment_descriptor - .stencil_load_op - .wgpu_into(), - stencil_store_op: depth_stencil_attachment_descriptor - .stencil_store_op - .wgpu_into(), - } - } - pub fn initialize_resource_providers( world: &mut World, resources: &mut Resources, @@ -398,35 +252,6 @@ impl WgpuRenderer { } } - fn get_swap_chain_outputs( - &mut self, - resources: &Resources, - ) -> (Option, HashMap) { - let primary_window_id = resources - .get::() - .unwrap() - .get_primary() - .map(|window| window.id); - let primary_swap_chain = - primary_window_id.map(|primary_window_id| primary_window_id.to_string()); - let swap_chain_outputs = self - .global_context - .render_resources - .wgpu_resources - .window_swap_chains - .iter_mut() - // TODO: include non-primary swap chains - .filter(|(window_id, _swap_chain)| **window_id == primary_window_id.unwrap()) - .map(|(window_id, swap_chain)| { - let swap_chain_texture = swap_chain - .get_next_texture() - .expect("Timeout when acquiring next swap chain texture"); - (window_id.to_string(), swap_chain_texture) - }) - .collect::>(); - (primary_swap_chain, swap_chain_outputs) - } - pub fn update(&mut self, world: &mut World, resources: &mut Resources) { Self::handle_window_created_events( resources, @@ -457,78 +282,80 @@ impl WgpuRenderer { &mut self.global_context.render_resources.wgpu_resources, ); - self.encoder = Some( - self.global_context - .device - .create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None }), - ); update_shader_assignments(world, resources, &self.global_context); self.create_queued_textures(resources); - let mut encoder = self.encoder.take().unwrap(); render_resource_sets_system().run(world, resources); // setup draw targets let mut render_graph = resources.get_mut::().unwrap(); render_graph.setup_pipeline_draw_targets(world, resources, &mut self.global_context); - let (primary_swap_chain, swap_chain_outputs) = self.get_swap_chain_outputs(resources); + // get next swap chain texture on primary window + let primary_window_id = resources + .get::() + .unwrap() + .get_primary() + .map(|window| window.id); + if let Some(primary_window_id) = primary_window_id { + self.global_context + .render_resources + .next_swap_chain_texture(primary_window_id); + self.global_context.primary_window = Some(primary_window_id); + } // begin render passes let pipeline_storage = resources.get::>().unwrap(); let pipeline_compiler = resources.get::().unwrap(); for (pass_name, pass_descriptor) in render_graph.pass_descriptors.iter() { - let mut render_pass = { - let global_render_resource_assignments = - resources.get::().unwrap(); - Self::create_render_pass( - &self.global_context.render_resources.wgpu_resources, - pass_descriptor, - &global_render_resource_assignments, - &mut encoder, - &primary_swap_chain, - &swap_chain_outputs, - ) - }; - if let Some(pass_pipelines) = render_graph.pass_pipelines.get(pass_name) { - for pass_pipeline in pass_pipelines.iter() { - if let Some(compiled_pipelines_iter) = - pipeline_compiler.iter_compiled_pipelines(*pass_pipeline) - { - for compiled_pipeline_handle in compiled_pipelines_iter { - let pipeline_descriptor = - pipeline_storage.get(compiled_pipeline_handle).unwrap(); - let render_pipeline = self - .global_context - .render_resources - .get_pipeline(*compiled_pipeline_handle) - .unwrap(); - render_pass.set_pipeline(render_pipeline); + let global_render_resource_assignments = + resources.get::().unwrap(); + self.global_context.begin_pass( + pass_descriptor, + &global_render_resource_assignments, + &mut |render_pass| { + if let Some(pass_pipelines) = render_graph.pass_pipelines.get(pass_name) { + for pass_pipeline in pass_pipelines.iter() { + if let Some(compiled_pipelines_iter) = + pipeline_compiler.iter_compiled_pipelines(*pass_pipeline) + { + for compiled_pipeline_handle in compiled_pipelines_iter { + let pipeline_descriptor = + pipeline_storage.get(compiled_pipeline_handle).unwrap(); + render_pass.set_pipeline(*compiled_pipeline_handle); - let mut wgpu_render_pass = WgpuRenderPass { - render_pass: &mut render_pass, - pipeline_descriptor, - render_context: &self.global_context, - bound_bind_groups: HashMap::default(), - }; - - for draw_target_name in pipeline_descriptor.draw_targets.iter() { - let draw_target = - render_graph.draw_targets.get(draw_target_name).unwrap(); - draw_target.draw( - world, - resources, - &mut wgpu_render_pass, - *compiled_pipeline_handle, - ); + for draw_target_name in pipeline_descriptor.draw_targets.iter() + { + let draw_target = render_graph + .draw_targets + .get(draw_target_name) + .unwrap(); + draw_target.draw( + world, + resources, + render_pass, + *compiled_pipeline_handle, + pipeline_descriptor, + ); + } + } } } } - } - } + }, + ); } - let command_buffer = encoder.finish(); - self.queue.submit(&[command_buffer]); + let command_buffer = self.global_context.finish_encoder(); + 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_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 f3e10ff384..c1d8022062 100644 --- a/bevy_wgpu/src/wgpu_resources.rs +++ b/bevy_wgpu/src/wgpu_resources.rs @@ -26,6 +26,7 @@ pub struct WgpuResources { 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, @@ -43,11 +44,14 @@ impl WgpuResources { 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); @@ -61,6 +65,21 @@ impl WgpuResources { 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(); + 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) + } + + pub fn remove_swap_chain_texture(&mut self, window_id: WindowId) { + self.swap_chain_outputs.remove(&window_id); + } + + pub fn remove_all_swap_chain_textures(&mut self) { + self.swap_chain_outputs.clear(); + } + pub fn create_window_swap_chain(&mut self, device: &wgpu::Device, window: &Window) { let swap_chain_descriptor: wgpu::SwapChainDescriptor = window.wgpu_into(); let surface = self