Vulkan之全局内存屏障

Execution Barrier只能控制执行的顺序,却不能控制memory的修改顺序,先执行的command不一定能先修改完memory,这是现代复杂的缓存机制导致的。因此我们需要更加深入的控制方式。

为了解决Execution Barrier的问题,Memory Barrier正式登场。Memory Barrier是一种更加严格的barrier,它可以更加严格的控制memory,用来解决Execution Barrier的存在的问题。

当memoryBarrierCount != 0时,pMemoryBarriers指向一个数组,这个数组的结构如下:

1
2
3
4
5
6
typedef struct VkMemoryBarrier {
VkStructureType sType; // VK_STRUCTURE_TYPE_MEMORY_BARRIER
const void* pNext;
VkAccessFlags srcAccessMask;
VkAccessFlags dstAccessMask;
} VkMemoryBarrier;

srcAccessMask 表示内存最后如何写入
dstAccessMask 表示内存接下来如何读取
srcAccessMask 和 dstAccessMask 控制着stage对内存的操作。

这个定义的标志位更加复杂:

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
typedef enum VkAccessFlagBits {
VK_ACCESS_INDIRECT_COMMAND_READ_BIT = 0x00000001,
VK_ACCESS_INDEX_READ_BIT = 0x00000002,
VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT = 0x00000004,
VK_ACCESS_UNIFORM_READ_BIT = 0x00000008,
VK_ACCESS_INPUT_ATTACHMENT_READ_BIT = 0x00000010,
VK_ACCESS_SHADER_READ_BIT = 0x00000020,
VK_ACCESS_SHADER_WRITE_BIT = 0x00000040,
VK_ACCESS_COLOR_ATTACHMENT_READ_BIT = 0x00000080,
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT = 0x00000100,
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT = 0x00000200,
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT = 0x00000400,
VK_ACCESS_TRANSFER_READ_BIT = 0x00000800,
VK_ACCESS_TRANSFER_WRITE_BIT = 0x00001000,
VK_ACCESS_HOST_READ_BIT = 0x00002000,
VK_ACCESS_HOST_WRITE_BIT = 0x00004000,
VK_ACCESS_MEMORY_READ_BIT = 0x00008000,
VK_ACCESS_MEMORY_WRITE_BIT = 0x00010000,
VK_ACCESS_TRANSFORM_FEEDBACK_WRITE_BIT_EXT = 0x02000000,
VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_READ_BIT_EXT = 0x04000000,
VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_WRITE_BIT_EXT = 0x08000000,
VK_ACCESS_CONDITIONAL_RENDERING_READ_BIT_EXT = 0x00100000,
VK_ACCESS_COLOR_ATTACHMENT_READ_NONCOHERENT_BIT_EXT = 0x00080000,
VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR = 0x00200000,
VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_KHR = 0x00400000,
VK_ACCESS_SHADING_RATE_IMAGE_READ_BIT_NV = 0x00800000,
VK_ACCESS_FRAGMENT_DENSITY_MAP_READ_BIT_EXT = 0x01000000,
VK_ACCESS_COMMAND_PREPROCESS_READ_BIT_NV = 0x00020000,
VK_ACCESS_COMMAND_PREPROCESS_WRITE_BIT_NV = 0x00040000,
VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_NV = VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR,
VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_NV = VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_KHR,
VK_ACCESS_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
} VkAccessFlagBits;
typedef VkFlags VkAccessFlags;

实际上通过设置VkAccessFlags可以解决内存访问的两个问题:
避免危险的写后读,读后写,写后写操作
保持数据的一致性

实际上srcStageMask + srcAccessMask 组合在一起控制了内存的写入
dstStageMask + dstAccessMask 组合控制了对内存的读取。

显示 Gitment 评论