mirror of
https://github.com/bevyengine/bevy
synced 2024-11-26 14:40:19 +00:00
RenderGraph2: Finish graph executor, fix window textures
This commit is contained in:
parent
8326a1a3c2
commit
5780bf4025
11 changed files with 226 additions and 120 deletions
|
@ -50,14 +50,15 @@ use self::{
|
|||
use bevy_app::{stage, AppBuilder, AppPlugin, GetEventReader};
|
||||
use bevy_asset::AssetStorage;
|
||||
use bevy_transform::prelude::LocalToWorld;
|
||||
use bevy_window::{WindowCreated, WindowResized};
|
||||
use bevy_window::{WindowCreated, WindowReference, WindowResized};
|
||||
use pass::PassDescriptor;
|
||||
use pipeline::pipelines::build_forward_pipeline;
|
||||
use render_graph_2::{
|
||||
nodes::{Camera2dNode, CameraNode, PassNode, SwapChainWindowSource, WindowSwapChainNode},
|
||||
nodes::{Camera2dNode, CameraNode, PassNode, WindowSwapChainNode, WindowTextureNode},
|
||||
RenderGraph2,
|
||||
};
|
||||
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_STAGE: &str = "render";
|
||||
|
@ -126,7 +127,28 @@ impl AppPlugin for RenderPlugin {
|
|||
render_graph.add_node_named(
|
||||
"swapchain",
|
||||
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::<WindowResized>(),
|
||||
),
|
||||
|
@ -164,7 +186,20 @@ impl AppPlugin for RenderPlugin {
|
|||
render_graph.add_node_edge("camera", "main_pass").unwrap();
|
||||
render_graph.add_node_edge("camera2d", "main_pass").unwrap();
|
||||
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();
|
||||
}
|
||||
app.add_resource(render_graph);
|
||||
|
|
|
@ -131,10 +131,10 @@ impl RenderGraph2 {
|
|||
|
||||
{
|
||||
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)?;
|
||||
input_node.add_input_edge(edge)?;
|
||||
input_node.edges.add_input_edge(edge)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -156,10 +156,10 @@ impl RenderGraph2 {
|
|||
|
||||
{
|
||||
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)?;
|
||||
input_node.add_input_edge(edge)?;
|
||||
input_node.edges.add_input_edge(edge)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -185,7 +185,7 @@ impl RenderGraph2 {
|
|||
if let Some(Edge::SlotEdge {
|
||||
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 {
|
||||
input_index: current_input_index,
|
||||
..
|
||||
|
@ -222,9 +222,9 @@ impl RenderGraph2 {
|
|||
let output_node_state = self.get_node_state(edge.get_output_node());
|
||||
let input_node_state = self.get_node_state(edge.get_input_node());
|
||||
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 input_node_state.input_edges.contains(edge) {
|
||||
if input_node_state.edges.input_edges.contains(edge) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -270,6 +270,7 @@ impl RenderGraph2 {
|
|||
) -> Result<impl Iterator<Item = (&Edge, &NodeState)>, RenderGraphError> {
|
||||
let node = self.get_node_state(label)?;
|
||||
Ok(node
|
||||
.edges
|
||||
.input_edges
|
||||
.iter()
|
||||
.map(|edge| (edge, edge.get_output_node()))
|
||||
|
@ -284,6 +285,7 @@ impl RenderGraph2 {
|
|||
) -> Result<impl Iterator<Item = (&Edge, &NodeState)>, RenderGraphError> {
|
||||
let node = self.get_node_state(label)?;
|
||||
Ok(node
|
||||
.edges
|
||||
.output_edges
|
||||
.iter()
|
||||
.map(|edge| (edge, edge.get_input_node()))
|
||||
|
|
|
@ -39,56 +39,13 @@ pub trait SystemNode: Node {
|
|||
fn get_system(&self, resources: &mut Resources) -> Box<dyn Schedulable>;
|
||||
}
|
||||
|
||||
pub struct NodeState {
|
||||
pub struct Edges {
|
||||
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 output_edges: Vec<Edge>,
|
||||
}
|
||||
|
||||
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),
|
||||
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)
|
||||
}
|
||||
|
||||
impl Edges {
|
||||
pub(crate) fn add_input_edge(&mut self, edge: Edge) -> Result<(), RenderGraphError> {
|
||||
if self.has_input_edge(&edge) {
|
||||
return Err(RenderGraphError::EdgeAlreadyExists(edge.clone()));
|
||||
|
@ -144,10 +101,64 @@ impl NodeState {
|
|||
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> {
|
||||
for i in 0..self.output_slots.len() {
|
||||
self.get_output_slot_edge(i)?;
|
||||
self.edges.get_output_slot_edge(i)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
@ -155,7 +166,7 @@ impl NodeState {
|
|||
|
||||
pub fn validate_input_slots(&self) -> Result<(), RenderGraphError> {
|
||||
for i in 0..self.input_slots.len() {
|
||||
self.get_input_slot_edge(i)?;
|
||||
self.edges.get_input_slot_edge(i)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
|
|
@ -2,13 +2,13 @@ use super::RenderGraphError;
|
|||
use crate::render_resource::{RenderResource, ResourceInfo};
|
||||
use std::borrow::Cow;
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ResourceSlot {
|
||||
pub resource: Option<RenderResource>,
|
||||
pub info: ResourceSlotInfo,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
#[derive(Default, Debug, Clone)]
|
||||
pub struct ResourceSlots {
|
||||
slots: Vec<ResourceSlot>,
|
||||
}
|
||||
|
@ -93,6 +93,10 @@ impl ResourceSlots {
|
|||
self.slots.iter()
|
||||
}
|
||||
|
||||
pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut ResourceSlot> {
|
||||
self.slots.iter_mut()
|
||||
}
|
||||
|
||||
pub fn len(&self) -> usize {
|
||||
self.slots.len()
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@ impl PassNode {
|
|||
for color_attachment in descriptor.color_attachments.iter() {
|
||||
if let TextureAttachment::Input(ref name) = color_attachment.attachment {
|
||||
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 {
|
||||
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 TextureAttachment::Input(ref name) = depth_stencil_attachment.attachment {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -4,23 +4,12 @@ use crate::{
|
|||
renderer_2::RenderContext,
|
||||
};
|
||||
use bevy_app::{EventReader, Events};
|
||||
use bevy_window::{WindowCreated, WindowId, WindowResized, Windows};
|
||||
use bevy_window::{WindowCreated, WindowResized, Windows, WindowReference};
|
||||
use legion::prelude::*;
|
||||
use std::borrow::Cow;
|
||||
|
||||
pub enum SwapChainWindowSource {
|
||||
Primary,
|
||||
Id(WindowId),
|
||||
}
|
||||
|
||||
impl Default for SwapChainWindowSource {
|
||||
fn default() -> Self {
|
||||
SwapChainWindowSource::Primary
|
||||
}
|
||||
}
|
||||
|
||||
pub struct WindowSwapChainNode {
|
||||
source_window: SwapChainWindowSource,
|
||||
window_reference: WindowReference,
|
||||
window_created_event_reader: EventReader<WindowCreated>,
|
||||
window_resized_event_reader: EventReader<WindowResized>,
|
||||
}
|
||||
|
@ -28,12 +17,12 @@ pub struct WindowSwapChainNode {
|
|||
impl WindowSwapChainNode {
|
||||
pub const OUT_TEXTURE: &'static str = "texture";
|
||||
pub fn new(
|
||||
source_window: SwapChainWindowSource,
|
||||
window_reference: WindowReference,
|
||||
window_created_event_reader: EventReader<WindowCreated>,
|
||||
window_resized_event_reader: EventReader<WindowResized>,
|
||||
) -> Self {
|
||||
WindowSwapChainNode {
|
||||
source_window,
|
||||
window_reference,
|
||||
window_created_event_reader,
|
||||
window_resized_event_reader,
|
||||
}
|
||||
|
@ -62,26 +51,22 @@ impl Node for WindowSwapChainNode {
|
|||
let window_resized_events = resources.get::<Events<WindowResized>>().unwrap();
|
||||
let windows = resources.get::<Windows>().unwrap();
|
||||
|
||||
let render_resources = render_context.resources_mut();
|
||||
let window = match self.source_window {
|
||||
SwapChainWindowSource::Primary => {
|
||||
let window = match self.window_reference {
|
||||
WindowReference::Primary => {
|
||||
windows.get_primary().expect("No primary window exists")
|
||||
}
|
||||
SwapChainWindowSource::Id(id) => windows
|
||||
WindowReference::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)
|
||||
{
|
||||
render_resources.create_swap_chain(window);
|
||||
}
|
||||
let render_resources = render_context.resources_mut();
|
||||
|
||||
// resize window swapchain
|
||||
if let Some(_) = window_resized_events
|
||||
.find_latest(&mut self.window_resized_event_reader, |e| e.id == window.id)
|
||||
// create window swapchain when window is resized or created
|
||||
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()
|
||||
{
|
||||
render_resources.create_swap_chain(window);
|
||||
}
|
||||
|
|
|
@ -1,23 +1,42 @@
|
|||
use crate::{
|
||||
render_graph_2::{Node, ResourceSlots, ResourceSlotInfo},
|
||||
render_graph_2::{Node, ResourceSlotInfo, ResourceSlots},
|
||||
render_resource::ResourceInfo,
|
||||
renderer_2::RenderContext,
|
||||
texture::TextureDescriptor,
|
||||
};
|
||||
use bevy_app::{EventReader, Events};
|
||||
use bevy_window::WindowResized;
|
||||
use bevy_window::{WindowCreated, WindowReference, WindowResized, Windows};
|
||||
use legion::prelude::*;
|
||||
use std::borrow::Cow;
|
||||
|
||||
pub struct WindowTextureNode {
|
||||
pub descriptor: TextureDescriptor,
|
||||
window_reference: WindowReference,
|
||||
descriptor: TextureDescriptor,
|
||||
window_created_event_reader: EventReader<WindowCreated>,
|
||||
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 {
|
||||
fn output(&self) -> &[ResourceSlotInfo] {
|
||||
static OUTPUT: &[ResourceSlotInfo] = &[ResourceSlotInfo {
|
||||
name: Cow::Borrowed("texture"),
|
||||
name: Cow::Borrowed(WindowTextureNode::OUT_TEXTURE),
|
||||
resource_type: ResourceInfo::Texture,
|
||||
}];
|
||||
OUTPUT
|
||||
|
@ -32,15 +51,29 @@ impl Node for WindowTextureNode {
|
|||
output: &mut ResourceSlots,
|
||||
) {
|
||||
const WINDOW_TEXTURE: usize = 0;
|
||||
let window_created_events = resources.get::<Events<WindowCreated>>().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();
|
||||
if let Some(old_texture) = output.get(WINDOW_TEXTURE) {
|
||||
render_resources.remove_texture(old_texture);
|
||||
}
|
||||
|
||||
self.descriptor.size.width = event.width;
|
||||
self.descriptor.size.height = event.height;
|
||||
self.descriptor.size.width = window.width;
|
||||
self.descriptor.size.height = window.height;
|
||||
let texture_resource = render_resources.create_texture(&self.descriptor);
|
||||
output.set(WINDOW_TEXTURE, texture_resource);
|
||||
}
|
||||
|
|
|
@ -187,6 +187,7 @@ fn stage_node(
|
|||
// 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)
|
||||
|| node
|
||||
.edges
|
||||
.input_edges
|
||||
.iter()
|
||||
.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
|
||||
if let Some((max_parent_stage, max_parent_job)) = node
|
||||
.edges
|
||||
.input_edges
|
||||
.iter()
|
||||
.map(|e| {
|
||||
|
@ -215,6 +217,7 @@ fn stage_node(
|
|||
{
|
||||
// count the number of parents that are in the highest stage
|
||||
let max_stage_parent_count = node
|
||||
.edges
|
||||
.input_edges
|
||||
.iter()
|
||||
.filter(|e| {
|
||||
|
|
|
@ -11,7 +11,7 @@ use bevy_render::{
|
|||
},
|
||||
pipeline::{BindGroupDescriptor, BindType, PipelineDescriptor},
|
||||
render_resource::{
|
||||
resource_name, RenderResource, RenderResourceAssignments, RenderResourceSetId, ResourceInfo,
|
||||
RenderResource, RenderResourceAssignments, RenderResourceSetId, ResourceInfo,
|
||||
},
|
||||
renderer_2::{RenderContext, RenderResourceContext},
|
||||
shader::Shader,
|
||||
|
@ -475,26 +475,13 @@ fn get_texture_view<'a>(
|
|||
attachment: &TextureAttachment,
|
||||
) -> &'a wgpu::TextureView {
|
||||
match attachment {
|
||||
TextureAttachment::Name(name) => match name.as_str() {
|
||||
resource_name::texture::SWAP_CHAIN => {
|
||||
if let Some(primary_swap_chain) = refs.swap_chain_outputs.values().next() {
|
||||
&primary_swap_chain.view
|
||||
} else {
|
||||
panic!("No primary swap chain found for color attachment");
|
||||
}
|
||||
}
|
||||
_ => match global_render_resource_assignments.get(&name) {
|
||||
TextureAttachment::Name(name) => 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"),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
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 std::sync::Arc;
|
||||
use std::{collections::HashMap, sync::Arc};
|
||||
|
||||
pub struct WgpuRenderGraphExecutor {
|
||||
pub max_thread_count: usize,
|
||||
|
@ -21,6 +24,7 @@ impl WgpuRenderGraphExecutor {
|
|||
.context
|
||||
.downcast_mut::<WgpuRenderResourceContext>()
|
||||
.unwrap();
|
||||
let mut node_outputs: HashMap<NodeId, ResourceSlots> = HashMap::new();
|
||||
for stage in stages.iter_mut() {
|
||||
// TODO: sort jobs and slice by "amount of work" / weights
|
||||
// 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 mut actual_thread_count = 0;
|
||||
crossbeam_utils::thread::scope(|s| {
|
||||
let node_outputs = &node_outputs;
|
||||
for jobs_chunk in stage.jobs.chunks_mut(chunk_size) {
|
||||
let sender = sender.clone();
|
||||
let world = &*world;
|
||||
|
@ -38,8 +43,37 @@ impl WgpuRenderGraphExecutor {
|
|||
s.spawn(move |_| {
|
||||
let mut render_context =
|
||||
WgpuRenderContext::new(device, render_resource_context);
|
||||
let mut local_node_outputs = HashMap::new();
|
||||
for job in jobs_chunk.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(
|
||||
world,
|
||||
resources,
|
||||
|
@ -47,9 +81,14 @@ impl WgpuRenderGraphExecutor {
|
|||
&node_state.input_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();
|
||||
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 {
|
||||
command_buffers.push(command_buffer);
|
||||
}
|
||||
|
||||
node_outputs.extend(local_node_outputs.drain());
|
||||
}
|
||||
|
||||
queue.submit(&command_buffers);
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
use uuid::Uuid;
|
||||
|
||||
pub enum WindowReference {
|
||||
Primary,
|
||||
Id(WindowId),
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
||||
pub struct WindowId(Uuid);
|
||||
|
||||
|
|
Loading…
Reference in a new issue