From 8b7e0bde53cc01d1038163907d192285f1857c0c Mon Sep 17 00:00:00 2001 From: Tyler Wilding Date: Sat, 3 Aug 2024 14:57:07 -0400 Subject: [PATCH] game: ensure the default `game-size` is also valid when initializing the `pc-settings.gc` file (#3624) Also saves out the default `pc-settings.gc` file so it's less confusing _and_ so we can request it from users to actually see what it's doing. The fix in the last release was only to fix bad `game-size` values when _loading_ the file. But if you don't have a file, it picks a default. Right now it picks that default by: 1. Your largest reported resolution 2. If that fails, the one that is currently set In reality this scenario can never really happen (if you have a set resolution, it will be one of the reported ones). However what can happen is for SDL to be misinformed by bad display/monitor drivers/the OS and be given "supported" resolutions that aren't actually supported. For example some users have a 4K resolution as their highest, despite them using a 1080p monitor. The solution is to not blindly assume the largest resolution is valid, instead use the one the user already has set. I'm also now filtering out resolutions by refresh rate, as perhaps this also caused a problem. ie. the monitor supports a resolution if the refresh rate is lowered, but it's currently set high (at 144hz for example). --- game/CMakeLists.txt | 3 +++ game/system/hid/display_manager.cpp | 26 +++++++++++++++++++++----- goal_src/jak1/pc/pckernel-common.gc | 9 +++++++-- goal_src/jak1/pc/pckernel-h.gc | 27 +++++++++++++++------------ 4 files changed, 46 insertions(+), 19 deletions(-) diff --git a/game/CMakeLists.txt b/game/CMakeLists.txt index 74e07e4c140..df32b480ad2 100644 --- a/game/CMakeLists.txt +++ b/game/CMakeLists.txt @@ -322,3 +322,6 @@ endif() add_executable(gk main.cpp) target_link_libraries(gk runtime) +if(WIN32) + set_target_properties(gk PROPERTIES VS_DPI_AWARE "PerMonitor") +endif() diff --git a/game/system/hid/display_manager.cpp b/game/system/hid/display_manager.cpp index 5094c8302a8..cef01758ecc 100644 --- a/game/system/hid/display_manager.cpp +++ b/game/system/hid/display_manager.cpp @@ -187,7 +187,7 @@ Resolution DisplayManager::get_resolution(int id) { } bool DisplayManager::is_supported_resolution(int width, int height) { - for (const auto resolution : m_available_resolutions) { + for (const auto& resolution : m_available_resolutions) { if (resolution.width == width && resolution.height == height) { return true; } @@ -358,6 +358,10 @@ void DisplayManager::update_video_modes() { DisplayMode new_mode = {display_name_str, curr_mode.format, curr_mode.w, curr_mode.h, curr_mode.refresh_rate, orient}; m_current_display_modes[display_id] = new_mode; + lg::info( + "[DISPLAY]: Found monitor {}, currently set to {}x{}@{}hz. Format: {}, Orientation: {}", + new_mode.display_name, new_mode.screen_width, new_mode.screen_height, new_mode.refresh_rate, + new_mode.sdl_pixel_format, static_cast(new_mode.orientation)); } update_resolutions(); } @@ -365,17 +369,29 @@ void DisplayManager::update_video_modes() { void DisplayManager::update_resolutions() { lg::info("[DISPLAY] Enumerating resolutions"); // Enumerate display's display modes to get the resolutions - auto num_display_modes = SDL_GetNumDisplayModes(get_active_display_id()); + const auto active_display_id = get_active_display_id(); + const auto active_refresh_rate = m_current_display_modes[active_display_id].refresh_rate; + auto num_display_modes = SDL_GetNumDisplayModes(active_display_id); SDL_DisplayMode curr_mode; for (int i = 0; i < num_display_modes; i++) { - auto ok = SDL_GetDisplayMode(get_active_display_id(), i, &curr_mode); + auto ok = SDL_GetDisplayMode(active_display_id, i, &curr_mode); if (ok != 0) { - sdl_util::log_error(fmt::format("unable to get display mode for display {}, index {}", - get_active_display_id(), i)); + sdl_util::log_error( + fmt::format("unable to get display mode for display {}, index {}", active_display_id, i)); + continue; + } + // Skip resolutions that aren't using the current refresh rate, they won't work. + // For example if your monitor is currently set to `60hz` and the monitor _could_ support + // resolution X but only at `30hz`...then there's no reason for us to consider it as an option. + if (curr_mode.refresh_rate != active_refresh_rate) { + lg::debug( + "[DISPLAY]: Skipping {}x{} as it requires {}hz but the monitor is currently set to {}hz", + curr_mode.w, curr_mode.h, curr_mode.refresh_rate, active_refresh_rate); continue; } Resolution new_res = {curr_mode.w, curr_mode.h, static_cast(curr_mode.w) / static_cast(curr_mode.h)}; + lg::info("[DISPLAY]: {}x{} is supported", new_res.width, new_res.height); m_available_resolutions.push_back(new_res); } diff --git a/goal_src/jak1/pc/pckernel-common.gc b/goal_src/jak1/pc/pckernel-common.gc index a01708a8187..7235b4ef445 100644 --- a/goal_src/jak1/pc/pckernel-common.gc +++ b/goal_src/jak1/pc/pckernel-common.gc @@ -34,13 +34,14 @@ (defmethod set-window-size! ((obj pc-settings) (width int) (height int)) "sets the size of the display window" (let ((display-mode (pc-get-display-mode))) - (format 0 "Setting ~A size to ~D x ~D~%" display-mode width height) (cond ((= display-mode 'windowed) (set! (-> obj window-width) width) (set! (-> obj window-height) height) + (format 0 "Setting window size to ~D x ~D~%" width height) (pc-set-window-size! (max PC_MIN_WIDTH (-> obj window-width)) (max PC_MIN_HEIGHT (-> obj window-height)))) (else + (format 0 "Setting borderless/fullscreen size to ~D x ~D~%" width height) (set! (-> obj width) width) (set! (-> obj height) height)))) (none)) @@ -642,7 +643,11 @@ (unless (read-from-file obj *pc-temp-string-1*) (format 0 "[PC] PC Settings found at '~S' but could not be loaded, using defaults!~%" *pc-temp-string-1*) (reset obj #t))) - (else (format 0 "[PC] PC Settings not found at '~S'...initializing with defaults!~%" *pc-temp-string-1*) (reset obj #t))) + (else + (format 0 "[PC] PC Settings not found at '~S'...initializing with defaults!~%" *pc-temp-string-1*) + (reset obj #t) + ;; save the file so users aren't confused, and so we can debug what the game is producing for them + (commit-to-file obj))) 0) (defmethod initialize ((obj pc-settings)) diff --git a/goal_src/jak1/pc/pckernel-h.gc b/goal_src/jak1/pc/pckernel-h.gc index 5077ecb4d53..176d94a2084 100644 --- a/goal_src/jak1/pc/pckernel-h.gc +++ b/goal_src/jak1/pc/pckernel-h.gc @@ -318,18 +318,21 @@ (set! (-> obj aspect-ratio-auto?) #t) (set! (-> obj vsync?) #t) (set! (-> obj letterbox?) #t) - ;; get screen size and set to borderless at screen res (if retail) - (cond - ((> (pc-get-num-resolutions) 0) - ;; pick first available resolution by default - (pc-get-resolution 0 (&-> obj width) (&-> obj height))) - (else - ;; somehow didn't get a single resolution. this is pretty bad. - (pc-get-active-display-size (&-> obj width) (&-> obj height)) - (max! (-> obj width) PC_MIN_WIDTH) - (max! (-> obj height) PC_MIN_HEIGHT) - (format 0 "!!!! failed to get any screen resolutions !!!!"))) - (format 0 "fullscreen resolution defaulted to ~D x ~D~%" (-> obj width) (-> obj height)) + ;; default to the displays currently chosen resolution + (pc-get-active-display-size (&-> obj width) (&-> obj height)) + (max! (-> obj width) PC_MIN_WIDTH) + (max! (-> obj height) PC_MIN_HEIGHT) + ;; ensure the default resolution was a valid choice + (let* ((saved-width (-> obj width)) + (saved-height (-> obj height)) + (supported-resolution? (pc-is-supported-resolution? saved-width saved-height))) + (cond + (supported-resolution? + (format 0 "[PC Settings]: Valid default game-size resolution set ~D x ~D~%" saved-width saved-height)) + (else + (pc-get-active-display-size (&-> obj width) (&-> obj height)) + (format 0 "[PC Settings]: Invalid game-size resolution ~D x ~D, defaulting to ~D x ~D~%" saved-width saved-height (-> obj width) (-> obj height))))) + (format 0 "[PC Settings]: fullscreen resolution defaulted to ~D x ~D~%" (-> obj width) (-> obj height)) (set! (-> obj gfx-msaa) PC_DEFAULT_MSAA) ;; default msaa 0)