过去几周我一直在与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;
}
Run Code Online (Sandbox Code Playgroud)
如果有人想要更多关于代码的信息,请随时提出,我会提供.这个项目有很多行代码,所以我不希望每个人都需要通过这一切.如果您愿意,可以在http://github.com/thirddegree/HatchitGraphics/tree/dev找到所有代码.
编辑:经过更多的探索后,我发现即使颜色也没有真正清晰.RenderDoc显示每个帧仅渲染猛禽的剪切,并且不会清除帧的其余部分.这是司机问题吗?
编辑:更多信息.我发现如果我绘制NOTHING,只是开始和结束渲染通道甚至不绘制我的全屏三角形,屏幕将清除.但是,如果我只绘制三角形,则深度是错误的(即使我不从屏幕外显示任何内容或应用任何类型的纹理).
编辑:更具体地说,颜色会清晰但深度不会.如果我不画任何东西,深度将保持黑色; 全0.为什么全屏三角形导致奇怪的深度静态我不确定.
Sas*_*ems 10
这正是我开始让我的Vulkan示例在AMD硬件上工作时发生的事情:
他们的GPU严重依赖于正确的图像转换(例如NVIDIA大多忽略了这些转换),我认为您在屏幕截图中看到的损坏是由于缺少预先存在的屏障.
预先存在的屏障(请参见此处)将颜色附件的图像布局转换为演示文稿格式,以便将其呈现给交换链.
完成渲染到颜色附件后必须完成此操作,以确保在显示附件之前完成附件.
您可以在我的示例的绘图例程中看到这样的示例.
在渲染下一帧时,您需要将颜色附件的图像格式转换回来,以便能够再次渲染它.
把它们加起来:
在渲染到您的颜色附件之前,将图像转换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
并呈现给交换链
感谢Sascha和新的1.0.5 LunarG SDK出现的一些额外错误,我设法解决了这个问题.可以在这里找到修复更改的提交(以及其他一些小事):https://github.com/thirddegree/HatchitGraphics/commit/515d0303f45a8e9c00f67a74c824530ea37b687a
这是几件事的组合:
我需要在swapchain的framebuffer附件上设置深度图像,VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT
而不是仅仅VK_IMAGE_ASPECT_DEPTH_BIT
对于几乎每一个图像内存屏障,我忘了specifiy了baseArrayLayer
的subresourceRange
.在版本1.0.5之前,这不会产生错误.
在1.0.5之前没有出现的另一个错误可能会帮助你跟踪类似的bug并影响我的纹理生成是在我将设备内存映射到纹理到主机内存之前我需要将其转换VK_IMAGE_LAYOUT_UNDEFINED
为VK_IMAGE_LAYOUT_GENERAL
,提交该命令映射内存,然后将其从GENERAL转换为VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
(不要忘记提交该命令).同样,这仅适用于您想要采样的纹理,但我猜这里的道德是"实际提交您的图像过渡"