我编写了一个 Vulkan 验证错误的最小可重现代码示例,该错误显然与交换链获取和命令缓冲区提交之间的同步相关(请参阅 Gist 上的完整代码示例)。
示例 C 代码应该只使用 GLFW 创建一个黑色窗口,并在单帧后立即返回。
相关部分在这里(我删除了栅栏以简化代码,无论有或没有它们,错误都是相同的):
VkSemaphore imageAvailableSemaphore = createSemaphore(device);
VkSemaphore renderFinishedSemaphore = createSemaphore(device);
uint32_t imageIndex;
vkAcquireNextImageKHR(
device, swapChain, UINT64_MAX, imageAvailableSemaphore, VK_NULL_HANDLE, &imageIndex);
VkSemaphore waitSemaphores[] = {imageAvailableSemaphore};
VkSemaphore signalSemaphores[] = {renderFinishedSemaphore};
VkPipelineStageFlags waitStages[] = {VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT};
VkSubmitInfo submitInfo = {};
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submitInfo.waitSemaphoreCount = 1;
submitInfo.pWaitSemaphores = waitSemaphores;
submitInfo.pWaitDstStageMask = waitStages;
submitInfo.signalSemaphoreCount = 1;
submitInfo.pSignalSemaphores = signalSemaphores;
submitInfo.commandBufferCount = 1;
submitInfo.pCommandBuffers = &commandBuffers[imageIndex];
VkQueue graphicsQueue;
vkGetDeviceQueue(device, queueFamilyIndex, 0, &graphicsQueue);
vkQueueSubmit(graphicsQueue, 1, &submitInfo, NULL);
命令缓冲区只是:
vkBeginCommandBuffer(commandBuffers[i], &beginInfo);
vkCmdBeginRenderPass(commandBuffers[i], &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE);
vkCmdEndRenderPass(commandBuffers[i]);
vkEndCommandBuffer(commandBuffers[i]);
队列提交时会引发以下 SYNC-HAZARD-WRITE-AFTER-READ 验证错误:
validation layer: Validation Error: [ SYNC-HAZARD-WRITE-AFTER-READ ] Object 0: handle =
0x5599afbbf520, type = VK_OBJECT_TYPE_QUEUE; | MessageID = 0x376bc9df | vkQueueSubmit(): Hazard
WRITE_AFTER_READ for entry 0, VkCommandBuffer 0x5599b202e960[], Submitted access info
(submitted_usage: SYNC_IMAGE_LAYOUT_TRANSITION, command: vkCmdBeginRenderPass, seq_no: 1,
renderpass: VkRenderPass 0xcad092000000000d[], reset_no: 1). Access info (prior_usage:
SYNC_PRESENT_ENGINE_SYNCVAL_PRESENT_ACQUIRE_READ_SYNCVAL, read_barriers:
VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT|VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT, ,
batch_tag: 1, vkAcquireNextImageKHR aquire_tag:1: VkSwapchainKHR 0xf443490000000006[],
image_index: 0image: VkImage 0xcb3ee80000000007[]).
此错误仅发生在特定配置上(具有最新 LunarG SDK v1.3.275 的 Linux)。我不知道问题是出在我的代码中还是验证层代码中。
我应该补充一点,如果我将
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT
中的 VK_PIPELINE_STAGE_ALL_COMMANDS_BIT
替换为 VkSubmitInfo.pWaitDstStageMask
,错误就会消失(但随后我会收到性能警告)。
我做错了什么?
我的配置:
Ubuntu 22.04
LunarG SDK version 1.3.275
Vulkan Instance Version: 1.3.275
NVIDIA GeForce RTX 2070 SUPER
NVIDIA-SMI 535.129.03
Driver Version: 535.129.03
CUDA Version: 12.2
我认为验证层 GitHub 中的这个讨论解释了这个问题以及如何解决它。
讨论的重要部分是:
应该有额外的执行依赖 COLOR_ATTACHMENT_OUTPUT 阶段,否则可以开始图像转换 在图像获取操作完成之前。目的地阶段已设定 到 COLOR_ATTACHMENT_OUTPUT,这保证了从 光栅化将等待。但图像布局发生转换 之前,通过将源阶段设置为 COLOR_ATTACHMENT_OUTPUT,我们 使用信号量等待操作创建执行依赖关系(我们链接 与 pWaitDstStageMask 也指定 COLOR_ATTACHMENT_OUTPUT )。
我实际上重现了您的问题,并添加了一个障碍来添加如上所述的依赖项,并且验证消息不再出现。这可能与您的情况不完全相同,但似乎有可能。