From 7415febd9348347b3fba2cb167f21697c0171f48 Mon Sep 17 00:00:00 2001 From: nmzik Date: Wed, 7 Oct 2026 03:15:06 +0400 Subject: [PATCH] SDL title fix Co-authored-by: netwarex --- .../presentation/window/hostInput.cpp | 3 +- src/graphics/presentation/window/hostInput.h | 2 +- .../presentation/window/swapchain.cpp | 2 +- src/graphics/presentation/window/window.cpp | 47 ++++++++----------- .../presentation/window/windowInternal.h | 3 +- 5 files changed, 26 insertions(+), 31 deletions(-) diff --git a/src/graphics/presentation/window/hostInput.cpp b/src/graphics/presentation/window/hostInput.cpp index d04d74fb..980673a2 100644 --- a/src/graphics/presentation/window/hostInput.cpp +++ b/src/graphics/presentation/window/hostInput.cpp @@ -454,7 +454,7 @@ void HostInputToggleMouseToJoystick() { LOGF("Mouse to right stick: enabled (F7 to release)\n"); } -bool HostInputWaitEvent(SDL_Event* event) { +bool HostInputWaitEvent(SDL_Event* event, int max_wait_ms) { int timeout = -1; if (!g_mouse.enabled || SDL_GetKeyboardFocus() != g_mouse_window) { g_mouse.next_poll = 0; @@ -473,6 +473,7 @@ bool HostInputWaitEvent(SDL_Event* event) { now_ms < g_cursor_hide_at ? static_cast(g_cursor_hide_at - now_ms) : 0; timeout = timeout < 0 ? cursor_timeout : std::min(timeout, cursor_timeout); } + timeout = timeout < 0 ? max_wait_ms : std::min(timeout, max_wait_ms); const bool has_event = SDL_WaitEventTimeout(event, timeout); if (Config::HideCursorEnabled()) { diff --git a/src/graphics/presentation/window/hostInput.h b/src/graphics/presentation/window/hostInput.h index bbf2e7f9..82448465 100644 --- a/src/graphics/presentation/window/hostInput.h +++ b/src/graphics/presentation/window/hostInput.h @@ -13,7 +13,7 @@ void HostInputShutdown(); void HostInputKey(int key_code, bool down); void HostInputMouseButton(uint8_t mouse_button, bool down); void HostInputToggleMouseToJoystick(); -[[nodiscard]] bool HostInputWaitEvent(SDL_Event* event); +[[nodiscard]] bool HostInputWaitEvent(SDL_Event* event, int max_wait_ms); } // namespace Libs::Graphics diff --git a/src/graphics/presentation/window/swapchain.cpp b/src/graphics/presentation/window/swapchain.cpp index 7bce6b34..ff684659 100644 --- a/src/graphics/presentation/window/swapchain.cpp +++ b/src/graphics/presentation/window/swapchain.cpp @@ -998,7 +998,7 @@ void Presenter::Impl::Present() { } presented_overlay_revision.store(overlay_visual.revision, std::memory_order_release); - window.UpdateTitle(); + window.loop.presented_frames.fetch_add(1, std::memory_order_relaxed); return; } LOGF("Vulkan presentation retry exhausted; dropping frame\n"); diff --git a/src/graphics/presentation/window/window.cpp b/src/graphics/presentation/window/window.cpp index 1250e5e4..1a1f366c 100644 --- a/src/graphics/presentation/window/window.cpp +++ b/src/graphics/presentation/window/window.cpp @@ -722,6 +722,10 @@ void WindowContext::Run() { loop.need_exit = false; loop.paused.store(false, std::memory_order_release); + constexpr uint64_t title_interval_ms = 1000; + auto title_time = SDL_GetTicks(); + auto title_frames = loop.presented_frames.load(std::memory_order_relaxed); + while (!loop.need_exit) { if (loop.paused.load(std::memory_order_acquire)) { if (!timer.IsPaused()) { @@ -731,7 +735,20 @@ void WindowContext::Run() { timer.Resume(); } - if (!HostInputWaitEvent(&loop.event)) { + // Refresh the title on the main thread without making presentation wait for it. + const auto now = SDL_GetTicks(); + const auto elapsed = now - title_time; + if (elapsed >= title_interval_ms) { + const auto frames = loop.presented_frames.load(std::memory_order_relaxed); + if (frames != 0) { + UpdateTitle(frames, static_cast(frames - title_frames) * 1000.0 / + static_cast(elapsed)); + } + title_time = now; + title_frames = frames; + } + const auto wait_ms = static_cast(title_interval_ms - (now - title_time)); + if (!HostInputWaitEvent(&loop.event, wait_ms)) { continue; } ProcessEvent(timer.GetTimeS()); @@ -913,7 +930,7 @@ void WindowContext::UpdateIcon() { } } -void WindowContext::UpdateTitle() { +void WindowContext::UpdateTitle(uint64_t frame_num, double current_fps) { static char title[128]; static char title_id[12]; static char app_ver[12]; @@ -923,10 +940,6 @@ void WindowContext::UpdateTitle() { static bool has_app_ver = Loader::SystemContentParamSfoGetString("APP_VER", app_ver, sizeof(app_ver)); static const std::string processor_name = Common::GetSystemInfo().ProcessorName; - static uint64_t fps_start = Common::Timer::QueryPerformanceCounter(); - static uint64_t frame_num = 0; - static uint64_t fps_frames = 0; - static double current_fps = 0.0; #if KYTY_BUILD == KYTY_BUILD_DEBUG static constexpr auto build_type = "Debug"; @@ -936,17 +949,6 @@ void WindowContext::UpdateTitle() { static constexpr auto build_type = "Unknown"; #endif - const auto now = Common::Timer::QueryPerformanceCounter(); - const auto frequency = Common::Timer::QueryPerformanceFrequency(); - frame_num++; - fps_frames++; - if (now - fps_start >= frequency) { - current_fps = static_cast(fps_frames) * static_cast(frequency) / - static_cast(now - fps_start); - fps_start = now; - fps_frames = 0; - } - const auto* device_name = graphic_ctx.GetPhysicalDeviceProperties().deviceName.data(); auto text = fmt::format( "[{} | {}] {}{}{}{}{}{}[{}] [{}], frame: {}, fps: {:.0f}", KYTY_BUILD_LABEL, build_type, @@ -954,16 +956,7 @@ void WindowContext::UpdateTitle() { (has_title_id ? ", " : ""), (has_app_ver ? app_ver : ""), (has_app_ver ? " " : ""), device_name, processor_name, frame_num, current_fps); - struct TitleUpdate { - SDL_Window* window; - std::string* text; - } update {window, &text}; - EXIT_IF(!SDL_RunOnMainThread( - [](void* data) { - auto& title = *static_cast(data); - SDL_SetWindowTitle(title.window, title.text->c_str()); - }, - &update, true)); + SDL_SetWindowTitle(window, text.c_str()); } } // namespace Libs::Graphics diff --git a/src/graphics/presentation/window/windowInternal.h b/src/graphics/presentation/window/windowInternal.h index f2ea8356..34305b74 100644 --- a/src/graphics/presentation/window/windowInternal.h +++ b/src/graphics/presentation/window/windowInternal.h @@ -27,6 +27,7 @@ struct WindowLoopState { SDL_Event event {}; bool need_exit = false; std::atomic_bool paused = false; + std::atomic presented_frames {0}; }; struct WindowContext { @@ -42,7 +43,7 @@ struct WindowContext { void RecreateSurface(); void RefreshSurfaceCapabilities(); void UpdateIcon(); - void UpdateTitle(); + void UpdateTitle(uint64_t frame_num, double current_fps); void Resize(int width, int height); void ProcessWindowEvent(const SDL_WindowEvent& event); void ProcessDisplayEvent(const SDL_DisplayEvent& event);