Refactor render passes

This commit is contained in:
Carter Anderson 2020-04-13 13:04:31 -07:00
parent 837e1dc139
commit a99b5600bc
14 changed files with 343 additions and 289 deletions

View File

@ -10,6 +10,7 @@ pub trait DrawTarget {
resources: &Resources,
render_pass: &mut dyn RenderPass,
pipeline_handle: Handle<PipelineDescriptor>,
pipeline_descriptor: &PipelineDescriptor,
);
fn setup(
&mut self,

View File

@ -19,14 +19,15 @@ impl DrawTarget for AssignedBatchesDrawTarget {
resources: &Resources,
render_pass: &mut dyn RenderPass,
pipeline_handle: Handle<PipelineDescriptor>,
pipeline_descriptor: &PipelineDescriptor,
) {
log::trace!("drawing batches for pipeline {:?}", pipeline_handle);
let asset_batches = resources.get::<AssetBatchers>().unwrap();
let global_render_resource_assignments =
resources.get::<RenderResourceAssignments>().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() {

View File

@ -23,6 +23,7 @@ impl DrawTarget for AssignedMeshesDrawTarget {
resources: &Resources,
render_pass: &mut dyn RenderPass,
pipeline_handle: Handle<PipelineDescriptor>,
pipeline_descriptor: &PipelineDescriptor,
) {
let shader_pipeline_assignments = resources.get::<PipelineAssignments>().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::<RenderResourceAssignments>().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);
}
}

View File

@ -19,6 +19,7 @@ impl DrawTarget for MeshesDrawTarget {
_resources: &Resources,
render_pass: &mut dyn RenderPass,
_pipeline_handle: Handle<PipelineDescriptor>,
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);
}
}

View File

@ -29,6 +29,7 @@ impl DrawTarget for UiDrawTarget {
resources: &Resources,
render_pass: &mut dyn RenderPass,
_pipeline_handle: Handle<PipelineDescriptor>,
pipeline_descriptor: &PipelineDescriptor,
) {
let render_resource_assignments = resources.get::<RenderResourceAssignments>().unwrap();
let ui_instances_buffer = {
@ -55,7 +56,7 @@ impl DrawTarget for UiDrawTarget {
let global_render_resource_assignments =
resources.get::<RenderResourceAssignments>().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);

View File

@ -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<PipelineDescriptor>);
fn draw_indexed(&mut self, indices: Range<u32>, base_vertex: i32, instances: Range<u32>);
// 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<Range<u32>>;
}

View File

@ -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<PipelineDescriptor>,
// pipeline_descriptor: &mut PipelineDescriptor,
// shader_storage: &AssetStorage<Shader>,
// );
// 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)
);
}

View File

@ -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<dyn RenderResourceContext + Send + Sync + 'static>,
@ -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;

View File

@ -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<wgpu::CommandEncoder> {
self.command_encoder.take()
}
pub fn set(&mut self, command_encoder: wgpu::CommandEncoder) {
self.command_encoder = Some(command_encoder);
}
}
pub struct WgpuRenderContext<T>
@ -40,6 +60,8 @@ where
T: RenderResourceContext,
{
pub device: Arc<wgpu::Device>,
// TODO: remove this
pub primary_window: Option<WindowId>,
command_encoder: LazyCommandEncoder,
pub render_resources: T,
}
@ -51,6 +73,7 @@ where
pub fn new(device: Arc<wgpu::Device>, 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<wgpu::CommandBuffer> {
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<T> RenderContext for WgpuRenderContext<T>
@ -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<T>,
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::<Vec<wgpu::RenderPassColorAttachmentDescriptor>>(),
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<T>,
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<T>,
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<T>,
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(),
}
}

View File

@ -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<wgpu::Device>,
@ -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<PipelineDescriptor>) -> 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);
}
}

View File

@ -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);
}
}

View File

@ -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<T>,
pub bound_bind_groups: HashMap<u32, RenderResourceSetId>,
}
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<Range<u32>> {
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<PipelineDescriptor>) {
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);
}
}

View File

@ -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<WgpuRenderResourceContext>,
pub queue: wgpu::Queue,
pub encoder: Option<wgpu::CommandEncoder>,
pub window_resized_event_reader: EventReader<WindowResized>,
pub window_created_event_reader: EventReader<WindowCreated>,
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<String>,
swap_chain_outputs: &'a HashMap<String, wgpu::SwapChainOutput>,
) -> 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::<Vec<wgpu::RenderPassColorAttachmentDescriptor>>(),
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<String>,
swap_chain_outputs: &'a HashMap<String, wgpu::SwapChainOutput>,
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<String>,
swap_chain_outputs: &'a HashMap<String, wgpu::SwapChainOutput>,
) -> 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<String>,
swap_chain_outputs: &'a HashMap<String, wgpu::SwapChainOutput>,
) -> 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<String>, HashMap<String, wgpu::SwapChainOutput>) {
let primary_window_id = resources
.get::<Windows>()
.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::<HashMap<String, wgpu::SwapChainOutput>>();
(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::<RenderGraph>().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::<Windows>()
.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::<AssetStorage<PipelineDescriptor>>().unwrap();
let pipeline_compiler = resources.get::<PipelineCompiler>().unwrap();
for (pass_name, pass_descriptor) in render_graph.pass_descriptors.iter() {
let mut render_pass = {
let global_render_resource_assignments =
resources.get::<RenderResourceAssignments>().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::<RenderResourceAssignments>().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);
}
}
}

View File

@ -26,6 +26,7 @@ pub struct WgpuResources {
pub asset_resources: AssetResources,
pub window_surfaces: HashMap<WindowId, wgpu::Surface>,
pub window_swap_chains: HashMap<WindowId, wgpu::SwapChain>,
pub swap_chain_outputs: HashMap<WindowId, wgpu::SwapChainOutput>,
pub buffers: HashMap<RenderResource, wgpu::Buffer>,
pub textures: HashMap<RenderResource, wgpu::TextureView>,
pub samplers: HashMap<RenderResource, wgpu::Sampler>,
@ -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