From 2a3fd05651df874f5a0f1ed149dff0c203687ca2 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 29 Feb 2020 22:45:18 -0800 Subject: [PATCH] Vulkan: Present using FIFO for vsync. This allows the setting to be changed at runtime in Vulkan too. Should help #10105. --- Common/Vulkan/VulkanContext.cpp | 21 +++++++++------------ Common/Vulkan/VulkanContext.h | 2 ++ Core/HLE/sceDisplay.cpp | 7 ++++++- UI/GameSettingsScreen.cpp | 6 +++++- Windows/GPU/WindowsVulkanContext.cpp | 15 +++++++++++---- Windows/MainWindowMenu.cpp | 1 + android/jni/AndroidVulkanContext.cpp | 11 +++++++++-- 7 files changed, 43 insertions(+), 20 deletions(-) diff --git a/Common/Vulkan/VulkanContext.cpp b/Common/Vulkan/VulkanContext.cpp index cb4dc0b33a..ca1e5dec19 100644 --- a/Common/Vulkan/VulkanContext.cpp +++ b/Common/Vulkan/VulkanContext.cpp @@ -949,20 +949,17 @@ bool VulkanContext::InitSwapchain() { ILOG("Supported present mode: %d (%s)", presentModes[i], PresentModeString(presentModes[i])); } for (size_t i = 0; i < presentModeCount; i++) { - if (swapchainPresentMode == VK_PRESENT_MODE_MAX_ENUM_KHR) { - // Default to the first present mode from the list. + bool match = false; + match = match || ((flags_ & VULKAN_FLAG_PRESENT_MAILBOX) && presentModes[i] == VK_PRESENT_MODE_MAILBOX_KHR); + match = match || ((flags_ & VULKAN_FLAG_PRESENT_FIFO_RELAXED) && presentModes[i] == VK_PRESENT_MODE_FIFO_RELAXED_KHR); + match = match || ((flags_ & VULKAN_FLAG_PRESENT_FIFO) && presentModes[i] == VK_PRESENT_MODE_FIFO_KHR); + match = match || ((flags_ & VULKAN_FLAG_PRESENT_IMMEDIATE) && presentModes[i] == VK_PRESENT_MODE_IMMEDIATE_KHR); + + // Default to the first present mode from the list. + if (match || swapchainPresentMode == VK_PRESENT_MODE_MAX_ENUM_KHR) { swapchainPresentMode = presentModes[i]; } - if ((flags_ & VULKAN_FLAG_PRESENT_MAILBOX) && presentModes[i] == VK_PRESENT_MODE_MAILBOX_KHR) { - swapchainPresentMode = VK_PRESENT_MODE_MAILBOX_KHR; - break; - } - if ((flags_ & VULKAN_FLAG_PRESENT_FIFO_RELAXED) && presentModes[i] == VK_PRESENT_MODE_FIFO_RELAXED_KHR) { - swapchainPresentMode = VK_PRESENT_MODE_FIFO_RELAXED_KHR; - break; - } - if ((flags_ & VULKAN_FLAG_PRESENT_IMMEDIATE) && presentModes[i] == VK_PRESENT_MODE_IMMEDIATE_KHR) { - swapchainPresentMode = VK_PRESENT_MODE_IMMEDIATE_KHR; + if (match) { break; } } diff --git a/Common/Vulkan/VulkanContext.h b/Common/Vulkan/VulkanContext.h index fccc3dc98e..f08d883ceb 100644 --- a/Common/Vulkan/VulkanContext.h +++ b/Common/Vulkan/VulkanContext.h @@ -13,6 +13,7 @@ enum { VULKAN_FLAG_PRESENT_MAILBOX = 2, VULKAN_FLAG_PRESENT_IMMEDIATE = 4, VULKAN_FLAG_PRESENT_FIFO_RELAXED = 8, + VULKAN_FLAG_PRESENT_FIFO = 16, }; enum { @@ -136,6 +137,7 @@ public: VkDevice GetDevice() const { return device_; } VkInstance GetInstance() const { return instance_; } uint32_t GetFlags() const { return flags_; } + void UpdateFlags(uint32_t flags) { flags_ = flags; } VulkanDeleteList &Delete() { return globalDeleteList_; } diff --git a/Core/HLE/sceDisplay.cpp b/Core/HLE/sceDisplay.cpp index 972e2e759f..41834a7f33 100644 --- a/Core/HLE/sceDisplay.cpp +++ b/Core/HLE/sceDisplay.cpp @@ -553,7 +553,12 @@ static void DoFrameTiming(bool &throttle, bool &skipFrame, float timestep) { // we have nothing to do here. bool doFrameSkip = g_Config.iFrameSkip != 0; - if (!throttle && g_Config.bFrameSkipUnthrottle) { + bool unthrottleNeedsSkip = g_Config.bFrameSkipUnthrottle; + if (g_Config.bVSync && GetGPUBackend() == GPUBackend::VULKAN) { + // Vulkan doesn't support the interval setting, so we force frameskip. + unthrottleNeedsSkip = true; + } + if (!throttle && unthrottleNeedsSkip) { doFrameSkip = true; skipFrame = true; if (numSkippedFrames >= 7) { diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index a6fae59fa4..4cdec193e6 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -342,7 +342,11 @@ void GameSettingsScreen::CreateViews() { #endif #ifdef _WIN32 - graphicsSettings->Add(new CheckBox(&g_Config.bVSync, gr->T("VSync"))); + CheckBox *vSync = graphicsSettings->Add(new CheckBox(&g_Config.bVSync, gr->T("VSync"))); + vSync->OnClick.Add([=](EventParams &e) { + NativeResized(); + return UI::EVENT_CONTINUE; + }); #endif CheckBox *hwTransform = graphicsSettings->Add(new CheckBox(&g_Config.bHardwareTransform, gr->T("Hardware Transform"))); diff --git a/Windows/GPU/WindowsVulkanContext.cpp b/Windows/GPU/WindowsVulkanContext.cpp index 7797b58289..772d037989 100644 --- a/Windows/GPU/WindowsVulkanContext.cpp +++ b/Windows/GPU/WindowsVulkanContext.cpp @@ -74,6 +74,15 @@ static VulkanContext *g_Vulkan; static VulkanLogOptions g_LogOptions; +static uint32_t FlagsFromConfig() { + uint32_t flags = 0; + flags = g_Config.bVSync ? VULKAN_FLAG_PRESENT_FIFO : VULKAN_FLAG_PRESENT_MAILBOX; + if (g_validate_) { + flags |= VULKAN_FLAG_VALIDATE; + } + return flags; +} + bool WindowsVulkanContext::Init(HINSTANCE hInst, HWND hWnd, std::string *error_message) { *error_message = "N/A"; @@ -100,10 +109,7 @@ bool WindowsVulkanContext::Init(HINSTANCE hInst, HWND hWnd, std::string *error_m VulkanContext::CreateInfo info{}; info.app_name = "PPSSPP"; info.app_ver = gitVer.ToInteger(); - info.flags = VULKAN_FLAG_PRESENT_MAILBOX; - if (g_validate_) { - info.flags |= VULKAN_FLAG_VALIDATE; - } + info.flags = FlagsFromConfig(); if (VK_SUCCESS != g_Vulkan->CreateInstance(info)) { *error_message = g_Vulkan->InitError(); delete g_Vulkan; @@ -184,6 +190,7 @@ void WindowsVulkanContext::Resize() { draw_->HandleEvent(Draw::Event::LOST_BACKBUFFER, g_Vulkan->GetBackbufferWidth(), g_Vulkan->GetBackbufferHeight()); g_Vulkan->DestroyObjects(); + g_Vulkan->UpdateFlags(FlagsFromConfig()); g_Vulkan->ReinitSurface(); g_Vulkan->InitObjects(); diff --git a/Windows/MainWindowMenu.cpp b/Windows/MainWindowMenu.cpp index 225e3ce681..32861c90f2 100644 --- a/Windows/MainWindowMenu.cpp +++ b/Windows/MainWindowMenu.cpp @@ -739,6 +739,7 @@ namespace MainWindow { case ID_OPTIONS_VSYNC: g_Config.bVSync = !g_Config.bVSync; + NativeResized(); break; case ID_OPTIONS_FRAMESKIP_AUTO: diff --git a/android/jni/AndroidVulkanContext.cpp b/android/jni/AndroidVulkanContext.cpp index 71c63077b6..1ff51b5f67 100644 --- a/android/jni/AndroidVulkanContext.cpp +++ b/android/jni/AndroidVulkanContext.cpp @@ -81,6 +81,13 @@ AndroidVulkanContext::~AndroidVulkanContext() { g_Vulkan = nullptr; } +static uint32_t FlagsFromConfig() { + if (g_Config.bVSync) { + return VULKAN_FLAG_PRESENT_FIFO; + } + return VULKAN_FLAG_PRESENT_MAILBOX | VULKAN_FLAG_PRESENT_FIFO_RELAXED; +} + bool AndroidVulkanContext::InitAPI() { ILOG("AndroidVulkanContext::Init"); init_glslang(); @@ -105,7 +112,7 @@ bool AndroidVulkanContext::InitAPI() { VulkanContext::CreateInfo info{}; info.app_name = "PPSSPP"; info.app_ver = gitVer.ToInteger(); - info.flags = VULKAN_FLAG_PRESENT_MAILBOX | VULKAN_FLAG_PRESENT_FIFO_RELAXED; + info.flags = FlagsFromConfig(); VkResult res = g_Vulkan->CreateInstance(info); if (res != VK_SUCCESS) { ELOG("Failed to create vulkan context: %s", g_Vulkan->InitError().c_str()); @@ -216,7 +223,7 @@ void AndroidVulkanContext::Resize() { draw_->HandleEvent(Draw::Event::LOST_BACKBUFFER, g_Vulkan->GetBackbufferWidth(), g_Vulkan->GetBackbufferHeight()); g_Vulkan->DestroyObjects(); - // backbufferResize updated these values. TODO: Notify another way? + g_Vulkan->UpdateFlags(FlagsFromConfig()); g_Vulkan->ReinitSurface(); g_Vulkan->InitObjects(); draw_->HandleEvent(Draw::Event::GOT_BACKBUFFER, g_Vulkan->GetBackbufferWidth(), g_Vulkan->GetBackbufferHeight());