From b3d4ae943f9a758623762cf3000055743d5c90da Mon Sep 17 00:00:00 2001 From: SRSaunders <82544213+SRSaunders@users.noreply.github.com> Date: Wed, 24 Jul 2024 18:30:31 -0400 Subject: [PATCH 1/5] Only add present handler if VK_GOOGLE_display_timing info is available during presentation --- MoltenVK/MoltenVK/GPUObjects/MVKImage.h | 2 +- MoltenVK/MoltenVK/GPUObjects/MVKImage.mm | 6 +++--- MoltenVK/MoltenVK/GPUObjects/MVKQueue.mm | 10 ++++++---- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKImage.h b/MoltenVK/MoltenVK/GPUObjects/MVKImage.h index 9fe33b661..bd2b475b4 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKImage.h +++ b/MoltenVK/MoltenVK/GPUObjects/MVKImage.h @@ -448,7 +448,7 @@ typedef struct { uint64_t desiredPresentTime; // VK_GOOGLE_display_timing desired presentation time in nanoseconds uint32_t presentID; // VK_GOOGLE_display_timing presentID VkPresentModeKHR presentMode; // VK_EXT_swapchain_maintenance1 present mode specialization - bool hasPresentTime; // Keep track of whether presentation included VK_GOOGLE_display_timing + bool hasPresentTimesInfo; // Keep track of whether presentation included VK_GOOGLE_display_timing } MVKImagePresentInfo; /** Tracks a semaphore and fence for later signaling. */ diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKImage.mm b/MoltenVK/MoltenVK/GPUObjects/MVKImage.mm index fa48391d9..8f97a8f88 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKImage.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKImage.mm @@ -1552,14 +1552,14 @@ static void signalAndUntrack(const MVKSwapchainSignaler& signaler) { id mtlDrwbl = getCAMetalDrawable(); MVKSwapchainSignaler signaler = getPresentationSignaler(); [mtlCmdBuff addScheduledHandler: ^(id mcb) { - - addPresentedHandler(mtlDrwbl, presentInfo, signaler); - // Try to do any present mode transitions as late as possible in an attempt // to avoid visual disruptions on any presents already on the queue. if (presentInfo.presentMode != VK_PRESENT_MODE_MAX_ENUM_KHR) { mtlDrwbl.layer.displaySyncEnabledMVK = (presentInfo.presentMode != VK_PRESENT_MODE_IMMEDIATE_KHR); } + if (presentInfo.hasPresentTimesInfo) { + addPresentedHandler(mtlDrwbl, presentInfo, signaler); + } if (presentInfo.desiredPresentTime) { [mtlDrwbl presentAtTime: (double)presentInfo.desiredPresentTime * 1.0e-9]; } else { diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKQueue.mm b/MoltenVK/MoltenVK/GPUObjects/MVKQueue.mm index aab47cffb..6ad8263e1 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKQueue.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKQueue.mm @@ -799,10 +799,12 @@ presentInfo.presentableImage = mvkSC->getPresentableImage(pPresentInfo->pImageIndices[scIdx]); presentInfo.presentMode = pPresentModes ? pPresentModes[scIdx] : VK_PRESENT_MODE_MAX_ENUM_KHR; presentInfo.fence = pFences ? (MVKFence*)pFences[scIdx] : nullptr; - if (pPresentTimes) { - presentInfo.hasPresentTime = true; - presentInfo.presentID = pPresentTimes[scIdx].presentID; - presentInfo.desiredPresentTime = pPresentTimes[scIdx].desiredPresentTime; + if (pPresentTimesInfo) { + presentInfo.hasPresentTimesInfo = true; + if (pPresentTimes) { + presentInfo.presentID = pPresentTimes[scIdx].presentID; + presentInfo.desiredPresentTime = pPresentTimes[scIdx].desiredPresentTime; + } } mvkSC->setLayerNeedsDisplay(pRegions ? &pRegions[scIdx] : nullptr); _presentInfo.push_back(presentInfo); From 5b54839c0c10fa1f5e12716077b66a7e296f51a1 Mon Sep 17 00:00:00 2001 From: SRSaunders <82544213+SRSaunders@users.noreply.github.com> Date: Wed, 24 Jul 2024 21:47:29 -0400 Subject: [PATCH 2/5] Run swapchainCount assertion even when pPresentTimesInfo->pTimes = nullptr --- MoltenVK/MoltenVK/GPUObjects/MVKQueue.mm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKQueue.mm b/MoltenVK/MoltenVK/GPUObjects/MVKQueue.mm index 6ad8263e1..5391398c6 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKQueue.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKQueue.mm @@ -771,7 +771,7 @@ // Populate the array of swapchain images, testing each one for status uint32_t scCnt = pPresentInfo->swapchainCount; const VkPresentTimeGOOGLE* pPresentTimes = nullptr; - if (pPresentTimesInfo && pPresentTimesInfo->pTimes) { + if (pPresentTimesInfo) { pPresentTimes = pPresentTimesInfo->pTimes; MVKAssert(pPresentTimesInfo->swapchainCount == scCnt, "VkPresentTimesInfoGOOGLE swapchainCount must match VkPresentInfo swapchainCount."); } From b2d722e8c6b36dbe0d345c7c82b5547269591244 Mon Sep 17 00:00:00 2001 From: SRSaunders <82544213+SRSaunders@users.noreply.github.com> Date: Sat, 27 Jul 2024 13:24:19 -0400 Subject: [PATCH 3/5] Only add present handler if VK_GOOGLE_display_timing extension is available and enabled --- MoltenVK/MoltenVK/GPUObjects/MVKImage.h | 1 - MoltenVK/MoltenVK/GPUObjects/MVKImage.mm | 2 +- MoltenVK/MoltenVK/GPUObjects/MVKQueue.mm | 9 +++------ 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKImage.h b/MoltenVK/MoltenVK/GPUObjects/MVKImage.h index bd2b475b4..451debfd3 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKImage.h +++ b/MoltenVK/MoltenVK/GPUObjects/MVKImage.h @@ -448,7 +448,6 @@ typedef struct { uint64_t desiredPresentTime; // VK_GOOGLE_display_timing desired presentation time in nanoseconds uint32_t presentID; // VK_GOOGLE_display_timing presentID VkPresentModeKHR presentMode; // VK_EXT_swapchain_maintenance1 present mode specialization - bool hasPresentTimesInfo; // Keep track of whether presentation included VK_GOOGLE_display_timing } MVKImagePresentInfo; /** Tracks a semaphore and fence for later signaling. */ diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKImage.mm b/MoltenVK/MoltenVK/GPUObjects/MVKImage.mm index 8f97a8f88..4e9b01d0f 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKImage.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKImage.mm @@ -1557,7 +1557,7 @@ static void signalAndUntrack(const MVKSwapchainSignaler& signaler) { if (presentInfo.presentMode != VK_PRESENT_MODE_MAX_ENUM_KHR) { mtlDrwbl.layer.displaySyncEnabledMVK = (presentInfo.presentMode != VK_PRESENT_MODE_IMMEDIATE_KHR); } - if (presentInfo.hasPresentTimesInfo) { + if (getEnabledExtensions().vk_GOOGLE_display_timing.enabled) { addPresentedHandler(mtlDrwbl, presentInfo, signaler); } if (presentInfo.desiredPresentTime) { diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKQueue.mm b/MoltenVK/MoltenVK/GPUObjects/MVKQueue.mm index 5391398c6..2dea507fd 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKQueue.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKQueue.mm @@ -799,12 +799,9 @@ presentInfo.presentableImage = mvkSC->getPresentableImage(pPresentInfo->pImageIndices[scIdx]); presentInfo.presentMode = pPresentModes ? pPresentModes[scIdx] : VK_PRESENT_MODE_MAX_ENUM_KHR; presentInfo.fence = pFences ? (MVKFence*)pFences[scIdx] : nullptr; - if (pPresentTimesInfo) { - presentInfo.hasPresentTimesInfo = true; - if (pPresentTimes) { - presentInfo.presentID = pPresentTimes[scIdx].presentID; - presentInfo.desiredPresentTime = pPresentTimes[scIdx].desiredPresentTime; - } + if (pPresentTimes) { + presentInfo.presentID = pPresentTimes[scIdx].presentID; + presentInfo.desiredPresentTime = pPresentTimes[scIdx].desiredPresentTime; } mvkSC->setLayerNeedsDisplay(pRegions ? &pRegions[scIdx] : nullptr); _presentInfo.push_back(presentInfo); From f1ec24f83162c3679954b78bf37477ebb080616a Mon Sep 17 00:00:00 2001 From: SRSaunders <82544213+SRSaunders@users.noreply.github.com> Date: Sat, 27 Jul 2024 13:33:24 -0400 Subject: [PATCH 4/5] Estimate VkPastPresentationTimingGOOGLE::presentMargin using actualPresentTime vs. earliestPresentTime --- MoltenVK/MoltenVK/GPUObjects/MVKImage.h | 1 + MoltenVK/MoltenVK/GPUObjects/MVKImage.mm | 3 ++- MoltenVK/MoltenVK/GPUObjects/MVKSwapchain.h | 2 +- MoltenVK/MoltenVK/GPUObjects/MVKSwapchain.mm | 6 +++--- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKImage.h b/MoltenVK/MoltenVK/GPUObjects/MVKImage.h index 451debfd3..d5c500915 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKImage.h +++ b/MoltenVK/MoltenVK/GPUObjects/MVKImage.h @@ -504,6 +504,7 @@ class MVKPresentableSwapchainImage : public MVKSwapchainImage { MVKSmallVector _availabilitySignalers; MVKSwapchainSignaler _preSignaler = {}; std::mutex _availabilityLock; + uint64_t _startPresentTime = 0; uint64_t _presentationStartTime = 0; }; diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKImage.mm b/MoltenVK/MoltenVK/GPUObjects/MVKImage.mm index 4e9b01d0f..54e7e65aa 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKImage.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKImage.mm @@ -1634,6 +1634,7 @@ static void signalAndUntrack(const MVKSwapchainSignaler& signaler) { void MVKPresentableSwapchainImage::beginPresentation(const MVKImagePresentInfo& presentInfo) { retain(); _swapchain->beginPresentation(presentInfo); + _startPresentTime = mvkGetRuntimeNanoseconds(); _presentationStartTime = getPerformanceTimestamp(); } @@ -1652,7 +1653,7 @@ static void signalAndUntrack(const MVKSwapchainSignaler& signaler) { // VkDevice, have been destroyed by the time of this callback, so do not reference them. lock_guard lock(_detachmentLock); if (_device) { addPerformanceInterval(getPerformanceStats().queue.presentSwapchains, _presentationStartTime); } - if (_swapchain) { _swapchain->endPresentation(presentInfo, actualPresentTime); } + if (_swapchain) { _swapchain->endPresentation(presentInfo, _startPresentTime, actualPresentTime); } } // Makes an image available for acquisition by the app. diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKSwapchain.h b/MoltenVK/MoltenVK/GPUObjects/MVKSwapchain.h index 4e24ed36e..99fc699de 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKSwapchain.h +++ b/MoltenVK/MoltenVK/GPUObjects/MVKSwapchain.h @@ -119,7 +119,7 @@ class MVKSwapchain : public MVKVulkanAPIDeviceObject { void renderWatermark(id mtlTexture, id mtlCmdBuff); void markFrameInterval(); void beginPresentation(const MVKImagePresentInfo& presentInfo); - void endPresentation(const MVKImagePresentInfo& presentInfo, uint64_t actualPresentTime = 0); + void endPresentation(const MVKImagePresentInfo& presentInfo, uint64_t startPresentTime, uint64_t actualPresentTime = 0); void forceUnpresentedImageCompletion(); MVKSurface* _surface = nullptr; diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKSwapchain.mm b/MoltenVK/MoltenVK/GPUObjects/MVKSwapchain.mm index 973f5b0b8..1a7e9abe1 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKSwapchain.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKSwapchain.mm @@ -251,7 +251,7 @@ _unpresentedImageCount++; } -void MVKSwapchain::endPresentation(const MVKImagePresentInfo& presentInfo, uint64_t actualPresentTime) { +void MVKSwapchain::endPresentation(const MVKImagePresentInfo& presentInfo, uint64_t startPresentTime, uint64_t actualPresentTime) { _unpresentedImageCount--; std::lock_guard lock(_presentHistoryLock); @@ -266,9 +266,9 @@ _presentTimingHistory[_presentHistoryIndex].presentID = presentInfo.presentID; _presentTimingHistory[_presentHistoryIndex].desiredPresentTime = presentInfo.desiredPresentTime; _presentTimingHistory[_presentHistoryIndex].actualPresentTime = actualPresentTime; - // These details are not available in Metal + // These details are not available in Metal, but can estimate earliestPresentTime by using actualPresentTime instead _presentTimingHistory[_presentHistoryIndex].earliestPresentTime = actualPresentTime; - _presentTimingHistory[_presentHistoryIndex].presentMargin = 0; + _presentTimingHistory[_presentHistoryIndex].presentMargin = actualPresentTime > startPresentTime ? actualPresentTime - startPresentTime : 0; _presentHistoryIndex = (_presentHistoryIndex + 1) % kMaxPresentationHistory; } From f4bb1b493ade9e7214cd77b771a503e599d022d9 Mon Sep 17 00:00:00 2001 From: SRSaunders <82544213+SRSaunders@users.noreply.github.com> Date: Mon, 29 Jul 2024 14:46:26 -0400 Subject: [PATCH 5/5] Revert guard on addPresentedHandler() and rename startPresentTime to beginPresentTime --- MoltenVK/MoltenVK/GPUObjects/MVKImage.h | 2 +- MoltenVK/MoltenVK/GPUObjects/MVKImage.mm | 10 +++++----- MoltenVK/MoltenVK/GPUObjects/MVKSwapchain.h | 2 +- MoltenVK/MoltenVK/GPUObjects/MVKSwapchain.mm | 4 ++-- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKImage.h b/MoltenVK/MoltenVK/GPUObjects/MVKImage.h index d5c500915..e42150838 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKImage.h +++ b/MoltenVK/MoltenVK/GPUObjects/MVKImage.h @@ -504,7 +504,7 @@ class MVKPresentableSwapchainImage : public MVKSwapchainImage { MVKSmallVector _availabilitySignalers; MVKSwapchainSignaler _preSignaler = {}; std::mutex _availabilityLock; - uint64_t _startPresentTime = 0; + uint64_t _beginPresentTime = 0; uint64_t _presentationStartTime = 0; }; diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKImage.mm b/MoltenVK/MoltenVK/GPUObjects/MVKImage.mm index 54e7e65aa..107b1d8d8 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKImage.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKImage.mm @@ -1552,14 +1552,14 @@ static void signalAndUntrack(const MVKSwapchainSignaler& signaler) { id mtlDrwbl = getCAMetalDrawable(); MVKSwapchainSignaler signaler = getPresentationSignaler(); [mtlCmdBuff addScheduledHandler: ^(id mcb) { + + addPresentedHandler(mtlDrwbl, presentInfo, signaler); + // Try to do any present mode transitions as late as possible in an attempt // to avoid visual disruptions on any presents already on the queue. if (presentInfo.presentMode != VK_PRESENT_MODE_MAX_ENUM_KHR) { mtlDrwbl.layer.displaySyncEnabledMVK = (presentInfo.presentMode != VK_PRESENT_MODE_IMMEDIATE_KHR); } - if (getEnabledExtensions().vk_GOOGLE_display_timing.enabled) { - addPresentedHandler(mtlDrwbl, presentInfo, signaler); - } if (presentInfo.desiredPresentTime) { [mtlDrwbl presentAtTime: (double)presentInfo.desiredPresentTime * 1.0e-9]; } else { @@ -1634,7 +1634,7 @@ static void signalAndUntrack(const MVKSwapchainSignaler& signaler) { void MVKPresentableSwapchainImage::beginPresentation(const MVKImagePresentInfo& presentInfo) { retain(); _swapchain->beginPresentation(presentInfo); - _startPresentTime = mvkGetRuntimeNanoseconds(); + _beginPresentTime = mvkGetRuntimeNanoseconds(); _presentationStartTime = getPerformanceTimestamp(); } @@ -1653,7 +1653,7 @@ static void signalAndUntrack(const MVKSwapchainSignaler& signaler) { // VkDevice, have been destroyed by the time of this callback, so do not reference them. lock_guard lock(_detachmentLock); if (_device) { addPerformanceInterval(getPerformanceStats().queue.presentSwapchains, _presentationStartTime); } - if (_swapchain) { _swapchain->endPresentation(presentInfo, _startPresentTime, actualPresentTime); } + if (_swapchain) { _swapchain->endPresentation(presentInfo, _beginPresentTime, actualPresentTime); } } // Makes an image available for acquisition by the app. diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKSwapchain.h b/MoltenVK/MoltenVK/GPUObjects/MVKSwapchain.h index 99fc699de..407065793 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKSwapchain.h +++ b/MoltenVK/MoltenVK/GPUObjects/MVKSwapchain.h @@ -119,7 +119,7 @@ class MVKSwapchain : public MVKVulkanAPIDeviceObject { void renderWatermark(id mtlTexture, id mtlCmdBuff); void markFrameInterval(); void beginPresentation(const MVKImagePresentInfo& presentInfo); - void endPresentation(const MVKImagePresentInfo& presentInfo, uint64_t startPresentTime, uint64_t actualPresentTime = 0); + void endPresentation(const MVKImagePresentInfo& presentInfo, uint64_t beginPresentTime, uint64_t actualPresentTime = 0); void forceUnpresentedImageCompletion(); MVKSurface* _surface = nullptr; diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKSwapchain.mm b/MoltenVK/MoltenVK/GPUObjects/MVKSwapchain.mm index 1a7e9abe1..084cd0d59 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKSwapchain.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKSwapchain.mm @@ -251,7 +251,7 @@ _unpresentedImageCount++; } -void MVKSwapchain::endPresentation(const MVKImagePresentInfo& presentInfo, uint64_t startPresentTime, uint64_t actualPresentTime) { +void MVKSwapchain::endPresentation(const MVKImagePresentInfo& presentInfo, uint64_t beginPresentTime, uint64_t actualPresentTime) { _unpresentedImageCount--; std::lock_guard lock(_presentHistoryLock); @@ -268,7 +268,7 @@ _presentTimingHistory[_presentHistoryIndex].actualPresentTime = actualPresentTime; // These details are not available in Metal, but can estimate earliestPresentTime by using actualPresentTime instead _presentTimingHistory[_presentHistoryIndex].earliestPresentTime = actualPresentTime; - _presentTimingHistory[_presentHistoryIndex].presentMargin = actualPresentTime > startPresentTime ? actualPresentTime - startPresentTime : 0; + _presentTimingHistory[_presentHistoryIndex].presentMargin = actualPresentTime > beginPresentTime ? actualPresentTime - beginPresentTime : 0; _presentHistoryIndex = (_presentHistoryIndex + 1) % kMaxPresentationHistory; }