1
0
mirror of https://github.com/doitsujin/dxvk.git synced 2025-02-20 10:54:16 +01:00

[dxvk] Do not clear read-only aspects inside render pass

Instead, end the render pass as necessary and clear outside of it.
May fix validation errors in some very rare scenarios where the game
performs a clear and then uses a read-only depth-stencil view.
This commit is contained in:
Philip Rebohle 2021-03-17 19:32:22 +01:00
parent f48e3f596f
commit b9360bacc2
No known key found for this signature in database
GPG Key ID: C8CC613427A31C99
4 changed files with 66 additions and 1 deletions

View File

@ -567,7 +567,7 @@ namespace dxvk {
// If not, we need to create a temporary framebuffer.
int32_t attachmentIndex = -1;
if (m_flags.test(DxvkContextFlag::GpRenderPassBound)
if (m_state.om.framebuffer != nullptr
&& m_state.om.framebuffer->isFullSize(imageView))
attachmentIndex = m_state.om.framebuffer->findAttachment(imageView);
@ -580,6 +580,9 @@ namespace dxvk {
// If there is overlap, we need to explicitly transition affected attachments.
this->spillRenderPass(true);
this->prepareImage(m_execBarriers, imageView->image(), imageView->subresources(), false);
} else if (!m_state.om.framebuffer->isWritable(attachmentIndex, clearAspects)) {
// We cannot inline clears if the clear aspects are not writable
this->spillRenderPass(true);
}
if (m_flags.test(DxvkContextFlag::GpRenderPassBound))
@ -1757,6 +1760,28 @@ namespace dxvk {
else if (discardAspects & VK_IMAGE_ASPECT_DEPTH_BIT)
depthOp.loadOpS = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
if (!m_flags.test(DxvkContextFlag::GpRenderPassBound) && (attachmentIndex >= 0)) {
// Do not fold the clear/discard into the render pass if any of the affected aspects
// isn't writable. We can only hit this particular path when starting a render pass,
// so we can safely manipulate load layouts here.
if (!m_state.om.framebuffer->isWritable(attachmentIndex, clearAspects | discardAspects)) {
int32_t colorIndex = m_state.om.framebuffer->getColorAttachmentIndex(attachmentIndex);
VkImageLayout renderLayout = m_state.om.framebuffer->getAttachment(attachmentIndex).layout;
if (colorIndex < 0) {
depthOp.loadLayout = m_state.om.renderPassOps.depthOps.loadLayout;
depthOp.storeLayout = renderLayout;
m_state.om.renderPassOps.depthOps.loadLayout = renderLayout;
} else {
colorOp.loadLayout = m_state.om.renderPassOps.colorOps[colorIndex].loadLayout;
colorOp.storeLayout = renderLayout;
m_state.om.renderPassOps.colorOps[colorIndex].loadLayout = renderLayout;
}
attachmentIndex = -1;
}
}
bool is3D = imageView->imageInfo().type == VK_IMAGE_TYPE_3D;
if ((clearAspects | discardAspects) == imageView->info().aspect && !is3D) {
@ -2718,6 +2743,9 @@ namespace dxvk {
&& m_state.om.framebuffer->isFullSize(imageView))
attachmentIndex = m_state.om.framebuffer->findAttachment(imageView);
if (attachmentIndex >= 0 && !m_state.om.framebuffer->isWritable(attachmentIndex, aspect))
attachmentIndex = -1;
if (attachmentIndex < 0) {
this->spillRenderPass(false);

View File

@ -78,6 +78,12 @@ namespace dxvk {
}
bool DxvkFramebuffer::isWritable(uint32_t attachmentIndex, VkImageAspectFlags aspects) const {
VkImageAspectFlags writableAspects = vk::getWritableAspectsForLayout(getAttachment(attachmentIndex).layout);
return (writableAspects & aspects) == aspects;
}
DxvkRenderPassFormat DxvkFramebuffer::getRenderPassFormat(const DxvkRenderTargets& renderTargets) {
DxvkRenderPassFormat format;

View File

@ -207,6 +207,16 @@ namespace dxvk {
* the framebuffer.
*/
bool isFullSize(const Rc<DxvkImageView>& view) const;
/**
* \brief Checks whether an attachment is writable
*
* Needed for certain clear optimizations.
* \param [in] attachmentIndex Attachment to check
* \param [in] aspects Aspect mask to check
* \returns \c true if all aspects can be written for the given attachment
*/
bool isWritable(uint32_t attachmentIndex, VkImageAspectFlags aspects) const;
/**
* \brief Generatess render pass format

View File

@ -76,6 +76,27 @@ namespace dxvk::vk {
&& a.baseArrayLayer + a.layerCount >= b.baseArrayLayer + b.layerCount;
}
inline VkImageAspectFlags getWritableAspectsForLayout(VkImageLayout layout) {
switch (layout) {
case VK_IMAGE_LAYOUT_GENERAL:
return VK_IMAGE_ASPECT_COLOR_BIT | VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:
return VK_IMAGE_ASPECT_COLOR_BIT;
case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL:
return VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
case VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL:
return VK_IMAGE_ASPECT_DEPTH_BIT;
case VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL:
return VK_IMAGE_ASPECT_STENCIL_BIT;
case VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL:
case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
return 0;
default:
Logger::err(str::format("Unhandled image layout ", layout));
return 0;
}
}
}