我编写了一个Vulkan验证错误的最小可重现代码示例,该错误显然与交换链获取和命令缓冲区提交(see the full code example on 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]);

在队列提交时引发以下同步风险读后写入验证错误:

    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)上.我不知道问题出在我的代码中还是在验证层代码中.

我要补充的是,如果我在VkSubmitInfo.pWaitDstStageMask中将VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT替换为VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,错误就会消失(但随后我会收到性能警告).

我做错了什么?

我的配置:

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

推荐答案

我认为验证层中的这discussion个GitHub解释了这个问题以及如何修复它.

讨论的重要部分是:

应该有额外的执行依赖项, COLOR_ATTACH_OUTPUT阶段,否则可以开始图像过渡 在图像采集操作完成之前.目标阶段已设置 到COLOR_ATTACH_OUTPUT,这保证了从 光栅化将会等待.但图像布局转换会发生 之前,通过将源阶段设置为COLOR_ATTACH_OUTPUT,我们 使用信号量等待操作创建执行依赖关系(WE链 使用还指定COLOR_ATTACH_OUTPUT的pWaitDstageMASK).

我实际上重现了您的问题,并添加了一个障碍来添加依赖项,如上所述,验证消息不再出现.这可能与你的情况不完全相同,但似乎是有可能的.

C++相关问答推荐

为指针 struct 创建宏

在函数中使用复合文字来初始化C语言中的变量

使用GOTO从多个嵌套循环C继续

如果dim指定数组中的数据量,使用dim-1会不会潜在地导致丢失一个元素?

我的程序在收到SIGUSR1信号以从PAUSE()继续程序时总是崩溃()

在为hashmap创建加载器时,我的存储桶指向它自己

为什么指针运算会产生错误的结果?

如何在C中只对字符串(包含数字、单词等)中的数字进行重复操作?

为什么函数是按照定义的顺序执行的,而不是按照从avr-c中的int main()调用的顺序执行的?

ifdef __cplusplus中的整数文字单引号

如何读取文件并将内容保存在字符串中?(在C语言中,没有崩溃或核心转储错误)

按长度对argv中的单词进行排序

这个空指针类型的转换是有效代码还是恶意代码?

通过k&;r语法的c声明无效

存储和访问指向 struct 的指针数组

C: NULL>;NULL总是false?

在C中使用字符串时是否不需要内存分配?

WSASocket在哪里定义?

为什么创建局部变量的指针需要过程在堆栈上分配空间?

如何在Linux上从控制台左上角开始打印文本?