ivy-rendergraph 0.10.3

Easy to use declarative rendergraph for vulkan and Ivy
use anyhow::Context;
use ivy_graphics::Renderer;
use ivy_resources::{Handle, Storage};
use ivy_vulkan::{
    descriptors::{DescriptorSet, IntoSet},
    shaderpass::ShaderPass,
    vk::ClearValue,
    PassInfo, Texture,
};
use std::marker::PhantomData;

use crate::{AttachmentInfo, Node, NodeKind};

pub struct FullscreenNode<Pass, T, E> {
    renderer: Handle<T>,
    marker: PhantomData<(Pass, E)>,
    color_attachments: Vec<AttachmentInfo>,
    read_attachments: Vec<Handle<Texture>>,
    input_attachments: Vec<Handle<Texture>>,
    depth_attachment: Option<AttachmentInfo>,
    clear_values: Vec<ClearValue>,
    sets: Vec<DescriptorSet>,
    set_count: usize,
}

impl<Pass, T, E> FullscreenNode<Pass, T, E>
where
    Pass: ShaderPass + Storage,
    T: Renderer<Error = E> + Storage,
    E: Into<anyhow::Error>,
{
    pub fn new(
        renderer: Handle<T>,
        color_attachments: Vec<AttachmentInfo>,
        read_attachments: Vec<Handle<Texture>>,
        input_attachments: Vec<Handle<Texture>>,
        depth_attachment: Option<AttachmentInfo>,
        clear_values: Vec<ClearValue>,
        sets: Vec<&dyn IntoSet>,
        frames_in_flight: usize,
    ) -> Self {
        let set_count = sets.len();

        let set_iter = sets.iter().map(|val| val.sets().into_iter().cycle());

        let sets = (0..frames_in_flight)
            .flat_map(|_| set_iter.clone().map(|mut val| (*val.next().unwrap())))
            .collect::<Vec<_>>();

        Self {
            renderer,
            marker: PhantomData,
            color_attachments,
            read_attachments,
            input_attachments,
            depth_attachment,
            clear_values,
            sets,
            set_count,
        }
    }
}

impl<Pass, T, E> Node for FullscreenNode<Pass, T, E>
where
    Pass: ShaderPass + Storage,
    T: Renderer<Error = E> + Storage,
    E: 'static + std::error::Error + Sync + Send,
{
    fn color_attachments(&self) -> &[AttachmentInfo] {
        &self.color_attachments
    }

    fn read_attachments(&self) -> &[Handle<Texture>] {
        &self.read_attachments
    }

    fn input_attachments(&self) -> &[Handle<Texture>] {
        &self.input_attachments
    }

    fn depth_attachment(&self) -> Option<&AttachmentInfo> {
        self.depth_attachment.as_ref()
    }

    fn clear_values(&self) -> &[ivy_vulkan::vk::ClearValue] {
        &self.clear_values
    }

    fn node_kind(&self) -> crate::NodeKind {
        NodeKind::Graphics
    }

    fn debug_name(&self) -> &'static str {
        "fullscreen node"
    }

    fn execute(
        &mut self,
        world: &mut hecs::World,
        resources: &ivy_resources::Resources,
        cmd: &ivy_vulkan::commands::CommandBuffer,
        pass_info: &PassInfo,
        current_frame: usize,
    ) -> anyhow::Result<()> {
        let offset = self.set_count * current_frame;
        resources
            .get_mut(self.renderer)?
            .draw::<Pass>(
                world,
                resources,
                cmd,
                &self.sets[offset..offset + self.set_count],
                pass_info,
                &[],
                current_frame,
            )
            .context("FullscreenNode failed to draw using supplied renderer")?;

        Ok(())
    }
}