Fix Vulkan swapchain synchronization
It is necessary to use a semaphore to synchronize rendering and presenting even when the graphics and present queues are the same. This fixes rendering artifacts encountered on a Mali-G78 device. Bug: dawn:269 Change-Id: Ieb0240d3668b7f9f68857ed3cf8d3bfea18cf33a Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/130221 Kokoro: Kokoro <noreply+kokoro@google.com> Commit-Queue: Albin Bernhardsson <albin.bernhardsson@arm.com> Reviewed-by: Austin Eng <enga@chromium.org> Reviewed-by: Corentin Wallez <cwallez@chromium.org>
This commit is contained in:
parent
1f0aa9b1f5
commit
42b688bcff
|
@ -39,6 +39,7 @@ struct CommandPoolAndBuffer {
|
||||||
struct CommandRecordingContext {
|
struct CommandRecordingContext {
|
||||||
VkCommandBuffer commandBuffer = VK_NULL_HANDLE;
|
VkCommandBuffer commandBuffer = VK_NULL_HANDLE;
|
||||||
std::vector<VkSemaphore> waitSemaphores = {};
|
std::vector<VkSemaphore> waitSemaphores = {};
|
||||||
|
std::vector<VkSemaphore> signalSemaphores = {};
|
||||||
|
|
||||||
// The internal buffers used in the workaround of texture-to-texture copies with compressed
|
// The internal buffers used in the workaround of texture-to-texture copies with compressed
|
||||||
// formats.
|
// formats.
|
||||||
|
|
|
@ -314,11 +314,11 @@ MaybeError Device::SubmitPendingCommands() {
|
||||||
fn, &mRecordingContext, mRecordingContext.mappableBuffersForEagerTransition);
|
fn, &mRecordingContext, mRecordingContext.mappableBuffersForEagerTransition);
|
||||||
}
|
}
|
||||||
|
|
||||||
ScopedSignalSemaphore scopedSignalSemaphore(this, VK_NULL_HANDLE);
|
ScopedSignalSemaphore externalTextureSemaphore(this, VK_NULL_HANDLE);
|
||||||
if (mRecordingContext.externalTexturesForEagerTransition.size() > 0) {
|
if (mRecordingContext.externalTexturesForEagerTransition.size() > 0) {
|
||||||
// Create an external semaphore for all external textures that have been used in the pending
|
// Create an external semaphore for all external textures that have been used in the pending
|
||||||
// submit.
|
// submit.
|
||||||
DAWN_TRY_ASSIGN(*scopedSignalSemaphore.InitializeInto(),
|
DAWN_TRY_ASSIGN(*externalTextureSemaphore.InitializeInto(),
|
||||||
mExternalSemaphoreService->CreateExportableSemaphore());
|
mExternalSemaphoreService->CreateExportableSemaphore());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -336,6 +336,10 @@ MaybeError Device::SubmitPendingCommands() {
|
||||||
std::vector<VkPipelineStageFlags> dstStageMasks(mRecordingContext.waitSemaphores.size(),
|
std::vector<VkPipelineStageFlags> dstStageMasks(mRecordingContext.waitSemaphores.size(),
|
||||||
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT);
|
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT);
|
||||||
|
|
||||||
|
if (externalTextureSemaphore.Get() != VK_NULL_HANDLE) {
|
||||||
|
mRecordingContext.signalSemaphores.push_back(externalTextureSemaphore.Get());
|
||||||
|
}
|
||||||
|
|
||||||
VkSubmitInfo submitInfo;
|
VkSubmitInfo submitInfo;
|
||||||
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
|
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
|
||||||
submitInfo.pNext = nullptr;
|
submitInfo.pNext = nullptr;
|
||||||
|
@ -344,8 +348,8 @@ MaybeError Device::SubmitPendingCommands() {
|
||||||
submitInfo.pWaitDstStageMask = dstStageMasks.data();
|
submitInfo.pWaitDstStageMask = dstStageMasks.data();
|
||||||
submitInfo.commandBufferCount = mRecordingContext.commandBufferList.size();
|
submitInfo.commandBufferCount = mRecordingContext.commandBufferList.size();
|
||||||
submitInfo.pCommandBuffers = mRecordingContext.commandBufferList.data();
|
submitInfo.pCommandBuffers = mRecordingContext.commandBufferList.data();
|
||||||
submitInfo.signalSemaphoreCount = (scopedSignalSemaphore.Get() == VK_NULL_HANDLE ? 0 : 1);
|
submitInfo.signalSemaphoreCount = mRecordingContext.signalSemaphores.size();
|
||||||
submitInfo.pSignalSemaphores = AsVkArray(scopedSignalSemaphore.InitializeInto());
|
submitInfo.pSignalSemaphores = AsVkArray(mRecordingContext.signalSemaphores.data());
|
||||||
|
|
||||||
VkFence fence = VK_NULL_HANDLE;
|
VkFence fence = VK_NULL_HANDLE;
|
||||||
DAWN_TRY_ASSIGN(fence, GetUnusedFence());
|
DAWN_TRY_ASSIGN(fence, GetUnusedFence());
|
||||||
|
@ -376,7 +380,7 @@ MaybeError Device::SubmitPendingCommands() {
|
||||||
// Export the signal semaphore.
|
// Export the signal semaphore.
|
||||||
ExternalSemaphoreHandle semaphoreHandle;
|
ExternalSemaphoreHandle semaphoreHandle;
|
||||||
DAWN_TRY_ASSIGN(semaphoreHandle,
|
DAWN_TRY_ASSIGN(semaphoreHandle,
|
||||||
mExternalSemaphoreService->ExportSemaphore(scopedSignalSemaphore.Get()));
|
mExternalSemaphoreService->ExportSemaphore(externalTextureSemaphore.Get()));
|
||||||
|
|
||||||
// Update all external textures, eagerly transitioned in the submit, with the exported
|
// Update all external textures, eagerly transitioned in the submit, with the exported
|
||||||
// handle, and the duplicated handles.
|
// handle, and the duplicated handles.
|
||||||
|
@ -1086,6 +1090,7 @@ void Device::DestroyImpl() {
|
||||||
fn.DestroySemaphore(mVkDevice, semaphore, nullptr);
|
fn.DestroySemaphore(mVkDevice, semaphore, nullptr);
|
||||||
}
|
}
|
||||||
mRecordingContext.waitSemaphores.clear();
|
mRecordingContext.waitSemaphores.clear();
|
||||||
|
mRecordingContext.signalSemaphores.clear();
|
||||||
|
|
||||||
// Some commands might still be marked as in-flight if we shut down because of a device
|
// Some commands might still be marked as in-flight if we shut down because of a device
|
||||||
// loss. Recycle them as unused so that we free them below.
|
// loss. Recycle them as unused so that we free them below.
|
||||||
|
|
|
@ -291,6 +291,15 @@ MaybeError SwapChain::Initialize(SwapChainBase* previousSwapChain) {
|
||||||
ToBackend(previousSwapChain->GetDevice())
|
ToBackend(previousSwapChain->GetDevice())
|
||||||
->GetFencedDeleter()
|
->GetFencedDeleter()
|
||||||
->DeleteWhenUnused(previousVkSwapChain);
|
->DeleteWhenUnused(previousVkSwapChain);
|
||||||
|
|
||||||
|
// Delete the previous swapchain's semaphores once they are not in use.
|
||||||
|
// TODO(crbug.com/dawn/269): Wait for presentation to finish rather than submission.
|
||||||
|
for (VkSemaphore semaphore : previousVulkanSwapChain->mSwapChainSemaphores) {
|
||||||
|
ToBackend(previousSwapChain->GetDevice())
|
||||||
|
->GetFencedDeleter()
|
||||||
|
->DeleteWhenUnused(semaphore);
|
||||||
|
}
|
||||||
|
previousVulkanSwapChain->mSwapChainSemaphores.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mVkSurface == VK_NULL_HANDLE) {
|
if (mVkSurface == VK_NULL_HANDLE) {
|
||||||
|
@ -340,6 +349,21 @@ MaybeError SwapChain::Initialize(SwapChainBase* previousSwapChain) {
|
||||||
AsVkArray(mSwapChainImages.data())),
|
AsVkArray(mSwapChainImages.data())),
|
||||||
"GetSwapChainImages2"));
|
"GetSwapChainImages2"));
|
||||||
|
|
||||||
|
// Create one semaphore per swapchain image.
|
||||||
|
mSwapChainSemaphores.resize(count);
|
||||||
|
|
||||||
|
VkSemaphoreCreateInfo semaphoreCreateInfo;
|
||||||
|
semaphoreCreateInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
|
||||||
|
semaphoreCreateInfo.pNext = nullptr;
|
||||||
|
semaphoreCreateInfo.flags = 0;
|
||||||
|
|
||||||
|
for (std::size_t i = 0; i < mSwapChainSemaphores.size(); i++) {
|
||||||
|
DAWN_TRY(
|
||||||
|
CheckVkSuccess(device->fn.CreateSemaphore(device->GetVkDevice(), &semaphoreCreateInfo,
|
||||||
|
nullptr, &*mSwapChainSemaphores[i]),
|
||||||
|
"CreateSemaphore"));
|
||||||
|
}
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -546,17 +570,17 @@ MaybeError SwapChain::PresentImpl() {
|
||||||
mTexture->TransitionUsageNow(recordingContext, kPresentTextureUsage,
|
mTexture->TransitionUsageNow(recordingContext, kPresentTextureUsage,
|
||||||
mTexture->GetAllSubresources());
|
mTexture->GetAllSubresources());
|
||||||
|
|
||||||
|
// Use a semaphore to make sure all rendering has finished before presenting.
|
||||||
|
VkSemaphore currentSemaphore = mSwapChainSemaphores[mLastImageIndex];
|
||||||
|
recordingContext->signalSemaphores.push_back(currentSemaphore);
|
||||||
|
|
||||||
DAWN_TRY(device->SubmitPendingCommands());
|
DAWN_TRY(device->SubmitPendingCommands());
|
||||||
|
|
||||||
// Assuming that the present queue is the same as the graphics queue, the proper
|
|
||||||
// synchronization has already been done on the queue so we don't need to wait on any
|
|
||||||
// semaphores.
|
|
||||||
// TODO(crbug.com/dawn/269): Support the present queue not being the main queue.
|
|
||||||
VkPresentInfoKHR presentInfo;
|
VkPresentInfoKHR presentInfo;
|
||||||
presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
|
presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
|
||||||
presentInfo.pNext = nullptr;
|
presentInfo.pNext = nullptr;
|
||||||
presentInfo.waitSemaphoreCount = 0;
|
presentInfo.waitSemaphoreCount = 1;
|
||||||
presentInfo.pWaitSemaphores = nullptr;
|
presentInfo.pWaitSemaphores = AsVkArray(¤tSemaphore);
|
||||||
presentInfo.swapchainCount = 1;
|
presentInfo.swapchainCount = 1;
|
||||||
presentInfo.pSwapchains = &*mSwapChain;
|
presentInfo.pSwapchains = &*mSwapChain;
|
||||||
presentInfo.pImageIndices = &mLastImageIndex;
|
presentInfo.pImageIndices = &mLastImageIndex;
|
||||||
|
@ -681,6 +705,12 @@ void SwapChain::DetachFromSurfaceImpl() {
|
||||||
mBlitTexture = nullptr;
|
mBlitTexture = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (VkSemaphore semaphore : mSwapChainSemaphores) {
|
||||||
|
// TODO(crbug.com/dawn/269): Wait for presentation to finish rather than submission.
|
||||||
|
ToBackend(GetDevice())->GetFencedDeleter()->DeleteWhenUnused(semaphore);
|
||||||
|
}
|
||||||
|
mSwapChainSemaphores.clear();
|
||||||
|
|
||||||
// The swapchain images are destroyed with the swapchain.
|
// The swapchain images are destroyed with the swapchain.
|
||||||
if (mSwapChain != VK_NULL_HANDLE) {
|
if (mSwapChain != VK_NULL_HANDLE) {
|
||||||
ToBackend(GetDevice())->GetFencedDeleter()->DeleteWhenUnused(mSwapChain);
|
ToBackend(GetDevice())->GetFencedDeleter()->DeleteWhenUnused(mSwapChain);
|
||||||
|
|
|
@ -76,6 +76,7 @@ class SwapChain : public SwapChainBase {
|
||||||
VkSurfaceKHR mVkSurface = VK_NULL_HANDLE;
|
VkSurfaceKHR mVkSurface = VK_NULL_HANDLE;
|
||||||
VkSwapchainKHR mSwapChain = VK_NULL_HANDLE;
|
VkSwapchainKHR mSwapChain = VK_NULL_HANDLE;
|
||||||
std::vector<VkImage> mSwapChainImages;
|
std::vector<VkImage> mSwapChainImages;
|
||||||
|
std::vector<VkSemaphore> mSwapChainSemaphores;
|
||||||
uint32_t mLastImageIndex = 0;
|
uint32_t mLastImageIndex = 0;
|
||||||
|
|
||||||
Ref<Texture> mBlitTexture;
|
Ref<Texture> mBlitTexture;
|
||||||
|
|
Loading…
Reference in New Issue