Vulkan:渲染到屏幕外的帧缓冲区并读取结果时遇到问题

时间:2019-12-12 02:54:31

标签: vulkan

我正在使用 Vulkan Android 编写游戏。对于游戏,我需要将深度缓冲区信息写入离屏帧缓冲区。我最终希望通过CPU读取此深度信息,但现在我将其绘制在四边形上以对其进行调试。我在图像中仅获得1.0的清晰深度值,因此我尝试简化该问题。首先,我决定使用颜色和深度附件,以防仅深度附件出现问题。然后我做了以下事情:

(1)设置一个渲染通道,该渲染通道使用颜色和深度附件并将其分别清除为绿色和{1.0,0},

(2)使用的帧缓冲区不使用交换链图像或普通深度缓冲区,而是专门为此屏幕外帧缓冲区创建的图像,

(3)转换布局,以便可以通过渲染过程将其写入

(4)绘制一个蓝色四边形,它将整个屏幕占据到帧缓冲区中,

(5)结束命令缓冲区,等待图形队列空闲,

(6)转换颜色附件的布局,以便着色器可以读取它,

(7)在不同的命令缓冲区中使用交换链图像开始新的渲染过程,

(8)使用其四边形绘制纹理,四边形是上一次渲染过程(颜色附加)的结果,

(9)结束命令缓冲区并提交到图形队列。

我看到的是一个绿色矩形(第一次渲染过程中的透明颜色),其中有一些蓝色正方形(蓝色是第一次渲染过程中绘制的四边形的颜色)。我希望看到整个屏幕由一个蓝色四边形占据。

我觉得我在某个地方缺少障碍物,篱笆或信号灯。但我不知道在哪里。我在提交每个命令(用于调试)之后在图形队列中等待,我添加了一个信号量,以使每组命令都发出下一组信号来表明已完成操作。因此,人们会认为渲染过程有问题,但是我将此渲染过程用于我的常规绘制操作(在交换链图像中完成并发送到当前队列),没有任何问题。

让我知道您需要查看代码的哪一部分。很长。

我启用了 Vulkan验证层,但没有收到任何投诉。我通过强迫它进行投诉来确保它正在工作。

我在OpenGL中做过同样的事情,而且效果很好。

我的加载和存储操作如下:

    colorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
    colorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
    colorAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
    colorAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;

    depthAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
    depthAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
    depthAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
    depthAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;

对于布局过渡,我在绘制之前对颜色附件图像执行以下过渡:

        vkBeginCommandBuffer(...);
        VkImageMemoryBarrier barrier = {};
        barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
        barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
        barrier.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
        barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
        barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
        barrier.image = colorImage;
        barrier.subresourceRange.baseMipLevel = 0;
        barrier.subresourceRange.levelCount = 1;
        barrier.subresourceRange.baseArrayLayer = 0;
        barrier.subresourceRange.layerCount = 1;
        barrier.srcAccessMask = 0;
        barrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
        sourceStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
        destinationStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;

        vkCmdPipelineBarrier(
                cmdBuffer,
                sourceStage, destinationStage,
                0,
                0, nullptr,
                0, nullptr,
                1, &barrier
        );
        vkEndCommandBuffer(...);
        vkQueueSubmit(...);
        vkQueueWaitIdle(graphicsQueue);

在渲染过程中,我将布局转换为VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,以便可以从着色器读取它。

        colorAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
        colorAttachment.finalLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;

        VkAttachmentReference colorAttachmentRef = {};
        colorAttachmentRef.attachment = 0;
        colorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;

子通道及其依赖项:

        VkSubpassDescription subpass = {};
        subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
        subpass.colorAttachmentCount = 1;
        subpass.pColorAttachments = &colorAttachmentRef;
        subpass.pDepthStencilAttachment = &depthAttachmentRef;

        VkSubpassDependency dependency = {};
        dependency.srcSubpass = VK_SUBPASS_EXTERNAL;
        dependency.dstSubpass = 0;
        dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
        dependency.srcAccessMask = 0;
        dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
        dependency.dstAccessMask =
                VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;

我的最终目标是拥有一个渲染过程,不包含颜色附件,而仅包含深度附件。颜色附件仅用于调试目的。

1 个答案:

答案 0 :(得分:0)

我对这个问题的想法是,这是一个驱动程序错误。该代码可在几台不同的Linux PC和Pixel 4XL android设备上正常工作。我进行了测试,看是否能为已知模型得到正确的结果。如果答案不正确,我将退回到OpenGL。