1
0
mirror of https://github.com/doitsujin/dxvk.git synced 2025-03-28 11:19:21 +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) { if (m_device->perfHints().preferFbDepthStencilCopy) {
useFb |= (dstSubresource.aspectMask == (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) useFb |= (dstSubresource.aspectMask == (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT))
&& (dstImage->info().usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_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) { if (!useFb) {
@ -4199,17 +4200,38 @@ namespace dxvk {
auto dstFormatInfo = dstImage->formatInfo(); 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(*dstImage, dstSubresource, dstOffset, extent, DxvkAccess::Write);
flushPendingAccesses(*srcImage, srcSubresource, srcOffset, extent, DxvkAccess::Read); flushPendingAccesses(*srcImage, srcSubresource, srcOffset, extent, DxvkAccess::Read);
VkImageLayout dstImageLayout = dstImage->pickLayout(VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); VkImageLayout dstImageLayout = VK_IMAGE_LAYOUT_GENERAL;
VkImageLayout srcImageLayout = srcImage->pickLayout(VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); 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); flushImageLayoutTransitions(DxvkCmdBuffer::ExecBuffer);
for (auto aspects = dstSubresource.aspectMask; aspects; ) { for (auto aspects = dstSubresource.aspectMask; aspects; ) {
@ -4245,11 +4267,15 @@ namespace dxvk {
m_cmd->cmdCopyImage(DxvkCmdBuffer::ExecBuffer, &copyInfo); m_cmd->cmdCopyImage(DxvkCmdBuffer::ExecBuffer, &copyInfo);
} }
accessImageRegion(DxvkCmdBuffer::ExecBuffer, *dstImage, dstSubresource, dstOffset, extent, dstImageLayout, if (hasOvelap) {
VK_PIPELINE_STAGE_2_TRANSFER_BIT, VK_ACCESS_2_TRANSFER_WRITE_BIT, DxvkAccessOp::None); 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);
accessImageRegion(DxvkCmdBuffer::ExecBuffer, *srcImage, srcSubresource, srcOffset, extent, srcImageLayout, } else {
VK_PIPELINE_STAGE_2_TRANSFER_BIT, VK_ACCESS_2_TRANSFER_READ_BIT, DxvkAccessOp::None); 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(dstImage, DxvkAccess::Write);
m_cmd->track(srcImage, DxvkAccess::Read); m_cmd->track(srcImage, DxvkAccess::Read);