use swap chain node

This commit is contained in:
Carter Anderson 2020-04-21 11:43:35 -07:00
parent 5fec31b63c
commit b6711d8eae
7 changed files with 97 additions and 105 deletions

View file

@ -40,21 +40,22 @@ use self::{
render_graph::RenderGraph,
render_resource::{
entity_render_resource_assignments_system,
resource_providers::{
LightResourceProvider,
UniformResourceProvider,
},
resource_providers::{LightResourceProvider, UniformResourceProvider},
AssetBatchers, EntityRenderResourceAssignments, RenderResourceAssignments,
},
shader::{uniforms::StandardMaterial, Shader},
texture::Texture,
};
use bevy_app::{stage, AppBuilder, AppPlugin};
use bevy_app::{stage, AppBuilder, AppPlugin, GetEventReader};
use bevy_asset::AssetStorage;
use bevy_transform::prelude::LocalToWorld;
use render_resource::resource_providers::{mesh_resource_provider_system};
use render_graph_2::{nodes::{Camera2dNode, CameraNode}, RenderGraph2};
use bevy_window::{WindowCreated, WindowResized};
use render_graph_2::{
nodes::{Camera2dNode, CameraNode, SwapChainWindowSource, WindowSwapChainNode},
RenderGraph2,
};
use render_resource::resource_providers::mesh_resource_provider_system;
pub static RENDER_RESOURCE_STAGE: &str = "render_resource";
pub static RENDER_STAGE: &str = "render";
@ -88,8 +89,14 @@ impl RenderPlugin {
impl AppPlugin for RenderPlugin {
fn build(&self, app: &mut AppBuilder) {
let mut render_graph = RenderGraph2::default();
render_graph.add_system_node(CameraNode::default(), app.resources_mut());
render_graph.add_system_node(Camera2dNode::default(), app.resources_mut());
let resources = app.resources_mut();
render_graph.add_system_node(CameraNode::default(), resources);
render_graph.add_system_node(Camera2dNode::default(), resources);
render_graph.add_node(WindowSwapChainNode::new(
SwapChainWindowSource::Primary,
resources.get_event_reader::<WindowCreated>(),
resources.get_event_reader::<WindowResized>(),
));
let mut asset_batchers = AssetBatchers::default();
asset_batchers.batch_types2::<Mesh, StandardMaterial>();
app.add_stage_after(stage::POST_UPDATE, RENDER_RESOURCE_STAGE)
@ -111,10 +118,7 @@ impl AppPlugin for RenderPlugin {
// core systems
.add_system(entity_render_resource_assignments_system())
.add_system_to_stage_init(stage::POST_UPDATE, camera::camera_update_system)
.add_system_to_stage(
stage::POST_UPDATE,
mesh::mesh_specializer_system(),
)
.add_system_to_stage(stage::POST_UPDATE, mesh::mesh_specializer_system())
.add_system_to_stage(stage::POST_UPDATE, mesh::mesh_batcher_system())
.add_system_to_stage(
stage::POST_UPDATE,

View file

@ -1,19 +1,41 @@
use crate::{
render_graph_2::{Node, ResourceBindings, ResourceSlot},
render_resource::{RenderResource, ResourceInfo},
render_resource::ResourceInfo,
renderer_2::RenderContext,
texture::TextureDescriptor,
};
use bevy_app::{EventReader, Events};
use bevy_window::{WindowCreated, WindowId, WindowResized, Windows};
use legion::prelude::*;
pub enum SwapChainWindowSource {
Primary,
Id(WindowId),
}
impl Default for SwapChainWindowSource {
fn default() -> Self {
SwapChainWindowSource::Primary
}
}
pub struct WindowSwapChainNode {
window_id: WindowId,
use_primary_window: bool,
window_resized_event_reader: EventReader<WindowResized>,
source_window: SwapChainWindowSource,
window_created_event_reader: EventReader<WindowCreated>,
swap_chain_resource: Option<RenderResource>,
window_resized_event_reader: EventReader<WindowResized>,
}
impl WindowSwapChainNode {
pub fn new(
source_window: SwapChainWindowSource,
window_created_event_reader: EventReader<WindowCreated>,
window_resized_event_reader: EventReader<WindowResized>,
) -> Self {
WindowSwapChainNode {
source_window,
window_created_event_reader,
window_resized_event_reader,
}
}
}
impl Node for WindowSwapChainNode {
@ -39,32 +61,30 @@ impl Node for WindowSwapChainNode {
let windows = resources.get::<Windows>().unwrap();
let render_resources = render_context.resources_mut();
let window = if self.use_primary_window {
windows.get_primary().expect("No primary window exists")
} else {
windows
.get(self.window_id)
.expect("Received window resized event for non-existent window")
let window = match self.source_window {
SwapChainWindowSource::Primary => {
windows.get_primary().expect("No primary window exists")
}
SwapChainWindowSource::Id(id) => windows
.get(id)
.expect("Received window resized event for non-existent window"),
};
// create window swapchain
if let Some(_) = window_created_events
.find_latest(&mut self.window_created_event_reader, |e| {
e.id == window.id
})
.find_latest(&mut self.window_created_event_reader, |e| e.id == window.id)
{
render_resources.create_swap_chain(window);
}
// resize window swapchain
if let Some(_) = window_resized_events
.find_latest(&mut self.window_resized_event_reader, |e| {
e.id == window.id
})
.find_latest(&mut self.window_resized_event_reader, |e| e.id == window.id)
{
render_resources.create_swap_chain(window);
}
output.set(WINDOW_TEXTURE, self.swap_chain_resource.unwrap());
let swap_chain_texture = render_resources.next_swap_chain_texture(window.id);
output.set(WINDOW_TEXTURE, swap_chain_texture);
}
}

View file

@ -24,8 +24,9 @@ impl GlobalRenderResourceContext {
pub trait RenderResourceContext: Downcast + Send + Sync + 'static {
fn create_swap_chain(&self, window: &Window);
fn next_swap_chain_texture(&self, window_id: WindowId);
fn drop_swap_chain_texture(&self, window_id: WindowId);
fn next_swap_chain_texture(&self, window_id: WindowId) -> RenderResource;
fn drop_swap_chain_texture(&self, render_resource: RenderResource);
fn drop_all_swap_chain_textures(&self);
fn create_sampler(&self, sampler_descriptor: &SamplerDescriptor) -> RenderResource;
fn create_texture(&self, texture_descriptor: &TextureDescriptor) -> RenderResource;
fn create_buffer(&self, buffer_info: BufferInfo) -> RenderResource;

View file

@ -426,7 +426,6 @@ impl RenderContext for WgpuRenderContext {
let mut encoder = self.command_encoder.take().unwrap();
{
let render_pass = create_render_pass(
self,
pass_descriptor,
render_resource_assignments,
&refs,
@ -447,7 +446,6 @@ impl RenderContext for WgpuRenderContext {
}
pub fn create_render_pass<'a, 'b>(
render_context: &'a WgpuRenderContext,
pass_descriptor: &PassDescriptor,
global_render_resource_assignments: &'b RenderResourceAssignments,
refs: &WgpuResourceRefs<'a>,
@ -459,7 +457,6 @@ pub fn create_render_pass<'a, 'b>(
.iter()
.map(|c| {
create_wgpu_color_attachment_descriptor(
render_context,
global_render_resource_assignments,
refs,
c,
@ -468,7 +465,6 @@ pub fn create_render_pass<'a, 'b>(
.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,
refs,
d,
@ -478,7 +474,6 @@ pub fn create_render_pass<'a, 'b>(
}
fn get_texture_view<'a>(
render_context: &'a WgpuRenderContext,
global_render_resource_assignments: &RenderResourceAssignments,
refs: &WgpuResourceRefs<'a>,
name: &str,
@ -487,10 +482,10 @@ fn get_texture_view<'a>(
resource_name::texture::SWAP_CHAIN => {
if let Some(primary_swap_chain) = refs
.swap_chain_outputs
.get(render_context.primary_window.as_ref().unwrap())
.map(|output| &output.view)
.values()
.next()
{
primary_swap_chain
&primary_swap_chain.view
} else {
panic!("No primary swap chain found for color attachment");
}
@ -509,13 +504,11 @@ fn get_texture_view<'a>(
}
fn create_wgpu_color_attachment_descriptor<'a>(
render_context: &'a WgpuRenderContext,
global_render_resource_assignments: &RenderResourceAssignments,
refs: &WgpuResourceRefs<'a>,
color_attachment_descriptor: &RenderPassColorAttachmentDescriptor,
) -> wgpu::RenderPassColorAttachmentDescriptor<'a> {
let attachment = get_texture_view(
render_context,
global_render_resource_assignments,
refs,
color_attachment_descriptor.attachment.as_str(),
@ -526,7 +519,6 @@ fn create_wgpu_color_attachment_descriptor<'a>(
.as_ref()
.map(|target| {
get_texture_view(
render_context,
global_render_resource_assignments,
refs,
target.as_str(),
@ -543,13 +535,11 @@ fn create_wgpu_color_attachment_descriptor<'a>(
}
fn create_wgpu_depth_stencil_attachment_descriptor<'a>(
render_context: &'a WgpuRenderContext,
global_render_resource_assignments: &RenderResourceAssignments,
refs: &WgpuResourceRefs<'a>,
depth_stencil_attachment_descriptor: &RenderPassDepthStencilAttachmentDescriptor,
) -> wgpu::RenderPassDepthStencilAttachmentDescriptor<'a> {
let attachment = get_texture_view(
render_context,
global_render_resource_assignments,
refs,
depth_stencil_attachment_descriptor.attachment.as_str(),

View file

@ -7,7 +7,7 @@ use bevy_render::{
shader::Shader,
texture::{SamplerDescriptor, TextureDescriptor},
};
use bevy_window::{Window, WindowId};
use bevy_window::Window;
use std::sync::Arc;
#[derive(Clone)]
@ -99,11 +99,15 @@ impl RenderResourceContext for WgpuRenderResourceContext {
self.wgpu_resources
.create_window_swap_chain(&self.device, window)
}
fn next_swap_chain_texture(&self, window_id: bevy_window::WindowId) {
self.wgpu_resources.next_swap_chain_texture(window_id);
fn next_swap_chain_texture(&self, window_id: bevy_window::WindowId) -> RenderResource {
self.wgpu_resources.next_swap_chain_texture(window_id)
}
fn drop_swap_chain_texture(&self, window_id: WindowId) {
self.wgpu_resources.remove_swap_chain_texture(window_id);
fn drop_swap_chain_texture(&self, render_resource: RenderResource) {
self.wgpu_resources
.remove_swap_chain_texture(render_resource);
}
fn drop_all_swap_chain_textures(&self) {
self.wgpu_resources.remove_all_swap_chain_textures();
}
fn set_asset_resource_untyped(
&self,

View file

@ -12,7 +12,7 @@ use bevy_render::{
};
use bevy_window::{WindowCreated, WindowResized, Windows};
use legion::prelude::*;
use std::{collections::HashSet, ops::Deref, sync::Arc};
use std::{ops::Deref, sync::Arc};
pub struct WgpuRenderer {
pub device: Arc<wgpu::Device>,
pub queue: wgpu::Queue,
@ -171,35 +171,6 @@ impl WgpuRenderer {
}
}
pub fn handle_window_resized_events(
&mut self,
resources: &Resources,
global_render_resources: &dyn RenderResourceContext,
) {
let windows = resources.get::<Windows>().unwrap();
let window_resized_events = resources.get::<Events<WindowResized>>().unwrap();
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
.iter(&mut self.window_resized_event_reader)
.rev()
{
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");
// TODO: consider making this a WgpuRenderContext method
global_render_resources.create_swap_chain(window);
handled_windows.insert(window_resized_event.id);
}
}
pub fn handle_window_created_events(
&mut self,
resources: &Resources,
@ -216,12 +187,11 @@ impl WgpuRenderer {
#[cfg(feature = "bevy_winit")]
{
let winit_windows = resources.get::<bevy_winit::WinitWindows>().unwrap();
let primary_winit_window = winit_windows.get_window(window.id).unwrap();
let surface = wgpu::Surface::create(primary_winit_window.deref());
let winit_window = winit_windows.get_window(window.id).unwrap();
let surface = wgpu::Surface::create(winit_window.deref());
global_render_resource_context
.wgpu_resources
.set_window_surface(window.id, surface);
global_render_resource_context.create_swap_chain(window);
}
}
}
@ -251,7 +221,13 @@ impl WgpuRenderer {
for mut stage in linear_scheduler.get_stages(&mut render_graph) {
for job in stage.iter_mut() {
for node_state in job.iter_mut() {
node_state.node.update(world, resources, &mut render_context, &node_state.input, &mut node_state.output);
node_state.node.update(
world,
resources,
&mut render_context,
&node_state.input,
&mut node_state.output,
);
}
}
}
@ -263,7 +239,6 @@ impl WgpuRenderer {
}
pub fn update(&mut self, world: &mut World, resources: &mut Resources) {
self.run_graph(world, resources);
let mut encoder = {
let mut global_context = resources.get_mut::<GlobalRenderResourceContext>().unwrap();
let render_resource_context = global_context
@ -273,7 +248,6 @@ impl WgpuRenderer {
self.handle_window_created_events(resources, render_resource_context);
self.handle_window_resized_events(resources, render_resource_context);
let mut render_context =
WgpuRenderContext::new(self.device.clone(), render_resource_context.clone());
if !self.intialized {
@ -292,6 +266,7 @@ impl WgpuRenderer {
render_context.command_encoder.take()
};
self.run_graph(world, resources);
// TODO: add to POST_UPDATE and remove redundant global_context
render_resource_sets_system().run(world, resources);
let mut global_context = resources.get_mut::<GlobalRenderResourceContext>().unwrap();
@ -317,9 +292,6 @@ impl WgpuRenderer {
.get_primary()
.map(|window| window.id);
if let Some(primary_window_id) = primary_window_id {
render_context
.render_resources
.next_swap_chain_texture(primary_window_id);
render_context.primary_window = Some(primary_window_id);
}
@ -371,11 +343,9 @@ impl WgpuRenderer {
self.queue.submit(&[command_buffer]);
}
// clear primary swap chain texture
if let Some(primary_window_id) = primary_window_id {
render_context
.render_resources
.drop_swap_chain_texture(primary_window_id);
}
// clear swap chain textures
render_context
.render_resources
.drop_all_swap_chain_textures();
}
}

View file

@ -43,7 +43,7 @@ pub struct WgpuBindGroupInfo {
pub struct WgpuResourcesReadLock<'a> {
pub buffers: RwLockReadGuard<'a, HashMap<RenderResource, wgpu::Buffer>>,
pub textures: RwLockReadGuard<'a, HashMap<RenderResource, wgpu::TextureView>>,
pub swap_chain_outputs: RwLockReadGuard<'a, HashMap<WindowId, wgpu::SwapChainOutput>>,
pub swap_chain_outputs: RwLockReadGuard<'a, HashMap<RenderResource, wgpu::SwapChainOutput>>,
pub render_pipelines:
RwLockReadGuard<'a, HashMap<Handle<PipelineDescriptor>, wgpu::RenderPipeline>>,
pub bind_groups: RwLockReadGuard<'a, HashMap<BindGroupDescriptorId, WgpuBindGroupInfo>>,
@ -65,7 +65,7 @@ impl<'a> WgpuResourcesReadLock<'a> {
pub struct WgpuResourceRefs<'a> {
pub buffers: &'a HashMap<RenderResource, wgpu::Buffer>,
pub textures: &'a HashMap<RenderResource, wgpu::TextureView>,
pub swap_chain_outputs: &'a HashMap<WindowId, wgpu::SwapChainOutput>,
pub swap_chain_outputs: &'a HashMap<RenderResource, wgpu::SwapChainOutput>,
pub render_pipelines: &'a HashMap<Handle<PipelineDescriptor>, wgpu::RenderPipeline>,
pub bind_groups: &'a HashMap<BindGroupDescriptorId, WgpuBindGroupInfo>,
}
@ -75,7 +75,7 @@ pub struct WgpuResources {
// TODO: remove this from WgpuResources. it doesn't need to be here
pub window_surfaces: Arc<RwLock<HashMap<WindowId, wgpu::Surface>>>,
pub window_swap_chains: Arc<RwLock<HashMap<WindowId, wgpu::SwapChain>>>,
pub swap_chain_outputs: Arc<RwLock<HashMap<WindowId, wgpu::SwapChainOutput>>>,
pub swap_chain_outputs: Arc<RwLock<HashMap<RenderResource, wgpu::SwapChainOutput>>>,
pub buffers: Arc<RwLock<HashMap<RenderResource, wgpu::Buffer>>>,
pub textures: Arc<RwLock<HashMap<RenderResource, wgpu::TextureView>>>,
pub samplers: Arc<RwLock<HashMap<RenderResource, wgpu::Sampler>>>,
@ -105,18 +105,21 @@ impl WgpuResources {
.insert(window_id, surface);
}
pub fn next_swap_chain_texture(&self, window_id: WindowId) {
pub fn next_swap_chain_texture(&self, window_id: WindowId) -> RenderResource {
let mut swap_chain_outputs = self.window_swap_chains.write().unwrap();
let swap_chain_output = swap_chain_outputs.get_mut(&window_id).unwrap();
let next_texture = swap_chain_output.get_next_texture().unwrap();
let render_resource = RenderResource::new();
// TODO: Add ResourceInfo
self.swap_chain_outputs
.write()
.unwrap()
.insert(window_id, next_texture);
.insert(render_resource, next_texture);
render_resource
}
pub fn remove_swap_chain_texture(&self, window_id: WindowId) {
self.swap_chain_outputs.write().unwrap().remove(&window_id);
pub fn remove_swap_chain_texture(&self, render_resource: RenderResource) {
self.swap_chain_outputs.write().unwrap().remove(&render_resource);
}
pub fn remove_all_swap_chain_textures(&self) {