16

在过去的几周里,我一直在与 Vulkan 合作,我遇到了一个只发生在 AMD 卡上的问题。特别是 AMD 7970M。我在 GTX 700 和 900 系列卡上运行我的项目没有问题。我什至在 Windows 上运行了带有 Nvidia 卡的 Linux(Steam OS),没有任何问题。这个问题只出现在 AMD 卡上,而且只出现在我的项目中;Sascha Willems的所有示例和项目都没有问题。

现在我正在绘制一个有纹理的 Raptor 模型并将其旋转到位。我将其渲染为纹理,然后将该纹理应用于全屏三角形;基本的离屏渲染。但是,我的 7970M 上的深度似乎无法正确清除。相反,我得到了这个奇怪的伪影,比如深度没有被正确清除:

坏猛禽

当然,我尝试使用 RenderDoc 进行深入研究,但深度完全错误。猛禽和它所绘制的全屏三角形都是一团糟:

深度不好

坏三深度

我尝试将我的代码与 Sascha Willems 的 Offscreen 示例进行比较,我似乎确实以相同的方式做几乎所有事情。我认为我创建深度的方式可能有问题,但与我见过的所有示例相比,它似乎还不错。

以下是我在哪里创建深度图像和视图的一些调试视图:

图像信息 图像查看信息

这是整个方法:

        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。为什么全屏三角形会导致奇怪的深度静态我不确定。

4

2 回答 2

11

当我开始让我的 Vulkan 示例在 AMD 硬件上运行时,这正是发生在我身上的事情:

在此处输入图像描述

他们的 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并将其呈现给交换链

于 2016-03-17T14:57:03.833 回答
6

感谢 Sascha 和新的 1.0.5 LunarG SDK 出现的一些额外错误,我已经设法解决了这个问题。可以在此处找到带有修复更改(以及其他一些小东西)的提交:https ://github.com/thirddegree/HatchitGraphics/commit/515d0303f45a8e9c00f67a74c824530ea37b687a

这是几件事的结合:

我需要将交换链的帧缓冲区附件上的深度图像设置为,VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT而不仅仅是VK_IMAGE_ASPECT_DEPTH_BIT

对于几乎每个图像内存屏障,我都忘记指定baseArrayLayer. subresourceRange直到版本 1.0.5 才产生错误。

直到 1.0.5 才出现的另一个错误可能会帮助您跟踪类似的错误并影响我的纹理生成,这是在我将纹理的设备内存映射到主机内存之前,我需要将其从 转换VK_IMAGE_LAYOUT_UNDEFINEDVK_IMAGE_LAYOUT_GENERAL,提交该命令,映射内存,然后将其从 GENERAL 转换为VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL(也不要忘记提交该命令)。同样,这仅适用于您想要采样的纹理,但我想这里的寓意是“实际提交您的图像过渡”

于 2016-03-22T18:19:29.700 回答