From affc22f17d329a4d17d595dd468ce82ac3a015dd Mon Sep 17 00:00:00 2001 From: TryTwo Date: Tue, 12 Aug 2025 02:00:44 -0700 Subject: [PATCH] Update code to work with new version of ImGui. UpdateImGuiTexture now handles creating font textures and modifying them. --- Source/Core/VideoCommon/AbstractTexture.cpp | 5 + Source/Core/VideoCommon/AbstractTexture.h | 5 +- Source/Core/VideoCommon/OnScreenUI.cpp | 134 ++++++++++++++++---- Source/Core/VideoCommon/OnScreenUI.h | 2 + 4 files changed, 117 insertions(+), 29 deletions(-) diff --git a/Source/Core/VideoCommon/AbstractTexture.cpp b/Source/Core/VideoCommon/AbstractTexture.cpp index d60925ab25..a557f46020 100644 --- a/Source/Core/VideoCommon/AbstractTexture.cpp +++ b/Source/Core/VideoCommon/AbstractTexture.cpp @@ -20,6 +20,11 @@ AbstractTexture::AbstractTexture(const TextureConfig& c) : m_config(c) { } +AbstractTexture::operator ImTextureRef() const +{ + return ImTextureRef(reinterpret_cast(this)); +} + void AbstractTexture::FinishedRendering() { } diff --git a/Source/Core/VideoCommon/AbstractTexture.h b/Source/Core/VideoCommon/AbstractTexture.h index da5c2d69b2..3abd535b13 100644 --- a/Source/Core/VideoCommon/AbstractTexture.h +++ b/Source/Core/VideoCommon/AbstractTexture.h @@ -10,15 +10,18 @@ #include "Common/MathUtil.h" #include "VideoCommon/TextureConfig.h" +struct ImTextureRef; + class AbstractTexture { public: explicit AbstractTexture(const TextureConfig& c); virtual ~AbstractTexture() = default; - // Support implicit conversion between AbstractTexture and ImTextureId + // Support implicit conversion between AbstractTexture and ImTextureId and ImTextureRef. using imgui_texture_id = unsigned long long; operator imgui_texture_id() const { return reinterpret_cast(this); } + operator ImTextureRef() const; virtual void CopyRectangleFromTexture(const AbstractTexture* src, const MathUtil::Rectangle& src_rect, u32 src_layer, diff --git a/Source/Core/VideoCommon/OnScreenUI.cpp b/Source/Core/VideoCommon/OnScreenUI.cpp index d1c15f7f80..e9f72587f5 100644 --- a/Source/Core/VideoCommon/OnScreenUI.cpp +++ b/Source/Core/VideoCommon/OnScreenUI.cpp @@ -17,6 +17,7 @@ #include "VideoCommon/AbstractGfx.h" #include "VideoCommon/AbstractPipeline.h" #include "VideoCommon/AbstractShader.h" +#include "VideoCommon/AbstractStagingTexture.h" #include "VideoCommon/FramebufferShaderGen.h" #include "VideoCommon/NetPlayChatUI.h" #include "VideoCommon/NetPlayGolfUI.h" @@ -71,30 +72,12 @@ bool OnScreenUI::Initialize(u32 width, u32 height, float scale) return false; } - // Font texture(s). - { - ImGuiIO& io = ImGui::GetIO(); - u8* font_tex_pixels; - int font_tex_width, font_tex_height; - io.Fonts->GetTexDataAsRGBA32(&font_tex_pixels, &font_tex_width, &font_tex_height); + // Font defaults + m_imgui_textures.clear(); - TextureConfig font_tex_config(font_tex_width, font_tex_height, 1, 1, 1, - AbstractTextureFormat::RGBA8, 0, - AbstractTextureType::Texture_2DArray); - std::unique_ptr font_tex = - g_gfx->CreateTexture(font_tex_config, "ImGui font texture"); - if (!font_tex) - { - PanicAlertFmt("Failed to create ImGui texture"); - return false; - } - font_tex->Load(0, font_tex_width, font_tex_height, font_tex_width, font_tex_pixels, - sizeof(u32) * font_tex_width * font_tex_height); - - io.Fonts->TexID = *font_tex.get(); - - m_imgui_textures.push_back(std::move(font_tex)); - } + // Setup new font management behavior. + ImGui::GetIO().BackendFlags |= + ImGuiBackendFlags_RendererHasTextures | ImGuiBackendFlags_RendererHasVtxOffset; if (!RecompileImGuiPipeline()) return false; @@ -113,6 +96,7 @@ OnScreenUI::~OnScreenUI() ImGui::EndFrame(); ImPlot::DestroyContext(); ImGui::DestroyContext(); + m_imgui_textures.clear(); } bool OnScreenUI::RecompileImGuiPipeline() @@ -252,7 +236,7 @@ void OnScreenUI::DrawImGui() static_cast(cmd.ClipRect.x), static_cast(cmd.ClipRect.y), static_cast(cmd.ClipRect.z), static_cast(cmd.ClipRect.w)), g_gfx->GetCurrentFramebuffer())); - g_gfx->SetTexture(0, reinterpret_cast(cmd.TextureId)); + g_gfx->SetTexture(0, reinterpret_cast(cmd.GetTexID())); g_gfx->DrawIndexed(base_index, cmd.ElemCount, base_vertex); base_index += cmd.ElemCount; } @@ -410,6 +394,98 @@ void OnScreenUI::Finalize() OSD::DrawMessages(); DrawChallengesAndLeaderboards(); ImGui::Render(); + + // Create or update fonts. + ImDrawData* draw_data = ImGui::GetDrawData(); + if (draw_data->Textures != nullptr) + for (ImTextureData* tex : *draw_data->Textures) + if (tex->Status != ImTextureStatus_OK) + UpdateImguiTexture(tex); +} + +void OnScreenUI::UpdateImguiTexture(ImTextureData* tex) +{ + if (tex->Status == ImTextureStatus_WantCreate) + { + // Create new font texture. + IM_ASSERT(tex->TexID == ImTextureID_Invalid); + IM_ASSERT(tex->Format == ImTextureFormat_RGBA32); + + TextureConfig font_tex_config(tex->Width, tex->Height, 1, 1, 1, AbstractTextureFormat::RGBA8, 0, + AbstractTextureType::Texture_2DArray); + std::unique_ptr font_tex = + g_gfx->CreateTexture(font_tex_config, "ImGui font texture"); + + if (!font_tex) + { + PanicAlertFmt("Failed to create ImGui texture"); + return; + } + + font_tex->Load(0, tex->Width, tex->Height, tex->Width, tex->Pixels, + sizeof(u32) * tex->Width * tex->Height); + + tex->SetTexID(static_cast(*font_tex.get())); + // Keeps the texture alive. + m_imgui_textures.push_back(std::move(font_tex)); + + tex->SetStatus(ImTextureStatus_OK); + } + else if (tex->Status == ImTextureStatus_WantUpdates) + { + AbstractTexture* font_tex = reinterpret_cast(tex->GetTexID()); + + if (!font_tex || tex->TexID == ImTextureID_Invalid) + { + PanicAlertFmt("ImGui texture not created before update"); + return; + } + + for (const ImTextureRect& r : tex->Updates) + { + // Rect of texture that will be updated. + const int x_offset = static_cast(r.x); + const int y_offset = static_cast(r.y); + const int width = static_cast(r.w); + const int height = static_cast(r.h); + + // Create a staging texture to update the font texture with. + TextureConfig font_tex_config(width, height, 1, 1, 1, AbstractTextureFormat::RGBA8, 0, + AbstractTextureType::Texture_2DArray); + std::unique_ptr stage = + g_gfx->CreateStagingTexture(StagingTextureType::Upload, font_tex_config); + + const int src_pitch = width * tex->BytesPerPixel; + + // Write to staging texture. + for (int y = 0; y < height; y++) + { + const MathUtil::Rectangle rect_line = {0, y, width, y + 1}; + stage->WriteTexels(rect_line, tex->GetPixelsAt(x_offset, y_offset + y), src_pitch); + } + + // Copy to font texture. + const MathUtil::Rectangle rect_staging = {0, 0, width, height}; + const MathUtil::Rectangle rect_target = {x_offset, y_offset, width + x_offset, + height + y_offset}; + + stage->CopyToTexture(rect_staging, font_tex, rect_target, 0, 0); + } + + tex->SetStatus(ImTextureStatus_OK); + } + else if (tex->Status == ImTextureStatus_WantDestroy && tex->UnusedFrames > 0) + { + AbstractTexture* font_tex = reinterpret_cast(tex->GetTexID()); + + tex->SetTexID(ImTextureID_Invalid); + + m_imgui_textures.erase( + std::find_if(m_imgui_textures.begin(), m_imgui_textures.end(), + [font_tex](auto& element) { return element.get() == font_tex; })); + + tex->Status = ImTextureStatus_Destroyed; + } } std::unique_lock OnScreenUI::GetImGuiLock() @@ -421,12 +497,14 @@ void OnScreenUI::SetScale(float backbuffer_scale) { ImGui::GetIO().DisplayFramebufferScale.x = backbuffer_scale; ImGui::GetIO().DisplayFramebufferScale.y = backbuffer_scale; - ImGui::GetIO().FontGlobalScale = backbuffer_scale; + // ScaleAllSizes scales in-place, so calling it twice will double-apply the scale // Reset the style first so that the scale is applied to the base style, not an already-scaled one - ImGui::GetStyle() = {}; - ImGui::GetStyle().WindowRounding = 7.0f; - ImGui::GetStyle().ScaleAllSizes(backbuffer_scale); + ImGuiStyle& style = ImGui::GetStyle(); + style = {}; + style.FontScaleMain = backbuffer_scale; + style.WindowRounding = 7.0f; + style.ScaleAllSizes(backbuffer_scale); m_backbuffer_scale = backbuffer_scale; } diff --git a/Source/Core/VideoCommon/OnScreenUI.h b/Source/Core/VideoCommon/OnScreenUI.h index 28749807be..7f9c7aa3c2 100644 --- a/Source/Core/VideoCommon/OnScreenUI.h +++ b/Source/Core/VideoCommon/OnScreenUI.h @@ -15,6 +15,7 @@ class NativeVertexFormat; class AbstractTexture; class AbstractPipeline; +class ImTextureData; namespace VideoCommon { @@ -62,6 +63,7 @@ public: private: void DrawDebugText(); void DrawChallengesAndLeaderboards(); + void UpdateImguiTexture(ImTextureData* tex); // ImGui resources. std::unique_ptr m_imgui_vertex_format;