1
0
mirror of https://github.com/doitsujin/dxvk.git synced 2025-02-24 13:54:17 +01:00

[dxvk] Ignore uninitialized image subresources during relocation

This commit is contained in:
Philip Rebohle 2024-10-17 21:10:45 +02:00
parent de4de00e04
commit e5482a2405

View File

@ -6271,6 +6271,26 @@ namespace dxvk {
const auto& info = imageInfos[i];
auto oldStorage = info.image->storage();
// The source image may only be partially initialized. Ignore any subresources
// that aren't, but try to do process as much in one go as possible.
VkImageSubresourceRange availableSubresources = info.image->getAvailableSubresources();
uint32_t mipStep = info.image->isInitialized(availableSubresources)
? availableSubresources.levelCount : 1u;
for (uint32_t m = 0; m < availableSubresources.levelCount; m += mipStep) {
VkImageSubresourceRange subresourceRange = availableSubresources;
subresourceRange.baseMipLevel = m;
subresourceRange.levelCount = mipStep;
uint32_t layerStep = info.image->isInitialized(subresourceRange)
? availableSubresources.layerCount : 1u;
for (uint32_t l = 0; l < availableSubresources.layerCount; l += layerStep) {
subresourceRange.baseArrayLayer = l;
subresourceRange.layerCount = layerStep;
if (info.image->isInitialized(subresourceRange)) {
VkImageMemoryBarrier2 dstBarrier = { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2 };
dstBarrier.srcStageMask = info.image->info().stages;
dstBarrier.srcAccessMask = info.image->info().access;
@ -6281,7 +6301,7 @@ namespace dxvk {
dstBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
dstBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
dstBarrier.image = info.storage->getImageInfo().image;
dstBarrier.subresourceRange = info.image->getAvailableSubresources();
dstBarrier.subresourceRange = subresourceRange;
VkImageMemoryBarrier2 srcBarrier = { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2 };
srcBarrier.srcStageMask = info.image->info().stages;
@ -6293,11 +6313,14 @@ namespace dxvk {
srcBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
srcBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
srcBarrier.image = oldStorage->getImageInfo().image;
srcBarrier.subresourceRange = info.image->getAvailableSubresources();
srcBarrier.subresourceRange = subresourceRange;
imageBarriers.push_back(dstBarrier);
imageBarriers.push_back(srcBarrier);
}
}
}
}
// Submit all pending barriers in one go
VkDependencyInfo depInfo = { VK_STRUCTURE_TYPE_DEPENDENCY_INFO };
@ -6349,6 +6372,8 @@ namespace dxvk {
DxvkResourceImageInfo dstInfo = info.storage->getImageInfo();
DxvkResourceImageInfo srcInfo = oldStorage->getImageInfo();
VkImageSubresourceRange availableSubresources = info.image->getAvailableSubresources();
// Iterate over all subresources and compute copy regions. We need
// one region per mip or plane, so size the local array accordingly.
small_vector<VkImageCopy2, 16> imageRegions;
@ -6362,11 +6387,23 @@ namespace dxvk {
for (uint32_t p = 0; p < planeCount; p++) {
for (uint32_t m = 0; m < info.image->info().mipLevels; m++) {
VkImageSubresourceRange subresourceRange = availableSubresources;
subresourceRange.baseMipLevel = m;
subresourceRange.levelCount = 1u;
uint32_t layerStep = info.image->isInitialized(subresourceRange)
? subresourceRange.layerCount : 1u;
for (uint32_t l = 0; l < subresourceRange.layerCount; l += layerStep) {
subresourceRange.baseArrayLayer = l;
subresourceRange.layerCount = layerStep;
if (info.image->isInitialized(subresourceRange)) {
VkImageCopy2 region = { VK_STRUCTURE_TYPE_IMAGE_COPY_2 };
region.dstSubresource.aspectMask = formatInfo->aspectMask;
region.dstSubresource.mipLevel = m;
region.dstSubresource.baseArrayLayer = 0;
region.dstSubresource.layerCount = info.image->info().numLayers;
region.dstSubresource.baseArrayLayer = l;
region.dstSubresource.layerCount = layerStep;
region.srcSubresource = region.dstSubresource;
region.extent = info.image->mipLevelExtent(m);
@ -6379,6 +6416,25 @@ namespace dxvk {
}
imageRegions.push_back(region);
// Emit image barrier for this region. We could in theory transition the
// entire image in one go as long as all subresources are initialized,
// but there is usually no reason to do so.
VkImageMemoryBarrier2 dstBarrier = { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2 };
dstBarrier.srcStageMask = info.image->info().stages;
dstBarrier.srcAccessMask = info.image->info().access;
dstBarrier.dstStageMask = info.image->info().stages;
dstBarrier.dstAccessMask = info.image->info().access;
dstBarrier.oldLayout = info.image->pickLayout(VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
dstBarrier.newLayout = info.image->info().layout;
dstBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
dstBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
dstBarrier.image = info.storage->getImageInfo().image;
dstBarrier.subresourceRange = vk::makeSubresourceRange(region.dstSubresource),
imageBarriers.push_back(dstBarrier);
}
}
}
}
@ -6393,22 +6449,7 @@ namespace dxvk {
m_cmd->cmdCopyImage(DxvkCmdBuffer::ExecBuffer, &copy);
m_cmd->track(info.image, DxvkAccess::Write);
// Invalidate image and emit post-copy barrier to use the correct layout
invalidateImageWithUsage(info.image, Rc<DxvkResourceAllocation>(info.storage), info.usageInfo);
VkImageMemoryBarrier2 dstBarrier = { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2 };
dstBarrier.srcStageMask = info.image->info().stages;
dstBarrier.srcAccessMask = info.image->info().access;
dstBarrier.dstStageMask = info.image->info().stages;
dstBarrier.dstAccessMask = info.image->info().access;
dstBarrier.oldLayout = info.image->pickLayout(VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
dstBarrier.newLayout = info.image->info().layout;
dstBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
dstBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
dstBarrier.image = info.storage->getImageInfo().image;
dstBarrier.subresourceRange = info.image->getAvailableSubresources();
imageBarriers.push_back(dstBarrier);
}
// Submit post-copy barriers