Vulkan:动态渲染图像过渡

问题描述 投票:0回答:1

我正在将渲染器从渲染通道移至动态渲染,并在 Linux(具体是 Nvidia 550.78)上看到验证消息,而在 Windows(具体是 AMD 24.3.1)上看不到。以下是我为便于阅读而格式化的几行:

[17:01:00.273][8314]: Swapchain image 0xcad092000000000d: 'ColorAttachmentOptimal'->'PresentSrcKHR'

[17:01:00.273][8314]: 
Validation Error: [ SYNC-HAZARD-WRITE-AFTER-READ ]
Object 0: handle = 0x555555b41130, type = VK_OBJECT_TYPE_QUEUE; |
MessageID = 0x376bc9df |
vkQueueSubmit(): 
Hazard WRITE_AFTER_READ for entry 0,
  VkCommandBuffer 0x5555582fad00[],
  Submitted access info (submitted_usage: SYNC_IMAGE_LAYOUT_TRANSITION,
                         command: vkCmdPipelineBarrier,
                         seq_no: 1,
                         VkImage 0xcad092000000000d[],
                         reset_no: 30).
  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: 677,
               vkAcquireNextImageKHR aquire_tag:677
               : VkSwapchainKHR 0xe88693000000000c[],
               image_index: 0
               image: VkImage 0xcad092000000000d[]).

[17:01:00.273][8314]: 
Validation Error: [ SYNC-HAZARD-WRITE-AFTER-WRITE ]
Object 0: handle = 0x555555b41130, type = VK_OBJECT_TYPE_QUEUE; |
MessageID = 0x5c0ec5d6 |
vkQueueSubmit():
  Hazard WRITE_AFTER_WRITE for entry 0,
  VkCommandBuffer 0x5555582fad00[],
  Submitted access info (submitted_usage: SYNC_IMAGE_LAYOUT_TRANSITION,
                         command: vkCmdPipelineBarrier,
                         seq_no: 2,
                         VkImage 0x2e2941000000001f[],
                         reset_no: 30).
  Access info (prior_usage: SYNC_LATE_FRAGMENT_TESTS_DEPTH_STENCIL_ATTACHMENT_WRITE,
               write_barriers: 0,
               queue: VkQueue 0x555555b41130[],
               submit: 88,
               batch: 0,
               batch_tag: 663,
               command: vkCmdEndRenderingKHR,
               command_buffer: VkCommandBuffer 0x555558313000[],
               seq_no: 11,
               reset_no: 28).

[17:01:00.289][8314]: Swapchain image 0x967dd1000000000e: 'Undefined'->'ColorAttachmentOptimal'
[17:01:00.289][8314]: Image 0x2e2941000000001f: 'Undefined'->'DepthAttachmentOptimal'

第一行和最后两行是我自己的日志记录,而“中间两行”是分解的验证消息。看起来好像有一些格式上的废话,但我保留了丢失的信息,并尽可能与我的格式保持一致。

无论如何,在我提交其中包含转换管道屏障的命令缓冲区后,我收到了读后写错误。这是实际控制何时创建障碍的代码。就在我调用

beginRenderingKHR()
之前,我转换了交换链图像和深度缓冲区:

auto &color_buffer = *Renderer::swapchain().images()[Renderer::image_index()];
color_buffer.transition_layout(Renderer::cmd_buffer(),
                               vk::ImageLayout::eUndefined,
                               vk::ImageLayout::eColorAttachmentOptimal);

_depth_buffer.transition_layout(Renderer::cmd_buffer(),
                                vk::ImageLayout::eUndefined,
                                vk::ImageLayout::eDepthAttachmentOptimal);

然后,就在之后调用

endRenderingKHR()
我转换颜色缓冲区:

auto &color_buffer = *Renderer::swapchain().images()[Renderer::image_index()];
color_buffer.transition_layout(Renderer::cmd_buffer(),
                               vk::ImageLayout::eColorAttachmentOptimal,
                               vk::ImageLayout::ePresentSrcKHR);

这是图像转换代码(

vkSwapchainImage
不适用于深度缓冲区,但逻辑是相同的):

void vkSwapchainImage::transition_layout(vkCmdBuffer const &cmd_buffer,
                                         vk::ImageLayout const old_layout,
                                         vk::ImageLayout const new_layout)
{
    BTX_TRACE("Swapchain image {}: '{:s}'->'{:s}'",
              _handle,
              vk::to_string(old_layout),
              vk::to_string(new_layout));

    vk::ImageMemoryBarrier barrier {
        .srcAccessMask = { },
        .dstAccessMask = { },
        .oldLayout = old_layout,
        .newLayout = new_layout,
        .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
        .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
        .image = _handle,
        .subresourceRange {
            .aspectMask     = vk::ImageAspectFlagBits::eColor,
            .baseMipLevel   = 0u,
            .levelCount     = 1u,
            .baseArrayLayer = 0u,
            .layerCount     = 1u,
        }
    };

    vk::PipelineStageFlags src_stage = vk::PipelineStageFlagBits::eNone;
    vk::PipelineStageFlags dst_stage = vk::PipelineStageFlagBits::eNone;

    if(old_layout == vk::ImageLayout::eUndefined) {
        barrier.srcAccessMask = vk::AccessFlagBits::eNone;

        if(new_layout == vk::ImageLayout::eColorAttachmentOptimal) {
            barrier.dstAccessMask = vk::AccessFlagBits::eColorAttachmentRead
                                    | vk::AccessFlagBits::eColorAttachmentWrite;

            src_stage = vk::PipelineStageFlagBits::eTopOfPipe;
            dst_stage = vk::PipelineStageFlagBits::eColorAttachmentOutput;
        }
        else if(new_layout == vk::ImageLayout::eDepthAttachmentOptimal) {
            barrier.dstAccessMask =
                vk::AccessFlagBits::eDepthStencilAttachmentRead
                | vk::AccessFlagBits::eDepthStencilAttachmentWrite;

            src_stage = vk::PipelineStageFlagBits::eTopOfPipe;
            dst_stage = vk::PipelineStageFlagBits::eEarlyFragmentTests
                        | vk::PipelineStageFlagBits::eLateFragmentTests;
        }
        else {
            BTX_CRITICAL("Unsupported image layout transition");
            return;
        }
    }
    else if(old_layout == vk::ImageLayout::eColorAttachmentOptimal) {
        barrier.srcAccessMask = vk::AccessFlagBits::eColorAttachmentRead
                                | vk::AccessFlagBits::eColorAttachmentWrite;

        barrier.dstAccessMask = vk::AccessFlagBits::eNone;

        src_stage = vk::PipelineStageFlagBits::eColorAttachmentOutput;
        dst_stage = vk::PipelineStageFlagBits::eBottomOfPipe;
    }
    else {
        BTX_CRITICAL("Unsupported image layout transition");
        return;
    }

    cmd_buffer.native().pipelineBarrier(
        src_stage,  // Source stage
        dst_stage,  // Destination stage
        { },        // Dependency flags
        nullptr,    // Memory barriers
        nullptr,    // Buffer memory barriers
        { barrier } // Image memory barriers
    );

    _layout = barrier.newLayout;
}

我努力从官方动态渲染示例代码中准确复制图像转换,它们在 Windows/AMD 上看起来很好,但我当然想了解哪些内容不完整或有什么问题。

当然,任何能够更好地处理图像过渡的结构改进都将受到欢迎。 =)

c++ linux nvidia vulkan
1个回答
0
投票

对于交换链图像,您可能不会等待它准备好(其获取完成)。 使用栅栏在 CPU 端等待或使用带有

VkSubmitInfo::pWaitSemaphores
的信号量。

对于深度图像:

VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT
在第一个同步范围(
src_stage
)中指定时不指定执行阶段。 即,您没有告诉 GPU 确保其先前的使用已完成并且缓存已刷新/无效。

您可能还需要

VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT
来代替
src_stage
,并带有适当的
VkAccessFlagBits

© www.soinside.com 2019 - 2024. All rights reserved.