2020-04-12 21:47:41 +00:00
|
|
|
use super::{wgpu_type_converter::WgpuInto, WgpuRenderPass, WgpuResources};
|
2020-04-12 07:05:47 +00:00
|
|
|
use crate::renderer_2::{
|
2020-04-12 21:47:41 +00:00
|
|
|
render_resource_sets_system, WgpuRenderContext, WgpuRenderResourceContext,
|
|
|
|
WgpuRenderResourceContextTrait, WgpuTransactionalRenderResourceContext,
|
2020-04-12 07:05:47 +00:00
|
|
|
};
|
2020-04-06 03:19:02 +00:00
|
|
|
use bevy_app::{EventReader, Events};
|
2020-04-12 21:47:41 +00:00
|
|
|
use bevy_asset::AssetStorage;
|
2020-04-06 03:19:02 +00:00
|
|
|
use bevy_render::{
|
|
|
|
pass::{
|
|
|
|
PassDescriptor, RenderPassColorAttachmentDescriptor,
|
|
|
|
RenderPassDepthStencilAttachmentDescriptor,
|
2020-03-26 08:57:36 +00:00
|
|
|
},
|
2020-04-06 03:19:02 +00:00
|
|
|
pipeline::{update_shader_assignments, PipelineCompiler, PipelineDescriptor},
|
|
|
|
render_graph::RenderGraph,
|
2020-04-12 21:47:41 +00:00
|
|
|
render_resource::{resource_name, RenderResourceAssignments},
|
|
|
|
renderer_2::RenderContext,
|
2020-01-20 08:57:54 +00:00
|
|
|
};
|
2020-04-10 08:39:38 +00:00
|
|
|
use bevy_window::{WindowCreated, WindowResized, Windows};
|
2020-04-06 03:19:02 +00:00
|
|
|
use legion::prelude::*;
|
2020-03-31 02:21:12 +00:00
|
|
|
use std::{
|
|
|
|
collections::{HashMap, HashSet},
|
|
|
|
ops::Deref,
|
2020-04-09 19:35:15 +00:00
|
|
|
sync::Arc,
|
2020-03-31 02:21:12 +00:00
|
|
|
};
|
2020-03-03 01:53:39 +00:00
|
|
|
|
|
|
|
pub struct WgpuRenderer {
|
2020-04-12 01:40:30 +00:00
|
|
|
pub global_context: WgpuRenderContext<WgpuRenderResourceContext>,
|
2020-03-03 01:53:39 +00:00
|
|
|
pub queue: wgpu::Queue,
|
|
|
|
pub encoder: Option<wgpu::CommandEncoder>,
|
2020-04-01 01:04:54 +00:00
|
|
|
pub window_resized_event_reader: EventReader<WindowResized>,
|
|
|
|
pub window_created_event_reader: EventReader<WindowCreated>,
|
2020-03-23 01:22:35 +00:00
|
|
|
pub intialized: bool,
|
2020-03-03 01:53:39 +00:00
|
|
|
}
|
|
|
|
|
2020-01-20 08:57:54 +00:00
|
|
|
impl WgpuRenderer {
|
2020-03-31 02:21:12 +00:00
|
|
|
pub async fn new(
|
2020-04-01 01:04:54 +00:00
|
|
|
window_resized_event_reader: EventReader<WindowResized>,
|
|
|
|
window_created_event_reader: EventReader<WindowCreated>,
|
2020-03-31 02:21:12 +00:00
|
|
|
) -> Self {
|
2020-01-20 08:57:54 +00:00
|
|
|
let adapter = wgpu::Adapter::request(
|
|
|
|
&wgpu::RequestAdapterOptions {
|
|
|
|
power_preference: wgpu::PowerPreference::Default,
|
2020-04-08 02:36:57 +00:00
|
|
|
compatible_surface: None,
|
2020-01-20 08:57:54 +00:00
|
|
|
},
|
|
|
|
wgpu::BackendBit::PRIMARY,
|
|
|
|
)
|
2020-03-30 07:56:15 +00:00
|
|
|
.await
|
2020-01-20 08:57:54 +00:00
|
|
|
.unwrap();
|
|
|
|
|
2020-03-31 02:21:12 +00:00
|
|
|
let (device, queue) = adapter
|
|
|
|
.request_device(&wgpu::DeviceDescriptor {
|
|
|
|
extensions: wgpu::Extensions {
|
|
|
|
anisotropic_filtering: false,
|
|
|
|
},
|
|
|
|
limits: wgpu::Limits::default(),
|
|
|
|
})
|
|
|
|
.await;
|
2020-04-12 01:40:30 +00:00
|
|
|
let device = Arc::new(device);
|
2020-01-20 08:57:54 +00:00
|
|
|
WgpuRenderer {
|
2020-04-12 01:40:30 +00:00
|
|
|
global_context: WgpuRenderContext::new(
|
|
|
|
device.clone(),
|
|
|
|
WgpuRenderResourceContext::new(device),
|
|
|
|
),
|
2020-01-20 08:57:54 +00:00
|
|
|
queue,
|
2020-02-04 08:06:17 +00:00
|
|
|
encoder: None,
|
2020-04-01 01:04:54 +00:00
|
|
|
window_resized_event_reader,
|
|
|
|
window_created_event_reader,
|
2020-03-23 01:22:35 +00:00
|
|
|
intialized: false,
|
2020-01-20 08:57:54 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-05 20:22:27 +00:00
|
|
|
pub fn create_render_pass<'a, 'b>(
|
2020-03-05 08:44:53 +00:00
|
|
|
wgpu_resources: &'a WgpuResources,
|
2020-01-20 08:57:54 +00:00
|
|
|
pass_descriptor: &PassDescriptor,
|
2020-04-05 20:22:27 +00:00
|
|
|
global_render_resource_assignments: &'b RenderResourceAssignments,
|
2020-01-20 08:57:54 +00:00
|
|
|
encoder: &'a mut wgpu::CommandEncoder,
|
2020-03-31 05:23:48 +00:00
|
|
|
primary_swap_chain: &Option<String>,
|
|
|
|
swap_chain_outputs: &'a HashMap<String, wgpu::SwapChainOutput>,
|
2020-01-20 08:57:54 +00:00
|
|
|
) -> wgpu::RenderPass<'a> {
|
|
|
|
encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
|
|
|
color_attachments: &pass_descriptor
|
|
|
|
.color_attachments
|
|
|
|
.iter()
|
2020-03-27 06:40:25 +00:00
|
|
|
.map(|c| {
|
|
|
|
Self::create_wgpu_color_attachment_descriptor(
|
|
|
|
wgpu_resources,
|
|
|
|
global_render_resource_assignments,
|
|
|
|
c,
|
2020-03-31 05:23:48 +00:00
|
|
|
primary_swap_chain,
|
|
|
|
swap_chain_outputs,
|
2020-03-27 06:40:25 +00:00
|
|
|
)
|
|
|
|
})
|
2020-01-20 08:57:54 +00:00
|
|
|
.collect::<Vec<wgpu::RenderPassColorAttachmentDescriptor>>(),
|
2020-03-09 03:06:59 +00:00
|
|
|
depth_stencil_attachment: pass_descriptor.depth_stencil_attachment.as_ref().map(|d| {
|
2020-03-27 06:40:25 +00:00
|
|
|
Self::create_wgpu_depth_stencil_attachment_descriptor(
|
|
|
|
wgpu_resources,
|
|
|
|
global_render_resource_assignments,
|
|
|
|
d,
|
2020-03-31 05:23:48 +00:00
|
|
|
primary_swap_chain,
|
|
|
|
swap_chain_outputs,
|
2020-03-27 06:40:25 +00:00
|
|
|
)
|
2020-03-09 03:06:59 +00:00
|
|
|
}),
|
2020-01-20 08:57:54 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2020-03-31 05:23:48 +00:00
|
|
|
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(),
|
2020-04-04 19:40:32 +00:00
|
|
|
None => {
|
|
|
|
if let Some(swap_chain_output) = swap_chain_outputs.get(name) {
|
|
|
|
&swap_chain_output.view
|
|
|
|
} else {
|
|
|
|
panic!("Color attachment {} does not exist", name);
|
|
|
|
}
|
2020-03-31 05:23:48 +00:00
|
|
|
}
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-20 08:57:54 +00:00
|
|
|
fn create_wgpu_color_attachment_descriptor<'a>(
|
2020-03-03 06:36:11 +00:00
|
|
|
wgpu_resources: &'a WgpuResources,
|
2020-03-27 06:40:25 +00:00
|
|
|
global_render_resource_assignments: &RenderResourceAssignments,
|
2020-01-20 08:57:54 +00:00
|
|
|
color_attachment_descriptor: &RenderPassColorAttachmentDescriptor,
|
2020-03-31 05:23:48 +00:00
|
|
|
primary_swap_chain: &Option<String>,
|
|
|
|
swap_chain_outputs: &'a HashMap<String, wgpu::SwapChainOutput>,
|
2020-01-20 08:57:54 +00:00
|
|
|
) -> wgpu::RenderPassColorAttachmentDescriptor<'a> {
|
2020-03-31 05:23:48 +00:00
|
|
|
let attachment = Self::get_texture_view(
|
|
|
|
wgpu_resources,
|
|
|
|
global_render_resource_assignments,
|
|
|
|
primary_swap_chain,
|
|
|
|
swap_chain_outputs,
|
|
|
|
color_attachment_descriptor.attachment.as_str(),
|
|
|
|
);
|
2020-01-20 08:57:54 +00:00
|
|
|
|
2020-03-31 05:23:48 +00:00
|
|
|
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(),
|
|
|
|
)
|
|
|
|
});
|
2020-01-20 08:57:54 +00:00
|
|
|
|
|
|
|
wgpu::RenderPassColorAttachmentDescriptor {
|
2020-04-06 03:19:02 +00:00
|
|
|
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(),
|
2020-01-20 08:57:54 +00:00
|
|
|
attachment,
|
|
|
|
resolve_target,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn create_wgpu_depth_stencil_attachment_descriptor<'a>(
|
2020-03-03 01:53:39 +00:00
|
|
|
wgpu_resources: &'a WgpuResources,
|
2020-03-27 06:40:25 +00:00
|
|
|
global_render_resource_assignments: &RenderResourceAssignments,
|
2020-01-20 08:57:54 +00:00
|
|
|
depth_stencil_attachment_descriptor: &RenderPassDepthStencilAttachmentDescriptor,
|
2020-03-31 05:23:48 +00:00
|
|
|
primary_swap_chain: &Option<String>,
|
|
|
|
swap_chain_outputs: &'a HashMap<String, wgpu::SwapChainOutput>,
|
2020-03-05 08:44:53 +00:00
|
|
|
) -> wgpu::RenderPassDepthStencilAttachmentDescriptor<'a> {
|
2020-03-31 05:23:48 +00:00
|
|
|
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(),
|
|
|
|
);
|
2020-01-20 08:57:54 +00:00
|
|
|
|
|
|
|
wgpu::RenderPassDepthStencilAttachmentDescriptor {
|
|
|
|
attachment,
|
|
|
|
clear_depth: depth_stencil_attachment_descriptor.clear_depth,
|
|
|
|
clear_stencil: depth_stencil_attachment_descriptor.clear_stencil,
|
2020-04-06 23:15:59 +00:00
|
|
|
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(),
|
2020-01-20 08:57:54 +00:00
|
|
|
}
|
|
|
|
}
|
2020-01-26 00:33:26 +00:00
|
|
|
|
2020-04-10 08:39:38 +00:00
|
|
|
pub fn initialize_resource_providers(
|
|
|
|
world: &mut World,
|
|
|
|
resources: &mut Resources,
|
2020-04-12 01:40:30 +00:00
|
|
|
render_context: &mut WgpuRenderContext<WgpuRenderResourceContext>,
|
2020-04-10 08:39:38 +00:00
|
|
|
) {
|
2020-04-05 20:22:27 +00:00
|
|
|
let mut render_graph = resources.get_mut::<RenderGraph>().unwrap();
|
2020-02-18 00:33:46 +00:00
|
|
|
for resource_provider in render_graph.resource_providers.iter_mut() {
|
2020-04-10 08:39:38 +00:00
|
|
|
resource_provider.initialize(render_context, world, resources);
|
2020-02-18 00:33:46 +00:00
|
|
|
}
|
|
|
|
}
|
2020-01-27 09:13:38 +00:00
|
|
|
|
2020-04-12 07:05:47 +00:00
|
|
|
fn parallel_resource_provider_update(
|
|
|
|
world: &World,
|
|
|
|
resources: &Resources,
|
2020-04-10 20:10:46 +00:00
|
|
|
device: Arc<wgpu::Device>,
|
2020-04-12 07:05:47 +00:00
|
|
|
global_wgpu_resources: &WgpuResources,
|
2020-04-12 21:47:41 +00:00
|
|
|
) -> (Vec<wgpu::CommandBuffer>, Vec<WgpuResources>) {
|
2020-04-12 07:54:51 +00:00
|
|
|
let max_thread_count = 8;
|
2020-04-12 07:05:47 +00:00
|
|
|
let (sender, receiver) = crossbeam_channel::bounded(max_thread_count);
|
2020-03-22 02:57:59 +00:00
|
|
|
let mut render_graph = resources.get_mut::<RenderGraph>().unwrap();
|
2020-04-12 21:47:41 +00:00
|
|
|
let chunk_size =
|
|
|
|
(render_graph.resource_providers.len() + max_thread_count - 1) / max_thread_count; // divide ints rounding remainder up
|
|
|
|
// println!("chunk {} {}", chunk_size, render_graph.resource_providers.len());
|
2020-04-12 07:05:47 +00:00
|
|
|
let mut actual_thread_count = 0;
|
|
|
|
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());
|
|
|
|
s.spawn(move |_| {
|
|
|
|
let mut render_context = WgpuRenderContext::new(
|
|
|
|
device,
|
|
|
|
WgpuTransactionalRenderResourceContext::new(
|
|
|
|
resource_device,
|
|
|
|
global_wgpu_resources,
|
|
|
|
),
|
|
|
|
);
|
|
|
|
for resource_provider in resource_provider_chunk.iter_mut() {
|
|
|
|
resource_provider.update(&mut render_context, world, resources);
|
|
|
|
}
|
|
|
|
sender.send(render_context.finish()).unwrap();
|
|
|
|
});
|
2020-04-10 20:10:46 +00:00
|
|
|
}
|
2020-04-12 21:47:41 +00:00
|
|
|
})
|
|
|
|
.unwrap();
|
2020-04-12 07:05:47 +00:00
|
|
|
|
2020-04-10 20:10:46 +00:00
|
|
|
let mut command_buffers = Vec::new();
|
2020-04-12 01:40:30 +00:00
|
|
|
let mut local_resources = Vec::new();
|
2020-04-12 21:47:41 +00:00
|
|
|
for _i in 0..actual_thread_count {
|
2020-04-12 07:05:47 +00:00
|
|
|
let (command_buffer, render_resources) = receiver.recv().unwrap();
|
2020-04-10 20:10:46 +00:00
|
|
|
if let Some(command_buffer) = command_buffer {
|
|
|
|
command_buffers.push(command_buffer);
|
|
|
|
}
|
|
|
|
|
2020-04-12 01:40:30 +00:00
|
|
|
local_resources.push(render_resources.local_resources);
|
2020-04-10 20:10:46 +00:00
|
|
|
|
|
|
|
// println!("got {}", i);
|
2020-03-22 02:57:59 +00:00
|
|
|
}
|
2020-01-20 08:57:54 +00:00
|
|
|
|
2020-04-12 07:05:47 +00:00
|
|
|
(command_buffers, local_resources)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn update_resource_providers(
|
|
|
|
world: &mut World,
|
|
|
|
resources: &mut Resources,
|
|
|
|
queue: &mut wgpu::Queue,
|
|
|
|
device: Arc<wgpu::Device>,
|
|
|
|
global_wgpu_resources: &mut WgpuResources,
|
|
|
|
) {
|
2020-04-12 21:47:41 +00:00
|
|
|
let (mut command_buffers, local_resources) = Self::parallel_resource_provider_update(
|
|
|
|
world,
|
|
|
|
resources,
|
|
|
|
device.clone(),
|
|
|
|
global_wgpu_resources,
|
|
|
|
);
|
2020-04-12 01:40:30 +00:00
|
|
|
for local_resource in local_resources {
|
|
|
|
global_wgpu_resources.consume(local_resource);
|
|
|
|
}
|
|
|
|
|
2020-04-12 07:05:47 +00:00
|
|
|
let mut render_graph = resources.get_mut::<RenderGraph>().unwrap();
|
2020-04-10 20:10:46 +00:00
|
|
|
let mut results = Vec::new();
|
2020-04-12 07:05:47 +00:00
|
|
|
let thread_count = 5;
|
|
|
|
let chunk_size = (render_graph.resource_providers.len() + thread_count - 1) / thread_count; // divide ints rounding remainder up
|
2020-04-12 21:47:41 +00:00
|
|
|
// crossbeam_utils::thread::scope(|s| {
|
2020-04-12 01:40:30 +00:00
|
|
|
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 resource_device = device.clone();
|
|
|
|
// let sender = sender.clone();
|
|
|
|
// s.spawn(|_| {
|
|
|
|
// TODO: replace WgpuResources with Global+Local resources
|
2020-04-12 07:05:47 +00:00
|
|
|
let mut render_context = WgpuRenderContext::new(
|
|
|
|
device,
|
|
|
|
WgpuTransactionalRenderResourceContext::new(resource_device, global_wgpu_resources),
|
|
|
|
);
|
2020-04-12 01:40:30 +00:00
|
|
|
for resource_provider in resource_provider_chunk.iter_mut() {
|
|
|
|
resource_provider.finish_update(&mut render_context, world, resources);
|
2020-04-10 20:10:46 +00:00
|
|
|
}
|
2020-04-12 01:40:30 +00:00
|
|
|
results.push(render_context.finish());
|
|
|
|
// sender.send(render_context.finish()).unwrap();
|
|
|
|
// });
|
|
|
|
}
|
2020-04-10 20:10:46 +00:00
|
|
|
// });
|
|
|
|
|
2020-04-12 01:40:30 +00:00
|
|
|
let mut local_resources = Vec::new();
|
|
|
|
for (command_buffer, render_resources) in results {
|
|
|
|
// for i in 0..thread_count {
|
2020-04-10 20:10:46 +00:00
|
|
|
// let (command_buffer, wgpu_resources) = receiver.recv().unwrap();
|
|
|
|
if let Some(command_buffer) = command_buffer {
|
|
|
|
command_buffers.push(command_buffer);
|
|
|
|
}
|
|
|
|
|
2020-04-12 01:40:30 +00:00
|
|
|
local_resources.push(render_resources.local_resources);
|
2020-04-10 20:10:46 +00:00
|
|
|
// println!("got {}", i);
|
2020-03-22 02:57:59 +00:00
|
|
|
}
|
2020-04-12 01:40:30 +00:00
|
|
|
for local_resource in local_resources {
|
|
|
|
global_wgpu_resources.consume(local_resource);
|
|
|
|
}
|
2020-04-10 20:10:46 +00:00
|
|
|
|
|
|
|
queue.submit(&command_buffers);
|
2020-03-22 02:57:59 +00:00
|
|
|
}
|
2020-02-18 00:33:46 +00:00
|
|
|
|
2020-03-22 02:57:59 +00:00
|
|
|
pub fn create_queued_textures(&mut self, resources: &mut Resources) {
|
|
|
|
let mut render_graph = resources.get_mut::<RenderGraph>().unwrap();
|
2020-03-27 06:40:25 +00:00
|
|
|
let mut render_resource_assignments =
|
|
|
|
resources.get_mut::<RenderResourceAssignments>().unwrap();
|
2020-03-22 02:57:59 +00:00
|
|
|
for (name, texture_descriptor) in render_graph.queued_textures.drain(..) {
|
2020-04-12 21:47:41 +00:00
|
|
|
let resource = self
|
|
|
|
.global_context
|
|
|
|
.resources_mut()
|
|
|
|
.create_texture(&texture_descriptor);
|
2020-03-27 06:40:25 +00:00
|
|
|
render_resource_assignments.set(&name, resource);
|
2020-03-22 02:57:59 +00:00
|
|
|
}
|
|
|
|
}
|
2020-02-05 06:07:02 +00:00
|
|
|
|
2020-04-10 08:39:38 +00:00
|
|
|
pub fn handle_window_resized_events(
|
|
|
|
resources: &mut Resources,
|
|
|
|
device: &wgpu::Device,
|
|
|
|
wgpu_resources: &mut WgpuResources,
|
|
|
|
window_resized_event_reader: &mut EventReader<WindowResized>,
|
|
|
|
) {
|
2020-03-31 02:21:12 +00:00
|
|
|
let windows = resources.get::<Windows>().unwrap();
|
2020-04-01 01:04:54 +00:00
|
|
|
let window_resized_events = resources.get::<Events<WindowResized>>().unwrap();
|
2020-03-31 02:21:12 +00:00
|
|
|
let mut handled_windows = HashSet::new();
|
|
|
|
// 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
|
2020-04-10 08:39:38 +00:00
|
|
|
.iter(window_resized_event_reader)
|
2020-03-31 02:21:12 +00:00
|
|
|
.rev()
|
2020-03-30 18:52:33 +00:00
|
|
|
{
|
2020-03-31 02:21:12 +00:00
|
|
|
if handled_windows.contains(&window_resized_event.id) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
let window = windows
|
|
|
|
.get(window_resized_event.id)
|
|
|
|
.expect("Received window resized event for non-existent window");
|
|
|
|
|
2020-04-10 08:39:38 +00:00
|
|
|
// TODO: consider making this a WgpuRenderContext method
|
2020-04-10 20:10:46 +00:00
|
|
|
wgpu_resources.create_window_swap_chain(device, window);
|
2020-03-31 02:21:12 +00:00
|
|
|
|
|
|
|
handled_windows.insert(window_resized_event.id);
|
2020-03-30 18:52:33 +00:00
|
|
|
}
|
2020-01-20 08:57:54 +00:00
|
|
|
}
|
|
|
|
|
2020-04-10 08:39:38 +00:00
|
|
|
pub fn handle_window_created_events(
|
|
|
|
resources: &mut Resources,
|
|
|
|
device: &wgpu::Device,
|
|
|
|
wgpu_resources: &mut WgpuResources,
|
|
|
|
window_created_event_reader: &mut EventReader<WindowCreated>,
|
|
|
|
) {
|
2020-03-31 02:21:12 +00:00
|
|
|
let windows = resources.get::<Windows>().unwrap();
|
2020-04-01 01:04:54 +00:00
|
|
|
let window_created_events = resources.get::<Events<WindowCreated>>().unwrap();
|
2020-04-10 08:39:38 +00:00
|
|
|
for window_created_event in window_created_events.iter(window_created_event_reader) {
|
2020-03-31 02:21:12 +00:00
|
|
|
let window = windows
|
|
|
|
.get(window_created_event.id)
|
|
|
|
.expect("Received window created event for non-existent window");
|
2020-04-06 03:19:02 +00:00
|
|
|
#[cfg(feature = "bevy_winit")]
|
2020-03-31 02:21:12 +00:00
|
|
|
{
|
2020-04-06 03:19:02 +00:00
|
|
|
let winit_windows = resources.get::<bevy_winit::WinitWindows>().unwrap();
|
2020-03-31 02:21:12 +00:00
|
|
|
let primary_winit_window = winit_windows.get_window(window.id).unwrap();
|
|
|
|
let surface = wgpu::Surface::create(primary_winit_window.deref());
|
2020-04-10 08:39:38 +00:00
|
|
|
wgpu_resources.set_window_surface(window.id, surface);
|
|
|
|
wgpu_resources.create_window_swap_chain(device, window);
|
2020-03-28 20:56:29 +00:00
|
|
|
}
|
2020-01-27 05:44:01 +00:00
|
|
|
}
|
2020-01-20 08:57:54 +00:00
|
|
|
}
|
|
|
|
|
2020-03-31 05:23:48 +00:00
|
|
|
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
|
2020-04-12 01:40:30 +00:00
|
|
|
.global_context
|
|
|
|
.render_resources
|
2020-03-31 05:23:48 +00:00
|
|
|
.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)
|
|
|
|
}
|
2020-03-31 02:21:12 +00:00
|
|
|
|
2020-04-12 21:47:41 +00:00
|
|
|
pub fn update(&mut self, world: &mut World, resources: &mut Resources) {
|
2020-04-10 08:39:38 +00:00
|
|
|
Self::handle_window_created_events(
|
|
|
|
resources,
|
2020-04-12 01:40:30 +00:00
|
|
|
&self.global_context.device,
|
|
|
|
&mut self.global_context.render_resources.wgpu_resources,
|
2020-04-10 08:39:38 +00:00
|
|
|
&mut self.window_created_event_reader,
|
|
|
|
);
|
|
|
|
Self::handle_window_resized_events(
|
|
|
|
resources,
|
2020-04-12 01:40:30 +00:00
|
|
|
&self.global_context.device,
|
|
|
|
&mut self.global_context.render_resources.wgpu_resources,
|
2020-04-10 08:39:38 +00:00
|
|
|
&mut self.window_resized_event_reader,
|
|
|
|
);
|
|
|
|
if !self.intialized {
|
2020-04-12 01:40:30 +00:00
|
|
|
Self::initialize_resource_providers(world, resources, &mut self.global_context);
|
|
|
|
let buffer = self.global_context.finish_encoder();
|
2020-04-10 20:10:46 +00:00
|
|
|
if let Some(buffer) = buffer {
|
|
|
|
self.queue.submit(&[buffer]);
|
|
|
|
}
|
2020-04-10 08:39:38 +00:00
|
|
|
self.intialized = true;
|
|
|
|
}
|
|
|
|
|
2020-04-10 20:10:46 +00:00
|
|
|
Self::update_resource_providers(
|
|
|
|
world,
|
|
|
|
resources,
|
|
|
|
&mut self.queue,
|
2020-04-12 01:40:30 +00:00
|
|
|
self.global_context.device.clone(),
|
|
|
|
&mut self.global_context.render_resources.wgpu_resources,
|
2020-04-10 20:10:46 +00:00
|
|
|
);
|
2020-04-10 08:39:38 +00:00
|
|
|
|
|
|
|
self.encoder = Some(
|
2020-04-12 01:40:30 +00:00
|
|
|
self.global_context
|
|
|
|
.device
|
2020-04-10 08:39:38 +00:00
|
|
|
.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None }),
|
|
|
|
);
|
2020-04-12 21:47:41 +00:00
|
|
|
update_shader_assignments(world, resources, &self.global_context);
|
2020-03-22 02:57:59 +00:00
|
|
|
self.create_queued_textures(resources);
|
2020-02-04 08:06:17 +00:00
|
|
|
let mut encoder = self.encoder.take().unwrap();
|
|
|
|
|
2020-04-12 18:45:44 +00:00
|
|
|
render_resource_sets_system().run(world, resources);
|
2020-03-09 03:06:59 +00:00
|
|
|
// setup draw targets
|
2020-04-05 20:22:27 +00:00
|
|
|
let mut render_graph = resources.get_mut::<RenderGraph>().unwrap();
|
2020-04-12 21:47:41 +00:00
|
|
|
render_graph.setup_pipeline_draw_targets(world, resources, &mut self.global_context);
|
2020-03-09 03:06:59 +00:00
|
|
|
|
2020-03-31 05:23:48 +00:00
|
|
|
let (primary_swap_chain, swap_chain_outputs) = self.get_swap_chain_outputs(resources);
|
|
|
|
|
2020-03-09 03:06:59 +00:00
|
|
|
// begin render passes
|
2020-04-05 20:22:27 +00:00
|
|
|
let pipeline_storage = resources.get::<AssetStorage<PipelineDescriptor>>().unwrap();
|
|
|
|
let pipeline_compiler = resources.get::<PipelineCompiler>().unwrap();
|
|
|
|
|
2020-01-20 08:57:54 +00:00
|
|
|
for (pass_name, pass_descriptor) in render_graph.pass_descriptors.iter() {
|
2020-04-05 20:22:27 +00:00
|
|
|
let mut render_pass = {
|
|
|
|
let global_render_resource_assignments =
|
|
|
|
resources.get::<RenderResourceAssignments>().unwrap();
|
|
|
|
Self::create_render_pass(
|
2020-04-12 01:40:30 +00:00
|
|
|
&self.global_context.render_resources.wgpu_resources,
|
2020-04-05 20:22:27 +00:00
|
|
|
pass_descriptor,
|
|
|
|
&global_render_resource_assignments,
|
|
|
|
&mut encoder,
|
|
|
|
&primary_swap_chain,
|
|
|
|
&swap_chain_outputs,
|
|
|
|
)
|
|
|
|
};
|
2020-01-20 08:57:54 +00:00
|
|
|
if let Some(pass_pipelines) = render_graph.pass_pipelines.get(pass_name) {
|
|
|
|
for pass_pipeline in pass_pipelines.iter() {
|
2020-03-27 06:40:25 +00:00
|
|
|
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();
|
2020-04-12 21:47:41 +00:00
|
|
|
let render_pipeline = self
|
|
|
|
.global_context
|
|
|
|
.render_resources
|
|
|
|
.get_pipeline(*compiled_pipeline_handle)
|
|
|
|
.unwrap();
|
2020-03-27 06:40:25 +00:00
|
|
|
render_pass.set_pipeline(render_pipeline);
|
|
|
|
|
|
|
|
let mut wgpu_render_pass = WgpuRenderPass {
|
|
|
|
render_pass: &mut render_pass,
|
|
|
|
pipeline_descriptor,
|
2020-04-12 21:47:41 +00:00
|
|
|
render_context: &self.global_context,
|
2020-03-29 03:33:11 +00:00
|
|
|
bound_bind_groups: HashMap::default(),
|
2020-03-27 06:40:25 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
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,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
2020-01-20 08:57:54 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
let command_buffer = encoder.finish();
|
|
|
|
self.queue.submit(&[command_buffer]);
|
|
|
|
}
|
2020-03-11 04:57:57 +00:00
|
|
|
}
|