Skip to main content

ursus_core/vulkan/core/
barrier.rs

1use ash::vk;
2
3pub fn make_barrier_range(
4    image: vk::Image,
5    aspect_mask: vk::ImageAspectFlags,
6    base_mip_level: u32,
7    level_count: u32,
8    old_layout: vk::ImageLayout,
9    new_layout: vk::ImageLayout,
10) -> vk::ImageMemoryBarrier2<'static> {
11    let (src_stage, src_access, dst_stage, dst_access) = layout_transition_masks(old_layout, new_layout);
12
13    vk::ImageMemoryBarrier2::default()
14        .src_stage_mask(src_stage)
15        .src_access_mask(src_access)
16        .dst_stage_mask(dst_stage)
17        .dst_access_mask(dst_access)
18        .old_layout(old_layout)
19        .new_layout(new_layout)
20        .src_queue_family_index(vk::QUEUE_FAMILY_IGNORED)
21        .dst_queue_family_index(vk::QUEUE_FAMILY_IGNORED)
22        .image(image)
23        .subresource_range(vk::ImageSubresourceRange {
24            aspect_mask,
25            base_mip_level,
26            level_count,
27            base_array_layer: 0,
28            layer_count: 1,
29        })
30}
31
32/// Returns (stage, access) for transitioning from/to the given layout.
33/// `is_src` determines whether the layout is interpreted as "from" (true)
34/// or "to" (false) - the only asymmetry in Vulkan semantics here
35/// is UNDEFINED (valid only as src) and the difference between EARLY/LATE fragment
36/// tests for depth attachments (see the comment in the branch).
37fn stage_access(layout: vk::ImageLayout, is_src: bool) -> (vk::PipelineStageFlags2, vk::AccessFlags2) {
38    use vk::AccessFlags2 as A;
39    use vk::ImageLayout as L;
40    use vk::PipelineStageFlags2 as S;
41
42    match layout {
43        L::UNDEFINED => {
44            assert!(is_src, "UNDEFINED is only valid as the source (src) layout of a transition");
45            (S::TOP_OF_PIPE, A::empty())
46        }
47        L::PRESENT_SRC_KHR => {
48            if is_src {
49                (S::TOP_OF_PIPE, A::empty())
50            } else {
51                (S::BOTTOM_OF_PIPE, A::empty())
52            }
53        }
54        L::COLOR_ATTACHMENT_OPTIMAL => (S::COLOR_ATTACHMENT_OUTPUT, A::COLOR_ATTACHMENT_WRITE),
55        L::DEPTH_ATTACHMENT_OPTIMAL => {
56            // src: the previous write must be visible (LATE = after blending/writes).
57            // dst: subsequent read/write operations can begin already at EARLY tests.
58            if is_src {
59                (S::LATE_FRAGMENT_TESTS, A::DEPTH_STENCIL_ATTACHMENT_WRITE)
60            } else {
61                (S::EARLY_FRAGMENT_TESTS, A::DEPTH_STENCIL_ATTACHMENT_READ | A::DEPTH_STENCIL_ATTACHMENT_WRITE)
62            }
63        }
64        L::SHADER_READ_ONLY_OPTIMAL => (S::FRAGMENT_SHADER, A::SHADER_READ),
65        L::TRANSFER_SRC_OPTIMAL => (S::TRANSFER, A::TRANSFER_READ),
66        L::TRANSFER_DST_OPTIMAL => (S::TRANSFER, A::TRANSFER_WRITE),
67        other => panic!("stage_access: unsupported layout {:?}", other),
68    }
69}
70
71pub(crate) fn layout_transition_masks(
72    from: vk::ImageLayout,
73    to: vk::ImageLayout,
74) -> (vk::PipelineStageFlags2, vk::AccessFlags2, vk::PipelineStageFlags2, vk::AccessFlags2) {
75    let (src_stage, src_access) = stage_access(from, true);
76    let (dst_stage, dst_access) = stage_access(to, false);
77    (src_stage, src_access, dst_stage, dst_access)
78}