From 4fd4aa1f19ef64b85712a1aa2e8c9759c333fc6e Mon Sep 17 00:00:00 2001 From: Yunchao He Date: Fri, 12 Jun 2020 17:01:41 +0000 Subject: [PATCH] Vulkan: use one barrier if we can for non-pass operations When we do transition barriers for a texture view outside of a pass (say copy, clear, initialization), if the texture view can cover all subresources, and its old usages across all subresources are the same, then we can use one transition barrier. We don't need to use separate barrier per each subresource. This patch can reduce barrier we delivered, and improve performance for particular situations. Bug: dawn:441 Change-Id: I2ae9b39793915553cbaaceacaf58bf87c9ba3bc6 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/23129 Reviewed-by: Corentin Wallez Reviewed-by: Austin Eng Commit-Queue: Yunchao He --- src/dawn_native/vulkan/TextureVk.cpp | 43 +++++++++++++++++++--------- 1 file changed, 30 insertions(+), 13 deletions(-) diff --git a/src/dawn_native/vulkan/TextureVk.cpp b/src/dawn_native/vulkan/TextureVk.cpp index 90a6d958f7..6698ac0ec7 100644 --- a/src/dawn_native/vulkan/TextureVk.cpp +++ b/src/dawn_native/vulkan/TextureVk.cpp @@ -807,22 +807,41 @@ namespace dawn_native { namespace vulkan { const Format& format = GetFormat(); wgpu::TextureUsage allLastUsages = wgpu::TextureUsage::None; + uint32_t subresourceCount = GetSubresourceCount(); // This transitions assume it is a 2D texture ASSERT(GetDimension() == wgpu::TextureDimension::e2D); - for (uint32_t layer = baseArrayLayer; layer < baseArrayLayer + layerCount; ++layer) { - for (uint32_t level = baseMipLevel; level < baseMipLevel + levelCount; ++level) { - uint32_t index = GetSubresourceIndex(level, layer); + // If the usages transitions can cover all subresources, and old usages of all subresources + // are the same, then we can use one barrier to do state transition for all subresources. + // Note that if the texture has only one mip level and one array slice, it will fall into + // this category. + bool isAllSubresourcesCovered = levelCount * layerCount == subresourceCount; + if (mSameLastUsagesAcrossSubresources && isAllSubresourcesCovered) { + ASSERT(baseMipLevel == 0 && baseArrayLayer == 0); + if (CanReuseWithoutBarrier(mSubresourceLastUsages[0], usage)) { + return; + } + barriers.push_back(BuildMemoryBarrier(format, mHandle, mSubresourceLastUsages[0], usage, + 0, levelCount, 0, layerCount)); + allLastUsages = mSubresourceLastUsages[0]; + for (uint32_t i = 0; i < subresourceCount; ++i) { + mSubresourceLastUsages[i] = usage; + } + } else { + for (uint32_t layer = baseArrayLayer; layer < baseArrayLayer + layerCount; ++layer) { + for (uint32_t level = baseMipLevel; level < baseMipLevel + levelCount; ++level) { + uint32_t index = GetSubresourceIndex(level, layer); - if (CanReuseWithoutBarrier(mSubresourceLastUsages[index], usage)) { - continue; + if (CanReuseWithoutBarrier(mSubresourceLastUsages[index], usage)) { + continue; + } + + barriers.push_back(BuildMemoryBarrier( + format, mHandle, mSubresourceLastUsages[index], usage, level, 1, layer, 1)); + allLastUsages |= mSubresourceLastUsages[index]; + mSubresourceLastUsages[index] = usage; } - - barriers.push_back(BuildMemoryBarrier( - format, mHandle, mSubresourceLastUsages[index], usage, level, 1, layer, 1)); - allLastUsages |= mSubresourceLastUsages[index]; - mSubresourceLastUsages[index] = usage; } } @@ -836,9 +855,7 @@ namespace dawn_native { namespace vulkan { ->fn.CmdPipelineBarrier(recordingContext->commandBuffer, srcStages, dstStages, 0, 0, nullptr, 0, nullptr, barriers.size(), barriers.data()); - // TODO(yunchao.he@intel.com): do the optimization to combine all barriers into a single one - // for a texture if possible. - mSameLastUsagesAcrossSubresources = levelCount * layerCount == GetSubresourceCount(); + mSameLastUsagesAcrossSubresources = isAllSubresourcesCovered; } MaybeError Texture::ClearTexture(CommandRecordingContext* recordingContext,