vulkan: Fix synchronization with acquire swapchain images.
The vkAcquireNextImageKHR method is a read operation in Vulkan which completes
before the semaphore/fence out parameters are signaled. This means that future uses
of the texture must performs a memory barriers that synchronizes with that
semaphore/barrier. Dawn uses the ALL_COMMANDS_BIT stage for the semaphore, however
such a semaphore doesn't synchronize with a subsequent BOTTOM_OF_PIPE or NONE
srcStage vkPipelineBarrier because there are no common stages. Instead we also use
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT for srcStage for presentable images, ensuring
correct ordering.
The kPresentTextureUsage is split in two different usages "Acquire" and
"Release". When acquiring the stage mask is set to ALL_COMMANDS_BIT and
the layout to UNDEFINED (because we will initialize the texture anyway).
When release the stage mask is 0 as noted in the Vulkan spec, but the
layout set to PRESENT_KHR.
Bug: 41497359
Change-Id: I158d3071602ee598e661fca7993865c0881d4f05
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/173463
Reviewed-by: Loko Kung <lokokung@google.com>
Reviewed-by: Austin Eng <enga@chromium.org>
Commit-Queue: Corentin Wallez <cwallez@chromium.org>
Kokoro: Kokoro <noreply+kokoro@google.com>
diff --git a/src/dawn/native/d3d12/SwapChainD3D12.cpp b/src/dawn/native/d3d12/SwapChainD3D12.cpp
index 993efab..fdd68a7 100644
--- a/src/dawn/native/d3d12/SwapChainD3D12.cpp
+++ b/src/dawn/native/d3d12/SwapChainD3D12.cpp
@@ -90,7 +90,7 @@
// presentable texture to present at the end of submits that use them.
CommandRecordingContext* commandContext;
DAWN_TRY_ASSIGN(commandContext, queue->GetPendingCommandContext());
- mApiTexture->TrackUsageAndTransitionNow(commandContext, kPresentTextureUsage,
+ mApiTexture->TrackUsageAndTransitionNow(commandContext, kPresentReleaseTextureUsage,
mApiTexture->GetAllSubresources());
DAWN_TRY(queue->SubmitPendingCommands());
diff --git a/src/dawn/native/d3d12/TextureD3D12.cpp b/src/dawn/native/d3d12/TextureD3D12.cpp
index 1847a02..4203c6f 100644
--- a/src/dawn/native/d3d12/TextureD3D12.cpp
+++ b/src/dawn/native/d3d12/TextureD3D12.cpp
@@ -61,10 +61,12 @@
D3D12_RESOURCE_STATES D3D12TextureUsage(wgpu::TextureUsage usage, const Format& format) {
D3D12_RESOURCE_STATES resourceState = D3D12_RESOURCE_STATE_COMMON;
- if (usage & kPresentTextureUsage) {
+ // D3D12 doesn't need special acquire operations for presentable textures.
+ DAWN_ASSERT(!(usage & kPresentAcquireTextureUsage));
+ if (usage & kPresentReleaseTextureUsage) {
// The present usage is only used internally by the swapchain and is never used in
// combination with other usages.
- DAWN_ASSERT(usage == kPresentTextureUsage);
+ DAWN_ASSERT(usage == kPresentReleaseTextureUsage);
return D3D12_RESOURCE_STATE_PRESENT;
}
diff --git a/src/dawn/native/dawn_platform.h b/src/dawn/native/dawn_platform.h
index 5aff6f5..cf1fffb 100644
--- a/src/dawn/native/dawn_platform.h
+++ b/src/dawn/native/dawn_platform.h
@@ -61,27 +61,30 @@
static constexpr wgpu::TextureUsage kReservedTextureUsage =
static_cast<wgpu::TextureUsage>(1u << 31);
-// Add an extra texture usage for textures that will be presented, for use in backends
-// that needs to transition to present usage.
-static constexpr wgpu::TextureUsage kPresentTextureUsage =
+// Extrea texture usages for textures that are used with the presentation engine.
+// Acquire is that Dawn is acquiring the texture from the presentation engine while Release is Dawn
+// releasing is to the presentation engine.
+static constexpr wgpu::TextureUsage kPresentAcquireTextureUsage =
static_cast<wgpu::TextureUsage>(1u << 30);
+static constexpr wgpu::TextureUsage kPresentReleaseTextureUsage =
+ static_cast<wgpu::TextureUsage>(1u << 29);
// Add an extra texture usage (readonly render attachment usage) for render pass resource
// tracking
static constexpr wgpu::TextureUsage kReadOnlyRenderAttachment =
- static_cast<wgpu::TextureUsage>(1u << 29);
+ static_cast<wgpu::TextureUsage>(1u << 28);
// Add an extra texture usage (readonly storage texture usage) for resource tracking
static constexpr wgpu::TextureUsage kReadOnlyStorageTexture =
- static_cast<wgpu::TextureUsage>(1u << 28);
+ static_cast<wgpu::TextureUsage>(1u << 27);
// Add an extra texture usage (writeonly storage texture usage) for resource tracking
static constexpr wgpu::TextureUsage kWriteOnlyStorageTexture =
- static_cast<wgpu::TextureUsage>(1u << 27);
+ static_cast<wgpu::TextureUsage>(1u << 26);
// Add an extra texture usage (load resolve texture to MSAA) for render pass resource tracking
static constexpr wgpu::TextureUsage kResolveAttachmentLoadingUsage =
- static_cast<wgpu::TextureUsage>(1u << 26);
+ static_cast<wgpu::TextureUsage>(1u << 25);
// Extra BufferBindingType for internal storage buffer binding.
static constexpr wgpu::BufferBindingType kInternalStorageBufferBinding =
diff --git a/src/dawn/native/vulkan/BackendVk.cpp b/src/dawn/native/vulkan/BackendVk.cpp
index efa1cd5c..fbc0b2f 100644
--- a/src/dawn/native/vulkan/BackendVk.cpp
+++ b/src/dawn/native/vulkan/BackendVk.cpp
@@ -137,11 +137,6 @@
"Access info (usage: SYNC_IMAGE_LAYOUT_TRANSITION, prior_usage: SYNC_COPY_TRANSFER_WRITE, "
"write_barriers: 0, command: vkCmdCopyBufferToImage"},
- // http://crbug.com/1524408
- {"SYNC-HAZARD-WRITE-AFTER-READ",
- "Access info (prior_usage: SYNC_PRESENT_ENGINE_SYNCVAL_PRESENT_ACQUIRE_READ_SYNCVAL, "
- "read_barriers: VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT"},
-
// http://anglebug.com/7513
{"VUID-VkGraphicsPipelineCreateInfo-pStages-06896",
"contains fragment shader state, but stages"},
diff --git a/src/dawn/native/vulkan/SwapChainVk.cpp b/src/dawn/native/vulkan/SwapChainVk.cpp
index adfcc0e..b33764e 100644
--- a/src/dawn/native/vulkan/SwapChainVk.cpp
+++ b/src/dawn/native/vulkan/SwapChainVk.cpp
@@ -591,8 +591,8 @@
// TODO(crbug.com/dawn/269): Remove the need for this by eagerly transitioning the
// presentable texture to present at the end of submits that use them and ideally even
// folding that in the free layout transition at the end of render passes.
- mTexture->TransitionUsageNow(recordingContext, kPresentTextureUsage, wgpu::ShaderStage::None,
- mTexture->GetAllSubresources());
+ mTexture->TransitionUsageNow(recordingContext, kPresentReleaseTextureUsage,
+ wgpu::ShaderStage::None, mTexture->GetAllSubresources());
// Use a semaphore to make sure all rendering has finished before presenting.
VkSemaphore currentSemaphore = mSwapChainSemaphores[mLastImageIndex];
diff --git a/src/dawn/native/vulkan/TextureVk.cpp b/src/dawn/native/vulkan/TextureVk.cpp
index dc90fc8..5d81718 100644
--- a/src/dawn/native/vulkan/TextureVk.cpp
+++ b/src/dawn/native/vulkan/TextureVk.cpp
@@ -153,10 +153,31 @@
if (usage & kReadOnlyRenderAttachment) {
flags |= VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT;
}
- if (usage & kPresentTextureUsage) {
- // The present usage is only used internally by the swapchain and is never used in
+
+ if (usage & kPresentAcquireTextureUsage) {
+ // The present acquire usage is only used internally by the swapchain and is never used in
// combination with other usages.
- DAWN_ASSERT(usage == kPresentTextureUsage);
+ DAWN_ASSERT(usage == kPresentAcquireTextureUsage);
+ // The Vulkan spec has the following note:
+ //
+ // When the presentable image will be accessed by some stage S, the recommended idiom
+ // for ensuring correct synchronization is:
+ //
+ // The VkSubmitInfo used to submit the image layout transition for execution includes
+ // vkAcquireNextImageKHR::semaphore in its pWaitSemaphores member, with the
+ // corresponding element of pWaitDstStageMask including S.
+ //
+ // The synchronization command that performs any necessary image layout transition
+ // includes S in both the srcStageMask and dstStageMask.
+ //
+ // There is no mention of an access flag because there is no access flag associated with
+ // the presentation engine, so we leave it to 0.
+ flags |= 0;
+ }
+ if (usage & kPresentReleaseTextureUsage) {
+ // The present release usage is only used internally by the swapchain and is never used in
+ // combination with other usages.
+ DAWN_ASSERT(usage == kPresentReleaseTextureUsage);
// The Vulkan spec has the following note:
//
// When transitioning the image to VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR or
@@ -221,10 +242,35 @@
flags |= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
}
}
- if (usage & kPresentTextureUsage) {
- // The present usage is only used internally by the swapchain and is never used in
+
+ if (usage & kPresentAcquireTextureUsage) {
+ // The present acquire usage is only used internally by the swapchain and is never used in
// combination with other usages.
- DAWN_ASSERT(usage == kPresentTextureUsage);
+ DAWN_ASSERT(usage == kPresentAcquireTextureUsage);
+ // The vkAcquireNextImageKHR method is a read operation in Vulkan which completes
+ // before the semaphore/fence out parameters are signaled. This means that future uses
+ // of the texture must performs a memory barriers that synchronizes with that
+ // semaphore/barrier. Dawn uses the ALL_COMMANDS_BIT stage for the semaphore, however
+ // such a semaphore doesn't synchronize with a subsequent BOTTOM_OF_PIPE or NONE
+ // srcStage vkPipelineBarrier because there are no common stages. Instead we also use
+ // VK_PIPELINE_STAGE_ALL_COMMANDS_BIT for srcStage for presentable images, ensuring
+ // correct ordering. This explains the idiom noted in the Vulkan spec:
+ //
+ // When the presentable image will be accessed by some stage S, the recommended idiom
+ // for ensuring correct synchronization is:
+ //
+ // The VkSubmitInfo used to submit the image layout transition for execution includes
+ // vkAcquireNextImageKHR::semaphore in its pWaitSemaphores member, with the
+ // corresponding element of pWaitDstStageMask including S.
+ //
+ // The synchronization command that performs any necessary image layout transition
+ // includes S in both the srcStageMask and dstStageMask.
+ flags |= VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
+ }
+ if (usage & kPresentReleaseTextureUsage) {
+ // The present release usage is only used internally by the swapchain and is never used in
+ // combination with other usages.
+ DAWN_ASSERT(usage == kPresentReleaseTextureUsage);
// The Vulkan spec has the following note:
//
// When transitioning the image to VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR or
@@ -611,8 +657,12 @@
case kReadOnlyRenderAttachment:
return VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL;
- case kPresentTextureUsage:
+ case kPresentReleaseTextureUsage:
return VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
+ case kPresentAcquireTextureUsage:
+ // We always consider images being acquired from the swapchain as uninitialized,
+ // so we can use the UNDEFINED Vulkan image layout.
+ return VK_IMAGE_LAYOUT_UNDEFINED;
case wgpu::TextureUsage::TransientAttachment:
// Will be covered by RenderAttachment above, as specification of
@@ -949,6 +999,7 @@
void Texture::InitializeForSwapChain(VkImage nativeImage) {
mHandle = nativeImage;
+ mSubresourceLastSyncInfos.Fill({kPresentAcquireTextureUsage, wgpu::ShaderStage::None});
SetLabelHelper("Dawn_SwapChainTexture");
}