diff --git a/UnleashedRecomp/gpu/rhi/rt64_d3d12.cpp b/UnleashedRecomp/gpu/rhi/rt64_d3d12.cpp index ff22332..9dfc246 100644 --- a/UnleashedRecomp/gpu/rhi/rt64_d3d12.cpp +++ b/UnleashedRecomp/gpu/rhi/rt64_d3d12.cpp @@ -1265,7 +1265,8 @@ namespace RT64 { while (WaitForSingleObjectEx(waitableObject, 0, FALSE)); } - HRESULT res = d3d->Present(1, 0); + UINT syncInterval = vsyncEnabled ? 1 : 0; + HRESULT res = d3d->Present(syncInterval, 0); return SUCCEEDED(res); } @@ -1299,6 +1300,14 @@ namespace RT64 { return (d3d == nullptr) || (windowWidth != width) || (windowHeight != height); } + void D3D12SwapChain::setVsyncEnabled(bool vsyncEnabled) { + this->vsyncEnabled = vsyncEnabled; + } + + bool D3D12SwapChain::isVsyncEnabled() const { + return vsyncEnabled; + } + uint32_t D3D12SwapChain::getWidth() const { return width; } diff --git a/UnleashedRecomp/gpu/rhi/rt64_d3d12.h b/UnleashedRecomp/gpu/rhi/rt64_d3d12.h index a1000c9..03f5757 100644 --- a/UnleashedRecomp/gpu/rhi/rt64_d3d12.h +++ b/UnleashedRecomp/gpu/rhi/rt64_d3d12.h @@ -103,12 +103,15 @@ namespace RT64 { uint32_t width = 0; uint32_t height = 0; uint32_t refreshRate = 0; + bool vsyncEnabled = true; D3D12SwapChain(D3D12CommandQueue *commandQueue, RenderWindow renderWindow, uint32_t textureCount, RenderFormat format); ~D3D12SwapChain() override; bool present(uint32_t textureIndex, RenderCommandSemaphore **waitSemaphores, uint32_t waitSemaphoreCount) override; bool resize() override; bool needsResize() const override; + void setVsyncEnabled(bool vsyncEnabled) override; + bool isVsyncEnabled() const override; uint32_t getWidth() const override; uint32_t getHeight() const override; RenderTexture *getTexture(uint32_t textureIndex) override; diff --git a/UnleashedRecomp/gpu/rhi/rt64_render_interface.h b/UnleashedRecomp/gpu/rhi/rt64_render_interface.h index ae066c9..438590b 100644 --- a/UnleashedRecomp/gpu/rhi/rt64_render_interface.h +++ b/UnleashedRecomp/gpu/rhi/rt64_render_interface.h @@ -85,6 +85,8 @@ namespace RT64 { virtual bool present(uint32_t textureIndex, RenderCommandSemaphore **waitSemaphores, uint32_t waitSemaphoreCount) = 0; virtual bool resize() = 0; virtual bool needsResize() const = 0; + virtual void setVsyncEnabled(bool vsyncEnabled) = 0; + virtual bool isVsyncEnabled() const = 0; virtual uint32_t getWidth() const = 0; virtual uint32_t getHeight() const = 0; virtual RenderTexture *getTexture(uint32_t textureIndex) = 0; diff --git a/UnleashedRecomp/gpu/rhi/rt64_vulkan.cpp b/UnleashedRecomp/gpu/rhi/rt64_vulkan.cpp index 7dbcc63..1e5c61b 100644 --- a/UnleashedRecomp/gpu/rhi/rt64_vulkan.cpp +++ b/UnleashedRecomp/gpu/rhi/rt64_vulkan.cpp @@ -2047,6 +2047,7 @@ namespace RT64 { std::vector presentModes(presentModeCount); vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, surface, &presentModeCount, presentModes.data()); + immediatePresentModeSupported = std::find(presentModes.begin(), presentModes.end(), VK_PRESENT_MODE_IMMEDIATE_KHR) != presentModes.end(); // Check if the format we requested is part of the supported surface formats. std::vector compatibleSurfaceFormats; @@ -2076,7 +2077,7 @@ namespace RT64 { } // FIFO is guaranteed to be supported. - pickedPresentMode = VK_PRESENT_MODE_FIFO_KHR; + requiredPresentMode = VK_PRESENT_MODE_FIFO_KHR; // Pick an alpha compositing mode, prefer opaque over inherit. if (surfaceCapabilities.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR) { @@ -2164,7 +2165,7 @@ namespace RT64 { createInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; createInfo.preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; createInfo.compositeAlpha = pickedAlphaFlag; - createInfo.presentMode = pickedPresentMode; + createInfo.presentMode = requiredPresentMode; createInfo.clipped = VK_TRUE; createInfo.oldSwapchain = vk; @@ -2174,6 +2175,9 @@ namespace RT64 { return false; } + // Store the chosen present mode to identify later whether the swapchain needs to be recreated. + createdPresentMode = requiredPresentMode; + // Reset present counter. presentCount = 1; @@ -2222,7 +2226,19 @@ namespace RT64 { bool VulkanSwapChain::needsResize() const { uint32_t windowWidth, windowHeight; getWindowSize(windowWidth, windowHeight); - return (vk == VK_NULL_HANDLE) || (windowWidth != width) || (windowHeight != height); + return (vk == VK_NULL_HANDLE) || (windowWidth != width) || (windowHeight != height) || (requiredPresentMode != createdPresentMode); + } + + void VulkanSwapChain::setVsyncEnabled(bool vsyncEnabled) { + // Immediate mode must be supported and the presentation mode will only be used on the next resize. + // needsResize() will return as true as long as the created and required present mode do not match. + if (immediatePresentModeSupported) { + requiredPresentMode = vsyncEnabled ? VK_PRESENT_MODE_FIFO_KHR : VK_PRESENT_MODE_IMMEDIATE_KHR; + } + } + + bool VulkanSwapChain::isVsyncEnabled() const { + return createdPresentMode == VK_PRESENT_MODE_FIFO_KHR; } uint32_t VulkanSwapChain::getWidth() const { diff --git a/UnleashedRecomp/gpu/rhi/rt64_vulkan.h b/UnleashedRecomp/gpu/rhi/rt64_vulkan.h index c89e90a..ef2f1ff 100644 --- a/UnleashedRecomp/gpu/rhi/rt64_vulkan.h +++ b/UnleashedRecomp/gpu/rhi/rt64_vulkan.h @@ -210,15 +210,19 @@ namespace RT64 { uint32_t height = 0; VkSwapchainCreateInfoKHR createInfo = {}; VkSurfaceFormatKHR pickedSurfaceFormat = {}; - VkPresentModeKHR pickedPresentMode = VK_PRESENT_MODE_FIFO_KHR; + VkPresentModeKHR createdPresentMode = VK_PRESENT_MODE_FIFO_KHR; + VkPresentModeKHR requiredPresentMode = VK_PRESENT_MODE_FIFO_KHR; VkCompositeAlphaFlagBitsKHR pickedAlphaFlag = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; std::vector textures; + bool immediatePresentModeSupported = false; VulkanSwapChain(VulkanCommandQueue *commandQueue, RenderWindow renderWindow, uint32_t textureCount, RenderFormat format); ~VulkanSwapChain() override; bool present(uint32_t textureIndex, RenderCommandSemaphore **waitSemaphores, uint32_t waitSemaphoreCount) override; bool resize() override; bool needsResize() const override; + void setVsyncEnabled(bool vsyncEnabled) override; + bool isVsyncEnabled() const override; uint32_t getWidth() const override; uint32_t getHeight() const override; RenderTexture *getTexture(uint32_t textureIndex) override; diff --git a/UnleashedRecomp/gpu/video.cpp b/UnleashedRecomp/gpu/video.cpp index 1c35277..2ac26bb 100644 --- a/UnleashedRecomp/gpu/video.cpp +++ b/UnleashedRecomp/gpu/video.cpp @@ -837,6 +837,7 @@ static void CreateHostDevice() g_copyCommandFence = g_device->createCommandFence(); g_swapChain = g_queue->createSwapChain(Window::s_windowHandle, Config::TripleBuffering ? 3 : 2, RenderFormat::B8G8R8A8_UNORM); + g_swapChain->setVsyncEnabled(Config::VSync); g_swapChainValid = !g_swapChain->needsResize(); for (auto& acquireSemaphore : g_acquireSemaphores)