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 <cwallez@chromium.org>
Reviewed-by: Austin Eng <enga@chromium.org>
Commit-Queue: Yunchao He <yunchao.he@intel.com>
This commit is contained in:
Yunchao He 2020-06-12 17:01:41 +00:00 committed by Commit Bot service account
parent f87b62a904
commit 4fd4aa1f19
1 changed files with 30 additions and 13 deletions

View File

@ -807,22 +807,41 @@ namespace dawn_native { namespace vulkan {
const Format& format = GetFormat(); const Format& format = GetFormat();
wgpu::TextureUsage allLastUsages = wgpu::TextureUsage::None; wgpu::TextureUsage allLastUsages = wgpu::TextureUsage::None;
uint32_t subresourceCount = GetSubresourceCount();
// This transitions assume it is a 2D texture // This transitions assume it is a 2D texture
ASSERT(GetDimension() == wgpu::TextureDimension::e2D); ASSERT(GetDimension() == wgpu::TextureDimension::e2D);
for (uint32_t layer = baseArrayLayer; layer < baseArrayLayer + layerCount; ++layer) { // If the usages transitions can cover all subresources, and old usages of all subresources
for (uint32_t level = baseMipLevel; level < baseMipLevel + levelCount; ++level) { // are the same, then we can use one barrier to do state transition for all subresources.
uint32_t index = GetSubresourceIndex(level, layer); // 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)) { if (CanReuseWithoutBarrier(mSubresourceLastUsages[index], usage)) {
continue; 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, ->fn.CmdPipelineBarrier(recordingContext->commandBuffer, srcStages, dstStages, 0, 0,
nullptr, 0, nullptr, barriers.size(), barriers.data()); nullptr, 0, nullptr, barriers.size(), barriers.data());
// TODO(yunchao.he@intel.com): do the optimization to combine all barriers into a single one mSameLastUsagesAcrossSubresources = isAllSubresourcesCovered;
// for a texture if possible.
mSameLastUsagesAcrossSubresources = levelCount * layerCount == GetSubresourceCount();
} }
MaybeError Texture::ClearTexture(CommandRecordingContext* recordingContext, MaybeError Texture::ClearTexture(CommandRecordingContext* recordingContext,