diff --git a/Source/Android/jni/MainAndroid.cpp b/Source/Android/jni/MainAndroid.cpp index 686053496e..441080e57a 100644 --- a/Source/Android/jni/MainAndroid.cpp +++ b/Source/Android/jni/MainAndroid.cpp @@ -595,9 +595,6 @@ static void Run(const std::vector& paths, bool first_open, ASSERT(!paths.empty()); __android_log_print(ANDROID_LOG_INFO, DOLPHIN_TAG, "Running : %s", paths[0].c_str()); - // Install our callbacks - OSD::AddCallback(OSD::CallbackType::Shutdown, ButtonManager::Shutdown); - RegisterMsgAlertHandler(&MsgAlert); Common::AndroidSetReportHandler(&ReportSend); DolphinAnalytics::AndroidSetGetValFunc(&GetAnalyticValue); @@ -639,6 +636,7 @@ static void Run(const std::vector& paths, bool first_open, } Core::Shutdown(); + ButtonManager::Shutdown(); UICommon::Shutdown(); guard.unlock(); diff --git a/Source/Core/DolphinQt/HotkeyScheduler.cpp b/Source/Core/DolphinQt/HotkeyScheduler.cpp index cd5c51822f..7cab2eb8a7 100644 --- a/Source/Core/DolphinQt/HotkeyScheduler.cpp +++ b/Source/Core/DolphinQt/HotkeyScheduler.cpp @@ -5,6 +5,7 @@ #include "DolphinQt/HotkeyScheduler.h" #include +#include #include #include @@ -26,6 +27,7 @@ #include "InputCommon/ControllerInterface/ControllerInterface.h" +#include "VideoCommon/OnScreenDisplay.h" #include "VideoCommon/RenderBase.h" #include "VideoCommon/VertexShaderManager.h" #include "VideoCommon/VideoConfig.h" @@ -286,43 +288,62 @@ void HotkeyScheduler::Run() else if (IsHotkey(HK_NEXT_GAME_WIIMOTE_PROFILE_4)) m_profile_cycler.NextWiimoteProfileForGame(3); - const auto show_msg = [](OSDMessage message) { - if (g_renderer) - g_renderer->ShowOSDMessage(message); + auto ShowVolume = []() { + OSD::AddMessage(std::string("Volume: ") + + (SConfig::GetInstance().m_IsMuted ? + "Muted" : + std::to_string(SConfig::GetInstance().m_Volume)) + + "%"); }; // Volume if (IsHotkey(HK_VOLUME_DOWN)) { - show_msg(OSDMessage::VolumeChanged); settings.DecreaseVolume(3); + ShowVolume(); } if (IsHotkey(HK_VOLUME_UP)) { - show_msg(OSDMessage::VolumeChanged); settings.IncreaseVolume(3); + ShowVolume(); } if (IsHotkey(HK_VOLUME_TOGGLE_MUTE)) { - show_msg(OSDMessage::VolumeChanged); AudioCommon::ToggleMuteVolume(); + ShowVolume(); } // Graphics const auto efb_scale = Config::Get(Config::GFX_EFB_SCALE); + auto ShowEFBScale = []() { + switch (Config::Get(Config::GFX_EFB_SCALE)) + { + case EFB_SCALE_AUTO_INTEGRAL: + OSD::AddMessage("Internal Resolution: Auto (integral)"); + break; + case 1: + OSD::AddMessage("Internal Resolution: Native"); + break; + default: + OSD::AddMessage("Internal Resolution: %dx", g_Config.iEFBScale); + break; + } + }; if (IsHotkey(HK_INCREASE_IR)) { - show_msg(OSDMessage::IRChanged); Config::SetCurrent(Config::GFX_EFB_SCALE, efb_scale + 1); + ShowEFBScale(); } if (IsHotkey(HK_DECREASE_IR)) { - show_msg(OSDMessage::IRChanged); if (efb_scale > EFB_SCALE_AUTO_INTEGRAL) + { Config::SetCurrent(Config::GFX_EFB_SCALE, efb_scale - 1); + ShowEFBScale(); + } } if (IsHotkey(HK_TOGGLE_CROP)) @@ -330,34 +351,55 @@ void HotkeyScheduler::Run() if (IsHotkey(HK_TOGGLE_AR)) { - show_msg(OSDMessage::ARToggled); const int aspect_ratio = (static_cast(Config::Get(Config::GFX_ASPECT_RATIO)) + 1) & 3; Config::SetCurrent(Config::GFX_ASPECT_RATIO, static_cast(aspect_ratio)); + switch (static_cast(aspect_ratio)) + { + case AspectMode::Stretch: + OSD::AddMessage("Stretch"); + break; + case AspectMode::Analog: + OSD::AddMessage("Force 4:3"); + break; + case AspectMode::AnalogWide: + OSD::AddMessage("Force 16:9"); + break; + case AspectMode::Auto: + default: + OSD::AddMessage("Auto"); + break; + } } if (IsHotkey(HK_TOGGLE_EFBCOPIES)) { - show_msg(OSDMessage::EFBCopyToggled); - Config::SetCurrent(Config::GFX_HACK_SKIP_EFB_COPY_TO_RAM, - !Config::Get(Config::GFX_HACK_SKIP_EFB_COPY_TO_RAM)); + const bool new_value = !Config::Get(Config::GFX_HACK_SKIP_EFB_COPY_TO_RAM); + Config::SetCurrent(Config::GFX_HACK_SKIP_EFB_COPY_TO_RAM, new_value); + OSD::AddMessage(StringFromFormat("Copy EFB: %s", new_value ? "to Texture" : "to RAM")); } + auto ShowXFBCopies = []() { + OSD::AddMessage(StringFromFormat( + "Copy XFB: %s%s", Config::Get(Config::GFX_HACK_IMMEDIATE_XFB) ? " (Immediate)" : "", + Config::Get(Config::GFX_HACK_SKIP_XFB_COPY_TO_RAM) ? "to Texture" : "to RAM")); + }; + if (IsHotkey(HK_TOGGLE_XFBCOPIES)) { - show_msg(OSDMessage::XFBChanged); Config::SetCurrent(Config::GFX_HACK_SKIP_XFB_COPY_TO_RAM, !Config::Get(Config::GFX_HACK_SKIP_XFB_COPY_TO_RAM)); + ShowXFBCopies(); } if (IsHotkey(HK_TOGGLE_IMMEDIATE_XFB)) { - show_msg(OSDMessage::XFBChanged); - Config::SetCurrent(Config::GFX_HACK_IMMEDIATE_XFB, !Config::Get(Config::GFX_HACK_IMMEDIATE_XFB)); + ShowXFBCopies(); } if (IsHotkey(HK_TOGGLE_FOG)) { - show_msg(OSDMessage::FogToggled); - Config::SetCurrent(Config::GFX_DISABLE_FOG, !Config::Get(Config::GFX_DISABLE_FOG)); + const bool new_value = !Config::Get(Config::GFX_DISABLE_FOG); + Config::SetCurrent(Config::GFX_DISABLE_FOG, new_value); + OSD::AddMessage(StringFromFormat("Fog: %s", new_value ? "Enabled" : "Disabled")); } if (IsHotkey(HK_TOGGLE_DUMPTEXTURES)) @@ -368,22 +410,28 @@ void HotkeyScheduler::Run() Core::SetIsThrottlerTempDisabled(IsHotkey(HK_TOGGLE_THROTTLE, true)); + auto ShowEmulationSpeed = []() { + OSD::AddMessage( + SConfig::GetInstance().m_EmulationSpeed <= 0 ? + "Speed Limit: Unlimited" : + StringFromFormat("Speed Limit: %li%%", + std::lround(SConfig::GetInstance().m_EmulationSpeed * 100.f))); + }; + if (IsHotkey(HK_DECREASE_EMULATION_SPEED)) { - show_msg(OSDMessage::SpeedChanged); - auto speed = SConfig::GetInstance().m_EmulationSpeed - 0.1; speed = (speed <= 0 || (speed >= 0.95 && speed <= 1.05)) ? 1.0 : speed; SConfig::GetInstance().m_EmulationSpeed = speed; + ShowEmulationSpeed(); } if (IsHotkey(HK_INCREASE_EMULATION_SPEED)) { - show_msg(OSDMessage::SpeedChanged); - auto speed = SConfig::GetInstance().m_EmulationSpeed + 0.1; speed = (speed >= 0.95 && speed <= 1.05) ? 1.0 : speed; SConfig::GetInstance().m_EmulationSpeed = speed; + ShowEmulationSpeed(); } // Slot Saving / Loading diff --git a/Source/Core/VideoBackends/D3D/Render.cpp b/Source/Core/VideoBackends/D3D/Render.cpp index 43dd44f60f..87190a6d2b 100644 --- a/Source/Core/VideoBackends/D3D/Render.cpp +++ b/Source/Core/VideoBackends/D3D/Render.cpp @@ -595,10 +595,6 @@ void Renderer::SwapImpl(AbstractTexture* texture, const EFBRectangle& xfb_region D3D11_VIEWPORT vp = CD3D11_VIEWPORT(0.0f, 0.0f, static_cast(m_backbuffer_width), static_cast(m_backbuffer_height)); D3D::context->RSSetViewports(1, &vp); - - Renderer::DrawDebugText(); - - OSD::DrawMessages(); DrawImGui(); g_texture_cache->Cleanup(frameCount); diff --git a/Source/Core/VideoBackends/OGL/Render.cpp b/Source/Core/VideoBackends/OGL/Render.cpp index e967ae6a75..c857cce083 100644 --- a/Source/Core/VideoBackends/OGL/Render.cpp +++ b/Source/Core/VideoBackends/OGL/Render.cpp @@ -1424,9 +1424,6 @@ void Renderer::SwapImpl(AbstractTexture* texture, const EFBRectangle& xfb_region ResetAPIState(); - // Do our OSD callbacks - OSD::DoCallbacks(OSD::CallbackType::OnFrame); - // Check if we need to render to a new surface. CheckForSurfaceChange(); CheckForSurfaceResize(); @@ -1451,10 +1448,6 @@ void Renderer::SwapImpl(AbstractTexture* texture, const EFBRectangle& xfb_region // Render OSD messages. glViewport(0, 0, m_backbuffer_width, m_backbuffer_height); - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - DrawDebugText(); - OSD::DrawMessages(); DrawImGui(); // Swap the back and front buffers, presenting the image. diff --git a/Source/Core/VideoBackends/Software/SWRenderer.cpp b/Source/Core/VideoBackends/Software/SWRenderer.cpp index 0b64022725..f8032f7e5d 100644 --- a/Source/Core/VideoBackends/Software/SWRenderer.cpp +++ b/Source/Core/VideoBackends/Software/SWRenderer.cpp @@ -97,13 +97,8 @@ std::unique_ptr SWRenderer::CreatePipeline(const AbstractPipel // Called on the GPU thread void SWRenderer::SwapImpl(AbstractTexture* texture, const EFBRectangle& xfb_region, u64 ticks) { - OSD::DoCallbacks(OSD::CallbackType::OnFrame); - if (!IsHeadless()) - { - DrawDebugText(); m_window->ShowImage(texture, xfb_region); - } UpdateActiveConfig(); } diff --git a/Source/Core/VideoBackends/Vulkan/Renderer.cpp b/Source/Core/VideoBackends/Vulkan/Renderer.cpp index 509269368d..5ae6093f24 100644 --- a/Source/Core/VideoBackends/Vulkan/Renderer.cpp +++ b/Source/Core/VideoBackends/Vulkan/Renderer.cpp @@ -704,9 +704,6 @@ void Renderer::DrawScreen(VKTexture* xfb_texture, const EFBRectangle& xfb_region // Draw OSD SetViewport(0.0f, 0.0f, static_cast(backbuffer->GetWidth()), static_cast(backbuffer->GetHeight()), 0.0f, 1.0f); - DrawDebugText(); - OSD::DoCallbacks(OSD::CallbackType::OnFrame); - OSD::DrawMessages(); StateTracker::GetInstance()->SetPendingRebind(); DrawImGui(); diff --git a/Source/Core/VideoCommon/OnScreenDisplay.cpp b/Source/Core/VideoCommon/OnScreenDisplay.cpp index 62997cd150..d6f9b38a3e 100644 --- a/Source/Core/VideoCommon/OnScreenDisplay.cpp +++ b/Source/Core/VideoCommon/OnScreenDisplay.cpp @@ -5,22 +5,79 @@ #include #include #include +#include #include +#include "imgui.h" + #include "Common/CommonTypes.h" #include "Common/Timer.h" #include "Core/ConfigManager.h" #include "VideoCommon/OnScreenDisplay.h" -#include "VideoCommon/RenderBase.h" namespace OSD { -static std::multimap s_callbacks; +constexpr float LEFT_MARGIN = 10.0f; // Pixels to the left of OSD messages. +constexpr float TOP_MARGIN = 10.0f; // Pixels above the first OSD message. +constexpr float WINDOW_PADDING = 4.0f; // Pixels between subsequent OSD messages. + +struct Message +{ + Message() {} + Message(const std::string& text_, u32 timestamp_, u32 color_) + : text(text_), timestamp(timestamp_), color(color_) + { + } + std::string text; + u32 timestamp; + u32 color; +}; static std::multimap s_messages; static std::mutex s_messages_mutex; +static ImVec4 RGBAToImVec4(const u32 rgba) +{ + return ImVec4(static_cast((rgba >> 16) & 0xFF) / 255.0f, + static_cast((rgba >> 8) & 0xFF) / 255.0f, + static_cast((rgba >> 0) & 0xFF) / 255.0f, + static_cast((rgba >> 24) & 0xFF) / 255.0f); +} + +static float DrawMessage(int index, const Message& msg, const ImVec2& position, int time_left) +{ + // We have to provide a window name, and these shouldn't be duplicated. + // So instead, we generate a name based on the number of messages drawn. + const std::string window_name = StringFromFormat("osd_%d", index); + + // The size must be reset, otherwise the length of old messages could influence new ones. + ImGui::SetNextWindowPos(position); + ImGui::SetNextWindowSize(ImVec2(0.0f, 0.0f)); + + // Gradually fade old messages away. + const float alpha = std::min(1.0f, std::max(0.0f, time_left / 1024.0f)); + ImGui::PushStyleVar(ImGuiStyleVar_Alpha, alpha); + + float window_height = 0.0f; + if (ImGui::Begin(window_name.c_str(), nullptr, + ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoInputs | + ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoSavedSettings | + ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoNav | + ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoFocusOnAppearing)) + { + // Use %s in case message contains %. + ImGui::TextColored(RGBAToImVec4(msg.color), "%s", msg.text.c_str()); + window_height = + ImGui::GetWindowSize().y + (WINDOW_PADDING * ImGui::GetIO().DisplayFramebufferScale.y); + } + + ImGui::End(); + ImGui::PopStyleVar(); + + return window_height; +} + void AddTypedMessage(MessageType type, const std::string& message, u32 ms, u32 rgba) { std::lock_guard lock(s_messages_mutex); @@ -35,14 +92,6 @@ void AddMessage(const std::string& message, u32 ms, u32 rgba) Message(message, Common::Timer::GetTimeMs() + ms, rgba)); } -void DrawMessage(const Message& msg, int top, int left, int time_left) -{ - float alpha = std::min(1.0f, std::max(0.0f, time_left / 1024.0f)); - u32 color = (msg.m_rgba & 0xFFFFFF) | ((u32)((msg.m_rgba >> 24) * alpha) << 24); - - g_renderer->RenderText(msg.m_str, left, top, color); -} - void DrawMessages() { if (!SConfig::GetInstance().bOnScreenDisplayMessages) @@ -51,21 +100,22 @@ void DrawMessages() { std::lock_guard lock(s_messages_mutex); - u32 now = Common::Timer::GetTimeMs(); - int left = 20, top = 35; + const u32 now = Common::Timer::GetTimeMs(); + float current_x = LEFT_MARGIN * ImGui::GetIO().DisplayFramebufferScale.x; + float current_y = TOP_MARGIN * ImGui::GetIO().DisplayFramebufferScale.y; + int index = 0; auto it = s_messages.begin(); while (it != s_messages.end()) { const Message& msg = it->second; - int time_left = (int)(msg.m_timestamp - now); - DrawMessage(msg, top, left, time_left); + const int time_left = static_cast(msg.timestamp - now); + current_y += DrawMessage(index++, msg, ImVec2(current_x, current_y), time_left); if (time_left <= 0) it = s_messages.erase(it); else ++it; - top += 15; } } } @@ -75,24 +125,4 @@ void ClearMessages() std::lock_guard lock(s_messages_mutex); s_messages.clear(); } - -// On-Screen Display Callbacks -void AddCallback(CallbackType type, Callback cb) -{ - s_callbacks.emplace(type, cb); } - -void DoCallbacks(CallbackType type) -{ - auto it_bounds = s_callbacks.equal_range(type); - for (auto it = it_bounds.first; it != it_bounds.second; ++it) - { - it->second(); - } - - // Wipe all callbacks on shutdown - if (type == CallbackType::Shutdown) - s_callbacks.clear(); -} - -} // namespace diff --git a/Source/Core/VideoCommon/OnScreenDisplay.h b/Source/Core/VideoCommon/OnScreenDisplay.h index a05f4058ef..51358aff19 100644 --- a/Source/Core/VideoCommon/OnScreenDisplay.h +++ b/Source/Core/VideoCommon/OnScreenDisplay.h @@ -11,15 +11,6 @@ namespace OSD { -struct Message -{ - Message() {} - Message(const std::string& s, u32 ts, u32 rgba) : m_str(s), m_timestamp(ts), m_rgba(rgba) {} - std::string m_str; - u32 m_timestamp; - u32 m_rgba; -}; - enum class MessageType { NetPlayPing, @@ -49,20 +40,7 @@ constexpr u32 VERY_LONG = 10000; void AddMessage(const std::string& message, u32 ms = Duration::SHORT, u32 rgba = Color::YELLOW); void AddTypedMessage(MessageType type, const std::string& message, u32 ms = Duration::SHORT, u32 rgba = Color::YELLOW); -void DrawMessage(const Message& msg, int top, int left, int time_left); // draw one message void DrawMessages(); // draw the current messages on the screen. Only call once // per frame. void ClearMessages(); - -// On-screen callbacks -enum class CallbackType -{ - Initialization, - OnFrame, - Shutdown -}; -using Callback = std::function; - -void AddCallback(CallbackType type, Callback cb); -void DoCallbacks(CallbackType type); } // namespace OSD diff --git a/Source/Core/VideoCommon/RenderBase.cpp b/Source/Core/VideoCommon/RenderBase.cpp index d30a7ccac3..76f3d29864 100644 --- a/Source/Core/VideoCommon/RenderBase.cpp +++ b/Source/Core/VideoCommon/RenderBase.cpp @@ -65,6 +65,7 @@ #include "VideoCommon/Statistics.h" #include "VideoCommon/TextureCacheBase.h" #include "VideoCommon/TextureDecoder.h" +#include "VideoCommon/VertexLoaderManager.h" #include "VideoCommon/VertexManagerBase.h" #include "VideoCommon/VertexShaderManager.h" #include "VideoCommon/VideoConfig.h" @@ -261,139 +262,64 @@ bool Renderer::CheckForHostConfigChanges() // Create On-Screen-Messages void Renderer::DrawDebugText() { - std::string final_yellow, final_cyan; + const auto& config = SConfig::GetInstance(); - if (g_ActiveConfig.bShowFPS || SConfig::GetInstance().m_ShowFrameCount) + if (g_ActiveConfig.bShowFPS) { - if (g_ActiveConfig.bShowFPS) - final_cyan += StringFromFormat("FPS: %.2f", m_fps_counter.GetFPS()); + // Position in the top-right corner of the screen. + ImGui::SetNextWindowPos(ImVec2(ImGui::GetIO().DisplaySize.x - (10.0f * m_backbuffer_scale), + 10.0f * m_backbuffer_scale), + ImGuiCond_Always, ImVec2(1.0f, 0.0f)); + ImGui::SetNextWindowSize(ImVec2(100.0f * m_backbuffer_scale, 30.0f * m_backbuffer_scale)); - if (g_ActiveConfig.bShowFPS && SConfig::GetInstance().m_ShowFrameCount) - final_cyan += " - "; - if (SConfig::GetInstance().m_ShowFrameCount) + if (ImGui::Begin("FPS", nullptr, + ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoInputs | + ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoSavedSettings | + ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoNav | + ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoFocusOnAppearing)) { - final_cyan += StringFromFormat("Frame: %" PRIu64, Movie::GetCurrentFrame()); + ImGui::TextColored(ImVec4(0.0f, 1.0f, 1.0f, 1.0f), "FPS: %.2f", m_fps_counter.GetFPS()); + } + ImGui::End(); + } + + const bool show_movie_window = + config.m_ShowFrameCount | config.m_ShowLag | config.m_ShowInputDisplay | config.m_ShowRTC; + if (show_movie_window) + { + // Position under the FPS display. + ImGui::SetNextWindowPos(ImVec2(ImGui::GetIO().DisplaySize.x - (10.0f * m_backbuffer_scale), + 50.0f * m_backbuffer_scale), + ImGuiCond_FirstUseEver, ImVec2(1.0f, 0.0f)); + ImGui::SetNextWindowSizeConstraints( + ImVec2(150.0f * m_backbuffer_scale, 20.0f * m_backbuffer_scale), + ImGui::GetIO().DisplaySize); + if (ImGui::Begin("Movie", nullptr, ImGuiWindowFlags_NoFocusOnAppearing)) + { + if (config.m_ShowFrameCount) + { + ImGui::Text("Frame: %" PRIu64, Movie::GetCurrentFrame()); + } if (Movie::IsPlayingInput()) - final_cyan += StringFromFormat("\nInput: %" PRIu64 " / %" PRIu64, - Movie::GetCurrentInputCount(), Movie::GetTotalInputCount()); + { + ImGui::Text("Input: %" PRIu64 " / %" PRIu64, Movie::GetCurrentInputCount(), + Movie::GetTotalInputCount()); + } + if (SConfig::GetInstance().m_ShowLag) + ImGui::Text("Lag: %" PRIu64 "\n", Movie::GetCurrentLagCount()); + if (SConfig::GetInstance().m_ShowInputDisplay) + ImGui::TextUnformatted(Movie::GetInputDisplay().c_str()); + if (SConfig::GetInstance().m_ShowRTC) + ImGui::TextUnformatted(Movie::GetRTCDisplay().c_str()); } - - final_cyan += "\n"; - final_yellow += "\n"; + ImGui::End(); } - if (SConfig::GetInstance().m_ShowLag) - { - final_cyan += StringFromFormat("Lag: %" PRIu64 "\n", Movie::GetCurrentLagCount()); - final_yellow += "\n"; - } - - if (SConfig::GetInstance().m_ShowInputDisplay) - { - final_cyan += Movie::GetInputDisplay(); - final_yellow += "\n"; - } - - if (SConfig::GetInstance().m_ShowRTC) - { - final_cyan += Movie::GetRTCDisplay(); - final_yellow += "\n"; - } - - // OSD Menu messages - if (m_osd_message > 0) - { - m_osd_time = Common::Timer::GetTimeMs() + 3000; - m_osd_message = -m_osd_message; - } - - if (static_cast(m_osd_time) > Common::Timer::GetTimeMs()) - { - std::string res_text; - switch (g_ActiveConfig.iEFBScale) - { - case EFB_SCALE_AUTO_INTEGRAL: - res_text = "Auto (integral)"; - break; - case 1: - res_text = "Native"; - break; - default: - res_text = StringFromFormat("%dx", g_ActiveConfig.iEFBScale); - break; - } - const char* ar_text = ""; - switch (g_ActiveConfig.aspect_mode) - { - case AspectMode::Stretch: - ar_text = "Stretch"; - break; - case AspectMode::Analog: - ar_text = "Force 4:3"; - break; - case AspectMode::AnalogWide: - ar_text = "Force 16:9"; - break; - case AspectMode::Auto: - default: - ar_text = "Auto"; - break; - } - const std::string audio_text = SConfig::GetInstance().m_IsMuted ? - "Muted" : - std::to_string(SConfig::GetInstance().m_Volume) + "%"; - - const char* const efbcopy_text = g_ActiveConfig.bSkipEFBCopyToRam ? "to Texture" : "to RAM"; - const char* const xfbcopy_text = g_ActiveConfig.bSkipXFBCopyToRam ? "to Texture" : "to RAM"; - - // The rows - const std::string lines[] = { - std::string("Internal Resolution: ") + res_text, - std::string("Aspect Ratio: ") + ar_text + (g_ActiveConfig.bCrop ? " (crop)" : ""), - std::string("Copy EFB: ") + efbcopy_text, - std::string("Fog: ") + (g_ActiveConfig.bDisableFog ? "Disabled" : "Enabled"), - SConfig::GetInstance().m_EmulationSpeed <= 0 ? - "Speed Limit: Unlimited" : - StringFromFormat("Speed Limit: %li%%", - std::lround(SConfig::GetInstance().m_EmulationSpeed * 100.f)), - std::string("Copy XFB: ") + xfbcopy_text + - (g_ActiveConfig.bImmediateXFB ? " (Immediate)" : ""), - "Volume: " + audio_text, - }; - - enum - { - lines_count = sizeof(lines) / sizeof(*lines) - }; - - // The latest changed setting in yellow - for (int i = 0; i != lines_count; ++i) - { - if (m_osd_message == -i - 1) - final_yellow += lines[i]; - final_yellow += '\n'; - } - - // The other settings in cyan - for (int i = 0; i != lines_count; ++i) - { - if (m_osd_message != -i - 1) - final_cyan += lines[i]; - final_cyan += '\n'; - } - } - - final_cyan += Common::Profiler::ToString(); - if (g_ActiveConfig.bOverlayStats) - final_cyan += Statistics::ToString(); + Statistics::Display(); if (g_ActiveConfig.bOverlayProjStats) - final_cyan += Statistics::ToStringProj(); - - // and then the text - RenderText(final_cyan, 20, 20, 0xFF00FFFF); - RenderText(final_yellow, 20, 20, 0xFFFFFF00); + Statistics::DisplayProj(); } float Renderer::CalculateDrawAspectRatio() const @@ -955,6 +881,8 @@ void Renderer::Swap(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight, const // Draw any imgui overlays we have. Note that "draw" here means "create commands", the actual // draw calls don't get issued until DrawImGui is called, which happens in SwapImpl. + DrawDebugText(); + OSD::DrawMessages(); ImGui::Render(); // TODO: merge more generic parts into VideoCommon @@ -1332,8 +1260,3 @@ std::unique_ptr Renderer::CreateAsyncShaderCom { return std::make_unique(); } - -void Renderer::ShowOSDMessage(OSDMessage message) -{ - m_osd_message = static_cast(message); -} diff --git a/Source/Core/VideoCommon/RenderBase.h b/Source/Core/VideoCommon/RenderBase.h index b232d2c61f..b31384794c 100644 --- a/Source/Core/VideoCommon/RenderBase.h +++ b/Source/Core/VideoCommon/RenderBase.h @@ -57,17 +57,6 @@ struct EfbPokeData extern int frameCount; -enum class OSDMessage : s32 -{ - IRChanged = 1, - ARToggled = 2, - EFBCopyToggled = 3, - FogToggled = 4, - SpeedChanged = 5, - XFBChanged = 6, - VolumeChanged = 7, -}; - // Renderer really isn't a very good name for this class - it's more like "Misc". // The long term goal is to get rid of this class and replace it with others that make // more sense. @@ -201,8 +190,6 @@ public: virtual std::unique_ptr CreateAsyncShaderCompiler(); - void ShowOSDMessage(OSDMessage message); - protected: std::tuple CalculateTargetScale(int x, int y) const; bool CalculateTargetSize(); @@ -303,9 +290,6 @@ private: u32 m_last_xfb_width = MAX_XFB_WIDTH; u32 m_last_xfb_height = MAX_XFB_HEIGHT; - s32 m_osd_message = 0; - s32 m_osd_time = 0; - // NOTE: The methods below are called on the framedumping thread. bool StartFrameDumpToAVI(const FrameDumpConfig& config); void DumpFrameToAVI(const FrameDumpConfig& config); diff --git a/Source/Core/VideoCommon/Statistics.cpp b/Source/Core/VideoCommon/Statistics.cpp index 0a4a9236b0..af122bfcdb 100644 --- a/Source/Core/VideoCommon/Statistics.cpp +++ b/Source/Core/VideoCommon/Statistics.cpp @@ -6,6 +6,8 @@ #include #include +#include "imgui.h" + #include "Common/StringUtil.h" #include "VideoCommon/Statistics.h" #include "VideoCommon/VertexLoaderManager.h" @@ -26,91 +28,98 @@ void Statistics::SwapDL() std::swap(stats.thisFrame.numBPLoadsInDL, stats.thisFrame.numBPLoads); } -std::string Statistics::ToString() +void Statistics::Display() { - std::string str; + const float scale = ImGui::GetIO().DisplayFramebufferScale.x; + ImGui::SetNextWindowPos(ImVec2(10.0f * scale, 10.0f * scale), ImGuiCond_FirstUseEver); + ImGui::SetNextWindowSizeConstraints(ImVec2(275.0f * scale, 400.0f * scale), + ImGui::GetIO().DisplaySize); + if (!ImGui::Begin("Statistics", nullptr, ImGuiWindowFlags_NoNavInputs)) + { + ImGui::End(); + return; + } + + ImGui::Columns(2, "Statistics", true); + +#define DRAW_STAT(name, format, ...) \ + ImGui::Text(name); \ + ImGui::NextColumn(); \ + ImGui::Text(format, __VA_ARGS__); \ + ImGui::NextColumn(); if (g_ActiveConfig.backend_info.api_type == APIType::Nothing) { - str += StringFromFormat("Objects: %i\n", stats.thisFrame.numDrawnObjects); - str += StringFromFormat("Vertices Loaded: %i\n", stats.thisFrame.numVerticesLoaded); - str += StringFromFormat("Triangles Input: %i\n", stats.thisFrame.numTrianglesIn); - str += StringFromFormat("Triangles Rejected: %i\n", stats.thisFrame.numTrianglesRejected); - str += StringFromFormat("Triangles Culled: %i\n", stats.thisFrame.numTrianglesCulled); - str += StringFromFormat("Triangles Clipped: %i\n", stats.thisFrame.numTrianglesClipped); - str += StringFromFormat("Triangles Drawn: %i\n", stats.thisFrame.numTrianglesDrawn); - str += StringFromFormat("Rasterized Pix: %i\n", stats.thisFrame.rasterizedPixels); - str += StringFromFormat("TEV Pix In: %i\n", stats.thisFrame.tevPixelsIn); - str += StringFromFormat("TEV Pix Out: %i\n", stats.thisFrame.tevPixelsOut); + DRAW_STAT("Objects", "%d", stats.thisFrame.numDrawnObjects); + DRAW_STAT("Vertices Loaded", "%d", stats.thisFrame.numVerticesLoaded); + DRAW_STAT("Triangles Input", "%d", stats.thisFrame.numTrianglesIn); + DRAW_STAT("Triangles Rejected", "%d", stats.thisFrame.numTrianglesRejected); + DRAW_STAT("Triangles Culled", "%d", stats.thisFrame.numTrianglesCulled); + DRAW_STAT("Triangles Clipped", "%d", stats.thisFrame.numTrianglesClipped); + DRAW_STAT("Triangles Drawn", "%d", stats.thisFrame.numTrianglesDrawn); + DRAW_STAT("Rasterized Pix", "%d", stats.thisFrame.rasterizedPixels); + DRAW_STAT("TEV Pix In", "%d", stats.thisFrame.tevPixelsIn); + DRAW_STAT("TEV Pix Out", "%d", stats.thisFrame.tevPixelsOut); } - str += StringFromFormat("Textures created: %i\n", stats.numTexturesCreated); - str += StringFromFormat("Textures uploaded: %i\n", stats.numTexturesUploaded); - str += StringFromFormat("Textures alive: %i\n", stats.numTexturesAlive); - str += StringFromFormat("pshaders created: %i\n", stats.numPixelShadersCreated); - str += StringFromFormat("pshaders alive: %i\n", stats.numPixelShadersAlive); - str += StringFromFormat("vshaders created: %i\n", stats.numVertexShadersCreated); - str += StringFromFormat("vshaders alive: %i\n", stats.numVertexShadersAlive); - str += StringFromFormat("shaders changes: %i\n", stats.thisFrame.numShaderChanges); - str += StringFromFormat("dlists called: %i\n", stats.thisFrame.numDListsCalled); - str += StringFromFormat("Primitive joins: %i\n", stats.thisFrame.numPrimitiveJoins); - str += StringFromFormat("Draw calls: %i\n", stats.thisFrame.numDrawCalls); - str += StringFromFormat("Primitives: %i\n", stats.thisFrame.numPrims); - str += StringFromFormat("Primitives (DL): %i\n", stats.thisFrame.numDLPrims); - str += StringFromFormat("XF loads: %i\n", stats.thisFrame.numXFLoads); - str += StringFromFormat("XF loads (DL): %i\n", stats.thisFrame.numXFLoadsInDL); - str += StringFromFormat("CP loads: %i\n", stats.thisFrame.numCPLoads); - str += StringFromFormat("CP loads (DL): %i\n", stats.thisFrame.numCPLoadsInDL); - str += StringFromFormat("BP loads: %i\n", stats.thisFrame.numBPLoads); - str += StringFromFormat("BP loads (DL): %i\n", stats.thisFrame.numBPLoadsInDL); - str += StringFromFormat("Vertex streamed: %i kB\n", stats.thisFrame.bytesVertexStreamed / 1024); - str += StringFromFormat("Index streamed: %i kB\n", stats.thisFrame.bytesIndexStreamed / 1024); - str += StringFromFormat("Uniform streamed: %i kB\n", stats.thisFrame.bytesUniformStreamed / 1024); - str += StringFromFormat("Vertex Loaders: %i\n", stats.numVertexLoaders); + DRAW_STAT("Textures created", "%d", stats.numTexturesCreated); + DRAW_STAT("Textures uploaded", "%d", stats.numTexturesUploaded); + DRAW_STAT("Textures alive", "%d", stats.numTexturesAlive); + DRAW_STAT("pshaders created", "%d", stats.numPixelShadersCreated); + DRAW_STAT("pshaders alive", "%d", stats.numPixelShadersAlive); + DRAW_STAT("vshaders created", "%d", stats.numVertexShadersCreated); + DRAW_STAT("vshaders alive", "%d", stats.numVertexShadersAlive); + DRAW_STAT("shaders changes", "%d", stats.thisFrame.numShaderChanges); + DRAW_STAT("dlists called", "%d", stats.thisFrame.numDListsCalled); + DRAW_STAT("Primitive joins", "%d", stats.thisFrame.numPrimitiveJoins); + DRAW_STAT("Draw calls", "%d", stats.thisFrame.numDrawCalls); + DRAW_STAT("Primitives", "%d", stats.thisFrame.numPrims); + DRAW_STAT("Primitives (DL)", "%d", stats.thisFrame.numDLPrims); + DRAW_STAT("XF loads", "%d", stats.thisFrame.numXFLoads); + DRAW_STAT("XF loads (DL)", "%d", stats.thisFrame.numXFLoadsInDL); + DRAW_STAT("CP loads", "%d", stats.thisFrame.numCPLoads); + DRAW_STAT("CP loads (DL)", "%d", stats.thisFrame.numCPLoadsInDL); + DRAW_STAT("BP loads", "%d", stats.thisFrame.numBPLoads); + DRAW_STAT("BP loads (DL)", "%d", stats.thisFrame.numBPLoadsInDL); + DRAW_STAT("Vertex streamed", "%i kB", stats.thisFrame.bytesVertexStreamed / 1024); + DRAW_STAT("Index streamed", "%i kB", stats.thisFrame.bytesIndexStreamed / 1024); + DRAW_STAT("Uniform streamed", "%i kB", stats.thisFrame.bytesUniformStreamed / 1024); + DRAW_STAT("Vertex Loaders", "%d", stats.numVertexLoaders); - std::string vertex_list = VertexLoaderManager::VertexLoadersToString(); +#undef DRAW_STAT - // TODO : at some point text1 just becomes too huge and overflows, we can't even read the added - // stuff - // since it gets added at the far bottom of the screen anyway (actually outside the rendering - // window) - // we should really reset the list instead of using substr - if (vertex_list.size() + str.size() > 8170) - vertex_list = vertex_list.substr(0, 8170 - str.size()); + ImGui::Columns(1); - str += vertex_list; - - return str; + ImGui::End(); } // Is this really needed? -std::string Statistics::ToStringProj() +void Statistics::DisplayProj() { - std::string projections; + if (!ImGui::Begin("Projection Statistics", nullptr, ImGuiWindowFlags_NoNavInputs)) + { + ImGui::End(); + return; + } - projections += "Projection #: X for Raw 6=0 (X for Raw 6!=0)\n\n"; - projections += StringFromFormat("Projection 0: %f (%f) Raw 0: %f\n", stats.gproj_0, - stats.g2proj_0, stats.proj_0); - projections += StringFromFormat("Projection 1: %f (%f)\n", stats.gproj_1, stats.g2proj_1); - projections += StringFromFormat("Projection 2: %f (%f) Raw 1: %f\n", stats.gproj_2, - stats.g2proj_2, stats.proj_1); - projections += StringFromFormat("Projection 3: %f (%f)\n\n", stats.gproj_3, stats.g2proj_3); - projections += StringFromFormat("Projection 4: %f (%f)\n", stats.gproj_4, stats.g2proj_4); - projections += StringFromFormat("Projection 5: %f (%f) Raw 2: %f\n", stats.gproj_5, - stats.g2proj_5, stats.proj_2); - projections += StringFromFormat("Projection 6: %f (%f) Raw 3: %f\n", stats.gproj_6, - stats.g2proj_6, stats.proj_3); - projections += StringFromFormat("Projection 7: %f (%f)\n\n", stats.gproj_7, stats.g2proj_7); - projections += StringFromFormat("Projection 8: %f (%f)\n", stats.gproj_8, stats.g2proj_8); - projections += StringFromFormat("Projection 9: %f (%f)\n", stats.gproj_9, stats.g2proj_9); - projections += StringFromFormat("Projection 10: %f (%f) Raw 4: %f\n\n", stats.gproj_10, - stats.g2proj_10, stats.proj_4); - projections += StringFromFormat("Projection 11: %f (%f) Raw 5: %f\n\n", stats.gproj_11, - stats.g2proj_11, stats.proj_5); - projections += StringFromFormat("Projection 12: %f (%f)\n", stats.gproj_12, stats.g2proj_12); - projections += StringFromFormat("Projection 13: %f (%f)\n", stats.gproj_13, stats.g2proj_13); - projections += StringFromFormat("Projection 14: %f (%f)\n", stats.gproj_14, stats.g2proj_14); - projections += StringFromFormat("Projection 15: %f (%f)\n", stats.gproj_15, stats.g2proj_15); + ImGui::Text("Projection #: X for Raw 6=0 (X for Raw 6!=0)"); + ImGui::NewLine(); + ImGui::Text("Projection 0: %f (%f) Raw 0: %f", stats.gproj_0, stats.g2proj_0, stats.proj_0); + ImGui::Text("Projection 1: %f (%f)", stats.gproj_1, stats.g2proj_1); + ImGui::Text("Projection 2: %f (%f) Raw 1: %f", stats.gproj_2, stats.g2proj_2, stats.proj_1); + ImGui::Text("Projection 3: %f (%f)", stats.gproj_3, stats.g2proj_3); + ImGui::Text("Projection 4: %f (%f)", stats.gproj_4, stats.g2proj_4); + ImGui::Text("Projection 5: %f (%f) Raw 2: %f", stats.gproj_5, stats.g2proj_5, stats.proj_2); + ImGui::Text("Projection 6: %f (%f) Raw 3: %f", stats.gproj_6, stats.g2proj_6, stats.proj_3); + ImGui::Text("Projection 7: %f (%f)", stats.gproj_7, stats.g2proj_7); + ImGui::Text("Projection 8: %f (%f)", stats.gproj_8, stats.g2proj_8); + ImGui::Text("Projection 9: %f (%f)", stats.gproj_9, stats.g2proj_9); + ImGui::Text("Projection 10: %f (%f) Raw 4: %f", stats.gproj_10, stats.g2proj_10, stats.proj_4); + ImGui::Text("Projection 11: %f (%f) Raw 5: %f", stats.gproj_11, stats.g2proj_11, stats.proj_5); + ImGui::Text("Projection 12: %f (%f)", stats.gproj_12, stats.g2proj_12); + ImGui::Text("Projection 13: %f (%f)", stats.gproj_13, stats.g2proj_13); + ImGui::Text("Projection 14: %f (%f)", stats.gproj_14, stats.g2proj_14); + ImGui::Text("Projection 15: %f (%f)", stats.gproj_15, stats.g2proj_15); - return projections; + ImGui::End(); } diff --git a/Source/Core/VideoCommon/Statistics.h b/Source/Core/VideoCommon/Statistics.h index 74ee317b82..c743bf7f08 100644 --- a/Source/Core/VideoCommon/Statistics.h +++ b/Source/Core/VideoCommon/Statistics.h @@ -65,9 +65,8 @@ struct Statistics ThisFrame thisFrame; void ResetFrame(); static void SwapDL(); - - static std::string ToString(); - static std::string ToStringProj(); + static void Display(); + static void DisplayProj(); }; extern Statistics stats; diff --git a/Source/Core/VideoCommon/VideoBackendBase.cpp b/Source/Core/VideoCommon/VideoBackendBase.cpp index fd6bbdfa2b..aa8b3d110f 100644 --- a/Source/Core/VideoCommon/VideoBackendBase.cpp +++ b/Source/Core/VideoCommon/VideoBackendBase.cpp @@ -278,9 +278,6 @@ void VideoBackendBase::InitializeShared() memset(&g_preprocess_cp_state, 0, sizeof(g_preprocess_cp_state)); memset(texMem, 0, TMEM_SIZE); - // Do our OSD callbacks - OSD::DoCallbacks(OSD::CallbackType::Initialization); - // do not initialize again for the config window m_initialized = true; @@ -303,9 +300,6 @@ void VideoBackendBase::InitializeShared() void VideoBackendBase::ShutdownShared() { - // Do our OSD callbacks - OSD::DoCallbacks(OSD::CallbackType::Shutdown); - m_initialized = false; VertexLoaderManager::Clear();