RenderGraph2: Finish graph executor, fix window textures

This commit is contained in:
Carter Anderson 2020-04-23 20:53:38 -07:00
parent 8326a1a3c2
commit 5780bf4025
11 changed files with 226 additions and 120 deletions

View File

@ -50,14 +50,15 @@ use self::{
use bevy_app::{stage, AppBuilder, AppPlugin, GetEventReader}; use bevy_app::{stage, AppBuilder, AppPlugin, GetEventReader};
use bevy_asset::AssetStorage; use bevy_asset::AssetStorage;
use bevy_transform::prelude::LocalToWorld; use bevy_transform::prelude::LocalToWorld;
use bevy_window::{WindowCreated, WindowResized}; use bevy_window::{WindowCreated, WindowReference, WindowResized};
use pass::PassDescriptor; use pass::PassDescriptor;
use pipeline::pipelines::build_forward_pipeline; use pipeline::pipelines::build_forward_pipeline;
use render_graph_2::{ use render_graph_2::{
nodes::{Camera2dNode, CameraNode, PassNode, SwapChainWindowSource, WindowSwapChainNode}, nodes::{Camera2dNode, CameraNode, PassNode, WindowSwapChainNode, WindowTextureNode},
RenderGraph2, RenderGraph2,
}; };
use render_resource::resource_providers::mesh_resource_provider_system; use render_resource::resource_providers::mesh_resource_provider_system;
use texture::{Extent3d, TextureDescriptor, TextureDimension, TextureFormat, TextureUsage};
pub static RENDER_RESOURCE_STAGE: &str = "render_resource"; pub static RENDER_RESOURCE_STAGE: &str = "render_resource";
pub static RENDER_STAGE: &str = "render"; pub static RENDER_STAGE: &str = "render";
@ -126,7 +127,28 @@ impl AppPlugin for RenderPlugin {
render_graph.add_node_named( render_graph.add_node_named(
"swapchain", "swapchain",
WindowSwapChainNode::new( WindowSwapChainNode::new(
SwapChainWindowSource::Primary, WindowReference::Primary,
resources.get_event_reader::<WindowCreated>(),
resources.get_event_reader::<WindowResized>(),
),
);
render_graph.add_node_named(
"main_pass_depth_texture",
WindowTextureNode::new(
WindowReference::Primary,
TextureDescriptor {
size: Extent3d {
depth: 1,
width: 1,
height: 1,
},
array_layer_count: 1,
mip_level_count: 1,
sample_count: 1,
dimension: TextureDimension::D2,
format: TextureFormat::Depth32Float, // PERF: vulkan recommends using 24 bit depth for better performance
usage: TextureUsage::OUTPUT_ATTACHMENT,
},
resources.get_event_reader::<WindowCreated>(), resources.get_event_reader::<WindowCreated>(),
resources.get_event_reader::<WindowResized>(), resources.get_event_reader::<WindowResized>(),
), ),
@ -164,7 +186,20 @@ impl AppPlugin for RenderPlugin {
render_graph.add_node_edge("camera", "main_pass").unwrap(); render_graph.add_node_edge("camera", "main_pass").unwrap();
render_graph.add_node_edge("camera2d", "main_pass").unwrap(); render_graph.add_node_edge("camera2d", "main_pass").unwrap();
render_graph render_graph
.add_slot_edge("swapchain", WindowSwapChainNode::OUT_TEXTURE, "main_pass", "color") .add_slot_edge(
"swapchain",
WindowSwapChainNode::OUT_TEXTURE,
"main_pass",
"color",
)
.unwrap();
render_graph
.add_slot_edge(
"main_pass_depth_texture",
WindowTextureNode::OUT_TEXTURE,
"main_pass",
"depth",
)
.unwrap(); .unwrap();
} }
app.add_resource(render_graph); app.add_resource(render_graph);

View File

@ -131,10 +131,10 @@ impl RenderGraph2 {
{ {
let output_node = self.get_node_state_mut(output_node_id)?; let output_node = self.get_node_state_mut(output_node_id)?;
output_node.add_output_edge(edge.clone())?; output_node.edges.add_output_edge(edge.clone())?;
} }
let input_node = self.get_node_state_mut(input_node_id)?; let input_node = self.get_node_state_mut(input_node_id)?;
input_node.add_input_edge(edge)?; input_node.edges.add_input_edge(edge)?;
Ok(()) Ok(())
} }
@ -156,10 +156,10 @@ impl RenderGraph2 {
{ {
let output_node = self.get_node_state_mut(output_node_id)?; let output_node = self.get_node_state_mut(output_node_id)?;
output_node.add_output_edge(edge.clone())?; output_node.edges.add_output_edge(edge.clone())?;
} }
let input_node = self.get_node_state_mut(input_node_id)?; let input_node = self.get_node_state_mut(input_node_id)?;
input_node.add_input_edge(edge)?; input_node.edges.add_input_edge(edge)?;
Ok(()) Ok(())
} }
@ -185,7 +185,7 @@ impl RenderGraph2 {
if let Some(Edge::SlotEdge { if let Some(Edge::SlotEdge {
output_node: current_output_node, output_node: current_output_node,
.. ..
}) = input_node_state.input_edges.iter().find(|e| { }) = input_node_state.edges.input_edges.iter().find(|e| {
if let Edge::SlotEdge { if let Edge::SlotEdge {
input_index: current_input_index, input_index: current_input_index,
.. ..
@ -222,9 +222,9 @@ impl RenderGraph2 {
let output_node_state = self.get_node_state(edge.get_output_node()); let output_node_state = self.get_node_state(edge.get_output_node());
let input_node_state = self.get_node_state(edge.get_input_node()); let input_node_state = self.get_node_state(edge.get_input_node());
if let Ok(output_node_state) = output_node_state { if let Ok(output_node_state) = output_node_state {
if output_node_state.output_edges.contains(edge) { if output_node_state.edges.output_edges.contains(edge) {
if let Ok(input_node_state) = input_node_state { if let Ok(input_node_state) = input_node_state {
if input_node_state.input_edges.contains(edge) { if input_node_state.edges.input_edges.contains(edge) {
return true; return true;
} }
} }
@ -270,6 +270,7 @@ impl RenderGraph2 {
) -> Result<impl Iterator<Item = (&Edge, &NodeState)>, RenderGraphError> { ) -> Result<impl Iterator<Item = (&Edge, &NodeState)>, RenderGraphError> {
let node = self.get_node_state(label)?; let node = self.get_node_state(label)?;
Ok(node Ok(node
.edges
.input_edges .input_edges
.iter() .iter()
.map(|edge| (edge, edge.get_output_node())) .map(|edge| (edge, edge.get_output_node()))
@ -284,6 +285,7 @@ impl RenderGraph2 {
) -> Result<impl Iterator<Item = (&Edge, &NodeState)>, RenderGraphError> { ) -> Result<impl Iterator<Item = (&Edge, &NodeState)>, RenderGraphError> {
let node = self.get_node_state(label)?; let node = self.get_node_state(label)?;
Ok(node Ok(node
.edges
.output_edges .output_edges
.iter() .iter()
.map(|edge| (edge, edge.get_input_node())) .map(|edge| (edge, edge.get_input_node()))

View File

@ -39,56 +39,13 @@ pub trait SystemNode: Node {
fn get_system(&self, resources: &mut Resources) -> Box<dyn Schedulable>; fn get_system(&self, resources: &mut Resources) -> Box<dyn Schedulable>;
} }
pub struct NodeState { pub struct Edges {
pub id: NodeId, pub id: NodeId,
pub name: Option<Cow<'static, str>>,
pub node: Box<dyn Node>,
pub input_slots: ResourceSlots,
pub output_slots: ResourceSlots,
pub input_edges: Vec<Edge>, pub input_edges: Vec<Edge>,
pub output_edges: Vec<Edge>, pub output_edges: Vec<Edge>,
} }
impl Debug for NodeState { impl Edges {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
writeln!(f, "{:?} ({:?})", self.id, self.name)
}
}
impl NodeState {
pub fn new<T>(id: NodeId, node: T) -> Self
where
T: Node,
{
NodeState {
id,
name: None,
input_slots: ResourceSlots::from(node.input()),
output_slots: ResourceSlots::from(node.output()),
node: Box::new(node),
input_edges: Vec::new(),
output_edges: Vec::new(),
}
}
pub fn node<T>(&self) -> Result<&T, RenderGraphError>
where
T: Node,
{
self.node
.downcast_ref::<T>()
.ok_or_else(|| RenderGraphError::WrongNodeType)
}
pub fn node_mut<T>(&mut self) -> Result<&mut T, RenderGraphError>
where
T: Node,
{
self.node
.downcast_mut::<T>()
.ok_or_else(|| RenderGraphError::WrongNodeType)
}
pub(crate) fn add_input_edge(&mut self, edge: Edge) -> Result<(), RenderGraphError> { pub(crate) fn add_input_edge(&mut self, edge: Edge) -> Result<(), RenderGraphError> {
if self.has_input_edge(&edge) { if self.has_input_edge(&edge) {
return Err(RenderGraphError::EdgeAlreadyExists(edge.clone())); return Err(RenderGraphError::EdgeAlreadyExists(edge.clone()));
@ -144,10 +101,64 @@ impl NodeState {
node: self.id, node: self.id,
}) })
} }
}
pub struct NodeState {
pub id: NodeId,
pub name: Option<Cow<'static, str>>,
pub node: Box<dyn Node>,
pub input_slots: ResourceSlots,
pub output_slots: ResourceSlots,
pub edges: Edges,
}
impl Debug for NodeState {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
writeln!(f, "{:?} ({:?})", self.id, self.name)
}
}
impl NodeState {
pub fn new<T>(id: NodeId, node: T) -> Self
where
T: Node,
{
NodeState {
id,
name: None,
input_slots: ResourceSlots::from(node.input()),
output_slots: ResourceSlots::from(node.output()),
node: Box::new(node),
edges: Edges {
id,
input_edges: Vec::new(),
output_edges: Vec::new(),
},
}
}
pub fn node<T>(&self) -> Result<&T, RenderGraphError>
where
T: Node,
{
self.node
.downcast_ref::<T>()
.ok_or_else(|| RenderGraphError::WrongNodeType)
}
pub fn node_mut<T>(&mut self) -> Result<&mut T, RenderGraphError>
where
T: Node,
{
self.node
.downcast_mut::<T>()
.ok_or_else(|| RenderGraphError::WrongNodeType)
}
pub fn validate_output_slots(&self) -> Result<(), RenderGraphError> { pub fn validate_output_slots(&self) -> Result<(), RenderGraphError> {
for i in 0..self.output_slots.len() { for i in 0..self.output_slots.len() {
self.get_output_slot_edge(i)?; self.edges.get_output_slot_edge(i)?;
} }
Ok(()) Ok(())
@ -155,7 +166,7 @@ impl NodeState {
pub fn validate_input_slots(&self) -> Result<(), RenderGraphError> { pub fn validate_input_slots(&self) -> Result<(), RenderGraphError> {
for i in 0..self.input_slots.len() { for i in 0..self.input_slots.len() {
self.get_input_slot_edge(i)?; self.edges.get_input_slot_edge(i)?;
} }
Ok(()) Ok(())

View File

@ -2,13 +2,13 @@ use super::RenderGraphError;
use crate::render_resource::{RenderResource, ResourceInfo}; use crate::render_resource::{RenderResource, ResourceInfo};
use std::borrow::Cow; use std::borrow::Cow;
#[derive(Debug)] #[derive(Debug, Clone)]
pub struct ResourceSlot { pub struct ResourceSlot {
pub resource: Option<RenderResource>, pub resource: Option<RenderResource>,
pub info: ResourceSlotInfo, pub info: ResourceSlotInfo,
} }
#[derive(Default, Debug)] #[derive(Default, Debug, Clone)]
pub struct ResourceSlots { pub struct ResourceSlots {
slots: Vec<ResourceSlot>, slots: Vec<ResourceSlot>,
} }
@ -93,6 +93,10 @@ impl ResourceSlots {
self.slots.iter() self.slots.iter()
} }
pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut ResourceSlot> {
self.slots.iter_mut()
}
pub fn len(&self) -> usize { pub fn len(&self) -> usize {
self.slots.len() self.slots.len()
} }

View File

@ -23,7 +23,7 @@ impl PassNode {
for color_attachment in descriptor.color_attachments.iter() { for color_attachment in descriptor.color_attachments.iter() {
if let TextureAttachment::Input(ref name) = color_attachment.attachment { if let TextureAttachment::Input(ref name) = color_attachment.attachment {
inputs.push(ResourceSlotInfo::new(name.to_string(), ResourceInfo::Texture)); inputs.push(ResourceSlotInfo::new(name.to_string(), ResourceInfo::Texture));
color_attachment_input_indices.push(Some(inputs.len())); color_attachment_input_indices.push(Some(inputs.len() - 1));
} else { } else {
color_attachment_input_indices.push(None); color_attachment_input_indices.push(None);
} }
@ -33,7 +33,7 @@ impl PassNode {
if let Some(ref depth_stencil_attachment)= descriptor.depth_stencil_attachment { if let Some(ref depth_stencil_attachment)= descriptor.depth_stencil_attachment {
if let TextureAttachment::Input(ref name) = depth_stencil_attachment.attachment { if let TextureAttachment::Input(ref name) = depth_stencil_attachment.attachment {
inputs.push(ResourceSlotInfo::new(name.to_string(), ResourceInfo::Texture)); inputs.push(ResourceSlotInfo::new(name.to_string(), ResourceInfo::Texture));
depth_stencil_attachment_input_index = Some(inputs.len()); depth_stencil_attachment_input_index = Some(inputs.len() - 1);
} }
} }

View File

@ -4,23 +4,12 @@ use crate::{
renderer_2::RenderContext, renderer_2::RenderContext,
}; };
use bevy_app::{EventReader, Events}; use bevy_app::{EventReader, Events};
use bevy_window::{WindowCreated, WindowId, WindowResized, Windows}; use bevy_window::{WindowCreated, WindowResized, Windows, WindowReference};
use legion::prelude::*; use legion::prelude::*;
use std::borrow::Cow; use std::borrow::Cow;
pub enum SwapChainWindowSource {
Primary,
Id(WindowId),
}
impl Default for SwapChainWindowSource {
fn default() -> Self {
SwapChainWindowSource::Primary
}
}
pub struct WindowSwapChainNode { pub struct WindowSwapChainNode {
source_window: SwapChainWindowSource, window_reference: WindowReference,
window_created_event_reader: EventReader<WindowCreated>, window_created_event_reader: EventReader<WindowCreated>,
window_resized_event_reader: EventReader<WindowResized>, window_resized_event_reader: EventReader<WindowResized>,
} }
@ -28,12 +17,12 @@ pub struct WindowSwapChainNode {
impl WindowSwapChainNode { impl WindowSwapChainNode {
pub const OUT_TEXTURE: &'static str = "texture"; pub const OUT_TEXTURE: &'static str = "texture";
pub fn new( pub fn new(
source_window: SwapChainWindowSource, window_reference: WindowReference,
window_created_event_reader: EventReader<WindowCreated>, window_created_event_reader: EventReader<WindowCreated>,
window_resized_event_reader: EventReader<WindowResized>, window_resized_event_reader: EventReader<WindowResized>,
) -> Self { ) -> Self {
WindowSwapChainNode { WindowSwapChainNode {
source_window, window_reference,
window_created_event_reader, window_created_event_reader,
window_resized_event_reader, window_resized_event_reader,
} }
@ -62,26 +51,22 @@ impl Node for WindowSwapChainNode {
let window_resized_events = resources.get::<Events<WindowResized>>().unwrap(); let window_resized_events = resources.get::<Events<WindowResized>>().unwrap();
let windows = resources.get::<Windows>().unwrap(); let windows = resources.get::<Windows>().unwrap();
let render_resources = render_context.resources_mut(); let window = match self.window_reference {
let window = match self.source_window { WindowReference::Primary => {
SwapChainWindowSource::Primary => {
windows.get_primary().expect("No primary window exists") windows.get_primary().expect("No primary window exists")
} }
SwapChainWindowSource::Id(id) => windows WindowReference::Id(id) => windows
.get(id) .get(id)
.expect("Received window resized event for non-existent window"), .expect("Received window resized event for non-existent window"),
}; };
// create window swapchain let render_resources = render_context.resources_mut();
if let Some(_) = window_created_events
.find_latest(&mut self.window_created_event_reader, |e| e.id == window.id)
{
render_resources.create_swap_chain(window);
}
// resize window swapchain // create window swapchain when window is resized or created
if let Some(_) = window_resized_events if window_created_events
.find_latest(&mut self.window_resized_event_reader, |e| e.id == window.id) .find_latest(&mut self.window_created_event_reader, |e| e.id == window.id).is_some() ||
window_resized_events
.find_latest(&mut self.window_resized_event_reader, |e| e.id == window.id).is_some()
{ {
render_resources.create_swap_chain(window); render_resources.create_swap_chain(window);
} }

View File

@ -1,23 +1,42 @@
use crate::{ use crate::{
render_graph_2::{Node, ResourceSlots, ResourceSlotInfo}, render_graph_2::{Node, ResourceSlotInfo, ResourceSlots},
render_resource::ResourceInfo, render_resource::ResourceInfo,
renderer_2::RenderContext, renderer_2::RenderContext,
texture::TextureDescriptor, texture::TextureDescriptor,
}; };
use bevy_app::{EventReader, Events}; use bevy_app::{EventReader, Events};
use bevy_window::WindowResized; use bevy_window::{WindowCreated, WindowReference, WindowResized, Windows};
use legion::prelude::*; use legion::prelude::*;
use std::borrow::Cow; use std::borrow::Cow;
pub struct WindowTextureNode { pub struct WindowTextureNode {
pub descriptor: TextureDescriptor, window_reference: WindowReference,
descriptor: TextureDescriptor,
window_created_event_reader: EventReader<WindowCreated>,
window_resized_event_reader: EventReader<WindowResized>, window_resized_event_reader: EventReader<WindowResized>,
} }
impl WindowTextureNode {
pub const OUT_TEXTURE: &'static str = "texture";
pub fn new(
window_reference: WindowReference,
descriptor: TextureDescriptor,
window_created_event_reader: EventReader<WindowCreated>,
window_resized_event_reader: EventReader<WindowResized>,
) -> Self {
WindowTextureNode {
window_reference,
descriptor,
window_created_event_reader,
window_resized_event_reader,
}
}
}
impl Node for WindowTextureNode { impl Node for WindowTextureNode {
fn output(&self) -> &[ResourceSlotInfo] { fn output(&self) -> &[ResourceSlotInfo] {
static OUTPUT: &[ResourceSlotInfo] = &[ResourceSlotInfo { static OUTPUT: &[ResourceSlotInfo] = &[ResourceSlotInfo {
name: Cow::Borrowed("texture"), name: Cow::Borrowed(WindowTextureNode::OUT_TEXTURE),
resource_type: ResourceInfo::Texture, resource_type: ResourceInfo::Texture,
}]; }];
OUTPUT OUTPUT
@ -32,15 +51,29 @@ impl Node for WindowTextureNode {
output: &mut ResourceSlots, output: &mut ResourceSlots,
) { ) {
const WINDOW_TEXTURE: usize = 0; const WINDOW_TEXTURE: usize = 0;
let window_created_events = resources.get::<Events<WindowCreated>>().unwrap();
let window_resized_events = resources.get::<Events<WindowResized>>().unwrap(); let window_resized_events = resources.get::<Events<WindowResized>>().unwrap();
if let Some(event) = window_resized_events.latest(&mut self.window_resized_event_reader) { let windows = resources.get::<Windows>().unwrap();
let window = match self.window_reference {
WindowReference::Primary => windows.get_primary().expect("No primary window exists"),
WindowReference::Id(id) => windows
.get(id)
.expect("Received window resized event for non-existent window"),
};
if window_created_events
.find_latest(&mut self.window_created_event_reader, |e| e.id == window.id).is_some() ||
window_resized_events
.find_latest(&mut self.window_resized_event_reader, |e| e.id == window.id).is_some()
{
let render_resources = render_context.resources_mut(); let render_resources = render_context.resources_mut();
if let Some(old_texture) = output.get(WINDOW_TEXTURE) { if let Some(old_texture) = output.get(WINDOW_TEXTURE) {
render_resources.remove_texture(old_texture); render_resources.remove_texture(old_texture);
} }
self.descriptor.size.width = event.width; self.descriptor.size.width = window.width;
self.descriptor.size.height = event.height; self.descriptor.size.height = window.height;
let texture_resource = render_resources.create_texture(&self.descriptor); let texture_resource = render_resources.create_texture(&self.descriptor);
output.set(WINDOW_TEXTURE, texture_resource); output.set(WINDOW_TEXTURE, texture_resource);
} }

View File

@ -187,6 +187,7 @@ fn stage_node(
// don't re-visit nodes or visit them before all of their parents have been visited // don't re-visit nodes or visit them before all of their parents have been visited
if node_stages_and_jobs.contains_key(&node.id) if node_stages_and_jobs.contains_key(&node.id)
|| node || node
.edges
.input_edges .input_edges
.iter() .iter()
.find(|e| !node_stages_and_jobs.contains_key(&e.get_output_node())) .find(|e| !node_stages_and_jobs.contains_key(&e.get_output_node()))
@ -204,6 +205,7 @@ fn stage_node(
// check to see if the current node has a parent. if so, grab the parent with the highest stage // check to see if the current node has a parent. if so, grab the parent with the highest stage
if let Some((max_parent_stage, max_parent_job)) = node if let Some((max_parent_stage, max_parent_job)) = node
.edges
.input_edges .input_edges
.iter() .iter()
.map(|e| { .map(|e| {
@ -215,6 +217,7 @@ fn stage_node(
{ {
// count the number of parents that are in the highest stage // count the number of parents that are in the highest stage
let max_stage_parent_count = node let max_stage_parent_count = node
.edges
.input_edges .input_edges
.iter() .iter()
.filter(|e| { .filter(|e| {

View File

@ -11,7 +11,7 @@ use bevy_render::{
}, },
pipeline::{BindGroupDescriptor, BindType, PipelineDescriptor}, pipeline::{BindGroupDescriptor, BindType, PipelineDescriptor},
render_resource::{ render_resource::{
resource_name, RenderResource, RenderResourceAssignments, RenderResourceSetId, ResourceInfo, RenderResource, RenderResourceAssignments, RenderResourceSetId, ResourceInfo,
}, },
renderer_2::{RenderContext, RenderResourceContext}, renderer_2::{RenderContext, RenderResourceContext},
shader::Shader, shader::Shader,
@ -475,26 +475,13 @@ fn get_texture_view<'a>(
attachment: &TextureAttachment, attachment: &TextureAttachment,
) -> &'a wgpu::TextureView { ) -> &'a wgpu::TextureView {
match attachment { match attachment {
TextureAttachment::Name(name) => match name.as_str() { TextureAttachment::Name(name) => match global_render_resource_assignments.get(&name) {
resource_name::texture::SWAP_CHAIN => { Some(resource) => refs.textures.get(&resource).unwrap(),
if let Some(primary_swap_chain) = refs.swap_chain_outputs.values().next() { None => {
&primary_swap_chain.view panic!("Color attachment {} does not exist", name);
} else {
panic!("No primary swap chain found for color attachment");
}
} }
_ => match global_render_resource_assignments.get(&name) {
Some(resource) => refs.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);
// }
}
},
}, },
TextureAttachment::RenderResource(render_resource) => refs.textures.get(&render_resource).unwrap(), TextureAttachment::RenderResource(render_resource) => refs.textures.get(&render_resource).unwrap_or_else(|| &refs.swap_chain_outputs.get(&render_resource).unwrap().view),
TextureAttachment::Input(_) => panic!("Encountered unset TextureAttachment::Input. The RenderGraph executor should always set TextureAttachment::Inputs to TextureAttachment::RenderResource before running. This is a bug"), TextureAttachment::Input(_) => panic!("Encountered unset TextureAttachment::Input. The RenderGraph executor should always set TextureAttachment::Inputs to TextureAttachment::RenderResource before running. This is a bug"),
} }
} }

View File

@ -1,7 +1,10 @@
use super::{WgpuRenderContext, WgpuRenderResourceContext}; use super::{WgpuRenderContext, WgpuRenderResourceContext};
use bevy_render::{render_graph_2::StageBorrow, renderer_2::GlobalRenderResourceContext}; use bevy_render::{
render_graph_2::{Edge, NodeId, ResourceSlots, StageBorrow},
renderer_2::GlobalRenderResourceContext,
};
use legion::prelude::{Resources, World}; use legion::prelude::{Resources, World};
use std::sync::Arc; use std::{collections::HashMap, sync::Arc};
pub struct WgpuRenderGraphExecutor { pub struct WgpuRenderGraphExecutor {
pub max_thread_count: usize, pub max_thread_count: usize,
@ -21,6 +24,7 @@ impl WgpuRenderGraphExecutor {
.context .context
.downcast_mut::<WgpuRenderResourceContext>() .downcast_mut::<WgpuRenderResourceContext>()
.unwrap(); .unwrap();
let mut node_outputs: HashMap<NodeId, ResourceSlots> = HashMap::new();
for stage in stages.iter_mut() { for stage in stages.iter_mut() {
// TODO: sort jobs and slice by "amount of work" / weights // TODO: sort jobs and slice by "amount of work" / weights
// stage.jobs.sort_by_key(|j| j.node_states.len()); // stage.jobs.sort_by_key(|j| j.node_states.len());
@ -29,6 +33,7 @@ impl WgpuRenderGraphExecutor {
let chunk_size = (stage.jobs.len() + self.max_thread_count - 1) / self.max_thread_count; // divide ints rounding remainder up let chunk_size = (stage.jobs.len() + self.max_thread_count - 1) / self.max_thread_count; // divide ints rounding remainder up
let mut actual_thread_count = 0; let mut actual_thread_count = 0;
crossbeam_utils::thread::scope(|s| { crossbeam_utils::thread::scope(|s| {
let node_outputs = &node_outputs;
for jobs_chunk in stage.jobs.chunks_mut(chunk_size) { for jobs_chunk in stage.jobs.chunks_mut(chunk_size) {
let sender = sender.clone(); let sender = sender.clone();
let world = &*world; let world = &*world;
@ -38,8 +43,37 @@ impl WgpuRenderGraphExecutor {
s.spawn(move |_| { s.spawn(move |_| {
let mut render_context = let mut render_context =
WgpuRenderContext::new(device, render_resource_context); WgpuRenderContext::new(device, render_resource_context);
let mut local_node_outputs = HashMap::new();
for job in jobs_chunk.iter_mut() { for job in jobs_chunk.iter_mut() {
for node_state in job.node_states.iter_mut() { for node_state in job.node_states.iter_mut() {
// bind inputs from connected node outputs
for (i, mut input_slot) in node_state.input_slots.iter_mut().enumerate()
{
if let Edge::SlotEdge {
output_node,
output_index,
..
} = node_state.edges.get_input_slot_edge(i).unwrap()
{
let outputs =
if let Some(outputs) = node_outputs.get(output_node) {
outputs
} else if let Some(outputs) =
local_node_outputs.get(output_node)
{
outputs
} else {
panic!("node inputs not set")
};
let output_resource = outputs
.get(*output_index)
.expect("output should be set");
input_slot.resource = Some(output_resource);
} else {
panic!("no edge connected to input")
}
}
node_state.node.update( node_state.node.update(
world, world,
resources, resources,
@ -47,9 +81,14 @@ impl WgpuRenderGraphExecutor {
&node_state.input_slots, &node_state.input_slots,
&mut node_state.output_slots, &mut node_state.output_slots,
); );
local_node_outputs
.insert(node_state.id, node_state.output_slots.clone());
} }
} }
sender.send(render_context.finish()).unwrap(); sender
.send((render_context.finish(), local_node_outputs))
.unwrap();
}); });
} }
}) })
@ -57,10 +96,12 @@ impl WgpuRenderGraphExecutor {
let mut command_buffers = Vec::new(); let mut command_buffers = Vec::new();
for _i in 0..actual_thread_count { for _i in 0..actual_thread_count {
let command_buffer = receiver.recv().unwrap(); let (command_buffer, mut local_node_outputs) = receiver.recv().unwrap();
if let Some(command_buffer) = command_buffer { if let Some(command_buffer) = command_buffer {
command_buffers.push(command_buffer); command_buffers.push(command_buffer);
} }
node_outputs.extend(local_node_outputs.drain());
} }
queue.submit(&command_buffers); queue.submit(&command_buffers);

View File

@ -1,5 +1,10 @@
use uuid::Uuid; use uuid::Uuid;
pub enum WindowReference {
Primary,
Id(WindowId),
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub struct WindowId(Uuid); pub struct WindowId(Uuid);