RenderGraph2: Finish graph executor, fix window textures
This commit is contained in:
parent
8326a1a3c2
commit
5780bf4025
@ -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);
|
||||||
|
|||||||
@ -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()))
|
||||||
|
|||||||
@ -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(())
|
||||||
|
|||||||
@ -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()
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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| {
|
||||||
|
|||||||
@ -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"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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);
|
||||||
|
|||||||
@ -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);
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user