1
0
mirror of https://github.com/doitsujin/dxvk.git synced 2025-03-23 18:19:41 +01:00

[dxvk] Fix image to image copies between overlapping subresources

This was broken for render targets because we would attempt to perform
multiple layout transitions on the same subresources at once.
This commit is contained in:
Philip Rebohle 2025-03-16 23:44:34 +01:00
parent 2ad721b46b
commit c49a151d3c

View File

@ -584,7 +584,8 @@ namespace dxvk {
if (m_device->perfHints().preferFbDepthStencilCopy) {
useFb |= (dstSubresource.aspectMask == (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT))
&& (dstImage->info().usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)
&& (srcImage->info().usage & VK_IMAGE_USAGE_SAMPLED_BIT);
&& (srcImage->info().usage & VK_IMAGE_USAGE_SAMPLED_BIT)
&& (srcImage != dstImage);
}
if (!useFb) {
@ -4199,17 +4200,38 @@ namespace dxvk {
auto dstFormatInfo = dstImage->formatInfo();
// If we copy between disjoint regions of the same image subresources,
// make sure that we only do one single transition to GENERAL.
bool hasOvelap = dstImage == srcImage && vk::checkSubresourceRangeOverlap(dstSubresourceRange, srcSubresourceRange);
VkImageSubresourceRange overlapSubresourceRange = { };
overlapSubresourceRange.aspectMask = srcSubresource.aspectMask | dstSubresource.aspectMask;
overlapSubresourceRange.baseArrayLayer = std::min(srcSubresource.baseArrayLayer, dstSubresource.baseArrayLayer);
overlapSubresourceRange.baseMipLevel = srcSubresource.mipLevel;
overlapSubresourceRange.layerCount = std::max(srcSubresource.baseArrayLayer, dstSubresource.baseArrayLayer)
+ dstSubresource.layerCount - overlapSubresourceRange.baseArrayLayer;
overlapSubresourceRange.levelCount = 1u;
flushPendingAccesses(*dstImage, dstSubresource, dstOffset, extent, DxvkAccess::Write);
flushPendingAccesses(*srcImage, srcSubresource, srcOffset, extent, DxvkAccess::Read);
VkImageLayout dstImageLayout = dstImage->pickLayout(VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
VkImageLayout srcImageLayout = srcImage->pickLayout(VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
VkImageLayout dstImageLayout = VK_IMAGE_LAYOUT_GENERAL;
VkImageLayout srcImageLayout = VK_IMAGE_LAYOUT_GENERAL;
if (hasOvelap) {
addImageLayoutTransition(*dstImage, overlapSubresourceRange, dstImageLayout,
VK_PIPELINE_STAGE_2_TRANSFER_BIT, VK_ACCESS_2_TRANSFER_READ_BIT | VK_ACCESS_2_TRANSFER_WRITE_BIT, false);
} else {
dstImageLayout = dstImage->pickLayout(VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
srcImageLayout = srcImage->pickLayout(VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
addImageLayoutTransition(*dstImage, dstSubresourceRange, dstImageLayout,
VK_PIPELINE_STAGE_2_TRANSFER_BIT, VK_ACCESS_2_TRANSFER_WRITE_BIT,
dstImage->isFullSubresource(dstSubresource, extent));
addImageLayoutTransition(*srcImage, srcSubresourceRange, srcImageLayout,
VK_PIPELINE_STAGE_2_TRANSFER_BIT, VK_ACCESS_2_TRANSFER_READ_BIT, false);
}
addImageLayoutTransition(*dstImage, dstSubresourceRange, dstImageLayout,
VK_PIPELINE_STAGE_2_TRANSFER_BIT, VK_ACCESS_2_TRANSFER_WRITE_BIT,
dstImage->isFullSubresource(dstSubresource, extent));
addImageLayoutTransition(*srcImage, srcSubresourceRange, srcImageLayout,
VK_PIPELINE_STAGE_2_TRANSFER_BIT, VK_ACCESS_2_TRANSFER_READ_BIT, false);
flushImageLayoutTransitions(DxvkCmdBuffer::ExecBuffer);
for (auto aspects = dstSubresource.aspectMask; aspects; ) {
@ -4245,11 +4267,15 @@ namespace dxvk {
m_cmd->cmdCopyImage(DxvkCmdBuffer::ExecBuffer, &copyInfo);
}
accessImageRegion(DxvkCmdBuffer::ExecBuffer, *dstImage, dstSubresource, dstOffset, extent, dstImageLayout,
VK_PIPELINE_STAGE_2_TRANSFER_BIT, VK_ACCESS_2_TRANSFER_WRITE_BIT, DxvkAccessOp::None);
accessImageRegion(DxvkCmdBuffer::ExecBuffer, *srcImage, srcSubresource, srcOffset, extent, srcImageLayout,
VK_PIPELINE_STAGE_2_TRANSFER_BIT, VK_ACCESS_2_TRANSFER_READ_BIT, DxvkAccessOp::None);
if (hasOvelap) {
accessImage(DxvkCmdBuffer::ExecBuffer, *dstImage, overlapSubresourceRange, dstImageLayout,
VK_PIPELINE_STAGE_2_TRANSFER_BIT, VK_ACCESS_2_TRANSFER_WRITE_BIT | VK_ACCESS_2_TRANSFER_READ_BIT, DxvkAccessOp::None);
} else {
accessImageRegion(DxvkCmdBuffer::ExecBuffer, *dstImage, dstSubresource, dstOffset, extent, dstImageLayout,
VK_PIPELINE_STAGE_2_TRANSFER_BIT, VK_ACCESS_2_TRANSFER_WRITE_BIT, DxvkAccessOp::None);
accessImageRegion(DxvkCmdBuffer::ExecBuffer, *srcImage, srcSubresource, srcOffset, extent, srcImageLayout,
VK_PIPELINE_STAGE_2_TRANSFER_BIT, VK_ACCESS_2_TRANSFER_READ_BIT, DxvkAccessOp::None);
}
m_cmd->track(dstImage, DxvkAccess::Write);
m_cmd->track(srcImage, DxvkAccess::Read);