atagen

monolith

public
Star0
Watch0
d3ea8aacd50c4e342f595db5079c0842344b9534
1
ssh://brewery@pls.lobotomise.me:33/atagen/monolith.git
crates/render-vk/src/barrier.rsRust166 lines5.4 KB
1
use crate::image::{ImageInner, color_range};
2
use ash::vk;
3
use std::sync::Arc;
4
5
/// Layout changes recorded into a command buffer that has not been submitted.
6
/// Images keep their old layout until `commit`, so a failed submit leaves the
7
/// tracking true to what the GPU has done.
8
#[derive(Default)]
9
pub(crate) struct LayoutLog(Vec<(Arc<ImageInner>, vk::ImageLayout)>);
10
11
impl LayoutLog {
12
    fn current(&self, image: &Arc<ImageInner>) -> vk::ImageLayout {
13
        self.0
14
            .iter()
15
            .rev()
16
            .find(|(i, _)| Arc::ptr_eq(i, image))
17
            .map_or_else(|| image.layout(), |(_, layout)| *layout)
18
    }
19
20
    pub fn commit(self) {
21
        for (image, layout) in self.0 {
22
            image.set_layout(layout);
23
        }
24
    }
25
}
26
27
struct Scope {
28
    stage: vk::PipelineStageFlags2,
29
    access: vk::AccessFlags2,
30
}
31
32
/// What an image may still be doing when it leaves `layout`. Layouts the
33
/// renderer does not use itself, the general layout of dmabufs among them,
34
/// wait for everything.
35
fn leaving(layout: vk::ImageLayout) -> Scope {
36
    let (stage, access) = match layout {
37
        vk::ImageLayout::UNDEFINED => (vk::PipelineStageFlags2::NONE, vk::AccessFlags2::NONE),
38
        vk::ImageLayout::TRANSFER_DST_OPTIMAL => (
39
            vk::PipelineStageFlags2::TRANSFER,
40
            vk::AccessFlags2::TRANSFER_WRITE,
41
        ),
42
        vk::ImageLayout::TRANSFER_SRC_OPTIMAL => {
43
            (vk::PipelineStageFlags2::TRANSFER, vk::AccessFlags2::NONE)
44
        }
45
        vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL => (
46
            vk::PipelineStageFlags2::FRAGMENT_SHADER,
47
            vk::AccessFlags2::NONE,
48
        ),
49
        vk::ImageLayout::COLOR_ATTACHMENT_OPTIMAL => (
50
            vk::PipelineStageFlags2::COLOR_ATTACHMENT_OUTPUT,
51
            vk::AccessFlags2::COLOR_ATTACHMENT_WRITE,
52
        ),
53
        _ => (
54
            vk::PipelineStageFlags2::ALL_COMMANDS,
55
            vk::AccessFlags2::MEMORY_WRITE,
56
        ),
57
    };
58
    Scope { stage, access }
59
}
60
61
/// What an image does once it is in `layout`.
62
fn entering(layout: vk::ImageLayout) -> Scope {
63
    let (stage, access) = match layout {
64
        vk::ImageLayout::TRANSFER_DST_OPTIMAL => (
65
            vk::PipelineStageFlags2::TRANSFER,
66
            vk::AccessFlags2::TRANSFER_WRITE,
67
        ),
68
        vk::ImageLayout::TRANSFER_SRC_OPTIMAL => (
69
            vk::PipelineStageFlags2::TRANSFER,
70
            vk::AccessFlags2::TRANSFER_READ,
71
        ),
72
        vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL => (
73
            vk::PipelineStageFlags2::FRAGMENT_SHADER,
74
            vk::AccessFlags2::SHADER_SAMPLED_READ,
75
        ),
76
        vk::ImageLayout::COLOR_ATTACHMENT_OPTIMAL => (
77
            vk::PipelineStageFlags2::COLOR_ATTACHMENT_OUTPUT,
78
            vk::AccessFlags2::COLOR_ATTACHMENT_READ | vk::AccessFlags2::COLOR_ATTACHMENT_WRITE,
79
        ),
80
        _ => (
81
            vk::PipelineStageFlags2::ALL_COMMANDS,
82
            vk::AccessFlags2::MEMORY_READ | vk::AccessFlags2::MEMORY_WRITE,
83
        ),
84
    };
85
    Scope { stage, access }
86
}
87
88
/// The image barriers of one phase of a command buffer, recorded together.
89
#[derive(Default)]
90
pub(crate) struct Barriers(Vec<vk::ImageMemoryBarrier2<'static>>);
91
92
impl Barriers {
93
    fn push(
94
        &mut self,
95
        image: vk::Image,
96
        (old, src_family): (vk::ImageLayout, u32),
97
        (new, dst_family): (vk::ImageLayout, u32),
98
    ) {
99
        let (from, to) = (leaving(old), entering(new));
100
        self.0.push(
101
            vk::ImageMemoryBarrier2::default()
102
                .src_stage_mask(from.stage)
103
                .src_access_mask(from.access)
104
                .dst_stage_mask(to.stage)
105
                .dst_access_mask(to.access)
106
                .old_layout(old)
107
                .new_layout(new)
108
                .src_queue_family_index(src_family)
109
                .dst_queue_family_index(dst_family)
110
                .image(image)
111
                .subresource_range(color_range()),
112
        );
113
    }
114
115
    /// Moves an image into `layout` for use on this queue. Dmabuf images come
116
    /// from the foreign queue family in the general layout, others continue
117
    /// from their tracked layout.
118
    pub fn acquire(
119
        &mut self,
120
        family: u32,
121
        image: &Arc<ImageInner>,
122
        layout: vk::ImageLayout,
123
        log: &mut LayoutLog,
124
    ) {
125
        if image.external {
126
            self.push(
127
                image.image,
128
                (vk::ImageLayout::GENERAL, vk::QUEUE_FAMILY_FOREIGN_EXT),
129
                (layout, family),
130
            );
131
        } else {
132
            let old = log.current(image);
133
            if old != layout {
134
                self.push(
135
                    image.image,
136
                    (old, vk::QUEUE_FAMILY_IGNORED),
137
                    (layout, vk::QUEUE_FAMILY_IGNORED),
138
                );
139
                log.0.push((image.clone(), layout));
140
            }
141
        }
142
    }
143
144
    /// Hands a dmabuf image back to the foreign queue family after use.
145
    pub fn release(&mut self, family: u32, image: &ImageInner, layout: vk::ImageLayout) {
146
        if image.external {
147
            self.push(
148
                image.image,
149
                (layout, family),
150
                (vk::ImageLayout::GENERAL, vk::QUEUE_FAMILY_FOREIGN_EXT),
151
            );
152
        }
153
    }
154
155
    pub unsafe fn record(self, d: &ash::Device, cmd: vk::CommandBuffer) {
156
        if self.0.is_empty() {
157
            return;
158
        }
159
        unsafe {
160
            d.cmd_pipeline_barrier2(
161
                cmd,
162
                &vk::DependencyInfo::default().image_memory_barriers(&self.0),
163
            )
164
        };
165
    }
166
}