Vulkan无法清除深度缓冲区

16

我最近几周一直在使用Vulkan,但遇到了一个问题,只有在AMD显卡上才会出现。具体来说是AMD 7970M。我已经在GTX 700和900系列的显卡上运行过我的项目,并且没有出现任何问题。我甚至在Windows和Linux(Steam OS)上使用Nvidia显卡运行也没有任何问题。问题只在AMD显卡上以及我的项目中出现;所有来自Sascha Willems的示例和项目都能正常运行。

现在我正在绘制一个带纹理的Raptor模型并将其旋转在原地。然后我将其呈现到一个纹理上,再将该纹理应用于全屏三角形;基本上是屏幕外渲染。但是在我的7970M上深度似乎无法正确清除。相反,出现了这种奇怪的伪影,就像深度没有被正确地清除:

Bad Raptor

当然,我尝试使用RenderDoc进行调试,发现深度完全错误。无论是Raptor还是绘制到上面的全屏三角形都是一团糟:

Bad Depth

Bad Tri Depth

我尝试将我的代码与Sascha Willems的屏幕外示例进行比较,发现我几乎以相同的方式处理。我认为可能是我创建深度的方式有问题,但与我看到的所有示例相比,它似乎没有问题。

这里是我创建深度图像和视图的一些调试视图:

image info image view info

这是整个方法:

        bool VKRenderTarget::setupFramebuffer(VKRenderer* renderer) 
            {
                VkDevice device = renderer->GetVKDevice();
                VkCommandBuffer setupCommand;

                m_colorFormat = renderer->GetPreferredImageFormat();
                m_depthFormat = renderer->GetPreferredDepthFormat();

                renderer->CreateSetupCommandBuffer();

                setupCommand = renderer->GetSetupCommandBuffer();

                VkResult err;

                //Color attachment
                VkImageCreateInfo imageInfo = {};
                imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
                imageInfo.pNext = nullptr;
                imageInfo.format = m_colorFormat;
                imageInfo.imageType = VK_IMAGE_TYPE_2D;
                imageInfo.extent.width = m_width;
                imageInfo.extent.height = m_height;
                imageInfo.mipLevels = 1;
                imageInfo.arrayLayers = 1;
                imageInfo.samples = VK_SAMPLE_COUNT_1_BIT;
                imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
                imageInfo.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
                imageInfo.flags = 0;

                VkMemoryAllocateInfo memAllocInfo = {};
                memAllocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;

                VkMemoryRequirements memReqs;

                err = vkCreateImage(device, &imageInfo, nullptr, &m_color.image);
                assert(!err);
                if (err != VK_SUCCESS)
                {
#ifdef _DEBUG
                    Core::DebugPrintF("VKRenderTarget::VPrepare(): Error creating color image!\n");
#endif
                    return false;
                }

                vkGetImageMemoryRequirements(device, m_color.image, &memReqs);
                memAllocInfo.allocationSize = memReqs.size;
                renderer->MemoryTypeFromProperties(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &memAllocInfo.memoryTypeIndex);

                err = vkAllocateMemory(device, &memAllocInfo, nullptr, &m_color.memory);
                assert(!err);
                if (err != VK_SUCCESS)
                {
#ifdef _DEBUG
                    Core::DebugPrintF("VKRenderTarget::VPrepare(): Error allocating color image memory!\n");
#endif
                    return false;
                }

                err = vkBindImageMemory(device, m_color.image, m_color.memory, 0);
                if (err != VK_SUCCESS)
                {
#ifdef _DEBUG
                    Core::DebugPrintF("VKRenderTarget::VPrepare(): Error binding color image memory!\n");
#endif
                    return false;
                }

                renderer->SetImageLayout(setupCommand, m_color.image, VK_IMAGE_ASPECT_COLOR_BIT,
                    VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);

                VkImageViewCreateInfo viewInfo = {};
                viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
                viewInfo.pNext = nullptr;
                viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
                viewInfo.format = m_colorFormat;
                viewInfo.flags = 0;
                viewInfo.subresourceRange = {};
                viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
                viewInfo.subresourceRange.baseMipLevel = 0;
                viewInfo.subresourceRange.levelCount = 1;
                viewInfo.subresourceRange.baseArrayLayer = 0;
                viewInfo.subresourceRange.layerCount = 1;
                viewInfo.image = m_color.image;

                err = vkCreateImageView(device, &viewInfo, nullptr, &m_color.view);
                if (err != VK_SUCCESS)
                {
#ifdef _DEBUG
                    Core::DebugPrintF("VKRenderTarget::VPrepare(): Error creating color image view!\n");
#endif
                    return false;
                }

                //We can reuse the same info structs to build the depth image
                imageInfo.format = m_depthFormat;
                imageInfo.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;

                err = vkCreateImage(device, &imageInfo, nullptr, &(m_depth.image));

                assert(!err);
                if (err != VK_SUCCESS)
                {
#ifdef _DEBUG
                    Core::DebugPrintF("VKRenderTarget::VPrepare(): Error creating depth image!\n");
#endif
                    return false;
                }

                viewInfo.format = m_depthFormat;
                viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;

                vkGetImageMemoryRequirements(device, m_depth.image, &memReqs);
                memAllocInfo.allocationSize = memReqs.size;
                renderer->MemoryTypeFromProperties(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &memAllocInfo.memoryTypeIndex);

                err = vkAllocateMemory(device, &memAllocInfo, nullptr, &m_depth.memory);
                assert(!err);
                if (err != VK_SUCCESS)
                {
#ifdef _DEBUG
                    Core::DebugPrintF("VKRenderTarget::VPrepare(): Error allocating depth image memory!\n");
#endif
                    return false;
                }

                err = vkBindImageMemory(device, m_depth.image, m_depth.memory, 0);
                if (err != VK_SUCCESS)
                {
#ifdef _DEBUG
                    Core::DebugPrintF("VKRenderTarget::VPrepare(): Error binding depth image memory!\n");
#endif
                    return false;
                }

                renderer->SetImageLayout(setupCommand, m_depth.image,
                    VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT,
                    VK_IMAGE_LAYOUT_UNDEFINED,
                    VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);

                viewInfo.image = m_depth.image;

                err = vkCreateImageView(device, &viewInfo, nullptr, &m_depth.view);
                if (err != VK_SUCCESS)
                {
#ifdef _DEBUG
                    Core::DebugPrintF("VKRenderTarget::VPrepare(): Error creating depth image view!\n");
#endif
                    return false;
                }

                renderer->FlushSetupCommandBuffer();

                //Finally create internal framebuffer
                VkImageView attachments[2];
                attachments[0] = m_color.view;
                attachments[1] = m_depth.view;

                VkFramebufferCreateInfo framebufferInfo = {};
                framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
                framebufferInfo.pNext = nullptr;
                framebufferInfo.flags = 0;
                framebufferInfo.renderPass = *((VKRenderPass*)m_renderPass)->GetVkRenderPass();
                framebufferInfo.attachmentCount = 2;
                framebufferInfo.pAttachments = attachments;
                framebufferInfo.width = m_width;
                framebufferInfo.height = m_height;
                framebufferInfo.layers = 1;

                err = vkCreateFramebuffer(device, &framebufferInfo, nullptr, &m_framebuffer);
                if (err != VK_SUCCESS)
                {
#ifdef _DEBUG
                    Core::DebugPrintF("VKRenderTarget::VPrepare(): Error creating framebuffer!\n");
#endif
                    return false;
                }

                return true;
            }

如果有人想要了解代码的更多信息,可以随时询问,我会提供。这个项目有很多行代码,所以我不希望每个人都要浏览所有代码。然而,如果您愿意,所有的代码都可以在http://github.com/thirddegree/HatchitGraphics/tree/dev找到。

编辑:经过再次探索,我发现颜色甚至不能正确清除。RenderDoc显示每一帧只渲染了迅猛龙的剪影,并没有清除其他区域的框架。这是驱动程序的问题吗?

编辑:更多信息。我发现如果什么都不画,只是开始和结束渲染,甚至不画全屏三角形,屏幕就会被清除。然而,如果我只画三角形,深度是错误的(即使我不从离屏绘制任何东西或应用任何纹理)。

编辑:更具体地说,颜色将被清除,但深度不会。如果什么都不画,深度将保持黑色;全部为0。为什么全屏三角形会导致深度的奇怪静态我不确定。

2个回答

12

当我开始让我的Vulkan示例在AMD硬件上正常工作时,就发生了这样的情况:

enter image description here

他们的GPU在正确的图像转换方面非常依赖(这在例如NVIDIA中大多被忽略),我认为你屏幕截图中看到的损坏是缺少预呈现屏障的结果。
预呈现屏障(参见此处)将您的颜色附件的图像布局转换为呈现格式,以便将其传递给交换链进行呈现。
这必须在完成对颜色附件的渲染之后完成,以确保在呈现之前完成附件。
您可以在我的示例的绘制例程中看到这个例子。
在渲染下一帧时,您需要将颜色附件的图像格式转换回来,以便能够再次渲染它。
总之:
  • 在渲染到你的颜色附件之前,将图像从VK_IMAGE_LAYOUT_PRESENT_SRC_KHR转换为VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL(也称为“呈现后”)

  • 进行渲染

  • 将您的颜色附件图像从VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL转换为VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,并将其呈现给交换链


这应该针对深度和颜色附件都进行吗? - Honeybunch
1
颜色附件应该足够了。如果您仍然看到损坏,即使有现有的屏障,请检查附件的存储和加载操作是否正确。 - Sascha Willems
对于这个问题的回复稍晚了,抱歉。我非常确定我的加载和存储操作是正确的。我并不认为前置和后置屏障是问题所在。我在我的引擎中实现它们的方式与你在示例中设置的方式非常相似,并没有对图像产生任何影响。事实上,在写这篇文章时,我想我刚刚解决了这个问题,只是忘记提交图像转换命令。 - Honeybunch
@SaschaWillems,你的绘制程序链接已经失效。我建议不要将如此关键的资源放在Git链接后面,如果可能的话,请提取相关片段并直接发布到SO上,并提供指向你自己示例的链接。 - Krupip

6
感谢Sascha的帮助和新1.0.5 LunarG SDK出现的额外错误,我已经成功解决了问题。包含修复更改(以及几个其他小事)的提交可在此处找到:https://github.com/thirddegree/HatchitGraphics/commit/515d0303f45a8e9c00f67a74c824530ea37b687a 这是几件事的结合: - 我需要将swapchain的深度图像设置为VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT而不仅仅是VK_IMAGE_ASPECT_DEPTH_BIT - 对于几乎每个图像内存屏障,我忘记了specifiy的subresourceRange的baseArrayLayer。直到版本1.0.5才会产生错误。 - 另一个直到1.0.5才会弹出的错误可能有助于您跟踪类似的错误,并影响我的纹理生成,即在将设备内存映射到主机内存之前,我需要将其从VK_IMAGE_LAYOUT_UNDEFINED转换为VK_IMAGE_LAYOUT_GENERAL,提交该命令,映射内存,然后将其从GENERAL转换为VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL(别忘了提交该命令)。同样,这仅适用于要采样的纹理,但我想这里的道德是“实际提交您的图像转换”。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接