fix: Make sure all textures are destroyed before glfw gets uninitialized

This commit is contained in:
WerWolv
2025-01-27 22:10:30 +01:00
parent 6e6c5bbc67
commit 24e7c2f3db
17 changed files with 104 additions and 56 deletions

View File

@@ -14,6 +14,7 @@
#include <imgui.h>
#include <hex/ui/imgui_imhex_extensions.h>
#include <hex/api/localization_manager.hpp>
#include <hex/helpers/auto_reset.hpp>
namespace hex {
@@ -405,4 +406,4 @@ namespace hex {
static Achievement& addAchievementImpl(std::unique_ptr<Achievement> &&newAchievement);
};
}
}

View File

@@ -444,6 +444,8 @@ namespace hex {
bool isWindowResizable();
void addAutoResetObject(hex::impl::AutoResetBase *object);
void removeAutoResetObject(hex::impl::AutoResetBase *object);
void cleanup();
}

View File

@@ -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;
}

View File

@@ -574,13 +574,22 @@ namespace hex {
return s_windowResizable;
}
static std::vector<hex::impl::AutoResetBase*> s_autoResetObjects;
static auto& getAutoResetObjects() {
static std::set<hex::impl::AutoResetBase*> 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();
}

View File

@@ -60,8 +60,6 @@ namespace hex {
double m_lastStartFrameTime = 0;
double m_lastFrameTime = 0;
ImGuiExt::Texture m_logoTexture;
std::mutex m_popupMutex;
std::list<std::string> m_popupsToOpen;
std::set<int> m_pressedKeys;

View File

@@ -6,6 +6,8 @@
#include <init/run.hpp>
#include <window.hpp>
#include <GLFW/glfw3.h>
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;

View File

@@ -2,6 +2,7 @@
#include <emscripten.h>
#include <emscripten/html5.h>
#include <GLFW/glfw3.h>
#include <hex/api/imhex_api.hpp>
#include <hex/api/events/requests_lifecycle.hpp>
@@ -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;
window.emplace();

View File

@@ -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;
}

View File

@@ -18,6 +18,7 @@
#include <atomic>
#include <random>
#include <hex/helpers/auto_reset.hpp>
namespace hex {

View File

@@ -11,6 +11,7 @@
#include <set>
#include <thread>
#include <hex/helpers/auto_reset.hpp>
#include <nlohmann/json.hpp>

View File

@@ -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:

View File

@@ -10,6 +10,7 @@
#include <hex/api/theme_manager.hpp>
#include <hex/api/tutorial_manager.hpp>
#include <hex/helpers/utils.hpp>
#include <hex/helpers/auto_reset.hpp>
#include <romfs/romfs.hpp>
#include <wolv/hash/uuid.hpp>
@@ -24,8 +25,8 @@ namespace hex::plugin::builtin {
namespace {
ImGuiExt::Texture s_imhexBanner;
ImGuiExt::Texture s_compassTexture, s_globeTexture;
AutoReset<ImGuiExt::Texture> s_imhexBanner;
AutoReset<ImGuiExt::Texture> s_compassTexture, s_globeTexture;
std::list<std::pair<std::fs::path, ImGuiExt::Texture>> 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);

View File

@@ -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<std::byte>(), ImGuiExt::Texture::Filter::Linear)),
link(std::move(link)) { }
AutoReset<ImGuiExt::Texture> texture;
std::string link;
};
static std::array DonationPages = {
DonationPage { ImGuiExt::Texture::fromImage(romfs::get("assets/common/donation/paypal.png").span<std::byte>(), ImGuiExt::Texture::Filter::Linear), "https://werwolv.net/donate" },
DonationPage { ImGuiExt::Texture::fromImage(romfs::get("assets/common/donation/github.png").span<std::byte>(), ImGuiExt::Texture::Filter::Linear), "https://github.com/sponsors/WerWolv" },
DonationPage { ImGuiExt::Texture::fromImage(romfs::get("assets/common/donation/patreon.png").span<std::byte>(), 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);

View File

@@ -41,7 +41,7 @@
namespace hex::plugin::builtin {
namespace {
ImGuiExt::Texture s_bannerTexture, s_nightlyTexture, s_backdropTexture, s_infoBannerTexture;
AutoReset<ImGuiExt::Texture> 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<bool>("hex.builtin.setting.general", "hex.builtin.setting.general.network_interface", false)
&& ContentRegistry::Settings::read<int>("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())));

View File

@@ -15,6 +15,7 @@
#include <fonts/vscode_icons.hpp>
#include <hex/api/tutorial_manager.hpp>
#include <hex/helpers/auto_reset.hpp>
#include <romfs/romfs.hpp>
#include <wolv/utils/guards.hpp>
@@ -27,7 +28,7 @@ namespace hex::plugin::builtin {
std::string s_windowTitle, s_windowTitleFull;
u32 s_searchBarPosition = 0;
ImGuiExt::Texture s_logoTexture;
AutoReset<ImGuiExt::Texture> s_logoTexture;
bool s_showSearchBar = true;
bool s_displayShortcutHighlights = true;
bool s_useNativeMenuBar = false;

View File

@@ -19,6 +19,7 @@
#include <romfs/romfs.hpp>
#include <numeric>
#include <hex/helpers/auto_reset.hpp>
namespace hex::plugin::visualizers {
@@ -85,7 +86,7 @@ namespace hex::plugin::visualizers {
IndexType s_indexType;
ImGuiExt::Texture s_modelTexture;
AutoReset<ImGuiExt::Texture> s_modelTexture;
gl::Vector<float, 3> s_translation = { { 0.0F, 0.0F, -3.0F } };
gl::Vector<float, 3> s_rotation = { { 0.0F, 0.0F, 0.0F } };
@@ -94,7 +95,7 @@ namespace hex::plugin::visualizers {
gl::Vector<float, 3> s_lightColor = { { 1.0F, 1.0F, 1.0F } };
gl::Matrix<float, 4, 4> s_rotate = gl::Matrix<float, 4, 4>::identity();
ImGuiExt::Texture s_texture;
AutoReset<ImGuiExt::Texture> 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<u8>(verticesPattern, indicesPattern, normalsPattern, colorsPattern, uvPattern);
}
}
}
}

View File

@@ -3,6 +3,7 @@
#include <content/visualizer_helpers.hpp>
#include <imgui.h>
#include <hex/helpers/auto_reset.hpp>
#include <hex/ui/imgui_imhex_extensions.h>
@@ -12,7 +13,7 @@ namespace hex::plugin::visualizers {
void drawImageVisualizer(pl::ptrn::Pattern &, bool shouldReset, std::span<const pl::core::Token::Literal> arguments) {
static ImGuiExt::Texture texture;
static AutoReset<ImGuiExt::Texture> 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<const pl::core::Token::Literal> arguments) {
static ImGuiExt::Texture texture;
static AutoReset<ImGuiExt::Texture> 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;