From 924756860ef074b9b16d2cb6958e4bbd3225f565 Mon Sep 17 00:00:00 2001 From: Connor McLaughlin Date: Sat, 3 Apr 2021 00:55:09 +1000 Subject: [PATCH] HostDisplay: Support refresh rate queries on all platforms except Mac --- .github/workflows/rolling-release.yml | 2 +- CMakeLists.txt | 3 + README.md | 2 +- .../app/src/cpp/android_host_interface.cpp | 36 ++-- android/app/src/cpp/android_host_interface.h | 3 +- src/common/CMakeLists.txt | 6 +- src/common/common.vcxproj | 1 + src/common/common.vcxproj.filters | 1 + src/common/drm_display.h | 5 + src/common/gl/context_egl_gbm.cpp | 12 +- src/common/gl/context_egl_gbm.h | 2 +- src/common/vulkan/context.cpp | 2 +- src/common/vulkan/swap_chain.cpp | 94 ++++----- src/common/vulkan/swap_chain.h | 15 +- src/common/window_info.cpp | 191 ++++++++++++++++++ src/common/window_info.h | 2 + src/core/host_display.cpp | 8 +- src/core/host_interface.cpp | 42 ---- src/core/host_interface.h | 4 - src/duckstation-nogui/sdl_host_interface.cpp | 23 +-- src/duckstation-qt/qthostinterface.cpp | 4 +- src/frontend-common/common_host_interface.cpp | 13 +- src/frontend-common/common_host_interface.h | 2 +- src/frontend-common/d3d11_host_display.cpp | 15 +- src/frontend-common/opengl_host_display.cpp | 26 +-- src/frontend-common/vulkan_host_display.cpp | 38 +--- 26 files changed, 344 insertions(+), 208 deletions(-) create mode 100644 src/common/window_info.cpp diff --git a/.github/workflows/rolling-release.yml b/.github/workflows/rolling-release.yml index 39936673b..9547f19e9 100644 --- a/.github/workflows/rolling-release.yml +++ b/.github/workflows/rolling-release.yml @@ -166,7 +166,7 @@ jobs: shell: bash run: | sudo apt-get update - sudo apt-get -y install cmake ninja-build ccache libsdl2-dev libgtk-3-dev qtbase5-dev qtbase5-dev-tools qtbase5-private-dev qt5-default qttools5-dev libegl1-mesa-dev libevdev-dev libgbm-dev libdrm-dev libwayland-dev libwayland-egl-backend-dev extra-cmake-modules libcurl4-gnutls-dev + sudo apt-get -y install cmake ninja-build ccache libsdl2-dev libgtk-3-dev qtbase5-dev qtbase5-dev-tools qtbase5-private-dev qt5-default qttools5-dev libegl1-mesa-dev libevdev-dev libgbm-dev libdrm-dev libwayland-dev libwayland-egl-backend-dev extra-cmake-modules libcurl4-gnutls-dev libxrandr-dev - name: Compile build shell: bash diff --git a/CMakeLists.txt b/CMakeLists.txt index d0163d371..773b60295 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -113,6 +113,9 @@ if(USE_EGL) endif() if(USE_X11) find_package(X11 REQUIRED) + if (NOT X11_Xrandr_FOUND) + message(FATAL_ERROR "XRandR extension is required") + endif() endif() if(USE_WAYLAND) find_package(ECM REQUIRED NO_MODULE) diff --git a/README.md b/README.md index 7c43b88b4..200cfad98 100644 --- a/README.md +++ b/README.md @@ -184,7 +184,7 @@ Requirements: ### Linux Requirements (Debian/Ubuntu package names): - CMake (`cmake`) - - SDL2 (`libsdl2-dev`) + - SDL2 (`libsdl2-dev`, `libxrandr-dev`) - pkgconfig (`pkg-config`) - Qt 5 (`qtbase5-dev`, `qtbase5-private-dev`, `qtbase5-dev-tools`, `qttools5-dev`) - libevdev (`libevdev-dev`) diff --git a/android/app/src/cpp/android_host_interface.cpp b/android/app/src/cpp/android_host_interface.cpp index 80a9c7be7..5a086db35 100644 --- a/android/app/src/cpp/android_host_interface.cpp +++ b/android/app/src/cpp/android_host_interface.cpp @@ -177,7 +177,7 @@ jbyteArray VectorToByteArray(JNIEnv* env, const std::vector& data) } jobjectArray CreateObjectArray(JNIEnv* env, jclass object_class, const jobject* objects, size_t num_objects, - bool release_refs/* = false*/) + bool release_refs /* = false*/) { if (!objects || num_objects == 0) return nullptr; @@ -294,18 +294,23 @@ void AndroidHostInterface::RegisterHotkeys() CommonHostInterface::RegisterHotkeys(); } -bool AndroidHostInterface::GetMainDisplayRefreshRate(float* refresh_rate) +float AndroidHostInterface::GetRefreshRate() const { if (!m_emulation_activity_object) - return false; + return 0.0f; - float value = AndroidHelpers::GetJNIEnv()->CallFloatMethod(m_emulation_activity_object, - s_EmulationActivity_method_getRefreshRate); - if (value <= 0.0f) - return false; + const float value = AndroidHelpers::GetJNIEnv()->CallFloatMethod(m_emulation_activity_object, + s_EmulationActivity_method_getRefreshRate); + return (value > 0.0f) ? value : 0.0f; +} - *refresh_rate = value; - return true; +float AndroidHostInterface::GetSurfaceScale(int width, int height) const +{ + if (width <= 0 || height <= 0) + return 1.0f; + + // TODO: Really need a better way of determining this. + return (width > height) ? (static_cast(width) / 1280.0f) : (static_cast(height) / 1280.0f); } void AndroidHostInterface::SetUserDirectory() @@ -591,9 +596,8 @@ bool AndroidHostInterface::AcquireHostDisplay() wi.window_handle = m_surface; wi.surface_width = ANativeWindow_getWidth(m_surface); wi.surface_height = ANativeWindow_getHeight(m_surface); - - // TODO: Really need a better way of determining this. - wi.surface_scale = 2.0f; + wi.surface_refresh_rate = GetRefreshRate(); + wi.surface_scale = GetSurfaceScale(wi.surface_width, wi.surface_height); switch (g_settings.gpu_renderer) { @@ -709,7 +713,7 @@ void AndroidHostInterface::SurfaceChanged(ANativeWindow* surface, int format, in if (m_display && (width != m_display->GetWindowWidth() || height != m_display->GetWindowHeight())) { m_display->ResizeRenderWindow(width, height); - OnHostDisplayResized(width, height, m_display->GetWindowScale()); + OnHostDisplayResized(); } return; @@ -724,11 +728,12 @@ void AndroidHostInterface::SurfaceChanged(ANativeWindow* surface, int format, in wi.window_handle = surface; wi.surface_width = width; wi.surface_height = height; - wi.surface_scale = m_display->GetWindowScale(); + wi.surface_refresh_rate = GetRefreshRate(); + wi.surface_scale = GetSurfaceScale(width, height); m_display->ChangeRenderWindow(wi); if (surface) - OnHostDisplayResized(width, height, m_display->GetWindowScale()); + OnHostDisplayResized(); if (surface && System::GetState() == System::State::Paused) PauseSystem(false); @@ -1666,7 +1671,6 @@ DEFINE_JNI_ARGS_METHOD(jstring, AndroidHostInterface_importBIOSImage, jobject ob return env->NewStringUTF(hash.ToString().c_str()); } - DEFINE_JNI_ARGS_METHOD(jboolean, AndroidHostInterface_hasMediaSubImages, jobject obj) { if (!System::IsValid()) diff --git a/android/app/src/cpp/android_host_interface.h b/android/app/src/cpp/android_host_interface.h index ae7d7265f..d14a092f6 100644 --- a/android/app/src/cpp/android_host_interface.h +++ b/android/app/src/cpp/android_host_interface.h @@ -39,7 +39,6 @@ public: void ReportMessage(const char* message) override; std::unique_ptr OpenPackageFile(const char* path, u32 flags) override; - bool GetMainDisplayRefreshRate(float* refresh_rate) override; bool IsEmulationThreadRunning() const { return m_emulation_thread_running.load(); } bool IsEmulationThreadPaused() const; @@ -90,6 +89,8 @@ private: void UpdateInputMap(SettingsInterface& si) override; void SetVibration(bool enabled); void UpdateVibration(); + float GetRefreshRate() const; + float GetSurfaceScale(int width, int height) const; jobject m_java_object = {}; jobject m_emulation_activity_object = {}; diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index beebd4280..f664c4e6d 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -108,6 +108,8 @@ add_library(common vulkan/util.h wav_writer.cpp wav_writer.h + window_info.cpp + window_info.h ) target_include_directories(common PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/..") @@ -147,8 +149,8 @@ if(USE_X11) gl/x11_window.h ) target_compile_definitions(common PRIVATE "-DUSE_X11=1") - target_include_directories(common PRIVATE "${X11_INCLUDE_DIR}") - target_link_libraries(common PRIVATE "${X11_LIBRARIES}") + target_include_directories(common PRIVATE "${X11_INCLUDE_DIR}" "${X11_Xrandr_INCLUDE_PATH}") + target_link_libraries(common PRIVATE "${X11_LIBRARIES}" "${X11_Xrandr_LIB}") endif() if(USE_DRMKMS) diff --git a/src/common/common.vcxproj b/src/common/common.vcxproj index 0e1306abe..ad1398e73 100644 --- a/src/common/common.vcxproj +++ b/src/common/common.vcxproj @@ -189,6 +189,7 @@ + diff --git a/src/common/common.vcxproj.filters b/src/common/common.vcxproj.filters index f9c3e31ab..522ba0038 100644 --- a/src/common/common.vcxproj.filters +++ b/src/common/common.vcxproj.filters @@ -217,6 +217,7 @@ + diff --git a/src/common/drm_display.h b/src/common/drm_display.h index d0411a50f..39506b7eb 100644 --- a/src/common/drm_display.h +++ b/src/common/drm_display.h @@ -17,6 +17,11 @@ public: int GetCardFD() const { return m_card_fd; } u32 GetWidth() const { return m_mode->hdisplay; } u32 GetHeight() const { return m_mode->vdisplay; } + float GetRefreshRate() const + { + return (static_cast(m_mode->clock) * 1000.0f) / + (static_cast(m_mode->htotal) * static_cast(m_mode->vtotal)); + } u32 GetModeCount() const { return m_connector->count_modes; } u32 GetModeWidth(u32 i) const { return m_connector->modes[i].hdisplay; } diff --git a/src/common/gl/context_egl_gbm.cpp b/src/common/gl/context_egl_gbm.cpp index fad615f61..8a8163af2 100644 --- a/src/common/gl/context_egl_gbm.cpp +++ b/src/common/gl/context_egl_gbm.cpp @@ -43,7 +43,7 @@ std::unique_ptr ContextEGLGBM::Create(const WindowInfo& wi, const Versi size_t num_versions_to_try) { std::unique_ptr context = std::make_unique(wi); - if (!context->CreateDisplay(wi) || !context->CreateGBMDevice() || + if (!context->CreateDisplay() || !context->CreateGBMDevice() || !context->Initialize(versions_to_try, num_versions_to_try)) { return nullptr; @@ -81,9 +81,15 @@ bool ContextEGLGBM::CreateGBMDevice() return true; } -bool ContextEGLGBM::CreateDisplay(const WindowInfo& wi) +bool ContextEGLGBM::CreateDisplay() { - return m_drm_display.Initialize(wi.surface_width, wi.surface_height, wi.surface_refresh_rate); + if (!m_drm_display.Initialize(m_wi.surface_width, m_wi.surface_height, m_wi.surface_refresh_rate)) + return false; + + m_wi.surface_width = m_drm_display.GetWidth(); + m_wi.surface_height = m_drm_display.GetHeight(); + m_wi.surface_refresh_rate = m_drm_display.GetRefreshRate(); + return true; } bool ContextEGLGBM::SetDisplay() diff --git a/src/common/gl/context_egl_gbm.h b/src/common/gl/context_egl_gbm.h index b6affe5f1..4cde5f69f 100644 --- a/src/common/gl/context_egl_gbm.h +++ b/src/common/gl/context_egl_gbm.h @@ -44,7 +44,7 @@ private: u32 fb_id; }; - bool CreateDisplay(const WindowInfo& wi); + bool CreateDisplay(); bool CreateGBMDevice(); Buffer* LockFrontBuffer(); diff --git a/src/common/vulkan/context.cpp b/src/common/vulkan/context.cpp index 884c4bbfd..b605ed5ab 100644 --- a/src/common/vulkan/context.cpp +++ b/src/common/vulkan/context.cpp @@ -353,7 +353,7 @@ bool Context::Create(std::string_view gpu_name, const WindowInfo* wi, std::uniqu wi_copy = *wi; if (enable_surface && - (surface = SwapChain::CreateVulkanSurface(instance, gpus[gpu_index], wi_copy)) == VK_NULL_HANDLE) + (surface = SwapChain::CreateVulkanSurface(instance, gpus[gpu_index], &wi_copy)) == VK_NULL_HANDLE) { vkDestroyInstance(instance, nullptr); Vulkan::UnloadVulkanLibrary(); diff --git a/src/common/vulkan/swap_chain.cpp b/src/common/vulkan/swap_chain.cpp index 5d8c5cd6e..aca98d728 100644 --- a/src/common/vulkan/swap_chain.cpp +++ b/src/common/vulkan/swap_chain.cpp @@ -20,9 +20,9 @@ Log_SetChannel(Vulkan::SwapChain); #if defined(__APPLE__) #include -static bool CreateMetalLayer(WindowInfo& wi) +static bool CreateMetalLayer(WindowInfo* wi) { - id view = reinterpret_cast(wi.window_handle); + id view = reinterpret_cast(wi->window_handle); Class clsCAMetalLayer = objc_getClass("CAMetalLayer"); if (!clsCAMetalLayer) @@ -55,28 +55,28 @@ static bool CreateMetalLayer(WindowInfo& wi) reinterpret_cast(objc_msgSend)(layer, sel_getUid("setContentsScale:"), factor); // Store the layer pointer, that way MoltenVK doesn't call [NSView layer] outside the main thread. - wi.surface_handle = layer; + wi->surface_handle = layer; return true; } -static void DestroyMetalLayer(WindowInfo& wi) +static void DestroyMetalLayer(WindowInfo* wi) { - id view = reinterpret_cast(wi.window_handle); - id layer = reinterpret_cast(wi.surface_handle); + id view = reinterpret_cast(wi->window_handle); + id layer = reinterpret_cast(wi->surface_handle); if (layer == nil) return; reinterpret_cast(objc_msgSend)(view, sel_getUid("setLayer:"), nil); reinterpret_cast(objc_msgSend)(view, sel_getUid("setWantsLayer:"), NO); reinterpret_cast(objc_msgSend)(layer, sel_getUid("release")); - wi.surface_handle = nullptr; + wi->surface_handle = nullptr; } #endif namespace Vulkan { SwapChain::SwapChain(const WindowInfo& wi, VkSurfaceKHR surface, bool vsync) - : m_wi(wi), m_vsync_enabled(vsync), m_surface(surface) + : m_window_info(wi), m_surface(surface), m_vsync_enabled(vsync) { } @@ -88,9 +88,9 @@ SwapChain::~SwapChain() DestroySurface(); } -static VkSurfaceKHR CreateDisplaySurface(VkInstance instance, VkPhysicalDevice physical_device, const WindowInfo& wi) +static VkSurfaceKHR CreateDisplaySurface(VkInstance instance, VkPhysicalDevice physical_device, WindowInfo* wi) { - Log_InfoPrintf("Trying to create a VK_KHR_display surface of %ux%u", wi.surface_width, wi.surface_height); + Log_InfoPrintf("Trying to create a VK_KHR_display surface of %ux%u", wi->surface_width, wi->surface_height); u32 num_displays; VkResult res = vkGetPhysicalDeviceDisplayPropertiesKHR(physical_device, &num_displays, nullptr); @@ -137,9 +137,9 @@ static VkSurfaceKHR CreateDisplaySurface(VkInstance instance, VkPhysicalDevice p refresh_rate); if (!matched_mode && - ((wi.surface_width == 0 && wi.surface_height == 0) || - (mode.parameters.visibleRegion.width == wi.surface_width && mode.parameters.visibleRegion.height && - (wi.surface_refresh_rate == 0.0f || std::abs(refresh_rate - wi.surface_refresh_rate) < 0.1f)))) + ((wi->surface_width == 0 && wi->surface_height == 0) || + (mode.parameters.visibleRegion.width == wi->surface_width && mode.parameters.visibleRegion.height && + (wi->surface_refresh_rate == 0.0f || std::abs(refresh_rate - wi->surface_refresh_rate) < 0.1f)))) { matched_mode = &mode; } @@ -219,6 +219,7 @@ static VkSurfaceKHR CreateDisplaySurface(VkInstance instance, VkPhysicalDevice p continue; } + wi->surface_refresh_rate = static_cast(matched_mode->parameters.refreshRate) / 1000.0f; return surface; } @@ -286,17 +287,17 @@ static std::vector GetDisplayModes(VkInstance ins return result; } -VkSurfaceKHR SwapChain::CreateVulkanSurface(VkInstance instance, VkPhysicalDevice physical_device, WindowInfo& wi) +VkSurfaceKHR SwapChain::CreateVulkanSurface(VkInstance instance, VkPhysicalDevice physical_device, WindowInfo* wi) { #if defined(VK_USE_PLATFORM_WIN32_KHR) - if (wi.type == WindowInfo::Type::Win32) + if (wi->type == WindowInfo::Type::Win32) { VkWin32SurfaceCreateInfoKHR surface_create_info = { VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR, // VkStructureType sType nullptr, // const void* pNext 0, // VkWin32SurfaceCreateFlagsKHR flags nullptr, // HINSTANCE hinstance - reinterpret_cast(wi.window_handle) // HWND hwnd + reinterpret_cast(wi->window_handle) // HWND hwnd }; VkSurfaceKHR surface; @@ -312,14 +313,14 @@ VkSurfaceKHR SwapChain::CreateVulkanSurface(VkInstance instance, VkPhysicalDevic #endif #if defined(VK_USE_PLATFORM_XLIB_KHR) - if (wi.type == WindowInfo::Type::X11) + if (wi->type == WindowInfo::Type::X11) { VkXlibSurfaceCreateInfoKHR surface_create_info = { VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR, // VkStructureType sType nullptr, // const void* pNext 0, // VkXlibSurfaceCreateFlagsKHR flags - static_cast(wi.display_connection), // Display* dpy - reinterpret_cast(wi.window_handle) // Window window + static_cast(wi->display_connection), // Display* dpy + reinterpret_cast(wi->window_handle) // Window window }; VkSurfaceKHR surface; @@ -335,11 +336,11 @@ VkSurfaceKHR SwapChain::CreateVulkanSurface(VkInstance instance, VkPhysicalDevic #endif #if defined(VK_USE_PLATFORM_WAYLAND_KHR) - if (wi.type == WindowInfo::Type::Wayland) + if (wi->type == WindowInfo::Type::Wayland) { VkWaylandSurfaceCreateInfoKHR surface_create_info = {VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR, nullptr, 0, - static_cast(wi.display_connection), - static_cast(wi.window_handle)}; + static_cast(wi->display_connection), + static_cast(wi->window_handle)}; VkSurfaceKHR surface; VkResult res = vkCreateWaylandSurfaceKHR(instance, &surface_create_info, nullptr, &surface); @@ -354,13 +355,13 @@ VkSurfaceKHR SwapChain::CreateVulkanSurface(VkInstance instance, VkPhysicalDevic #endif #if defined(VK_USE_PLATFORM_ANDROID_KHR) - if (wi.type == WindowInfo::Type::Android) + if (wi->type == WindowInfo::Type::Android) { VkAndroidSurfaceCreateInfoKHR surface_create_info = { - VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR, // VkStructureType sType - nullptr, // const void* pNext - 0, // VkAndroidSurfaceCreateFlagsKHR flags - reinterpret_cast(wi.window_handle) // ANativeWindow* window + VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR, // VkStructureType sType + nullptr, // const void* pNext + 0, // VkAndroidSurfaceCreateFlagsKHR flags + reinterpret_cast(wi->window_handle) // ANativeWindow* window }; VkSurfaceKHR surface; @@ -376,13 +377,13 @@ VkSurfaceKHR SwapChain::CreateVulkanSurface(VkInstance instance, VkPhysicalDevic #endif #if defined(VK_USE_PLATFORM_METAL_EXT) - if (wi.type == WindowInfo::Type::MacOS) + if (wi->type == WindowInfo::Type::MacOS) { - if (!wi.surface_handle && !CreateMetalLayer(wi)) + if (!wi->surface_handle && !CreateMetalLayer(wi)) return VK_NULL_HANDLE; VkMetalSurfaceCreateInfoEXT surface_create_info = {VK_STRUCTURE_TYPE_METAL_SURFACE_CREATE_INFO_EXT, nullptr, 0, - static_cast(wi.surface_handle)}; + static_cast(wi->surface_handle)}; VkSurfaceKHR surface; VkResult res = vkCreateMetalSurfaceEXT(instance, &surface_create_info, nullptr, &surface); @@ -395,10 +396,10 @@ VkSurfaceKHR SwapChain::CreateVulkanSurface(VkInstance instance, VkPhysicalDevic return surface; } #elif defined(VK_USE_PLATFORM_MACOS_MVK) - if (wi.type == WindowInfo::Type::MacOS) + if (wi->type == WindowInfo::Type::MacOS) { VkMacOSSurfaceCreateInfoMVK surface_create_info = {VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK, nullptr, 0, - wi.window_handle}; + wi->window_handle}; VkSurfaceKHR surface; VkResult res = vkCreateMacOSSurfaceMVK(instance, &surface_create_info, nullptr, &surface); @@ -412,18 +413,18 @@ VkSurfaceKHR SwapChain::CreateVulkanSurface(VkInstance instance, VkPhysicalDevic } #endif - if (wi.type == WindowInfo::Type::Display) + if (wi->type == WindowInfo::Type::Display) return CreateDisplaySurface(instance, physical_device, wi); return VK_NULL_HANDLE; } -void SwapChain::DestroyVulkanSurface(VkInstance instance, WindowInfo& wi, VkSurfaceKHR surface) +void SwapChain::DestroyVulkanSurface(VkInstance instance, WindowInfo* wi, VkSurfaceKHR surface) { vkDestroySurfaceKHR(g_vulkan_context->GetVulkanInstance(), surface, nullptr); #if defined(__APPLE__) - if (wi.type == WindowInfo::Type::MacOS && wi.surface_handle) + if (wi->type == WindowInfo::Type::MacOS && wi->surface_handle) DestroyMetalLayer(wi); #endif } @@ -567,8 +568,8 @@ bool SwapChain::CreateSwapChain() if (size.width == UINT32_MAX) #endif { - size.width = m_wi.surface_width; - size.height = m_wi.surface_height; + size.width = m_window_info.surface_width; + size.height = m_window_info.surface_height; } size.width = std::clamp(size.width, surface_capabilities.minImageExtent.width, surface_capabilities.maxImageExtent.width); @@ -637,8 +638,8 @@ bool SwapChain::CreateSwapChain() if (old_swap_chain != VK_NULL_HANDLE) vkDestroySwapchainKHR(g_vulkan_context->GetDevice(), old_swap_chain, nullptr); - m_width = size.width; - m_height = size.height; + m_window_info.surface_width = size.width; + m_window_info.surface_height = size.height; return true; } @@ -675,8 +676,8 @@ bool SwapChain::SetupSwapChainImages() image.image = images[i]; // Create texture object, which creates a view of the backbuffer - if (!image.texture.Adopt(image.image, VK_IMAGE_VIEW_TYPE_2D, m_width, m_height, 1, 1, m_surface_format.format, - VK_SAMPLE_COUNT_1_BIT)) + if (!image.texture.Adopt(image.image, VK_IMAGE_VIEW_TYPE_2D, m_window_info.surface_width, + m_window_info.surface_height, 1, 1, m_surface_format.format, VK_SAMPLE_COUNT_1_BIT)) { return false; } @@ -723,8 +724,8 @@ bool SwapChain::ResizeSwapChain(u32 new_width /* = 0 */, u32 new_height /* = 0 * if (new_width != 0 && new_height != 0) { - m_wi.surface_width = new_width; - m_wi.surface_height = new_height; + m_window_info.surface_width = new_width; + m_window_info.surface_height = new_height; } if (!CreateSwapChain() || !SetupSwapChainImages() || !CreateSemaphores()) @@ -769,8 +770,9 @@ bool SwapChain::RecreateSurface(const WindowInfo& new_wi) DestroySurface(); // Re-create the surface with the new native handle - m_wi = new_wi; - m_surface = CreateVulkanSurface(g_vulkan_context->GetVulkanInstance(), g_vulkan_context->GetPhysicalDevice(), m_wi); + m_window_info = new_wi; + m_surface = + CreateVulkanSurface(g_vulkan_context->GetVulkanInstance(), g_vulkan_context->GetPhysicalDevice(), &m_window_info); if (m_surface == VK_NULL_HANDLE) return false; @@ -799,7 +801,7 @@ bool SwapChain::RecreateSurface(const WindowInfo& new_wi) void SwapChain::DestroySurface() { - DestroyVulkanSurface(g_vulkan_context->GetVulkanInstance(), m_wi, m_surface); + DestroyVulkanSurface(g_vulkan_context->GetVulkanInstance(), &m_window_info, m_surface); m_surface = VK_NULL_HANDLE; } diff --git a/src/common/vulkan/swap_chain.h b/src/common/vulkan/swap_chain.h index 728752e81..02360145a 100644 --- a/src/common/vulkan/swap_chain.h +++ b/src/common/vulkan/swap_chain.h @@ -21,10 +21,10 @@ public: ~SwapChain(); // Creates a vulkan-renderable surface for the specified window handle. - static VkSurfaceKHR CreateVulkanSurface(VkInstance instance, VkPhysicalDevice physical_device, WindowInfo& wi); + static VkSurfaceKHR CreateVulkanSurface(VkInstance instance, VkPhysicalDevice physical_device, WindowInfo* wi); // Destroys a previously-created surface. - static void DestroyVulkanSurface(VkInstance instance, WindowInfo& wi, VkSurfaceKHR surface); + static void DestroyVulkanSurface(VkInstance instance, WindowInfo* wi, VkSurfaceKHR surface); // Enumerates fullscreen modes for window info. struct FullscreenModeInfo @@ -44,8 +44,9 @@ public: ALWAYS_INLINE VkFormat GetTextureFormat() const { return m_surface_format.format; } ALWAYS_INLINE bool IsVSyncEnabled() const { return m_vsync_enabled; } ALWAYS_INLINE VkSwapchainKHR GetSwapChain() const { return m_swap_chain; } - ALWAYS_INLINE u32 GetWidth() const { return m_width; } - ALWAYS_INLINE u32 GetHeight() const { return m_height; } + ALWAYS_INLINE const WindowInfo& GetWindowInfo() const { return m_window_info; } + ALWAYS_INLINE u32 GetWidth() const { return m_window_info.surface_width; } + ALWAYS_INLINE u32 GetHeight() const { return m_window_info.surface_height; } ALWAYS_INLINE u32 GetCurrentImageIndex() const { return m_current_image; } ALWAYS_INLINE u32 GetImageCount() const { return static_cast(m_images.size()); } ALWAYS_INLINE VkImage GetCurrentImage() const { return m_images[m_current_image].image; } @@ -87,10 +88,7 @@ private: VkFramebuffer framebuffer; }; - u32 m_width = 0; - u32 m_height = 0; - WindowInfo m_wi; - bool m_vsync_enabled = false; + WindowInfo m_window_info; VkSurfaceKHR m_surface = VK_NULL_HANDLE; VkSurfaceFormatKHR m_surface_format = {}; @@ -105,6 +103,7 @@ private: VkSwapchainKHR m_swap_chain = VK_NULL_HANDLE; std::vector m_images; u32 m_current_image = 0; + bool m_vsync_enabled = false; }; } // namespace Vulkan diff --git a/src/common/window_info.cpp b/src/common/window_info.cpp new file mode 100644 index 000000000..7d88ab3f3 --- /dev/null +++ b/src/common/window_info.cpp @@ -0,0 +1,191 @@ +#include "window_info.h" +#include "common/log.h" +Log_SetChannel(WindowInfo); + +#if defined(_WIN32) + +#include "common/windows_headers.h" +#include + +static bool GetRefreshRateFromDWM(HWND hwnd, float* refresh_rate) +{ + static HMODULE dwm_module = nullptr; + static HRESULT(STDAPICALLTYPE * is_composition_enabled)(BOOL * pfEnabled) = nullptr; + static HRESULT(STDAPICALLTYPE * get_timing_info)(HWND hwnd, DWM_TIMING_INFO * pTimingInfo) = nullptr; + static bool load_tried = false; + if (!load_tried) + { + load_tried = true; + dwm_module = LoadLibrary("dwmapi.dll"); + if (dwm_module) + { + std::atexit([]() { + FreeLibrary(dwm_module); + dwm_module = nullptr; + }); + is_composition_enabled = + reinterpret_cast(GetProcAddress(dwm_module, "DwmIsCompositionEnabled")); + get_timing_info = + reinterpret_cast(GetProcAddress(dwm_module, "DwmGetCompositionTimingInfo")); + } + } + + BOOL composition_enabled; + if (!is_composition_enabled || FAILED(is_composition_enabled(&composition_enabled) || !get_timing_info)) + return false; + + DWM_TIMING_INFO ti = {}; + ti.cbSize = sizeof(ti); + HRESULT hr = get_timing_info(nullptr, &ti); + if (SUCCEEDED(hr)) + { + if (ti.rateRefresh.uiNumerator == 0 || ti.rateRefresh.uiDenominator == 0) + return false; + + *refresh_rate = static_cast(ti.rateRefresh.uiNumerator) / static_cast(ti.rateRefresh.uiDenominator); + return true; + } + + return false; +} + +static bool GetRefreshRateFromMonitor(HWND hwnd, float* refresh_rate) +{ + HMONITOR mon = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST); + if (!mon) + return false; + + MONITORINFOEXW mi = {}; + mi.cbSize = sizeof(mi); + if (GetMonitorInfoW(mon, &mi)) + { + DEVMODEW dm = {}; + dm.dmSize = sizeof(dm); + + // 0/1 are reserved for "defaults". + if (EnumDisplaySettingsW(mi.szDevice, ENUM_CURRENT_SETTINGS, &dm) && dm.dmDisplayFrequency > 1) + { + *refresh_rate = static_cast(dm.dmDisplayFrequency); + return true; + } + } + + return false; +} + +bool WindowInfo::QueryRefreshRateForWindow(const WindowInfo& wi, float* refresh_rate) +{ + if (wi.type != Type::Win32 || !wi.window_handle) + return false; + + // Try DWM first, then fall back to integer values. + const HWND hwnd = static_cast(wi.window_handle); + return GetRefreshRateFromDWM(hwnd, refresh_rate) || GetRefreshRateFromMonitor(hwnd, refresh_rate); +} + +#elif defined(__linux__) + +#ifdef USE_X11 + +#include "common/scope_guard.h" +#include "gl/x11_window.h" +#include + +static bool GetRefreshRateFromXRandR(const WindowInfo& wi, float* refresh_rate) +{ + Display* display = static_cast(wi.display_connection); + Window window = static_cast(reinterpret_cast(wi.window_handle)); + if (!display || !window) + return false; + + GL::X11InhibitErrors inhibiter; + + XRRScreenResources* res = XRRGetScreenResources(display, window); + if (!res) + { + Log_ErrorPrint("XRRGetScreenResources() failed"); + return false; + } + + Common::ScopeGuard res_guard([res]() { XRRFreeScreenResources(res); }); + + int num_monitors; + XRRMonitorInfo* mi = XRRGetMonitors(display, window, True, &num_monitors); + if (num_monitors < 0) + { + Log_ErrorPrint("XRRGetMonitors() failed"); + return false; + } + else if (num_monitors > 1) + { + Log_WarningPrintf("XRRGetMonitors() returned %d monitors, using first", num_monitors); + } + + Common::ScopeGuard mi_guard([mi]() { XRRFreeMonitors(mi); }); + if (mi->noutput <= 0) + { + Log_ErrorPrint("Monitor has no outputs"); + return false; + } + else if (mi->noutput > 1) + { + Log_WarningPrintf("Monitor has %d outputs, using first", mi->noutput); + } + + XRROutputInfo* oi = XRRGetOutputInfo(display, res, mi->outputs[0]); + if (!oi) + { + Log_ErrorPrint("XRRGetOutputInfo() failed"); + return false; + } + + Common::ScopeGuard oi_guard([oi]() { XRRFreeOutputInfo(oi); }); + + XRRCrtcInfo* ci = XRRGetCrtcInfo(display, res, oi->crtc); + if (!ci) + { + Log_ErrorPrint("XRRGetCrtcInfo() failed"); + return false; + } + + Common::ScopeGuard ci_guard([ci]() { XRRFreeCrtcInfo(ci); }); + + XRRModeInfo* mode = nullptr; + for (int i = 0; i < res->nmode; i++) + { + if (res->modes[i].id == ci->mode) + { + mode = &res->modes[i]; + break; + } + } + if (!mode) + { + Log_ErrorPrintf("Failed to look up mode %d (of %d)", static_cast(ci->mode), res->nmode); + return false; + } + + if (mode->dotClock == 0 || mode->hTotal == 0 || mode->vTotal == 0) + { + Log_ErrorPrintf("Modeline is invalid: %ld/%d/%d", mode->dotClock, mode->hTotal, mode->vTotal); + return false; + } + + *refresh_rate = + static_cast(mode->dotClock) / (static_cast(mode->hTotal) * static_cast(mode->vTotal)); + return true; +} + +#endif // USE_X11 + +bool WindowInfo::QueryRefreshRateForWindow(const WindowInfo& wi, float* refresh_rate) +{ +#if defined(USE_X11) + if (wi.type == WindowInfo::Type::X11) + return GetRefreshRateFromXRandR(wi, refresh_rate); +#endif + + return false; +} + +#endif \ No newline at end of file diff --git a/src/common/window_info.h b/src/common/window_info.h index 29194c75c..342d316c4 100644 --- a/src/common/window_info.h +++ b/src/common/window_info.h @@ -38,4 +38,6 @@ struct WindowInfo #ifdef __APPLE__ void* surface_handle = nullptr; #endif + + static bool QueryRefreshRateForWindow(const WindowInfo& wi, float* refresh_rate); }; diff --git a/src/core/host_display.cpp b/src/core/host_display.cpp index 141fcad5e..3bf681032 100644 --- a/src/core/host_display.cpp +++ b/src/core/host_display.cpp @@ -88,7 +88,13 @@ bool HostDisplay::SetDisplayPixels(HostDisplayPixelFormat format, u32 width, u32 bool HostDisplay::GetHostRefreshRate(float* refresh_rate) { - return g_host_interface->GetMainDisplayRefreshRate(refresh_rate); + if (m_window_info.surface_refresh_rate > 0.0f) + { + *refresh_rate = m_window_info.surface_refresh_rate; + return true; + } + + return WindowInfo::QueryRefreshRateForWindow(m_window_info, refresh_rate); } void HostDisplay::SetSoftwareCursor(std::unique_ptr texture, float scale /*= 1.0f*/) diff --git a/src/core/host_interface.cpp b/src/core/host_interface.cpp index ec87c62fa..6bd71b512 100644 --- a/src/core/host_interface.cpp +++ b/src/core/host_interface.cpp @@ -25,11 +25,6 @@ #include Log_SetChannel(HostInterface); -#ifdef _WIN32 -#include "common/windows_headers.h" -#include -#endif - HostInterface* g_host_interface; HostInterface::HostInterface() @@ -1065,43 +1060,6 @@ std::string HostInterface::TranslateStdString(const char* context, const char* s return result; } -bool HostInterface::GetMainDisplayRefreshRate(float* refresh_rate) -{ -#ifdef _WIN32 - static HMODULE dwm_module = nullptr; - static HRESULT(STDAPICALLTYPE * get_timing_info)(HWND hwnd, DWM_TIMING_INFO * pTimingInfo) = nullptr; - static bool load_tried = false; - if (!load_tried) - { - load_tried = true; - dwm_module = LoadLibrary("dwmapi.dll"); - if (dwm_module) - { - std::atexit([]() { - FreeLibrary(dwm_module); - dwm_module = nullptr; - }); - get_timing_info = - reinterpret_cast(GetProcAddress(dwm_module, "DwmGetCompositionTimingInfo")); - } - } - - DWM_TIMING_INFO ti = {}; - ti.cbSize = sizeof(ti); - HRESULT hr = get_timing_info(nullptr, &ti); - if (SUCCEEDED(hr)) - { - if (ti.rateRefresh.uiNumerator == 0 || ti.rateRefresh.uiDenominator == 0) - return false; - - *refresh_rate = static_cast(ti.rateRefresh.uiNumerator) / static_cast(ti.rateRefresh.uiDenominator); - return true; - } -#endif - - return false; -} - void HostInterface::ToggleSoftwareRendering() { if (System::IsShutdown() || g_settings.gpu_renderer == GPURenderer::Software) diff --git a/src/core/host_interface.h b/src/core/host_interface.h index bba76465e..945b4fcdc 100644 --- a/src/core/host_interface.h +++ b/src/core/host_interface.h @@ -126,10 +126,6 @@ public: virtual std::string TranslateStdString(const char* context, const char* str, const char* disambiguation = nullptr, int n = -1) const; - /// Returns the refresh rate for the "main" display. Use when it's not possible to query the graphics API for the - /// refresh rate of the monitor the window is running in. - virtual bool GetMainDisplayRefreshRate(float* refresh_rate); - /// Returns the path to the directory to search for BIOS images. virtual std::string GetBIOSDirectory(); diff --git a/src/duckstation-nogui/sdl_host_interface.cpp b/src/duckstation-nogui/sdl_host_interface.cpp index d49fe7cd5..6cf9e0361 100644 --- a/src/duckstation-nogui/sdl_host_interface.cpp +++ b/src/duckstation-nogui/sdl_host_interface.cpp @@ -95,12 +95,6 @@ bool SDLHostInterface::SetFullscreen(bool enabled) return true; SDL_SetWindowFullscreen(m_window, enabled ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0); - - int window_width, window_height; - SDL_GetWindowSize(m_window, &window_width, &window_height); - m_display->ResizeRenderWindow(window_width, window_height); - OnHostDisplayResized(window_width, window_height, GetDPIScaleFactor(m_window)); - m_fullscreen = enabled; return true; } @@ -119,11 +113,6 @@ bool SDLHostInterface::RequestRenderWindowSize(s32 new_window_width, s32 new_win 1); SDL_SetWindowSize(m_window, scaled_width, scaled_height); - - s32 window_width, window_height; - SDL_GetWindowSize(m_window, &window_width, &window_height); - m_display->ResizeRenderWindow(window_width, window_height); - return true; } @@ -287,14 +276,12 @@ void SDLHostInterface::HandleSDLEvent(const SDL_Event* event) { case SDL_WINDOWEVENT: { - if (event->window.event == SDL_WINDOWEVENT_RESIZED) + if (event->window.event == SDL_WINDOWEVENT_SIZE_CHANGED) { - m_display->ResizeRenderWindow(event->window.data1, event->window.data2); - OnHostDisplayResized(event->window.data1, event->window.data2, GetDPIScaleFactor(m_window)); - } - else if (event->window.event == SDL_WINDOWEVENT_MOVED) - { - // TODO: Do we want to update DPI scale here? + s32 window_width, window_height; + SDL_GetWindowSize(m_window, &window_width, &window_height); + m_display->ResizeRenderWindow(window_width, window_height); + OnHostDisplayResized(); } } break; diff --git a/src/duckstation-qt/qthostinterface.cpp b/src/duckstation-qt/qthostinterface.cpp index 5e87f8c7d..678e1bf3e 100644 --- a/src/duckstation-qt/qthostinterface.cpp +++ b/src/duckstation-qt/qthostinterface.cpp @@ -470,7 +470,7 @@ void QtHostInterface::onDisplayWindowResized(int width, int height) Log_DevPrintf("Display window resized to %dx%d", width, height); m_display->ResizeRenderWindow(width, height); - OnHostDisplayResized(width, height, m_display->GetWindowScale()); + OnHostDisplayResized(); // re-render the display, since otherwise it will be out of date and stretched if paused if (!System::IsShutdown()) @@ -615,7 +615,7 @@ void QtHostInterface::updateDisplayState() connectDisplaySignals(display_widget); m_is_exclusive_fullscreen = m_display->IsFullscreen(); - OnHostDisplayResized(m_display->GetWindowWidth(), m_display->GetWindowHeight(), m_display->GetWindowScale()); + OnHostDisplayResized(); if (!System::IsShutdown()) { diff --git a/src/frontend-common/common_host_interface.cpp b/src/frontend-common/common_host_interface.cpp index a87dba177..cf3df6b44 100644 --- a/src/frontend-common/common_host_interface.cpp +++ b/src/frontend-common/common_host_interface.cpp @@ -520,6 +520,8 @@ bool CommonHostInterface::CreateHostDisplayResources() const float framebuffer_scale = m_display->GetWindowScale(); ImGui::GetIO().DisplayFramebufferScale = ImVec2(framebuffer_scale, framebuffer_scale); + ImGui::GetIO().DisplaySize.x = static_cast(m_display->GetWindowWidth()); + ImGui::GetIO().DisplaySize.y = static_cast(m_display->GetWindowHeight()); ImGui::GetStyle() = ImGuiStyle(); ImGui::StyleColorsDarker(); ImGui::GetStyle().ScaleAllSizes(framebuffer_scale); @@ -566,8 +568,15 @@ void CommonHostInterface::ReleaseHostDisplayResources() m_logo_texture.reset(); } -void CommonHostInterface::OnHostDisplayResized(u32 new_width, u32 new_height, float new_scale) +void CommonHostInterface::OnHostDisplayResized() { + const u32 new_width = m_display ? std::max(m_display->GetWindowWidth(), 1) : 0; + const u32 new_height = m_display ? std::max(m_display->GetWindowHeight(), 1) : 0; + const float new_scale = m_display ? m_display->GetWindowScale() : 1.0f; + + ImGui::GetIO().DisplaySize.x = static_cast(new_width); + ImGui::GetIO().DisplaySize.y = static_cast(new_height); + if (new_scale != ImGui::GetIO().DisplayFramebufferScale.x) { ImGui::GetIO().DisplayFramebufferScale = ImVec2(new_scale, new_scale); @@ -1792,7 +1801,7 @@ void CommonHostInterface::RegisterGeneralHotkeys() if (pressed) SetTurboEnabled(!m_turbo_enabled); }); -#ifndef ANDROID +#ifndef __ANDROID__ RegisterHotkey(StaticString(TRANSLATABLE("Hotkeys", "General")), StaticString("ToggleFullscreen"), StaticString(TRANSLATABLE("Hotkeys", "Toggle Fullscreen")), [this](bool pressed) { if (pressed) diff --git a/src/frontend-common/common_host_interface.h b/src/frontend-common/common_host_interface.h index e340f8c14..21816f8e9 100644 --- a/src/frontend-common/common_host_interface.h +++ b/src/frontend-common/common_host_interface.h @@ -414,7 +414,7 @@ protected: bool CreateHostDisplayResources(); void ReleaseHostDisplayResources(); - void OnHostDisplayResized(u32 new_width, u32 new_height, float new_scale); + void OnHostDisplayResized(); virtual void DrawImGuiWindows(); diff --git a/src/frontend-common/d3d11_host_display.cpp b/src/frontend-common/d3d11_host_display.cpp index 12faaf857..177c05fde 100644 --- a/src/frontend-common/d3d11_host_display.cpp +++ b/src/frontend-common/d3d11_host_display.cpp @@ -473,10 +473,17 @@ bool D3D11HostDisplay::CreateSwapChainRTV() m_window_info.surface_width = backbuffer_desc.Width; m_window_info.surface_height = backbuffer_desc.Height; - if (ImGui::GetCurrentContext()) + BOOL fullscreen = FALSE; + DXGI_SWAP_CHAIN_DESC desc; + if (SUCCEEDED(m_swap_chain->GetFullscreenState(&fullscreen, nullptr)) && fullscreen && + SUCCEEDED(m_swap_chain->GetDesc(&desc))) { - ImGui::GetIO().DisplaySize.x = static_cast(backbuffer_desc.Width); - ImGui::GetIO().DisplaySize.y = static_cast(backbuffer_desc.Height); + m_window_info.surface_refresh_rate = static_cast(desc.BufferDesc.RefreshRate.Numerator) / + static_cast(desc.BufferDesc.RefreshRate.Denominator); + } + else + { + m_window_info.surface_refresh_rate = 0.0f; } return true; @@ -664,8 +671,6 @@ void D3D11HostDisplay::DestroyResources() bool D3D11HostDisplay::CreateImGuiContext() { - ImGui::GetIO().DisplaySize.x = static_cast(m_window_info.surface_width); - ImGui::GetIO().DisplaySize.y = static_cast(m_window_info.surface_height); return ImGui_ImplDX11_Init(m_device.Get(), m_context.Get()); } diff --git a/src/frontend-common/opengl_host_display.cpp b/src/frontend-common/opengl_host_display.cpp index 2e2e7f7d1..15a2157ad 100644 --- a/src/frontend-common/opengl_host_display.cpp +++ b/src/frontend-common/opengl_host_display.cpp @@ -384,9 +384,7 @@ bool OpenGLHostDisplay::CreateRenderDevice(const WindowInfo& wi, std::string_vie return false; } - m_window_info = wi; - m_window_info.surface_width = m_gl_context->GetSurfaceWidth(); - m_window_info.surface_height = m_gl_context->GetSurfaceHeight(); + m_window_info = m_gl_context->GetWindowInfo(); return true; } @@ -467,16 +465,7 @@ bool OpenGLHostDisplay::ChangeRenderWindow(const WindowInfo& new_wi) return false; } - m_window_info = new_wi; - m_window_info.surface_width = m_gl_context->GetSurfaceWidth(); - m_window_info.surface_height = m_gl_context->GetSurfaceHeight(); - - if (ImGui::GetCurrentContext()) - { - ImGui::GetIO().DisplaySize.x = static_cast(m_window_info.surface_width); - ImGui::GetIO().DisplaySize.y = static_cast(m_window_info.surface_height); - } - + m_window_info = m_gl_context->GetWindowInfo(); return true; } @@ -486,14 +475,7 @@ void OpenGLHostDisplay::ResizeRenderWindow(s32 new_window_width, s32 new_window_ return; m_gl_context->ResizeSurface(static_cast(new_window_width), static_cast(new_window_height)); - m_window_info.surface_width = m_gl_context->GetSurfaceWidth(); - m_window_info.surface_height = m_gl_context->GetSurfaceHeight(); - - if (ImGui::GetCurrentContext()) - { - ImGui::GetIO().DisplaySize.x = static_cast(m_window_info.surface_width); - ImGui::GetIO().DisplaySize.y = static_cast(m_window_info.surface_height); - } + m_window_info = m_gl_context->GetWindowInfo(); } bool OpenGLHostDisplay::SupportsFullscreen() const @@ -539,8 +521,6 @@ void OpenGLHostDisplay::DestroyRenderSurface() bool OpenGLHostDisplay::CreateImGuiContext() { - ImGui::GetIO().DisplaySize.x = static_cast(m_window_info.surface_width); - ImGui::GetIO().DisplaySize.y = static_cast(m_window_info.surface_height); return ImGui_ImplOpenGL3_Init(GetGLSLVersionString()); } diff --git a/src/frontend-common/vulkan_host_display.cpp b/src/frontend-common/vulkan_host_display.cpp index 8d9529977..493cf601d 100644 --- a/src/frontend-common/vulkan_host_display.cpp +++ b/src/frontend-common/vulkan_host_display.cpp @@ -76,12 +76,13 @@ bool VulkanHostDisplay::ChangeRenderWindow(const WindowInfo& new_wi) { g_vulkan_context->ExecuteCommandBuffer(true); m_swap_chain.reset(); + m_window_info = new_wi; return true; } WindowInfo wi_copy(new_wi); VkSurfaceKHR surface = Vulkan::SwapChain::CreateVulkanSurface(g_vulkan_context->GetVulkanInstance(), - g_vulkan_context->GetPhysicalDevice(), wi_copy); + g_vulkan_context->GetPhysicalDevice(), &wi_copy); if (surface == VK_NULL_HANDLE) { Log_ErrorPrintf("Failed to create new surface for swap chain"); @@ -95,16 +96,7 @@ bool VulkanHostDisplay::ChangeRenderWindow(const WindowInfo& new_wi) return false; } - m_window_info = wi_copy; - m_window_info.surface_width = m_swap_chain->GetWidth(); - m_window_info.surface_height = m_swap_chain->GetHeight(); - - if (ImGui::GetCurrentContext()) - { - ImGui::GetIO().DisplaySize.x = static_cast(m_window_info.surface_width); - ImGui::GetIO().DisplaySize.y = static_cast(m_window_info.surface_height); - } - + m_window_info = m_swap_chain->GetWindowInfo(); return true; } @@ -115,14 +107,7 @@ void VulkanHostDisplay::ResizeRenderWindow(s32 new_window_width, s32 new_window_ if (!m_swap_chain->ResizeSwapChain(new_window_width, new_window_height)) Panic("Failed to resize swap chain"); - m_window_info.surface_width = m_swap_chain->GetWidth(); - m_window_info.surface_height = m_swap_chain->GetHeight(); - - if (ImGui::GetCurrentContext()) - { - ImGui::GetIO().DisplaySize.x = static_cast(m_window_info.surface_width); - ImGui::GetIO().DisplaySize.y = static_cast(m_window_info.surface_height); - } + m_window_info = m_swap_chain->GetWindowInfo(); } bool VulkanHostDisplay::SupportsFullscreen() const @@ -320,19 +305,15 @@ void VulkanHostDisplay::SetVSync(bool enabled) bool VulkanHostDisplay::CreateRenderDevice(const WindowInfo& wi, std::string_view adapter_name, bool debug_device, bool threaded_presentation) { - if (!Vulkan::Context::Create(adapter_name, &wi, &m_swap_chain, threaded_presentation, debug_device, false)) + WindowInfo local_wi(wi); + if (!Vulkan::Context::Create(adapter_name, &local_wi, &m_swap_chain, threaded_presentation, debug_device, false)) { Log_ErrorPrintf("Failed to create Vulkan context"); + m_window_info = {}; return false; } - m_window_info = wi; - if (m_swap_chain) - { - m_window_info.surface_width = m_swap_chain->GetWidth(); - m_window_info.surface_height = m_swap_chain->GetHeight(); - } - + m_window_info = m_swap_chain ? m_swap_chain->GetWindowInfo() : local_wi; return true; } @@ -526,9 +507,6 @@ void VulkanHostDisplay::DestroyResources() bool VulkanHostDisplay::CreateImGuiContext() { - ImGui::GetIO().DisplaySize.x = static_cast(m_window_info.surface_width); - ImGui::GetIO().DisplaySize.y = static_cast(m_window_info.surface_height); - ImGui_ImplVulkan_InitInfo vii = {}; vii.Instance = g_vulkan_context->GetVulkanInstance(); vii.PhysicalDevice = g_vulkan_context->GetPhysicalDevice();