aboutsummaryrefslogtreecommitdiff
path: root/stockton-skeleton/src/draw_passes/mod.rs
blob: 17564fa7b605db6c615e9a35aa104a94f3cb8659 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
//! Traits and common draw passes.
use std::ops::Range;

use crate::{
    context::RenderingContext, queue_negotiator::QueueFamilyNegotiator, session::Session, types::*,
};
use hal::{
    image::Layout,
    pass::{AttachmentLoadOp, AttachmentOps, AttachmentStoreOp},
};

use anyhow::Result;

mod cons;
pub mod util;

pub use cons::ConsDrawPass;

/// One of several 'passes' that draw on each frame.
pub trait DrawPass<P: PassPosition> {
    /// Queue any necessary draw commands to cmd_buffer
    /// This should assume the command buffer isn't in the middle of a renderpass, and should leave it as such.
    fn queue_draw(
        &mut self,
        session: &Session,
        img_view: &ImageViewT,
        cmd_buffer: &mut CommandBufferT,
    ) -> Result<()>;

    /// Called just after the surface changes (probably a resize).
    /// This takes ownership and returns itself to ensure that the `DrawPass` is not called again if it fails.
    /// This means you should deactivate as much as possible in case of an error.
    fn handle_surface_change(
        self,
        session: &Session,
        context: &mut RenderingContext,
    ) -> Result<Self>
    where
        Self: Sized;

    /// Deactivate any vulkan parts that need to be deactivated
    fn deactivate(self, context: &mut RenderingContext) -> Result<()>;
}

/// A type that can be made into a specific draw pass type.
/// This allows extra data to be used in initialisation without the Renderer needing to worry about it.
pub trait IntoDrawPass<T: DrawPass<P>, P: PassPosition> {
    fn init(self, session: &mut Session, context: &mut RenderingContext) -> Result<T>;

    /// This function should ask the queue negotatior to find families for any auxilary operations this draw pass needs to perform
    /// For example, .find(&TexLoadQueue)
    fn find_aux_queues(
        adapter: &Adapter,
        queue_negotiator: &mut QueueFamilyNegotiator,
    ) -> Result<()>;
}

/// Used so that draw passes can determine what state shared resources are in and how they should be left.
pub trait PassPosition: private::Sealed {
    /// The layout the image is in going in.
    fn layout_in() -> Layout;

    /// The layout the image should be once this drawpass is completed
    fn layout_out() -> Layout;

    /// Has the layout already been cleared this frame
    fn is_cleared() -> bool;

    /// Convenience function to get a range from layout_in() to layout_out()
    fn layout_as_range() -> Range<Layout> {
        Self::layout_in()..Self::layout_out()
    }

    /// Convenience function to get the attachment ops that should be used when loading the image attachment.
    fn attachment_ops() -> AttachmentOps {
        match Self::is_cleared() {
            true => AttachmentOps::new(AttachmentLoadOp::Load, AttachmentStoreOp::Store),
            false => AttachmentOps::new(AttachmentLoadOp::Clear, AttachmentStoreOp::Store),
        }
    }
}

/// Pass is at the beginning of the list
pub struct Beginning;
impl PassPosition for Beginning {
    fn layout_in() -> Layout {
        Layout::Undefined
    }

    fn layout_out() -> Layout {
        Layout::ColorAttachmentOptimal
    }

    fn is_cleared() -> bool {
        false
    }
}

/// Pass is in the middle of the list
pub struct Middle;
impl PassPosition for Middle {
    fn layout_in() -> Layout {
        Layout::ColorAttachmentOptimal
    }

    fn layout_out() -> Layout {
        Layout::ColorAttachmentOptimal
    }

    fn is_cleared() -> bool {
        true
    }
}

/// Pass is at the end of the list
pub struct End;
impl PassPosition for End {
    fn layout_in() -> Layout {
        Layout::ColorAttachmentOptimal
    }

    fn layout_out() -> Layout {
        Layout::Present
    }

    fn is_cleared() -> bool {
        true
    }
}

/// Pass is the only draw pass being used
pub struct Singular;
impl PassPosition for Singular {
    fn layout_in() -> Layout {
        Layout::Undefined
    }

    fn layout_out() -> Layout {
        Layout::Present
    }

    fn is_cleared() -> bool {
        false
    }
}

mod private {
    use super::{Beginning, End, Middle, Singular};

    pub trait Sealed {}
    impl Sealed for Beginning {}
    impl Sealed for Middle {}
    impl Sealed for End {}
    impl Sealed for Singular {}
}