From e806d939ae2f9f901b153c2b21fa2825fc324edf Mon Sep 17 00:00:00 2001 From: Stenzek Date: Wed, 29 Nov 2023 19:48:39 +1000 Subject: [PATCH] Qt: Fix crash on language change with system active --- src/duckstation-qt/mainwindow.cpp | 23 ++++++++++++----- src/duckstation-qt/qttranslations.cpp | 37 ++++++++++++++++----------- src/util/imgui_manager.cpp | 32 ++++++++++++++++------- src/util/imgui_manager.h | 5 +--- 4 files changed, 63 insertions(+), 34 deletions(-) diff --git a/src/duckstation-qt/mainwindow.cpp b/src/duckstation-qt/mainwindow.cpp index f13e3badb..39456bd77 100644 --- a/src/duckstation-qt/mainwindow.cpp +++ b/src/duckstation-qt/mainwindow.cpp @@ -709,12 +709,14 @@ std::string MainWindow::getDeviceDiscPath(const QString& title) void MainWindow::recreate() { - if (s_system_valid) + const bool was_display_created = m_display_created; + if (was_display_created) { - requestShutdown(false, true, true); - - while (s_system_valid) + g_emu_thread->setSurfaceless(true); + while (m_display_widget || !g_emu_thread->isSurfaceless()) QApplication::processEvents(QEventLoop::ExcludeUserInputEvents, 1); + + m_display_created = false; } // We need to close input sources, because e.g. DInput uses our window handle. @@ -724,11 +726,19 @@ void MainWindow::recreate() g_main_window = nullptr; MainWindow* new_main_window = new MainWindow(); + DebugAssert(g_main_window == new_main_window); new_main_window->show(); deleteLater(); // Reload the sources we just closed. g_emu_thread->reloadInputSources(); + + if (was_display_created) + { + g_emu_thread->setSurfaceless(false); + g_main_window->updateEmulationActions(false, System::IsValid(), Achievements::IsHardcoreModeActive()); + g_main_window->onFullscreenUIStateChange(g_emu_thread->isRunningFullscreenUI()); + } } void MainWindow::destroySubWindows() @@ -2464,10 +2474,11 @@ void MainWindow::showEvent(QShowEvent* event) void MainWindow::closeEvent(QCloseEvent* event) { // If there's no VM, we can just exit as normal. - if (!s_system_valid) + if (!s_system_valid || !m_display_created) { saveGeometryToConfig(); - g_emu_thread->stopFullscreenUI(); + if (m_display_created) + g_emu_thread->stopFullscreenUI(); destroySubWindows(); QMainWindow::closeEvent(event); return; diff --git a/src/duckstation-qt/qttranslations.cpp b/src/duckstation-qt/qttranslations.cpp index 2464280fa..99dc9a127 100644 --- a/src/duckstation-qt/qttranslations.cpp +++ b/src/duckstation-qt/qttranslations.cpp @@ -53,8 +53,6 @@ static QString FixLanguageName(const QString& language); static std::string GetFontPath(const GlyphInfo* gi); static void UpdateGlyphRanges(const std::string_view& language); static const GlyphInfo* GetGlyphInfo(const std::string_view& language); - -static std::vector s_glyph_ranges; } // namespace QtHost static std::vector s_translators; @@ -133,9 +131,18 @@ void QtHost::InstallTranslator() qApp->installTranslator(translator); s_translators.push_back(translator); - UpdateGlyphRanges(language.toStdString()); - - Host::ClearTranslationCache(); + // We end up here both on language change, and on startup. + if (g_emu_thread) + { + Host::RunOnCPUThread([language = language.toStdString()]() { + UpdateGlyphRanges(language); + Host::ClearTranslationCache(); + }); + } + else + { + UpdateGlyphRanges(language.toStdString()); + } } QString QtHost::FixLanguageName(const QString& language) @@ -233,10 +240,11 @@ void QtHost::UpdateGlyphRanges(const std::string_view& language) const GlyphInfo* gi = GetGlyphInfo(language); std::string font_path; - s_glyph_ranges.clear(); + std::vector glyph_ranges; + glyph_ranges.clear(); // Base Latin range is always included. - s_glyph_ranges.insert(s_glyph_ranges.begin(), std::begin(s_base_latin_range), std::end(s_base_latin_range)); + glyph_ranges.insert(glyph_ranges.begin(), std::begin(s_base_latin_range), std::end(s_base_latin_range)); if (gi) { @@ -247,8 +255,8 @@ void QtHost::UpdateGlyphRanges(const std::string_view& language) { // Always should be in pairs. DebugAssert(ptr[0] != 0 && ptr[1] != 0); - s_glyph_ranges.push_back(*(ptr++)); - s_glyph_ranges.push_back(*(ptr++)); + glyph_ranges.push_back(*(ptr++)); + glyph_ranges.push_back(*(ptr++)); } } @@ -258,16 +266,15 @@ void QtHost::UpdateGlyphRanges(const std::string_view& language) // If we don't have any specific glyph range, assume Central European, except if English, then keep the size down. if ((!gi || !gi->used_glyphs) && language != "en") { - s_glyph_ranges.insert(s_glyph_ranges.begin(), std::begin(s_central_european_ranges), - std::end(s_central_european_ranges)); + glyph_ranges.insert(glyph_ranges.begin(), std::begin(s_central_european_ranges), + std::end(s_central_european_ranges)); } // List terminator. - s_glyph_ranges.push_back(0); - s_glyph_ranges.push_back(0); + glyph_ranges.push_back(0); + glyph_ranges.push_back(0); - ImGuiManager::SetFontPath(std::move(font_path)); - ImGuiManager::SetFontRange(s_glyph_ranges.data()); + ImGuiManager::SetFontPathAndRange(std::move(font_path), std::move(glyph_ranges)); } // clang-format off diff --git a/src/util/imgui_manager.cpp b/src/util/imgui_manager.cpp index fc9f764d2..25056f788 100644 --- a/src/util/imgui_manager.cpp +++ b/src/util/imgui_manager.cpp @@ -74,7 +74,7 @@ static float s_global_prescale = 1.0f; // before window scale static float s_global_scale = 1.0f; static std::string s_font_path; -static const ImWchar* s_font_range = nullptr; +static std::vector s_font_range; static ImFont* s_standard_font; static ImFont* s_fixed_font; @@ -109,16 +109,30 @@ static bool s_global_prescale_changed = false; static std::array s_software_cursors = {}; } // namespace ImGuiManager -void ImGuiManager::SetFontPath(std::string path) +void ImGuiManager::SetFontPathAndRange(std::string path, std::vector range) { - s_font_path = std::move(path); - s_standard_font_data = {}; -} + if (s_font_path == path && s_font_range == range) + return; -void ImGuiManager::SetFontRange(const u16* range) -{ - s_font_range = range; + s_font_path = std::move(path); + s_font_range = std::move(range); s_standard_font_data = {}; + + if (ImGui::GetCurrentContext()) + { + ImGui::EndFrame(); + + if (!LoadFontData()) + Panic("Failed to load font data"); + + if (!AddImGuiFonts(HasFullscreenFonts())) + Panic("Failed to create ImGui font text"); + + if (!g_gpu_device->UpdateImGuiFontTexture()) + Panic("Failed to recreate font texture after scale+resize"); + + NewFrame(); + } } void ImGuiManager::SetGlobalScale(float global_scale) @@ -527,7 +541,7 @@ ImFont* ImGuiManager::AddTextFont(float size) cfg.FontDataOwnedByAtlas = false; return ImGui::GetIO().Fonts->AddFontFromMemoryTTF(s_standard_font_data.data(), static_cast(s_standard_font_data.size()), size, &cfg, - s_font_range ? s_font_range : default_ranges); + s_font_range.empty() ? default_ranges : s_font_range.data()); } ImFont* ImGuiManager::AddFixedFont(float size) diff --git a/src/util/imgui_manager.h b/src/util/imgui_manager.h index 29e2930ed..ce47d1cf5 100644 --- a/src/util/imgui_manager.h +++ b/src/util/imgui_manager.h @@ -13,10 +13,7 @@ enum class GenericInputBinding : u8; namespace ImGuiManager { /// Sets the path to the font to use. Empty string means to use the default. -void SetFontPath(std::string path); - -/// Sets the glyph range to use when loading fonts. -void SetFontRange(const u16* range); +void SetFontPathAndRange(std::string path, std::vector range); /// Changes the global scale. void SetGlobalScale(float global_scale);