过去几周我一直在与Vulkan合作,我遇到的问题只发生在AMD卡上。特别是AMD 7970M。我在GTX 700和900系列卡上运行我的项目没有问题。我甚至在Windows上运行了一个带有Nvidia卡的Linux(Steam OS)。问题只出现在AMD卡上,只出现在我的项目中;来自Sascha Willems的所有样本和项目都没有问题。
现在我正在绘制纹理Raptor模型并将其旋转到位。我将其渲染到纹理,然后将该纹理应用于全屏三角形;基本的屏幕外渲染。但是我的7970M上的深度似乎没有正确清晰。相反,我得到了这种奇怪的伪像,就像深度没有被正确清除一样:
当然我尝试用RenderDoc挖掘它,深度是完全错误的。 Raptor和Fullscreen Triangle都只是一团糟:
我尝试将我的代码与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显示每个帧仅渲染猛禽的剪切,并且不会清除帧的其余部分。这是司机问题吗?
编辑:更多信息。我发现如果我绘制NOTHING,只是开始和结束渲染通道甚至不绘制我的全屏三角形,屏幕将清除。但是,如果我只绘制三角形,则深度是错误的(即使我不从屏幕外显示任何内容或应用任何类型的纹理)。
编辑:更具体地说,颜色会清晰但深度不会。如果我不画任何东西,深度将保持黑色;全0。为什么全屏三角形会导致奇怪的深度静态,我不确定。
答案 0 :(得分:10)
当我开始让我的Vulkan示例在AMD硬件上工作时,这正是我发生的事情:
他们的GPU在很大程度上依赖于正确的图像转换(例如NVIDIA大多忽略了这种转换),我认为您在屏幕截图中看到的损坏是由于缺少预先存在的障碍而导致的。
预先存在的障碍(请参阅here)将颜色附件的图像布局转换为演示文稿格式,以便将其呈现给交换链。
必须在完成渲染到颜色附件后完成此操作,以确保在显示附件之前完成附件。
您可以在我的示例的draw routine中看到此示例。
在渲染下一帧时,您需要将颜色附件的图像格式转换回来,以便能够再次渲染它。
总结一下:
在渲染到您的颜色附件之前,将您的图片从VK_IMAGE_LAYOUT_PRESENT_SRC_KHR
转换为VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
(又名“post present”)
进行渲染
将您的颜色附件图片从VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
转换为VK_IMAGE_LAYOUT_PRESENT_SRC_KHR
并将其呈现给交换链
答案 1 :(得分: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
的{{1}}。在版本1.0.5之前,这不会产生错误。
在1.0.5之前没有弹出的另一个错误可能会帮助你跟踪类似的错误并影响我的纹理生成是在我将纹理的设备内存映射到主机内存之前我需要从{{{ 1}}到subresourceRange
,提交该命令,映射内存,然后将其从GENERAL转换为VK_IMAGE_LAYOUT_UNDEFINED
(不要忘记提交该命令)。同样,这仅适用于您想要采样的纹理,但我想这里的道德是“实际上提交您的图像过渡”