diff --git a/src/dxvk/dxvk_context.cpp b/src/dxvk/dxvk_context.cpp index 9323d5932..9977bb1a3 100644 --- a/src/dxvk/dxvk_context.cpp +++ b/src/dxvk/dxvk_context.cpp @@ -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, ©Info); } - 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);