Vulkan: Combine all the barriers before dispatch() in one call
This patch combines all the resource barriers added before each dispatch() into one call to reduce the number of vkCmdPipelineBarrier() in the Vulkan command buffer. BUG=dawn:522 Change-Id: I1b5943e62eb0a09db96de12196fcabb3448e9e4d Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/28283 Reviewed-by: Corentin Wallez <cwallez@chromium.org> Reviewed-by: Austin Eng <enga@chromium.org> Commit-Queue: Jiawei Shao <jiawei.shao@intel.com>
This commit is contained in:
parent
39d1cc9e9c
commit
87f25134a8
|
@ -186,56 +186,52 @@ namespace dawn_native { namespace vulkan {
|
||||||
|
|
||||||
void Buffer::TransitionUsageNow(CommandRecordingContext* recordingContext,
|
void Buffer::TransitionUsageNow(CommandRecordingContext* recordingContext,
|
||||||
wgpu::BufferUsage usage) {
|
wgpu::BufferUsage usage) {
|
||||||
std::vector<VkBufferMemoryBarrier> barriers;
|
VkBufferMemoryBarrier barrier;
|
||||||
VkPipelineStageFlags srcStages = 0;
|
VkPipelineStageFlags srcStages = 0;
|
||||||
VkPipelineStageFlags dstStages = 0;
|
VkPipelineStageFlags dstStages = 0;
|
||||||
|
|
||||||
TransitionUsageNow(recordingContext, usage, &barriers, &srcStages, &dstStages);
|
if (TransitionUsageAndGetResourceBarrier(usage, &barrier, &srcStages, &dstStages)) {
|
||||||
|
ASSERT(srcStages != 0 && dstStages != 0);
|
||||||
if (barriers.size() > 0) {
|
|
||||||
ASSERT(barriers.size() == 1);
|
|
||||||
ToBackend(GetDevice())
|
ToBackend(GetDevice())
|
||||||
->fn.CmdPipelineBarrier(recordingContext->commandBuffer, srcStages, dstStages, 0, 0,
|
->fn.CmdPipelineBarrier(recordingContext->commandBuffer, srcStages, dstStages, 0, 0,
|
||||||
nullptr, barriers.size(), barriers.data(), 0, nullptr);
|
nullptr, 1u, &barrier, 0, nullptr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Buffer::TransitionUsageNow(CommandRecordingContext* recordingContext,
|
bool Buffer::TransitionUsageAndGetResourceBarrier(wgpu::BufferUsage usage,
|
||||||
wgpu::BufferUsage usage,
|
VkBufferMemoryBarrier* barrier,
|
||||||
std::vector<VkBufferMemoryBarrier>* bufferBarriers,
|
VkPipelineStageFlags* srcStages,
|
||||||
VkPipelineStageFlags* srcStages,
|
VkPipelineStageFlags* dstStages) {
|
||||||
VkPipelineStageFlags* dstStages) {
|
|
||||||
bool lastIncludesTarget = (mLastUsage & usage) == usage;
|
bool lastIncludesTarget = (mLastUsage & usage) == usage;
|
||||||
bool lastReadOnly = (mLastUsage & kReadOnlyBufferUsages) == mLastUsage;
|
bool lastReadOnly = (mLastUsage & kReadOnlyBufferUsages) == mLastUsage;
|
||||||
|
|
||||||
// We can skip transitions to already current read-only usages.
|
// We can skip transitions to already current read-only usages.
|
||||||
if (lastIncludesTarget && lastReadOnly) {
|
if (lastIncludesTarget && lastReadOnly) {
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Special-case for the initial transition: Vulkan doesn't allow access flags to be 0.
|
// Special-case for the initial transition: Vulkan doesn't allow access flags to be 0.
|
||||||
if (mLastUsage == wgpu::BufferUsage::None) {
|
if (mLastUsage == wgpu::BufferUsage::None) {
|
||||||
mLastUsage = usage;
|
mLastUsage = usage;
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
*srcStages |= VulkanPipelineStage(mLastUsage);
|
*srcStages |= VulkanPipelineStage(mLastUsage);
|
||||||
*dstStages |= VulkanPipelineStage(usage);
|
*dstStages |= VulkanPipelineStage(usage);
|
||||||
|
|
||||||
VkBufferMemoryBarrier barrier;
|
barrier->sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
|
||||||
barrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
|
barrier->pNext = nullptr;
|
||||||
barrier.pNext = nullptr;
|
barrier->srcAccessMask = VulkanAccessFlags(mLastUsage);
|
||||||
barrier.srcAccessMask = VulkanAccessFlags(mLastUsage);
|
barrier->dstAccessMask = VulkanAccessFlags(usage);
|
||||||
barrier.dstAccessMask = VulkanAccessFlags(usage);
|
barrier->srcQueueFamilyIndex = 0;
|
||||||
barrier.srcQueueFamilyIndex = 0;
|
barrier->dstQueueFamilyIndex = 0;
|
||||||
barrier.dstQueueFamilyIndex = 0;
|
barrier->buffer = mHandle;
|
||||||
barrier.buffer = mHandle;
|
barrier->offset = 0;
|
||||||
barrier.offset = 0;
|
barrier->size = GetSize();
|
||||||
barrier.size = GetSize();
|
|
||||||
|
|
||||||
bufferBarriers->push_back(barrier);
|
|
||||||
|
|
||||||
mLastUsage = usage;
|
mLastUsage = usage;
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Buffer::IsCPUWritableAtCreation() const {
|
bool Buffer::IsCPUWritableAtCreation() const {
|
||||||
|
|
|
@ -37,11 +37,10 @@ namespace dawn_native { namespace vulkan {
|
||||||
// `commands`.
|
// `commands`.
|
||||||
// TODO(cwallez@chromium.org): coalesce barriers and do them early when possible.
|
// TODO(cwallez@chromium.org): coalesce barriers and do them early when possible.
|
||||||
void TransitionUsageNow(CommandRecordingContext* recordingContext, wgpu::BufferUsage usage);
|
void TransitionUsageNow(CommandRecordingContext* recordingContext, wgpu::BufferUsage usage);
|
||||||
void TransitionUsageNow(CommandRecordingContext* recordingContext,
|
bool TransitionUsageAndGetResourceBarrier(wgpu::BufferUsage usage,
|
||||||
wgpu::BufferUsage usage,
|
VkBufferMemoryBarrier* barrier,
|
||||||
std::vector<VkBufferMemoryBarrier>* bufferBarriers,
|
VkPipelineStageFlags* srcStages,
|
||||||
VkPipelineStageFlags* srcStages,
|
VkPipelineStageFlags* dstStages);
|
||||||
VkPipelineStageFlags* dstStages);
|
|
||||||
|
|
||||||
void EnsureDataInitialized(CommandRecordingContext* recordingContext);
|
void EnsureDataInitialized(CommandRecordingContext* recordingContext);
|
||||||
void EnsureDataInitializedAsDestination(CommandRecordingContext* recordingContext,
|
void EnsureDataInitializedAsDestination(CommandRecordingContext* recordingContext,
|
||||||
|
|
|
@ -146,43 +146,59 @@ namespace dawn_native { namespace vulkan {
|
||||||
mDirtyBindGroupsObjectChangedOrIsDynamic, mBindGroups,
|
mDirtyBindGroupsObjectChangedOrIsDynamic, mBindGroups,
|
||||||
mDynamicOffsetCounts, mDynamicOffsets);
|
mDynamicOffsetCounts, mDynamicOffsets);
|
||||||
|
|
||||||
// TODO(jiawei.shao@intel.com): combine the following barriers in one
|
std::vector<VkBufferMemoryBarrier> bufferBarriers;
|
||||||
// vkCmdPipelineBarrier() call.
|
std::vector<VkImageMemoryBarrier> imageBarriers;
|
||||||
|
VkPipelineStageFlags srcStages = 0;
|
||||||
|
VkPipelineStageFlags dstStages = 0;
|
||||||
|
|
||||||
for (BindGroupIndex index : IterateBitSet(mBindGroupLayoutsMask)) {
|
for (BindGroupIndex index : IterateBitSet(mBindGroupLayoutsMask)) {
|
||||||
BindGroupLayoutBase* layout = mBindGroups[index]->GetLayout();
|
BindGroupLayoutBase* layout = mBindGroups[index]->GetLayout();
|
||||||
for (BindingIndex binding{0}; binding < layout->GetBindingCount(); ++binding) {
|
for (BindingIndex binding{0}; binding < layout->GetBindingCount(); ++binding) {
|
||||||
switch (layout->GetBindingInfo(binding).type) {
|
switch (layout->GetBindingInfo(binding).type) {
|
||||||
case wgpu::BindingType::StorageBuffer:
|
case wgpu::BindingType::StorageBuffer:
|
||||||
case wgpu::BindingType::ReadonlyStorageBuffer:
|
case wgpu::BindingType::ReadonlyStorageBuffer: {
|
||||||
ToBackend(
|
VkBufferMemoryBarrier bufferBarrier;
|
||||||
mBindGroups[index]->GetBindingAsBufferBinding(binding).buffer)
|
if (ToBackend(mBindGroups[index]
|
||||||
->TransitionUsageNow(recordingContext,
|
->GetBindingAsBufferBinding(binding)
|
||||||
wgpu::BufferUsage::Storage);
|
.buffer)
|
||||||
|
->TransitionUsageAndGetResourceBarrier(
|
||||||
|
wgpu::BufferUsage::Storage, &bufferBarrier, &srcStages,
|
||||||
|
&dstStages)) {
|
||||||
|
bufferBarriers.push_back(bufferBarrier);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case wgpu::BindingType::ReadonlyStorageTexture:
|
case wgpu::BindingType::ReadonlyStorageTexture:
|
||||||
case wgpu::BindingType::WriteonlyStorageTexture: {
|
case wgpu::BindingType::WriteonlyStorageTexture: {
|
||||||
TextureViewBase* view =
|
TextureViewBase* view =
|
||||||
mBindGroups[index]->GetBindingAsTextureView(binding);
|
mBindGroups[index]->GetBindingAsTextureView(binding);
|
||||||
ToBackend(view->GetTexture())
|
ToBackend(view->GetTexture())
|
||||||
->TransitionUsageNow(recordingContext,
|
->TransitionUsageAndGetResourceBarrier(
|
||||||
wgpu::TextureUsage::Storage,
|
wgpu::TextureUsage::Storage, view->GetSubresourceRange(),
|
||||||
view->GetSubresourceRange());
|
&imageBarriers, &srcStages, &dstStages);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case wgpu::BindingType::UniformBuffer:
|
case wgpu::BindingType::UniformBuffer: {
|
||||||
ToBackend(
|
VkBufferMemoryBarrier bufferBarrier;
|
||||||
mBindGroups[index]->GetBindingAsBufferBinding(binding).buffer)
|
if (ToBackend(mBindGroups[index]
|
||||||
->TransitionUsageNow(recordingContext,
|
->GetBindingAsBufferBinding(binding)
|
||||||
wgpu::BufferUsage::Uniform);
|
.buffer)
|
||||||
|
->TransitionUsageAndGetResourceBarrier(
|
||||||
|
wgpu::BufferUsage::Uniform, &bufferBarrier, &srcStages,
|
||||||
|
&dstStages)) {
|
||||||
|
bufferBarriers.push_back(bufferBarrier);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case wgpu::BindingType::SampledTexture: {
|
case wgpu::BindingType::SampledTexture: {
|
||||||
TextureViewBase* view =
|
TextureViewBase* view =
|
||||||
mBindGroups[index]->GetBindingAsTextureView(binding);
|
mBindGroups[index]->GetBindingAsTextureView(binding);
|
||||||
ToBackend(view->GetTexture())
|
ToBackend(view->GetTexture())
|
||||||
->TransitionUsageNow(recordingContext,
|
->TransitionUsageAndGetResourceBarrier(
|
||||||
wgpu::TextureUsage::Sampled,
|
wgpu::TextureUsage::Sampled, view->GetSubresourceRange(),
|
||||||
view->GetSubresourceRange());
|
&imageBarriers, &srcStages, &dstStages);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -200,6 +216,15 @@ namespace dawn_native { namespace vulkan {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!bufferBarriers.empty() || !imageBarriers.empty()) {
|
||||||
|
ASSERT(srcStages != 0 && dstStages != 0);
|
||||||
|
device->fn.CmdPipelineBarrier(recordingContext->commandBuffer, srcStages,
|
||||||
|
dstStages, 0, 0, nullptr, bufferBarriers.size(),
|
||||||
|
bufferBarriers.data(), imageBarriers.size(),
|
||||||
|
imageBarriers.data());
|
||||||
|
}
|
||||||
|
|
||||||
DidApply();
|
DidApply();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -459,8 +484,12 @@ namespace dawn_native { namespace vulkan {
|
||||||
for (size_t i = 0; i < usages.buffers.size(); ++i) {
|
for (size_t i = 0; i < usages.buffers.size(); ++i) {
|
||||||
Buffer* buffer = ToBackend(usages.buffers[i]);
|
Buffer* buffer = ToBackend(usages.buffers[i]);
|
||||||
buffer->EnsureDataInitialized(recordingContext);
|
buffer->EnsureDataInitialized(recordingContext);
|
||||||
buffer->TransitionUsageNow(recordingContext, usages.bufferUsages[i],
|
|
||||||
&bufferBarriers, &srcStages, &dstStages);
|
VkBufferMemoryBarrier bufferBarrier;
|
||||||
|
if (buffer->TransitionUsageAndGetResourceBarrier(
|
||||||
|
usages.bufferUsages[i], &bufferBarrier, &srcStages, &dstStages)) {
|
||||||
|
bufferBarriers.push_back(bufferBarrier);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (size_t i = 0; i < usages.textures.size(); ++i) {
|
for (size_t i = 0; i < usages.textures.size(); ++i) {
|
||||||
|
|
|
@ -818,6 +818,32 @@ namespace dawn_native { namespace vulkan {
|
||||||
wgpu::TextureUsage usage,
|
wgpu::TextureUsage usage,
|
||||||
const SubresourceRange& range) {
|
const SubresourceRange& range) {
|
||||||
std::vector<VkImageMemoryBarrier> barriers;
|
std::vector<VkImageMemoryBarrier> barriers;
|
||||||
|
|
||||||
|
VkPipelineStageFlags srcStages = 0;
|
||||||
|
VkPipelineStageFlags dstStages = 0;
|
||||||
|
|
||||||
|
TransitionUsageAndGetResourceBarrier(usage, range, &barriers, &srcStages, &dstStages);
|
||||||
|
|
||||||
|
if (mExternalState != ExternalState::InternalOnly) {
|
||||||
|
TweakTransitionForExternalUsage(recordingContext, &barriers, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!barriers.empty()) {
|
||||||
|
ASSERT(srcStages != 0 && dstStages != 0);
|
||||||
|
ToBackend(GetDevice())
|
||||||
|
->fn.CmdPipelineBarrier(recordingContext->commandBuffer, srcStages, dstStages, 0, 0,
|
||||||
|
nullptr, 0, nullptr, barriers.size(), barriers.data());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Texture::TransitionUsageAndGetResourceBarrier(
|
||||||
|
wgpu::TextureUsage usage,
|
||||||
|
const SubresourceRange& range,
|
||||||
|
std::vector<VkImageMemoryBarrier>* imageBarriers,
|
||||||
|
VkPipelineStageFlags* srcStages,
|
||||||
|
VkPipelineStageFlags* dstStages) {
|
||||||
|
ASSERT(imageBarriers != nullptr);
|
||||||
|
|
||||||
const Format& format = GetFormat();
|
const Format& format = GetFormat();
|
||||||
|
|
||||||
wgpu::TextureUsage allLastUsages = wgpu::TextureUsage::None;
|
wgpu::TextureUsage allLastUsages = wgpu::TextureUsage::None;
|
||||||
|
@ -837,7 +863,7 @@ namespace dawn_native { namespace vulkan {
|
||||||
if (CanReuseWithoutBarrier(mSubresourceLastUsages[0], usage)) {
|
if (CanReuseWithoutBarrier(mSubresourceLastUsages[0], usage)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
barriers.push_back(
|
imageBarriers->push_back(
|
||||||
BuildMemoryBarrier(format, mHandle, mSubresourceLastUsages[0], usage, range));
|
BuildMemoryBarrier(format, mHandle, mSubresourceLastUsages[0], usage, range));
|
||||||
allLastUsages = mSubresourceLastUsages[0];
|
allLastUsages = mSubresourceLastUsages[0];
|
||||||
for (uint32_t i = 0; i < GetSubresourceCount(); ++i) {
|
for (uint32_t i = 0; i < GetSubresourceCount(); ++i) {
|
||||||
|
@ -868,22 +894,15 @@ namespace dawn_native { namespace vulkan {
|
||||||
mSubresourceLastUsages[index] = usage;
|
mSubresourceLastUsages[index] = usage;
|
||||||
}
|
}
|
||||||
|
|
||||||
barriers.push_back(BuildMemoryBarrier(
|
imageBarriers->push_back(BuildMemoryBarrier(
|
||||||
format, mHandle, lastUsage, usage,
|
format, mHandle, lastUsage, usage,
|
||||||
SubresourceRange::SingleMipAndLayer(level, layer, format.aspects)));
|
SubresourceRange::SingleMipAndLayer(level, layer, format.aspects)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mExternalState != ExternalState::InternalOnly) {
|
*srcStages |= VulkanPipelineStage(allLastUsages, format);
|
||||||
TweakTransitionForExternalUsage(recordingContext, &barriers, 0);
|
*dstStages |= VulkanPipelineStage(usage, format);
|
||||||
}
|
|
||||||
|
|
||||||
VkPipelineStageFlags srcStages = VulkanPipelineStage(allLastUsages, format);
|
|
||||||
VkPipelineStageFlags dstStages = VulkanPipelineStage(usage, format);
|
|
||||||
ToBackend(GetDevice())
|
|
||||||
->fn.CmdPipelineBarrier(recordingContext->commandBuffer, srcStages, dstStages, 0, 0,
|
|
||||||
nullptr, 0, nullptr, barriers.size(), barriers.data());
|
|
||||||
|
|
||||||
mSameLastUsagesAcrossSubresources = areAllSubresourcesCovered;
|
mSameLastUsagesAcrossSubresources = areAllSubresourcesCovered;
|
||||||
}
|
}
|
||||||
|
|
|
@ -70,6 +70,11 @@ namespace dawn_native { namespace vulkan {
|
||||||
void TransitionUsageNow(CommandRecordingContext* recordingContext,
|
void TransitionUsageNow(CommandRecordingContext* recordingContext,
|
||||||
wgpu::TextureUsage usage,
|
wgpu::TextureUsage usage,
|
||||||
const SubresourceRange& range);
|
const SubresourceRange& range);
|
||||||
|
void TransitionUsageAndGetResourceBarrier(wgpu::TextureUsage usage,
|
||||||
|
const SubresourceRange& range,
|
||||||
|
std::vector<VkImageMemoryBarrier>* imageBarriers,
|
||||||
|
VkPipelineStageFlags* srcStages,
|
||||||
|
VkPipelineStageFlags* dstStages);
|
||||||
void TransitionUsageForPass(CommandRecordingContext* recordingContext,
|
void TransitionUsageForPass(CommandRecordingContext* recordingContext,
|
||||||
const PassTextureUsage& textureUsages,
|
const PassTextureUsage& textureUsages,
|
||||||
std::vector<VkImageMemoryBarrier>* imageBarriers,
|
std::vector<VkImageMemoryBarrier>* imageBarriers,
|
||||||
|
|
Loading…
Reference in New Issue