Memory 为什么VkAccessFlagBits同时包含读取位和写入位?

Memory 为什么VkAccessFlagBits同时包含读取位和写入位?,memory,synchronization,vulkan,Memory,Synchronization,Vulkan,在vulkan.h中,VkAccessFlagBits的每个实例都成对出现,其中包含一个srcAccessMask和一个dstAccessMask: 根据我的理解,在任何情况下,这些掩码的目的都是帮助指定两组操作,以便第一组操作的结果对第二组操作可见。例如,在屏障之前发生的写操作不应该挂起在缓存中,而是应该一直传播到屏障之后可以读取它们的位置。或者类似的 访问标志有读和写两种形式: /* ... */ VK_ACCESS_SHADER_READ_BIT = 0x00000020, VK_ACCE

在vulkan.h中,VkAccessFlagBits的每个实例都成对出现,其中包含一个srcAccessMask和一个dstAccessMask:

根据我的理解,在任何情况下,这些掩码的目的都是帮助指定两组操作,以便第一组操作的结果对第二组操作可见。例如,在屏障之前发生的写操作不应该挂起在缓存中,而是应该一直传播到屏障之后可以读取它们的位置。或者类似的

访问标志有读和写两种形式:

/* ... */
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,
/* ... */
但在我看来,srccessmask应该始终是某种VK_访问*_写入*_位组合,而dstAccessMask应该始终是VK_访问*_读取*_位值的组合。如果这是真的,那么读/写区别与src/dst区别相同,并且隐含在src/dst区别中,因此它应该足够好,只具有VK_访问_着色器_位等,而不具有读或写变体


那么,为什么会有读和写变体呢?指定某些读取操作必须在其他操作开始之前完全完成是否有用?请注意,所有使用VkAccessFlagBits的操作都会产生执行依赖性和内存依赖性。在我看来,执行依赖性应该足够好,以防止早期读取接收后期写入的值。

在编写此问题时,我在Vulkan规范中遇到一条语句,该语句至少提供了部分答案:

内存依赖性用于解决数据危害,例如,确保后续读操作可以看到写后读取危害以及写后写入危害。读后写和读后读危险只需要同步执行依赖项

这来自第6.4节。执行和内存依赖关系。此外,从该节前面的内容:

应用程序必须使用内存依赖关系使写操作可见,然后后续读取才能依赖它们,然后后续写入才能覆盖它们。否则会导致读取结果未定义,写入顺序未定义

由此我推测,是的,Vulkan命令产生的涉及这些访问标志的执行依赖性可能使您不必将VK_访问*_读取位放入srcAccessMask字段,但实际上您可能希望在某些dstAccessMask字段中具有读取标志、写入标志或两者,因为很明显,可以使用显式依赖关系来防止写后读的危险,而不防止写后写的危险。也许反之亦然

比如,如果Vulkan碰巧知道读操作只是从同一个缓存中读取,从而节省了一些时间,那么可能您的Vulkan有时会决定写操作实际上不需要通过特定缓存一直传播到其最终指定的目的地?但是可能会发生第二次写入,然后写入到不同的缓存,在一场比赛中,将剩下两个缓存,选择winner undefined将它们的两个值发送到同一地点。还是什么?也许我对这些缓存的心理模型是完全错误的


至少,记忆障碍是令人困惑的,这一点已经相当确定了。

让我们回顾一下所有的可能性:

读——读——好吧,是的,那一本很没用。Khronos似乎同意src中的无意义值基本上等于0

读写执行依赖项应足以在没有此依赖项的情况下进行同步。Khronos似乎同意src中的无意义值基本上等于0

写-读-这是最明显和最常见的一个

写-写-类似于上面写-读的原因。如果没有它,写入顺序将无法定义。在大多数情况下,写一些你甚至没有读过的东西是没有意义的。但是,嘿,现在你有了同步它的方法

您可以向src和dst提供更多这些掩码的位掩码。在这种情况下,让驱动程序同时使用两个掩码来为您排序依赖项是有意义的。我不期望在API级别上有这样的性能开销,所以它是方便的


从API设计的角度来看,这可能意味着为SRCCESS添加不同的枚举。但是,也许可以通过有效的用法在srccess中禁止读变体,这使得这个论点很弱。src==READ变量可能被保留,因为它是良性的。

这似乎与我在回答中的粗略说法相冲突,即永远不需要在srccessmask中设置READ位标志。你认为这个说法是错误的吗?@麦奎赫:这不是你的问题吗?你的国际米兰
解释是否正确?@krOoze:仅执行依赖项就可以确保读->写问题。内存依赖性,这正是这些都是关于写作的。@nicolbolas这回答了这个问题,但表明Vulkan可能毕竟需要被告知这些读->写情况,如果是这样,我需要更多的解释。但在这一点上,你似乎与我的答案一致。@Nicolas你被迫通过布局转换或队列族转换来添加内存屏障。无论如何,如果有一个与我不同的人真的知道这些缓存或其他在某些真实硬件上的工作方式,想解释一下告诉Vulkan一个屏障是多么重要这是一个写-读障碍,而另一个是写-写障碍,比如,详细地说,为什么它不只是以相同的方式处理这两个问题?或者我真的做到了吗???那么我会很高兴的。但是一个普通的Vulkan用户并不需要知道,我想我很确定这与硬件本身无关。硬件线程调度可以包括基于写地址的分片。碎片将共享缓存,这样就可以避免在没有缓存刷新的情况下一次又一次地写入,而只需要执行顺序同步。我不知道是否有硬件真正实现了这种切分。但Vulkan规范旨在对应用程序进行完全控制,这需要对操作进行非常详细的描述,以便以同样最佳的方式支持所有类型的可能硬件。
/* ... */
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,
/* ... */