mirror of
https://github.com/Vita3K/Vita3K.git
synced 2026-01-09 06:34:07 +08:00
gui: free textures after frame is drawn
Fixes crashes when GUI attempts to destroy textures still in use during the current frame
This commit is contained in:
parent
28a0d4492c
commit
20df386acb
@ -20,6 +20,8 @@
|
||||
#include <imgui.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <mutex>
|
||||
#include <vector>
|
||||
|
||||
struct SDL_Window;
|
||||
struct SDL_Cursor;
|
||||
@ -42,6 +44,9 @@ struct ImGui_State {
|
||||
bool is_typing = false;
|
||||
bool do_clear_screen = true;
|
||||
|
||||
std::mutex textures_to_free_mutex;
|
||||
std::vector<ImTextureID> textures_to_free;
|
||||
|
||||
ImGui_State() = default;
|
||||
|
||||
virtual ~ImGui_State() = default;
|
||||
@ -55,13 +60,11 @@ public:
|
||||
ImGui_Texture() = default;
|
||||
ImGui_Texture(ImGui_State *new_state, void *data, int width, int height);
|
||||
ImGui_Texture(ImGui_Texture &&texture) noexcept;
|
||||
|
||||
void init(ImGui_State *new_state, ImTextureID texture);
|
||||
void init(ImGui_State *new_state, void *data, int width, int height);
|
||||
ImGui_Texture(const ImGui_Texture &) = delete;
|
||||
|
||||
operator bool() const;
|
||||
operator ImTextureID() const;
|
||||
bool operator==(const ImGui_Texture &texture);
|
||||
bool operator==(const ImGui_Texture &texture) const;
|
||||
|
||||
ImGui_Texture &operator=(ImGui_Texture &&texture) noexcept;
|
||||
ImGui_Texture &operator=(const ImGui_Texture &texture) = delete;
|
||||
|
||||
@ -352,7 +352,7 @@ static IconData load_app_icon(GuiState &gui, EmuEnvState &emuenv, const std::str
|
||||
void init_app_icon(GuiState &gui, EmuEnvState &emuenv, const std::string &app_path) {
|
||||
IconData data = load_app_icon(gui, emuenv, app_path);
|
||||
if (data.data) {
|
||||
gui.app_selector.user_apps_icon[app_path].init(gui.imgui_state.get(), data.data.get(), data.width, data.height);
|
||||
gui.app_selector.user_apps_icon[app_path] = ImGui_Texture(gui.imgui_state.get(), data.data.get(), data.width, data.height);
|
||||
}
|
||||
}
|
||||
|
||||
@ -364,7 +364,7 @@ void IconAsyncLoader::commit(GuiState &gui) {
|
||||
|
||||
for (const auto &pair : icon_data) {
|
||||
if (pair.second.data) {
|
||||
gui.app_selector.user_apps_icon[pair.first].init(gui.imgui_state.get(), pair.second.data.get(), pair.second.width, pair.second.height);
|
||||
gui.app_selector.user_apps_icon[pair.first] = ImGui_Texture(gui.imgui_state.get(), pair.second.data.get(), pair.second.width, pair.second.height);
|
||||
}
|
||||
}
|
||||
|
||||
@ -435,7 +435,7 @@ void init_app_background(GuiState &gui, EmuEnvState &emuenv, const std::string &
|
||||
LOG_ERROR("Invalid background for application {} [{}].", title, app_path);
|
||||
return;
|
||||
}
|
||||
gui.apps_background[app_path].init(gui.imgui_state.get(), data, width, height);
|
||||
gui.apps_background[app_path] = ImGui_Texture(gui.imgui_state.get(), data, width, height);
|
||||
stbi_image_free(data);
|
||||
}
|
||||
|
||||
|
||||
@ -427,7 +427,31 @@ static void ImGui_ImplSDL3_UpdateGamepads(ImGui_State *state) {
|
||||
#undef MAP_ANALOG
|
||||
}
|
||||
|
||||
static void ImGui_ImplSdl_FreeTextures(ImGui_State *state) {
|
||||
std::lock_guard<std::mutex> lock(state->textures_to_free_mutex);
|
||||
switch (state->renderer->current_backend) {
|
||||
case renderer::Backend::OpenGL: {
|
||||
for (auto texture : state->textures_to_free) {
|
||||
ImGui_ImplSdlGL3_DeleteTexture(texture);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case renderer::Backend::Vulkan: {
|
||||
for (auto texture : state->textures_to_free) {
|
||||
ImGui_ImplSdlVulkan_DeleteTexture(dynamic_cast<ImGui_VulkanState &>(*state), texture);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
LOG_ERROR("Missing ImGui init for backend {}.", static_cast<int>(state->renderer->current_backend));
|
||||
}
|
||||
state->textures_to_free.clear();
|
||||
}
|
||||
|
||||
IMGUI_API void ImGui_ImplSdl_NewFrame(ImGui_State *state) {
|
||||
// Free textures, marked as deleted on previous frame.
|
||||
ImGui_ImplSdl_FreeTextures(state);
|
||||
ImGuiIO &io = ImGui::GetIO();
|
||||
|
||||
// Setup display size (every frame to accommodate for window resizing)
|
||||
@ -493,16 +517,8 @@ IMGUI_API ImTextureID ImGui_ImplSdl_CreateTexture(ImGui_State *state, void *data
|
||||
}
|
||||
|
||||
IMGUI_API void ImGui_ImplSdl_DeleteTexture(ImGui_State *state, ImTextureID texture) {
|
||||
switch (state->renderer->current_backend) {
|
||||
case renderer::Backend::OpenGL:
|
||||
return ImGui_ImplSdlGL3_DeleteTexture(texture);
|
||||
|
||||
case renderer::Backend::Vulkan:
|
||||
return ImGui_ImplSdlVulkan_DeleteTexture(dynamic_cast<ImGui_VulkanState &>(*state), texture);
|
||||
|
||||
default:
|
||||
LOG_ERROR("Missing ImGui init for backend {}.", static_cast<int>(state->renderer->current_backend));
|
||||
}
|
||||
std::lock_guard<std::mutex> lock(state->textures_to_free_mutex);
|
||||
state->textures_to_free.push_back(texture);
|
||||
}
|
||||
|
||||
// Use if you want to reset your rendering device without losing ImGui state.
|
||||
@ -532,17 +548,10 @@ IMGUI_API bool ImGui_ImplSdl_CreateDeviceObjects(ImGui_State *state) {
|
||||
}
|
||||
}
|
||||
|
||||
void ImGui_Texture::init(ImGui_State *new_state, ImTextureID texture) {
|
||||
assert(!texture_id);
|
||||
|
||||
ImGui_Texture::ImGui_Texture(ImGui_State *new_state, void *data, int width, int height) {
|
||||
state = new_state;
|
||||
texture_id = texture;
|
||||
texture_id = ImGui_ImplSdl_CreateTexture(new_state, data, width, height);
|
||||
}
|
||||
|
||||
void ImGui_Texture::init(ImGui_State *new_state, void *data, int width, int height) {
|
||||
init(new_state, ImGui_ImplSdl_CreateTexture(new_state, data, width, height));
|
||||
}
|
||||
|
||||
ImGui_Texture::operator bool() const {
|
||||
return texture_id != nullptr;
|
||||
}
|
||||
@ -551,31 +560,21 @@ ImGui_Texture::operator ImTextureID() const {
|
||||
return texture_id;
|
||||
}
|
||||
|
||||
bool ImGui_Texture::operator==(const ImGui_Texture &texture) {
|
||||
bool ImGui_Texture::operator==(const ImGui_Texture &texture) const {
|
||||
return texture_id == texture.texture_id;
|
||||
}
|
||||
|
||||
ImGui_Texture::ImGui_Texture(ImGui_Texture &&texture) noexcept {
|
||||
std::swap(state, texture.state);
|
||||
std::swap(texture_id, texture.texture_id);
|
||||
}
|
||||
|
||||
ImGui_Texture &ImGui_Texture::operator=(ImGui_Texture &&texture) noexcept {
|
||||
this->state = texture.state;
|
||||
this->texture_id = texture.texture_id;
|
||||
|
||||
texture.state = nullptr;
|
||||
texture.texture_id = nullptr;
|
||||
|
||||
std::swap(state, texture.state);
|
||||
std::swap(texture_id, texture.texture_id);
|
||||
return *this;
|
||||
}
|
||||
|
||||
ImGui_Texture::ImGui_Texture(ImGui_State *new_state, void *data, int width, int height) {
|
||||
init(new_state, data, width, height);
|
||||
}
|
||||
|
||||
ImGui_Texture::ImGui_Texture(ImGui_Texture &&texture) noexcept
|
||||
: state(texture.state)
|
||||
, texture_id(texture.texture_id) {
|
||||
texture.state = nullptr;
|
||||
texture.texture_id = nullptr;
|
||||
}
|
||||
|
||||
ImGui_Texture::~ImGui_Texture() {
|
||||
if (texture_id)
|
||||
ImGui_ImplSdl_DeleteTexture(state, texture_id);
|
||||
|
||||
@ -114,7 +114,7 @@ static bool init_notice_icon(GuiState &gui, EmuEnvState &emuenv, const fs::path
|
||||
LOG_ERROR("Invalid icon for notice id: {} in path {}.", info.id, content_path);
|
||||
return false;
|
||||
}
|
||||
gui.notice_info_icon[info.time].init(gui.imgui_state.get(), data, width, height);
|
||||
gui.notice_info_icon[info.time] = ImGui_Texture(gui.imgui_state.get(), data, width, height);
|
||||
stbi_image_free(data);
|
||||
|
||||
return gui.notice_info_icon.contains(info.time);
|
||||
|
||||
@ -268,7 +268,7 @@ void init_live_area(GuiState &gui, EmuEnvState &emuenv, const std::string &app_p
|
||||
continue;
|
||||
}
|
||||
|
||||
gui.live_area_contents[app_path][contents.first].init(gui.imgui_state.get(), data, width, height);
|
||||
gui.live_area_contents[app_path][contents.first] = ImGui_Texture(gui.imgui_state.get(), data, width, height);
|
||||
stbi_image_free(data);
|
||||
}
|
||||
|
||||
|
||||
@ -184,7 +184,7 @@ static void get_themes_list(GuiState &gui, EmuEnvState &emuenv) {
|
||||
continue;
|
||||
}
|
||||
|
||||
gui.themes_preview[content_id][preview_type].init(gui.imgui_state.get(), data, width, height);
|
||||
gui.themes_preview[content_id][preview_type] = ImGui_Texture(gui.imgui_state.get(), data, width, height);
|
||||
stbi_image_free(data);
|
||||
}
|
||||
}
|
||||
|
||||
@ -56,8 +56,7 @@ bool init_user_background(GuiState &gui, EmuEnvState &emuenv, const std::string
|
||||
return false;
|
||||
}
|
||||
|
||||
gui.user_backgrounds[background_path] = {};
|
||||
gui.user_backgrounds[background_path].init(gui.imgui_state.get(), data, width, height);
|
||||
gui.user_backgrounds[background_path] = ImGui_Texture(gui.imgui_state.get(), data, width, height);
|
||||
stbi_image_free(data);
|
||||
fclose(f);
|
||||
|
||||
@ -178,7 +177,7 @@ void init_theme_start_background(GuiState &gui, EmuEnvState &emuenv, const std::
|
||||
return;
|
||||
}
|
||||
|
||||
gui.start_background.init(gui.imgui_state.get(), data, width, height);
|
||||
gui.start_background = ImGui_Texture(gui.imgui_state.get(), data, width, height);
|
||||
stbi_image_free(data);
|
||||
}
|
||||
|
||||
@ -203,7 +202,7 @@ bool init_user_start_background(GuiState &gui, const std::string &image_path) {
|
||||
return false;
|
||||
}
|
||||
|
||||
gui.start_background.init(gui.imgui_state.get(), data, width, height);
|
||||
gui.start_background = ImGui_Texture(gui.imgui_state.get(), data, width, height);
|
||||
stbi_image_free(data);
|
||||
fclose(f);
|
||||
|
||||
@ -299,7 +298,7 @@ bool init_theme(GuiState &gui, EmuEnvState &emuenv, const std::string &content_i
|
||||
LOG_ERROR("Invalid notice icon for content id: {}.", content_id);
|
||||
continue;
|
||||
}
|
||||
gui.theme_information_bar_notice[type].init(gui.imgui_state.get(), data, width, height);
|
||||
gui.theme_information_bar_notice[type] = ImGui_Texture(gui.imgui_state.get(), data, width, height);
|
||||
stbi_image_free(data);
|
||||
}
|
||||
}
|
||||
@ -345,7 +344,7 @@ bool init_theme(GuiState &gui, EmuEnvState &emuenv, const std::string &content_i
|
||||
continue;
|
||||
}
|
||||
|
||||
gui.app_selector.sys_apps_icon[title_id].init(gui.imgui_state.get(), data, width, height);
|
||||
gui.app_selector.sys_apps_icon[title_id] = ImGui_Texture(gui.imgui_state.get(), data, width, height);
|
||||
stbi_image_free(data);
|
||||
}
|
||||
|
||||
|
||||
@ -258,7 +258,7 @@ void init_trophy_collection(GuiState &gui, EmuEnvState &emuenv) {
|
||||
continue;
|
||||
}
|
||||
|
||||
gui.trophy_np_com_id_list_icons[np_com_id][group.first].init(gui.imgui_state.get(), data, width, height);
|
||||
gui.trophy_np_com_id_list_icons[np_com_id][group.first] = ImGui_Texture(gui.imgui_state.get(), data, width, height);
|
||||
stbi_image_free(data);
|
||||
}
|
||||
}
|
||||
@ -346,7 +346,7 @@ static void get_trophy_list(GuiState &gui, EmuEnvState &emuenv, const std::strin
|
||||
continue;
|
||||
}
|
||||
|
||||
gui.trophy_list[trophy_id].init(gui.imgui_state.get(), data, width, height);
|
||||
gui.trophy_list[trophy_id] = ImGui_Texture(gui.imgui_state.get(), data, width, height);
|
||||
stbi_image_free(data);
|
||||
|
||||
auto &common = gui.lang.common.main;
|
||||
|
||||
@ -74,8 +74,7 @@ static bool init_avatar(GuiState &gui, EmuEnvState &emuenv, const std::string &u
|
||||
return false;
|
||||
}
|
||||
|
||||
gui.users_avatar[user_id] = {};
|
||||
gui.users_avatar[user_id].init(gui.imgui_state.get(), data, width, height);
|
||||
gui.users_avatar[user_id] = ImGui_Texture(gui.imgui_state.get(), data, width, height);
|
||||
stbi_image_free(data);
|
||||
fclose(f);
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user