From 24e7c2f3dbce5d44a0cdd27e22f694299d3f4215 Mon Sep 17 00:00:00 2001 From: WerWolv Date: Mon, 27 Jan 2025 22:10:30 +0100 Subject: [PATCH] fix: Make sure all textures are destroyed before glfw gets uninitialized --- .../include/hex/api/achievement_manager.hpp | 3 ++- lib/libimhex/include/hex/api/imhex_api.hpp | 2 ++ .../include/hex/helpers/auto_reset.hpp | 14 ++++++++++++ lib/libimhex/source/api/imhex_api.cpp | 15 ++++++++++--- main/gui/include/window.hpp | 2 -- main/gui/source/init/run/native.cpp | 22 ++++++++++++++----- main/gui/source/init/run/web.cpp | 10 +++++++++ main/gui/source/window/window.cpp | 6 ----- .../include/content/helpers/diagrams.hpp | 1 + .../providers/process_memory_provider.hpp | 1 + .../data_processor_nodes/other_nodes.cpp | 6 ++--- .../source/content/out_of_box_experience.cpp | 17 +++++++------- .../source/content/views/view_about.cpp | 18 +++++++++------ .../builtin/source/content/welcome_screen.cpp | 20 ++++++++--------- .../source/content/window_decoration.cpp | 3 ++- .../content/pl_visualizers/3d_model.cpp | 9 ++++---- .../source/content/pl_visualizers/image.cpp | 11 +++++----- 17 files changed, 104 insertions(+), 56 deletions(-) diff --git a/lib/libimhex/include/hex/api/achievement_manager.hpp b/lib/libimhex/include/hex/api/achievement_manager.hpp index 7a6f836e1..22064c843 100644 --- a/lib/libimhex/include/hex/api/achievement_manager.hpp +++ b/lib/libimhex/include/hex/api/achievement_manager.hpp @@ -14,6 +14,7 @@ #include #include #include +#include namespace hex { @@ -405,4 +406,4 @@ namespace hex { static Achievement& addAchievementImpl(std::unique_ptr &&newAchievement); }; -} \ No newline at end of file +} diff --git a/lib/libimhex/include/hex/api/imhex_api.hpp b/lib/libimhex/include/hex/api/imhex_api.hpp index 6e9917382..c07d87b8d 100644 --- a/lib/libimhex/include/hex/api/imhex_api.hpp +++ b/lib/libimhex/include/hex/api/imhex_api.hpp @@ -444,6 +444,8 @@ namespace hex { bool isWindowResizable(); void addAutoResetObject(hex::impl::AutoResetBase *object); + void removeAutoResetObject(hex::impl::AutoResetBase *object); + void cleanup(); } diff --git a/lib/libimhex/include/hex/helpers/auto_reset.hpp b/lib/libimhex/include/hex/helpers/auto_reset.hpp index a79752e3f..96117823f 100644 --- a/lib/libimhex/include/hex/helpers/auto_reset.hpp +++ b/lib/libimhex/include/hex/helpers/auto_reset.hpp @@ -23,6 +23,20 @@ namespace hex { ImHexApi::System::impl::addAutoResetObject(this); } + AutoReset(const T &value) : AutoReset() { + m_value = value; + m_valid = true; + } + + AutoReset(T &&value) noexcept : AutoReset() { + m_value = std::move(value); + m_valid = true; + } + + ~AutoReset() { + ImHexApi::System::impl::removeAutoResetObject(this); + } + T* operator->() { return &m_value; } diff --git a/lib/libimhex/source/api/imhex_api.cpp b/lib/libimhex/source/api/imhex_api.cpp index 999be6725..1e16f42d6 100644 --- a/lib/libimhex/source/api/imhex_api.cpp +++ b/lib/libimhex/source/api/imhex_api.cpp @@ -574,13 +574,22 @@ namespace hex { return s_windowResizable; } - static std::vector s_autoResetObjects; + static auto& getAutoResetObjects() { + static std::set autoResetObjects; + + return autoResetObjects; + } + void addAutoResetObject(hex::impl::AutoResetBase *object) { - s_autoResetObjects.emplace_back(object); + getAutoResetObjects().insert(object); + } + + void removeAutoResetObject(hex::impl::AutoResetBase *object) { + getAutoResetObjects().erase(object); } void cleanup() { - for (const auto &object : s_autoResetObjects) + for (const auto &object : getAutoResetObjects()) object->reset(); } diff --git a/main/gui/include/window.hpp b/main/gui/include/window.hpp index 0e11b535e..288b29c9f 100644 --- a/main/gui/include/window.hpp +++ b/main/gui/include/window.hpp @@ -60,8 +60,6 @@ namespace hex { double m_lastStartFrameTime = 0; double m_lastFrameTime = 0; - ImGuiExt::Texture m_logoTexture; - std::mutex m_popupMutex; std::list m_popupsToOpen; std::set m_pressedKeys; diff --git a/main/gui/source/init/run/native.cpp b/main/gui/source/init/run/native.cpp index 740ff1c5d..06de3fd6d 100644 --- a/main/gui/source/init/run/native.cpp +++ b/main/gui/source/init/run/native.cpp @@ -6,6 +6,8 @@ #include #include + #include + namespace hex::init { int runImHex() { @@ -27,14 +29,22 @@ handleFileOpenRequest(); } - // Main window { - Window window; - window.loop(); + // Initialize GLFW + if (!glfwInit()) { + log::fatal("Failed to initialize GLFW!"); + std::abort(); + } + ON_SCOPE_EXIT { glfwTerminate(); }; + + // Main window + { + Window window; + window.loop(); + } + + deinitializeImHex(); } - - deinitializeImHex(); - } while (shouldRestart); return EXIT_SUCCESS; diff --git a/main/gui/source/init/run/web.cpp b/main/gui/source/init/run/web.cpp index 577ccb7ae..d1cf91664 100644 --- a/main/gui/source/init/run/web.cpp +++ b/main/gui/source/init/run/web.cpp @@ -2,6 +2,7 @@ #include #include + #include #include #include @@ -49,9 +50,12 @@ emscripten_cancel_main_loop(); + ON_SCOPE_EXIT { glfwTerminate(); }; + try { saveFsData(); deinitializeImHex(); + return ""; } catch (const std::exception &e) { static std::string message; @@ -65,6 +69,12 @@ emscripten_cancel_main_loop(); + // Initialize GLFW + if (!glfwInit()) { + log::fatal("Failed to initialize GLFW!"); + std::abort(); + } + // Main window static std::optional window; window.emplace(); diff --git a/main/gui/source/window/window.cpp b/main/gui/source/window/window.cpp index f8b0c995c..ea239ea28 100644 --- a/main/gui/source/window/window.cpp +++ b/main/gui/source/window/window.cpp @@ -925,11 +925,6 @@ namespace hex { } }); - if (!glfwInit()) { - log::fatal("Failed to initialize GLFW!"); - std::abort(); - } - configureGLFW(); glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE); @@ -1297,7 +1292,6 @@ namespace hex { void Window::exitGLFW() { glfwDestroyWindow(m_window); - glfwTerminate(); m_window = nullptr; } diff --git a/plugins/builtin/include/content/helpers/diagrams.hpp b/plugins/builtin/include/content/helpers/diagrams.hpp index fa935e08f..3374869e9 100644 --- a/plugins/builtin/include/content/helpers/diagrams.hpp +++ b/plugins/builtin/include/content/helpers/diagrams.hpp @@ -18,6 +18,7 @@ #include #include +#include namespace hex { diff --git a/plugins/builtin/include/content/providers/process_memory_provider.hpp b/plugins/builtin/include/content/providers/process_memory_provider.hpp index fe651f319..de60b166f 100644 --- a/plugins/builtin/include/content/providers/process_memory_provider.hpp +++ b/plugins/builtin/include/content/providers/process_memory_provider.hpp @@ -11,6 +11,7 @@ #include #include +#include #include diff --git a/plugins/builtin/source/content/data_processor_nodes/other_nodes.cpp b/plugins/builtin/source/content/data_processor_nodes/other_nodes.cpp index 5051ec301..dc625cb4a 100644 --- a/plugins/builtin/source/content/data_processor_nodes/other_nodes.cpp +++ b/plugins/builtin/source/content/data_processor_nodes/other_nodes.cpp @@ -306,7 +306,7 @@ namespace hex::plugin::builtin { const auto &rawData = this->getBufferOnInput(0); m_data = rawData; - m_texture = {}; + m_texture.reset(); } private: @@ -332,7 +332,7 @@ namespace hex::plugin::builtin { } void process() override { - m_texture = { }; + m_texture.reset(); const auto &rawData = this->getBufferOnInput(0); const auto &width = this->getIntegerOnInput(1); @@ -343,7 +343,7 @@ namespace hex::plugin::builtin { throwNodeError(hex::format("Image requires at least {} bytes of data, but only {} bytes are available", requiredBytes, rawData.size())); m_data = rawData; - m_texture = {}; + m_texture.reset(); } private: diff --git a/plugins/builtin/source/content/out_of_box_experience.cpp b/plugins/builtin/source/content/out_of_box_experience.cpp index 88986318a..87fe259da 100644 --- a/plugins/builtin/source/content/out_of_box_experience.cpp +++ b/plugins/builtin/source/content/out_of_box_experience.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -24,8 +25,8 @@ namespace hex::plugin::builtin { namespace { - ImGuiExt::Texture s_imhexBanner; - ImGuiExt::Texture s_compassTexture, s_globeTexture; + AutoReset s_imhexBanner; + AutoReset s_compassTexture, s_globeTexture; std::list> s_screenshots; nlohmann::json s_screenshotDescriptions; @@ -77,9 +78,9 @@ namespace hex::plugin::builtin { // Draw banner ImGui::SetCursorPos(scaled({ 25 * bannerSlideIn, 25 })); - const auto bannerSize = s_imhexBanner.getSize() / (3.0F * (1.0F / ImHexApi::System::getGlobalScale())); + const auto bannerSize = s_imhexBanner->getSize() / (3.0F * (1.0F / ImHexApi::System::getGlobalScale())); ImGui::Image( - s_imhexBanner, + *s_imhexBanner, bannerSize, { 0, 0 }, { 1, 1 }, { 1, 1, 1, (bannerFadeIn - 0.5F) * 2.0F } @@ -222,9 +223,9 @@ namespace hex::plugin::builtin { currLanguage = languages.begin(); // Draw globe image - const auto imageSize = s_compassTexture.getSize() / (1.5F * (1.0F / ImHexApi::System::getGlobalScale())); + const auto imageSize = s_compassTexture->getSize() / (1.5F * (1.0F / ImHexApi::System::getGlobalScale())); ImGui::SetCursorPos((ImGui::GetWindowSize() / 2 - imageSize / 2) - ImVec2(0, 50_scaled)); - ImGui::Image(s_globeTexture, imageSize); + ImGui::Image(*s_globeTexture, imageSize); ImGui::NewLine(); ImGui::NewLine(); @@ -372,9 +373,9 @@ namespace hex::plugin::builtin { ImGui::NewLine(); // Draw compass image - const auto imageSize = s_compassTexture.getSize() / (1.5F * (1.0F / ImHexApi::System::getGlobalScale())); + const auto imageSize = s_compassTexture->getSize() / (1.5F * (1.0F / ImHexApi::System::getGlobalScale())); ImGui::SetCursorPos((ImGui::GetWindowSize() / 2 - imageSize / 2) - ImVec2(0, 50_scaled)); - ImGui::Image(s_compassTexture, imageSize); + ImGui::Image(*s_compassTexture, imageSize); // Draw information text about playing the tutorial ImGui::SetCursorPosX(0); diff --git a/plugins/builtin/source/content/views/view_about.cpp b/plugins/builtin/source/content/views/view_about.cpp index ada18900c..d49e542fd 100644 --- a/plugins/builtin/source/content/views/view_about.cpp +++ b/plugins/builtin/source/content/views/view_about.cpp @@ -155,14 +155,18 @@ namespace hex::plugin::builtin { ImGui::NewLine(); struct DonationPage { - ImGuiExt::Texture texture; - const char *link; + DonationPage(const std::fs::path &path, const std::string &link) : + texture(ImGuiExt::Texture::fromImage(romfs::get(path).span(), ImGuiExt::Texture::Filter::Linear)), + link(std::move(link)) { } + + AutoReset texture; + std::string link; }; static std::array DonationPages = { - DonationPage { ImGuiExt::Texture::fromImage(romfs::get("assets/common/donation/paypal.png").span(), ImGuiExt::Texture::Filter::Linear), "https://werwolv.net/donate" }, - DonationPage { ImGuiExt::Texture::fromImage(romfs::get("assets/common/donation/github.png").span(), ImGuiExt::Texture::Filter::Linear), "https://github.com/sponsors/WerWolv" }, - DonationPage { ImGuiExt::Texture::fromImage(romfs::get("assets/common/donation/patreon.png").span(), ImGuiExt::Texture::Filter::Linear), "https://patreon.com/werwolv" }, + DonationPage("assets/common/donation/paypal.png", "https://werwolv.net/donate"), + DonationPage("assets/common/donation/github.png", "https://github.com/sponsors/WerWolv"), + DonationPage("assets/common/donation/patreon.png", "https://patreon.com/werwolv") }; if (ImGui::BeginTable("DonationLinks", 5, ImGuiTableFlags_SizingStretchSame)) { @@ -172,9 +176,9 @@ namespace hex::plugin::builtin { for (const auto &page : DonationPages) { ImGui::TableNextColumn(); - const auto size = page.texture.getSize() / 1.5F; + const auto size = page.texture->getSize() / 1.5F; const auto startPos = ImGui::GetCursorScreenPos(); - ImGui::Image(page.texture, page.texture.getSize() / 1.5F); + ImGui::Image(*page.texture, page.texture->getSize() / 1.5F); if (ImGui::IsItemHovered()) { ImGui::GetForegroundDrawList()->AddShadowCircle(startPos + size / 2, size.x / 2, ImGui::GetColorU32(ImGuiCol_Button), 100.0F, ImVec2(), ImDrawFlags_ShadowCutOutShapeBackground); diff --git a/plugins/builtin/source/content/welcome_screen.cpp b/plugins/builtin/source/content/welcome_screen.cpp index b47c798a8..57edfba98 100644 --- a/plugins/builtin/source/content/welcome_screen.cpp +++ b/plugins/builtin/source/content/welcome_screen.cpp @@ -41,7 +41,7 @@ namespace hex::plugin::builtin { namespace { - ImGuiExt::Texture s_bannerTexture, s_nightlyTexture, s_backdropTexture, s_infoBannerTexture; + AutoReset s_bannerTexture, s_nightlyTexture, s_backdropTexture, s_infoBannerTexture; std::string s_tipOfTheDay; @@ -173,7 +173,7 @@ namespace hex::plugin::builtin { void drawWelcomeScreenContentSimplified() { const ImVec2 backdropSize = scaled({ 350, 350 }); ImGui::SetCursorPos((ImGui::GetContentRegionAvail() - backdropSize) / 2); - ImGui::Image(s_backdropTexture, backdropSize); + ImGui::Image(*s_backdropTexture, backdropSize); ImGuiExt::TextFormattedCentered("hex.builtin.welcome.drop_file"_lang); } @@ -193,7 +193,7 @@ namespace hex::plugin::builtin { if (ImGui::BeginTable("Welcome Left", 1, ImGuiTableFlags_NoBordersInBody, ImVec2(availableSpace.x / 2, 0))) { ImGui::TableNextRow(); ImGui::TableNextColumn(); - ImGui::Image(s_bannerTexture, s_bannerTexture.getSize()); + ImGui::Image(*s_bannerTexture, s_bannerTexture->getSize()); if (ImHexApi::System::isNightlyBuild()) { auto cursor = ImGui::GetCursorPos(); @@ -202,7 +202,7 @@ namespace hex::plugin::builtin { ImGui::SetCursorPosX(ImGui::GetCursorPosX() - 15_scaled); ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 5_scaled); - ImGui::Image(s_nightlyTexture, s_nightlyTexture.getSize()); + ImGui::Image(*s_nightlyTexture, s_nightlyTexture->getSize()); ImGuiExt::InfoTooltip(hex::format("{0}\n\nCommit: {1}@{2}", "hex.builtin.welcome.nightly_build"_lang, ImHexApi::System::getCommitBranch(), ImHexApi::System::getCommitHash(true)).c_str()); ImGui::SetCursorPos(cursor); @@ -344,7 +344,7 @@ namespace hex::plugin::builtin { ImGuiExt::EndSubWindow(); } - if (s_infoBannerTexture.isValid()) { + if (s_infoBannerTexture->isValid()) { static bool hovered = false; ImGui::PushStyleColor(ImGuiCol_Border, ImGui::GetStyleColorVec4(hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Border)); @@ -352,7 +352,7 @@ namespace hex::plugin::builtin { if (ImGuiExt::BeginSubWindow("hex.builtin.welcome.header.info"_lang, nullptr, ImVec2(), ImGuiChildFlags_AutoResizeX)) { const auto height = 80_scaled; - ImGui::Image(s_infoBannerTexture, ImVec2(height * s_infoBannerTexture.getAspectRatio(), height)); + ImGui::Image(*s_infoBannerTexture, ImVec2(height * s_infoBannerTexture->getAspectRatio(), height)); hovered = ImGui::IsItemHovered(); if (ImGui::IsItemClicked()) { @@ -464,7 +464,7 @@ namespace hex::plugin::builtin { auto imagePos = (ImGui::GetContentRegionAvail() - imageSize) / 2; ImGui::SetCursorPos(imagePos); - ImGui::Image(s_backdropTexture, imageSize); + ImGui::Image(*s_backdropTexture, imageSize); auto loadDefaultText = "hex.builtin.layouts.none.restore_default"_lang; auto textSize = ImGui::CalcTextSize(loadDefaultText); @@ -544,7 +544,7 @@ namespace hex::plugin::builtin { s_nightlyTexture = changeTextureSvg(hex::format("assets/{}/nightly.svg", "common"), 35_scaled); s_backdropTexture = changeTexture(hex::format("assets/{}/backdrop.png", ThemeManager::getImageTheme())); - if (!s_bannerTexture.isValid()) { + if (!s_bannerTexture->isValid()) { log::error("Failed to load banner texture!"); } }); @@ -671,14 +671,14 @@ namespace hex::plugin::builtin { if (wolv::io::fs::exists(infoBannerPath)) { s_infoBannerTexture = ImGuiExt::Texture::fromImage(infoBannerPath, ImGuiExt::Texture::Filter::Linear); - if (s_infoBannerTexture.isValid()) + if (s_infoBannerTexture->isValid()) break; } } auto allowNetworking = ContentRegistry::Settings::read("hex.builtin.setting.general", "hex.builtin.setting.general.network_interface", false) && ContentRegistry::Settings::read("hex.builtin.setting.general", "hex.builtin.setting.general.server_contact", 0) != 0; - if (!s_infoBannerTexture.isValid() && allowNetworking) { + if (!s_infoBannerTexture->isValid() && allowNetworking) { TaskManager::createBackgroundTask("hex.builtin.task.loading_banner"_lang, [](auto&) { HttpRequest request("GET", ImHexApiURL + hex::format("/info/{}/image", hex::toLower(ImHexApi::System::getOSName()))); diff --git a/plugins/builtin/source/content/window_decoration.cpp b/plugins/builtin/source/content/window_decoration.cpp index ae350c521..2ba4268b9 100644 --- a/plugins/builtin/source/content/window_decoration.cpp +++ b/plugins/builtin/source/content/window_decoration.cpp @@ -15,6 +15,7 @@ #include #include +#include #include #include @@ -27,7 +28,7 @@ namespace hex::plugin::builtin { std::string s_windowTitle, s_windowTitleFull; u32 s_searchBarPosition = 0; - ImGuiExt::Texture s_logoTexture; + AutoReset s_logoTexture; bool s_showSearchBar = true; bool s_displayShortcutHighlights = true; bool s_useNativeMenuBar = false; diff --git a/plugins/visualizers/source/content/pl_visualizers/3d_model.cpp b/plugins/visualizers/source/content/pl_visualizers/3d_model.cpp index 8d1376b44..3d8ec7e1e 100644 --- a/plugins/visualizers/source/content/pl_visualizers/3d_model.cpp +++ b/plugins/visualizers/source/content/pl_visualizers/3d_model.cpp @@ -19,6 +19,7 @@ #include #include +#include namespace hex::plugin::visualizers { @@ -85,7 +86,7 @@ namespace hex::plugin::visualizers { IndexType s_indexType; - ImGuiExt::Texture s_modelTexture; + AutoReset s_modelTexture; gl::Vector s_translation = { { 0.0F, 0.0F, -3.0F } }; gl::Vector s_rotation = { { 0.0F, 0.0F, 0.0F } }; @@ -94,7 +95,7 @@ namespace hex::plugin::visualizers { gl::Vector s_lightColor = { { 1.0F, 1.0F, 1.0F } }; gl::Matrix s_rotate = gl::Matrix::identity(); - ImGuiExt::Texture s_texture; + AutoReset s_texture; std::fs::path s_texturePath; u32 s_vertexCount; @@ -806,7 +807,7 @@ namespace hex::plugin::visualizers { } if (s_drawTexture) - glBindTexture(GL_TEXTURE_2D, s_modelTexture); + glBindTexture(GL_TEXTURE_2D, *s_modelTexture); buffers.indices.bind(); if (buffers.indices.getSize() == 0) @@ -938,4 +939,4 @@ namespace hex::plugin::visualizers { processRendering(verticesPattern, indicesPattern, normalsPattern, colorsPattern, uvPattern); } } -} \ No newline at end of file +} diff --git a/plugins/visualizers/source/content/pl_visualizers/image.cpp b/plugins/visualizers/source/content/pl_visualizers/image.cpp index e6d888ecf..8aa6c1438 100644 --- a/plugins/visualizers/source/content/pl_visualizers/image.cpp +++ b/plugins/visualizers/source/content/pl_visualizers/image.cpp @@ -3,6 +3,7 @@ #include #include +#include #include @@ -12,7 +13,7 @@ namespace hex::plugin::visualizers { void drawImageVisualizer(pl::ptrn::Pattern &, bool shouldReset, std::span arguments) { - static ImGuiExt::Texture texture; + static AutoReset texture; static float scale = 1.0F; if (shouldReset) { @@ -20,11 +21,11 @@ namespace hex::plugin::visualizers { auto data = pattern->getBytes(); texture = ImGuiExt::Texture::fromImage(data.data(), data.size(), ImGuiExt::Texture::Filter::Nearest); - scale = 200_scaled / texture.getSize().x; + scale = 200_scaled / texture->getSize().x; } if (texture.isValid()) - ImGui::Image(texture, texture.getSize() * scale); + ImGui::Image(*texture, texture->getSize() * scale); if (ImGui::IsWindowHovered()) { auto scrollDelta = ImGui::GetIO().MouseWheel; @@ -36,7 +37,7 @@ namespace hex::plugin::visualizers { } void drawBitmapVisualizer(pl::ptrn::Pattern &, bool shouldReset, std::span arguments) { - static ImGuiExt::Texture texture; + static AutoReset texture; static float scale = 1.0F; if (shouldReset) { @@ -62,7 +63,7 @@ namespace hex::plugin::visualizers { } if (texture.isValid()) - ImGui::Image(texture, texture.getSize() * scale); + ImGui::Image(*texture, texture->getSize() * scale); if (ImGui::IsWindowHovered()) { auto scrollDelta = ImGui::GetIO().MouseWheel;