VK_KHR_maintenance8
本提案详细说明并解决了 VK_KHR_maintenance8
扩展解决的问题。
1. 问题陈述
随着时间的推移,需要创建一个维护扩展来处理一组小的特性,这些特性本身都不足以构成一个完整的扩展。
以下是本提案中考虑的问题列表
-
允许在深度/模板附件和“匹配”颜色附件之间进行复制
-
允许在
vkMergePipelineCaches
中隐式同步dstCache
。 -
要求在进行队列族所有权转移时,src/dst 同步范围能够工作
-
支持纹理采样和获取操作中的
Offset
(作为ConstOffset
的替代方案)图像操作数 -
使用 OpSRem 和 OpSMod 的 SPIR-V 定义,使这些操作为负操作数产生明确定义的结果
-
在从 3D 图像闪存到其他图像类型时,放宽图层限制
-
为 VkMemoryBarrier2、VkBufferMemoryBarrier2 和 VkImageMemoryBarrier2 添加额外的 64 个访问标志的空间
2. 提案
此扩展引入的项目是
2.1. 支持纹理采样和获取操作中的 Offset
(作为 ConstOffset
的替代方案)图像操作数
ConstOffset
仅允许常量偏移。在 maintenance8 之前,仅对 gather 操作支持 Offset
。这是 D3D12 分层的问题。
2.3. vkMergePipelineCaches
中的显式同步
vkMergePipelineCaches
函数要求其 dstCache
参数在外部同步。目前,可能同时从不同线程调用 vkMergePipelineCaches
的应用程序必须在管道缓存周围实现锁定,即使该管道缓存是在没有 VK_PIPELINE_CACHE_CREATE_EXTERNALLY_SYNCHRONIZED_BIT 的情况下创建的,也要对 vkCreate*Pipelines
进行锁定。这可能对性能不利,特别是当 vkMergePipelineCaches
很少发生时。
在创建管道缓存时可以使用新的 VK_PIPELINE_CACHE_CREATE_INTERNALLY_SYNCHRONIZED_MERGE_BIT_KHR
标志来指示当用作 vkMergePipelineCaches
的 dstCache
参数时,管道创建函数不需要外部同步。此标志与 VK_PIPELINE_CACHE_CREATE_EXTERNALLY_SYNCHRONIZED_BIT
互斥。
2.4. 队列族所有权转移的有意义的阶段
此扩展添加了一个新的依赖标志,指示在执行队列族所有权转移时,两个阶段掩码现在都有意义
VK_DEPENDENCY_QUEUE_FAMILY_OWNERSHIP_TRANSFER_USE_ALL_STAGES_BIT_KHR = 0xTBD,
当 VkDependencyFlags 中包含 VK_DEPENDENCY_QUEUE_FAMILY_OWNERSHIP_TRANSFER_USE_ALL_STAGES_BIT_KHR
时,指定队列族所有权转移的缓冲区和图像内存屏障将使用两个同步范围。
如果没有这个新标志,每个队列上的操作只能通过使用 VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT
来同步,这可能导致许多实现上的设备完全停顿。指定此标志后,可以使用阶段标志来同步这些操作,就像其他任何同步操作一样。
保持目标阶段与源阶段相同通常可以最大限度地减少过度同步,因此建议这样做,但它们没有必要匹配。类似地,两个队列中的阶段掩码也没有必要匹配。
3. 示例
以下代码执行颜色附件的队列族所有权转移,从图形队列转移到计算队列作为存储图像
VkImageMemoryBarrier2 imageMemoryBarrier = {
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2,
.srcStageMask = VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT,
.dstStageMask = VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT,
.srcAccessMask = VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT,
.oldLayout = VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL,
.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
.srcQueueFamilyIndex = graphicsQueueFamilyIndex,
.dstQueueFamilyIndex = computeQueueFamilyIndex,
.image = ...,
.subresourceRange = ...};
VkDependencyInfo dependencyInfo = {
.sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO,
.dependencyFlags = VK_DEPENDENCY_QUEUE_FAMILY_OWNERSHIP_TRANSFER_USE_ALL_STAGES_BIT_KHR,
.imageMemoryBarrierCount = 1,
.imageMemoryBarrier = &imageMemoryBarrier,
}
vkCmdPipelineBarrier2(graphicsCommandBuffer, &dependencyInfo);
VkSemaphoreSubmitInfo semaphoreSignalInfo = {
.sType = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO,
.semaphore = transferSemaphore,
.stageMask = VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT }; // Do not signal the semaphore until color attachment output completes
VkCommandBufferSubmitInfo graphicsCommandBufferInfo = {
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_SUBMIT_INFO,
.commandBuffer = graphicsCommandBuffer };
VkSubmitInfo2 submitInfo = {
.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO_2,
.commandBufferInfoCount = 1,
.pCommandBufferInfos = &graphicsCommandBufferInfo,
.signalSemaphoreInfoCount = 1,
.pSignalSemaphoreInfos = &semaphoreSignalInfo,
vkQueueSubmit2(graphicsQueue, 1, &submitInfo, VK_NULL_HANDLE);
VkImageMemoryBarrier2 imageMemoryBarrier = {
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2,
.srcStageMask = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,
.dstStageMask = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,
.dstAccessMask = VK_ACCESS_2_SHADER_READ_BIT,
.oldLayout = VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL,
.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
.srcQueueFamilyIndex = graphicsQueueFamilyIndex,
.dstQueueFamilyIndex = computeQueueFamilyIndex,
.image = ...,
.subresourceRange = ...};
VkDependencyInfo dependencyInfo = {
.sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO,
.dependencyFlags = VK_DEPENDENCY_QUEUE_FAMILY_OWNERSHIP_TRANSFER_USE_ALL_STAGES_BIT_KHR,
.imageMemoryBarrierCount = 1,
.imageMemoryBarrier = &imageMemoryBarrier,
}
vkCmdPipelineBarrier2(computeCommandBuffer, &dependencyInfo);
VkSemaphoreSubmitInfo semaphoreWaitInfo = {
.sType = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO,
.semaphore = transferSemaphore,
.stageMask = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT }; // Do not execute compute shader stages in the destination until semaphore is signaled.
VkCommandBufferSubmitInfo computeCommandBufferInfo = {
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_SUBMIT_INFO,
.commandBuffer = computeCommandBuffer };
VkSubmitInfo2 submitInfo = {
.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO_2,
.waitSemaphoreInfoCount = 1,
.pWaitSemaphoreInfos = &semaphoreWaitInfo,
.commandBufferInfoCount = 1,
.pCommandBufferInfos = &computeCommandBufferInfo,
vkQueueSubmit2(graphicsQueue, 1, &submitInfo, VK_NULL_HANDLE);