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

[dxvk] Use clears to impelemnt image copies if possible

Optimizes away a large amount of redundant depth-stencil clear+copy
madness in Final Fantasy XIV for a small performance improvement.
This commit is contained in:
Philip Rebohle 2021-03-06 02:33:39 +01:00
parent 8a4beefd3a
commit 95740eb78c
No known key found for this signature in database
GPG Key ID: C8CC613427A31C99
3 changed files with 88 additions and 0 deletions

View File

@ -766,6 +766,10 @@ namespace dxvk {
VkOffset3D srcOffset,
VkExtent3D extent) {
this->spillRenderPass(true);
if (this->copyImageClear(dstImage, dstSubresource, dstOffset, extent, srcImage, srcSubresource))
return;
this->prepareImage(m_execBarriers, dstImage, vk::makeSubresourceRange(dstSubresource));
this->prepareImage(m_execBarriers, srcImage, vk::makeSubresourceRange(srcSubresource));
@ -3183,6 +3187,73 @@ namespace dxvk {
}
bool DxvkContext::copyImageClear(
const Rc<DxvkImage>& dstImage,
VkImageSubresourceLayers dstSubresource,
VkOffset3D dstOffset,
VkExtent3D dstExtent,
const Rc<DxvkImage>& srcImage,
VkImageSubresourceLayers srcSubresource) {
// If the source image has a pending deferred clear, we can
// implement the copy by clearing the destination image to
// the same clear value.
const VkImageUsageFlags attachmentUsage
= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT
| VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
if (!(dstImage->info().usage & attachmentUsage)
|| !(srcImage->info().usage & attachmentUsage))
return false;
// Ignore 3D images since those are complicated to handle
if (dstImage->info().type == VK_IMAGE_TYPE_3D
|| srcImage->info().type == VK_IMAGE_TYPE_3D)
return false;
// Find a pending clear that overlaps with the source image
const DxvkDeferredClear* clear = nullptr;
for (const auto& entry : m_deferredClears) {
// Entries in the deferred clear array cannot overlap, so
// if we find an entry covering all source subresources,
// it's the only one in the list that does.
if ((entry.imageView->image() == srcImage) && ((srcSubresource.aspectMask & entry.clearAspects) == srcSubresource.aspectMask)
&& (vk::checkSubresourceRangeSuperset(entry.imageView->subresources(), vk::makeSubresourceRange(srcSubresource)))) {
clear = &entry;
break;
}
}
if (!clear)
return false;
// Create a view for the destination image with the general
// properties ofthe source image view used for the clear
DxvkImageViewCreateInfo viewInfo = clear->imageView->info();
viewInfo.type = dstImage->info().type == VK_IMAGE_TYPE_1D
? VK_IMAGE_VIEW_TYPE_1D_ARRAY
: VK_IMAGE_VIEW_TYPE_2D_ARRAY;
viewInfo.minLevel = dstSubresource.mipLevel;
viewInfo.numLevels = 1;
viewInfo.minLayer = dstSubresource.baseArrayLayer;
viewInfo.numLayers = dstSubresource.layerCount;
// That is, if the formats are actually compatible
// so that we can safely use the same clear value
if (!dstImage->isViewCompatible(viewInfo.format))
return false;
// Ignore mismatched size for now, needs more testing since we'd
// need to prepare the image first and then call clearImageViewFb
if (dstImage->mipLevelExtent(dstSubresource.mipLevel) != dstExtent)
return false;
auto view = m_device->createImageView(dstImage, viewInfo);
this->deferClear(view, clear->clearAspects, clear->clearValue);
return true;
}
void DxvkContext::resolveImageHw(
const Rc<DxvkImage>& dstImage,
const Rc<DxvkImage>& srcImage,

View File

@ -1067,6 +1067,14 @@ namespace dxvk {
VkOffset3D srcOffset,
VkExtent3D extent);
bool copyImageClear(
const Rc<DxvkImage>& dstImage,
VkImageSubresourceLayers dstSubresource,
VkOffset3D dstOffset,
VkExtent3D dstExtent,
const Rc<DxvkImage>& srcImage,
VkImageSubresourceLayers srcSubresource);
void resolveImageHw(
const Rc<DxvkImage>& dstImage,
const Rc<DxvkImage>& srcImage,

View File

@ -67,6 +67,15 @@ namespace dxvk::vk {
&& a.baseArrayLayer + a.layerCount > b.baseArrayLayer;
}
inline bool checkSubresourceRangeSuperset(
const VkImageSubresourceRange& a,
const VkImageSubresourceRange& b) {
return a.baseMipLevel <= b.baseMipLevel
&& a.baseMipLevel + a.levelCount >= b.baseMipLevel + b.levelCount
&& a.baseArrayLayer <= b.baseArrayLayer
&& a.baseArrayLayer + a.layerCount >= b.baseArrayLayer + b.layerCount;
}
}