在vulkan.h中,VkAccessFlagBits
的每个实例都出现在包含srcAccessMask
和dstAccessMask
的对中:
VkAccessFlags srcAccessMask;
VkAccessFlags dstAccessMask;
在每种情况下,根据我的理解,这些掩码的目的是帮助指定两组操作,使得第一组中的操作结果对于第二组中的操作是可见的。例如,在屏障之前发生的写入操作不应该在高速缓存中挂起,而应该一直传播到屏障后可以读取它们的位置。或类似的东西。
访问标志有READ和WRITE形式:
/* ... */
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,
/* ... */
但在我看来,srcAccessMask
应该总是某种VK_ACCESS_*_WRITE_BIT
组合,而dstAccessMask
应始终是VK_ACCESS_*_READ_BIT
值的组合。如果这是真的,则READ / WRITE区别与src / dst区别相同且隐含,因此它应该足够好,只有VK_ACCESS_SHADER_BIT等,没有READ_或WRITE_变体。
为什么有READ_和WRITE_变体呢?在某些其他操作开始之前,指定某些读操作必须完全完成是否有用?请注意,使用VkAccessFlagBits
的所有操作都会产生(我认为)执行依赖项以及内存依赖性。在我看来,执行依赖性应该足够好,以防止早期读取接收后来写入写入的值。
答案 0 :(得分:2)
在写这个问题时,我在Vulkan规范中遇到了一个声明,该声明提供了至少部分答案:
内存依赖性用于解决数据危害,例如:确保写操作对后续读操作(写后读写危险)以及写后写入危险可见。写后读和读后读危险只需要执行依赖性来同步。
这是 6.4部分。执行和内存依赖。此外,从该部分的早期开始:
应用程序必须使用内存依赖性,以便在后续读取可以依赖它们之前,以及在后续写入可以覆盖它们之前使写入可见。如果不这样做会导致读取结果未定义,并且写入顺序未定义。
由此我猜测,是的,Vulkan命令产生的涉及这些访问标志的执行依赖关系可能使您不必将VK_ACCESS_*_READ_BIT
放入srcAccessMask
字段 - 但是事实上,您可能希望在某些dstAccessMask
字段中包含READ_标志,WRITE_标志或两者,因为显然可以使用显式依赖关系来防止写入后写入危险一种写入后写入危险的方法。 (反之亦然?)
就像,也许你的Vulkan有时会决定写入实际上不需要通过特定的缓存传播到其最终指定的目的地,以便进行后续的读取操作,如果Vulkan碰巧知道那个读取操作只会从同一个缓存读取,节省一些时间?但是然后可能会发生第二次写入,并写入另一个缓存,并且在比赛中留下两个缓存(选择未定义的赢家)将它们的两个值发送到同一位置。或者其他的东西?也许我对这些缓存的心智模型是完全错误的。
至少,内存障碍令人困惑,这是相当坚定的。
答案 1 :(得分:1)
让我们回顾一切可能性:
读 - 好 - 是的,那个人很没用。 Khronos似乎同意#131 src
中的这一点毫无意义(基本上相当于0
)。
读写 - 执行依赖应该足以在没有这个的情况下进行同步。 Khronos似乎同意#131 src
中的这一点毫无意义(基本上相当于0
)。
写 - 读 - 这是显而易见且最常见的。
写 - 写上面写的类似的原因。没有它,写入的顺序将是未定义的。在大多数情况下写一些你甚至都没读过的东西是没有意义的。但是,嘿,现在你有办法同步它。
您可以为src和dst提供更多这些掩码的位掩码。在这种情况下,让驱动程序使用两个掩码为您排序依赖项是有意义的。 (我不希望API级别的性能开销,因此可以方便)
从API设计的角度来看,它可能意味着为srcAccess
添加不同的枚举。但是_READ
变体可能只能在srcAccess
中通过“有效用法”被禁止,这使得这个论点变弱了。可能保留了src == READ
变体,因为它是良性的。