1
0
mirror of synced 2025-01-19 01:24:15 +01:00

fix: OpenGL textures not being cleaned up correctly

This commit is contained in:
WerWolv 2022-09-18 20:38:45 +02:00
parent 5eabc05396
commit 3cdc8c5884
8 changed files with 115 additions and 112 deletions

View File

@ -31,27 +31,40 @@ enum ImGuiCustomCol {
namespace ImGui {
struct Texture {
ImTextureID textureId = nullptr;
int width = 0, height = 0;
class Texture {
public:
Texture() = default;
Texture(const ImU8 *buffer, int size);
Texture(const char *path);
Texture(const Texture&) = delete;
Texture(Texture&& other) noexcept;
[[nodiscard]] constexpr bool valid() const noexcept {
return this->textureId != nullptr;
~Texture();
void operator=(const Texture&) = delete;
void operator=(Texture&& other) noexcept;
[[nodiscard]] constexpr bool isValid() const noexcept {
return this->m_textureId != nullptr;
}
[[nodiscard]] constexpr operator ImTextureID() {
return this->textureId;
return this->m_textureId;
}
[[nodiscard]] auto size() const noexcept {
return ImVec2(this->width, this->height);
[[nodiscard]] auto getSize() const noexcept {
return ImVec2(this->m_width, this->m_height);
}
[[nodiscard]] constexpr auto aspectRatio() const noexcept {
if (this->height == 0) return 1.0F;
[[nodiscard]] constexpr auto getAspectRatio() const noexcept {
if (this->m_height == 0) return 1.0F;
return float(this->width) / float(this->height);
return float(this->m_width) / float(this->m_height);
}
private:
ImTextureID m_textureId = nullptr;
int m_width = 0, m_height = 0;
};
int UpdateStringSizeCallback(ImGuiInputTextCallbackData *data);
@ -82,10 +95,6 @@ namespace ImGui {
return static_cast<ImU32>(ImGui::GetTime() * 100) % 100 <= static_cast<ImU32>(ImGui::GetIO().DeltaTime * 100);
}
Texture LoadImageFromPath(const char *path);
Texture LoadImageFromMemory(const ImU8 *buffer, int size);
void UnloadImage(Texture &texture);
void OpenPopupInWindow(const char *window_name, const char *popup_name);
struct ImHexCustomData {

View File

@ -17,6 +17,74 @@
namespace ImGui {
Texture::Texture(const ImU8 *buffer, int size) {
unsigned char *imageData = stbi_load_from_memory(buffer, size, &this->m_width, &this->m_height, nullptr, 4);
if (imageData == nullptr)
return;
GLuint texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
#if defined(GL_UNPACK_ROW_LENGTH)
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
#endif
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, this->m_width, this->m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, imageData);
stbi_image_free(imageData);
this->m_textureId = reinterpret_cast<ImTextureID>(static_cast<intptr_t>(texture));
}
Texture::Texture(const char *path) {
unsigned char *imageData = stbi_load(path, &this->m_width, &this->m_height, nullptr, 4);
if (imageData == nullptr)
return;
GLuint texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
#if defined(GL_UNPACK_ROW_LENGTH)
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
#endif
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, this->m_width, this->m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, imageData);
stbi_image_free(imageData);
this->m_textureId = reinterpret_cast<ImTextureID>(static_cast<intptr_t>(texture));
}
Texture::Texture(Texture&& other) noexcept {
this->m_textureId = other.m_textureId;
this->m_width = other.m_width;
this->m_height = other.m_height;
other.m_textureId = nullptr;
}
void Texture::operator=(Texture&& other) noexcept {
this->m_textureId = other.m_textureId;
this->m_width = other.m_width;
this->m_height = other.m_height;
other.m_textureId = nullptr;
}
Texture::~Texture() {
if (this->m_textureId == nullptr)
return;
auto glTextureId = static_cast<GLuint>(reinterpret_cast<intptr_t>(this->m_textureId));
glDeleteTextures(1, &glTextureId);
}
int UpdateStringSizeCallback(ImGuiInputTextCallbackData *data) {
if (data->EventFlag == ImGuiInputTextFlags_CallbackResize) {
auto &string = *static_cast<std::string *>(data->UserData);
@ -298,66 +366,6 @@ namespace ImGui {
colors[ImGuiCustomCol_Highlight] = ImColor(77, 198, 155);
}
Texture LoadImageFromPath(const char *path) {
int imageWidth = 0;
int imageHeight = 0;
unsigned char *imageData = stbi_load(path, &imageWidth, &imageHeight, nullptr, 4);
if (imageData == nullptr)
return { nullptr, -1, -1 };
GLuint texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
#if defined(GL_UNPACK_ROW_LENGTH)
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
#endif
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, imageWidth, imageHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, imageData);
stbi_image_free(imageData);
return { reinterpret_cast<ImTextureID>(static_cast<intptr_t>(texture)), imageWidth, imageHeight };
}
Texture LoadImageFromMemory(const ImU8 *buffer, int size) {
int imageWidth = 0;
int imageHeight = 0;
unsigned char *imageData = stbi_load_from_memory(buffer, size, &imageWidth, &imageHeight, nullptr, 4);
if (imageData == nullptr)
return { nullptr, -1, -1 };
GLuint texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
#if defined(GL_UNPACK_ROW_LENGTH)
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
#endif
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, imageWidth, imageHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, imageData);
stbi_image_free(imageData);
return { reinterpret_cast<ImTextureID>(static_cast<intptr_t>(texture)), imageWidth, imageHeight };
}
void UnloadImage(Texture &texture) {
if (texture.textureId == nullptr)
return;
auto glTextureId = static_cast<GLuint>(reinterpret_cast<intptr_t>(texture.textureId));
glDeleteTextures(1, &glTextureId);
texture = { nullptr, 0, 0 };
}
void OpenPopupInWindow(const char *window_name, const char *popup_name) {
if (ImGui::Begin(window_name)) {
ImGui::OpenPopup(popup_name);

View File

@ -72,15 +72,13 @@ namespace hex::init {
bool WindowSplash::loop() {
auto splash = romfs::get("splash.png");
ImGui::Texture splashTexture = ImGui::LoadImageFromMemory(reinterpret_cast<const ImU8 *>(splash.data()), splash.size());
ImGui::Texture splashTexture = ImGui::Texture(reinterpret_cast<const ImU8 *>(splash.data()), splash.size());
if (splashTexture == nullptr) {
if (!splashTexture.isValid()) {
log::fatal("Could not load splash screen image!");
exit(EXIT_FAILURE);
}
ON_SCOPE_EXIT { ImGui::UnloadImage(splashTexture); };
auto tasksSucceeded = processTasksAsync();
auto scale = ImHexApi::System::getGlobalScale();
@ -97,7 +95,7 @@ namespace hex::init {
auto drawList = ImGui::GetForegroundDrawList();
drawList->AddImage(splashTexture, ImVec2(0, 0), splashTexture.size() * scale);
drawList->AddImage(splashTexture, ImVec2(0, 0), splashTexture.getSize() * scale);
drawList->AddText(ImVec2(15, 120) * scale, ImColor(0xFF, 0xFF, 0xFF, 0xFF), hex::format("WerWolv 2020 - {0}", &__DATE__[7]).c_str());
@ -107,8 +105,8 @@ namespace hex::init {
drawList->AddText(ImVec2(15, 140) * scale, ImColor(0xFF, 0xFF, 0xFF, 0xFF), hex::format("{0}", IMHEX_VERSION).c_str());
#endif
drawList->AddRectFilled(ImVec2(0, splashTexture.size().y - 5) * scale, ImVec2(splashTexture.size().x * this->m_progress, splashTexture.size().y) * scale, 0xFFFFFFFF);
drawList->AddText(ImVec2(15, splashTexture.size().y - 25) * scale, ImColor(0xFF, 0xFF, 0xFF, 0xFF), hex::format("[{}] {}", "|/-\\"[ImU32(ImGui::GetTime() * 15) % 4], this->m_currTaskName).c_str());
drawList->AddRectFilled(ImVec2(0, splashTexture.getSize().y - 5) * scale, ImVec2(splashTexture.getSize().x * this->m_progress, splashTexture.getSize().y) * scale, 0xFFFFFFFF);
drawList->AddText(ImVec2(15, splashTexture.getSize().y - 25) * scale, ImColor(0xFF, 0xFF, 0xFF, 0xFF), hex::format("[{}] {}", "|/-\\"[ImU32(ImGui::GetTime() * 15) % 4], this->m_currTaskName).c_str());
}
ImGui::Render();

View File

@ -153,8 +153,8 @@ namespace hex {
std::signal(SIGFPE, signalHandler);
std::set_terminate([]{ signalHandler(SIGABRT); });
auto imhexLogo = romfs::get("logo.png");
this->m_logoTexture = ImGui::LoadImageFromMemory(reinterpret_cast<const ImU8 *>(imhexLogo.data()), imhexLogo.size());
auto logoData = romfs::get("logo.png");
this->m_logoTexture = ImGui::Texture(reinterpret_cast<const ImU8 *>(logoData.data()), logoData.size());
ContentRegistry::Settings::store();
EventManager::post<EventSettingsChanged>();

View File

@ -14,7 +14,6 @@ namespace hex::plugin::builtin {
class ViewAbout : public View {
public:
ViewAbout();
~ViewAbout() override;
void drawContent() override;

View File

@ -960,10 +960,10 @@ namespace hex::plugin::builtin {
NodeVisualizerImage() : Node("hex.builtin.nodes.visualizer.image.header", { dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Buffer, "hex.builtin.nodes.common.input") }) { }
void drawNode() override {
ImGui::Image(this->m_texture, scaled(ImVec2(this->m_texture.aspectRatio() * 200, 200)));
ImGui::Image(this->m_texture, scaled(ImVec2(this->m_texture.getAspectRatio() * 200, 200)));
if (ImGui::IsItemHovered()) {
ImGui::BeginTooltip();
ImGui::Image(this->m_texture, scaled(ImVec2(this->m_texture.aspectRatio() * 600, 600)));
ImGui::Image(this->m_texture, scaled(ImVec2(this->m_texture.getAspectRatio() * 600, 600)));
ImGui::EndTooltip();
}
}
@ -971,10 +971,7 @@ namespace hex::plugin::builtin {
void process() override {
auto rawData = this->getBufferOnInput(0);
if (this->m_texture.valid())
ImGui::UnloadImage(this->m_texture);
this->m_texture = ImGui::LoadImageFromMemory(rawData.data(), rawData.size());
this->m_texture = ImGui::Texture(rawData.data(), rawData.size());
}
private:

View File

@ -25,10 +25,6 @@ namespace hex::plugin::builtin {
});
}
ViewAbout::~ViewAbout() {
ImGui::UnloadImage(this->m_logoTexture);
}
static void link(const std::string &name, const std::string &author, const std::string &url) {
if (ImGui::BulletHyperlink(name.c_str()))
hex::openWebpage(url);
@ -50,12 +46,12 @@ namespace hex::plugin::builtin {
ImGui::TableNextRow();
ImGui::TableNextColumn();
if (!this->m_logoTexture.valid()) {
if (!this->m_logoTexture.isValid()) {
auto logo = romfs::get("logo.png");
this->m_logoTexture = ImGui::LoadImageFromMemory(reinterpret_cast<const ImU8 *>(logo.data()), logo.size());
this->m_logoTexture = ImGui::Texture(reinterpret_cast<const ImU8 *>(logo.data()), logo.size());
}
ImGui::Image(this->m_logoTexture.textureId, scaled({ 64, 64 }));
ImGui::Image(this->m_logoTexture, scaled({ 64, 64 }));
ImGui::TableNextColumn();
ImGui::TextFormatted("ImHex Hex Editor v{} by WerWolv - " ICON_FA_CODE_BRANCH, IMHEX_VERSION);

View File

@ -182,7 +182,7 @@ namespace hex::plugin::builtin {
static void drawWelcomeScreenContent() {
const auto availableSpace = ImGui::GetContentRegionAvail();
ImGui::Image(s_bannerTexture, s_bannerTexture.size() / (2 * (1.0F / ImHexApi::System::getGlobalScale())));
ImGui::Image(s_bannerTexture, s_bannerTexture.getSize() / (2 * (1.0F / ImHexApi::System::getGlobalScale())));
ImGui::Indent();
if (ImGui::BeginTable("Welcome Left", 1, ImGuiTableFlags_NoBordersInBody, ImVec2(availableSpace.x / 2, 0))) {
@ -432,14 +432,10 @@ namespace hex::plugin::builtin {
});
(void)EventManager::subscribe<RequestChangeTheme>([](u32 theme) {
auto changeTexture = [&](const std::string &path, const ImGui::Texture &texture) {
auto changeTexture = [&](const std::string &path) {
auto textureData = romfs::get(path);
auto oldTexture = texture;
auto newTexture = ImGui::LoadImageFromMemory(reinterpret_cast<const ImU8 *>(textureData.data()), textureData.size());
if (oldTexture.valid()) { ImGui::UnloadImage(oldTexture); }
return newTexture;
return ImGui::Texture(reinterpret_cast<const ImU8*>(textureData.data()), textureData.size());
};
switch (theme) {
@ -449,8 +445,8 @@ namespace hex::plugin::builtin {
ImGui::StyleColorsDark();
ImGui::StyleCustomColorsDark();
ImPlot::StyleColorsDark();
s_bannerTexture = changeTexture("banner_dark.png", s_bannerTexture);
s_backdropTexture = changeTexture("backdrop_dark.png", s_backdropTexture);
s_bannerTexture = changeTexture("banner_dark.png");
s_backdropTexture = changeTexture("backdrop_dark.png");
break;
}
@ -459,8 +455,8 @@ namespace hex::plugin::builtin {
ImGui::StyleColorsLight();
ImGui::StyleCustomColorsLight();
ImPlot::StyleColorsLight();
s_bannerTexture = changeTexture("banner_light.png", s_bannerTexture);
s_backdropTexture = changeTexture("backdrop_light.png", s_backdropTexture);
s_bannerTexture = changeTexture("banner_light.png");
s_backdropTexture = changeTexture("backdrop_light.png");
break;
}
@ -469,8 +465,8 @@ namespace hex::plugin::builtin {
ImGui::StyleColorsClassic();
ImGui::StyleCustomColorsClassic();
ImPlot::StyleColorsClassic();
s_bannerTexture = changeTexture("banner_dark.png", s_bannerTexture);
s_backdropTexture = changeTexture("backdrop_dark.png", s_backdropTexture);
s_bannerTexture = changeTexture("banner_dark.png");
s_backdropTexture = changeTexture("backdrop_dark.png");
break;
}
@ -481,7 +477,7 @@ namespace hex::plugin::builtin {
ImGui::GetStyle().Colors[ImGuiCol_TitleBgActive] = ImGui::GetStyle().Colors[ImGuiCol_MenuBarBg];
ImGui::GetStyle().Colors[ImGuiCol_TitleBgCollapsed] = ImGui::GetStyle().Colors[ImGuiCol_MenuBarBg];
if (!s_bannerTexture.valid()) {
if (!s_bannerTexture.isValid()) {
log::error("Failed to load banner texture!");
}
});