mirror of
https://github.com/doitsujin/dxvk.git
synced 2025-02-21 13:54:18 +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:
parent
8a4beefd3a
commit
95740eb78c
@ -766,6 +766,10 @@ namespace dxvk {
|
|||||||
VkOffset3D srcOffset,
|
VkOffset3D srcOffset,
|
||||||
VkExtent3D extent) {
|
VkExtent3D extent) {
|
||||||
this->spillRenderPass(true);
|
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, dstImage, vk::makeSubresourceRange(dstSubresource));
|
||||||
this->prepareImage(m_execBarriers, srcImage, vk::makeSubresourceRange(srcSubresource));
|
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(
|
void DxvkContext::resolveImageHw(
|
||||||
const Rc<DxvkImage>& dstImage,
|
const Rc<DxvkImage>& dstImage,
|
||||||
const Rc<DxvkImage>& srcImage,
|
const Rc<DxvkImage>& srcImage,
|
||||||
|
@ -1067,6 +1067,14 @@ namespace dxvk {
|
|||||||
VkOffset3D srcOffset,
|
VkOffset3D srcOffset,
|
||||||
VkExtent3D extent);
|
VkExtent3D extent);
|
||||||
|
|
||||||
|
bool copyImageClear(
|
||||||
|
const Rc<DxvkImage>& dstImage,
|
||||||
|
VkImageSubresourceLayers dstSubresource,
|
||||||
|
VkOffset3D dstOffset,
|
||||||
|
VkExtent3D dstExtent,
|
||||||
|
const Rc<DxvkImage>& srcImage,
|
||||||
|
VkImageSubresourceLayers srcSubresource);
|
||||||
|
|
||||||
void resolveImageHw(
|
void resolveImageHw(
|
||||||
const Rc<DxvkImage>& dstImage,
|
const Rc<DxvkImage>& dstImage,
|
||||||
const Rc<DxvkImage>& srcImage,
|
const Rc<DxvkImage>& srcImage,
|
||||||
|
@ -67,6 +67,15 @@ namespace dxvk::vk {
|
|||||||
&& a.baseArrayLayer + a.layerCount > b.baseArrayLayer;
|
&& 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;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user