diff --git a/src/xenia/app/emulator_window.cc b/src/xenia/app/emulator_window.cc index 62ff25948..b40202370 100644 --- a/src/xenia/app/emulator_window.cc +++ b/src/xenia/app/emulator_window.cc @@ -100,6 +100,13 @@ bool EmulatorWindow::Initialize() { window_->on_key_down.AddListener([this](KeyEvent* e) { bool handled = true; switch (e->key_code()) { + case 0x48: { // h + if (e->is_shift_pressed()) { + window_->FPSTextScale(); + } else { + window_->ToggleFPS(); + } + } break; case 0x4F: { // o if (e->is_ctrl_pressed()) { FileOpen(); diff --git a/src/xenia/ui/window.cc b/src/xenia/ui/window.cc index 8be8900c8..e43dd117f 100644 --- a/src/xenia/ui/window.cc +++ b/src/xenia/ui/window.cc @@ -17,6 +17,8 @@ #include "xenia/base/logging.h" #include "xenia/ui/imgui_drawer.h" +#include "xenia/base/profiling.h" + namespace xe { namespace ui { @@ -183,6 +185,33 @@ void Window::OnPaint(UIEvent* e) { tick_frequency)); fps_update_time_ticks_ = now_ticks; fps_frame_count_ = 0; + +#if XE_OPTION_PROFILING + // This means FPS counter will not work with profiling disabled (e.g. on + // Linux) + float fToMs = + MicroProfileTickToMsMultiplier(MicroProfileTicksPerSecondCpu()); + uint64_t nFlipTicks = 0; + { + std::lock_guard lock(MicroProfileGetMutex()); + MicroProfile& S = *MicroProfileGet(); + nFlipTicks = S.nFlipTicks; + } + float fMs = fToMs * nFlipTicks; + + if (fMs != 0.0f) { + game_fps_ = static_cast(1000.0f / fMs); + } +#endif + + title_fps_text_ = base_title_; + title_fps_text_ += " | "; + title_fps_text_ += std::to_string(game_fps_); + title_fps_text_ += " FPS"; + set_title(title_fps_text_, false); + + osd_fps_text_ = std::to_string(game_fps_); + osd_fps_text_ += " FPS"; } GraphicsContextLock context_lock(context_.get()); @@ -213,6 +242,20 @@ void Window::OnPaint(UIEvent* e) { ForEachListener([e](auto listener) { listener->OnPaint(e); }); on_paint(e); + if (display_fps_) { + ImGui::Begin("FPS", (bool*)0, + ImGuiWindowFlags_::ImGuiWindowFlags_NoTitleBar | + ImGuiWindowFlags_::ImGuiWindowFlags_NoResize | + ImGuiWindowFlags_::ImGuiWindowFlags_NoMove | + ImGuiWindowFlags_::ImGuiWindowFlags_NoScrollbar | + ImGuiWindowFlags_::ImGuiWindowFlags_NoSavedSettings | + ImGuiWindowFlags_::ImGuiWindowFlags_NoInputs); + ImGui::SetWindowFontScale(fps_font_scale_); + ImGui::Text("%s", osd_fps_text_.c_str()); + ImGui::SetWindowSize({0.0f, 0.0f}); // Resize to fit content + ImGui::End(); + } + // Flush ImGui buffers before we swap. ImGui::Render(); imgui_drawer_->RenderDrawLists(); diff --git a/src/xenia/ui/window.h b/src/xenia/ui/window.h index e1e48e2a0..551d235ab 100644 --- a/src/xenia/ui/window.h +++ b/src/xenia/ui/window.h @@ -47,15 +47,27 @@ class Window { virtual void EnableMainMenu() = 0; virtual void DisableMainMenu() = 0; + const std::string& title() const { return title_; } - virtual bool set_title(const std::string& title) { + virtual bool set_title(const std::string& title, + bool set_base_title = true) { if (title == title_) { return false; } title_ = title; + if (set_base_title) { + base_title_ = title; + } return true; } + void ToggleFPS() { display_fps_ = !display_fps_; } + + void FPSTextScale() { + fps_font_scale_ = fps_font_scale_ * 2.0f; + fps_font_scale_ = (fps_font_scale_ > 4.0f) ? 1.0f : fps_font_scale_; + } + virtual bool SetIcon(const void* buffer, size_t size) = 0; void ResetIcon() { SetIcon(nullptr, 0); } @@ -171,7 +183,10 @@ class Window { Loop* loop_ = nullptr; std::unique_ptr main_menu_; + std::string title_; + std::string base_title_; + int32_t width_ = 0; int32_t height_ = 0; bool has_focus_ = true; @@ -187,6 +202,13 @@ class Window { uint64_t fps_frame_count_ = 0; uint64_t last_paint_time_ticks_ = 0; + bool display_fps_ = false; + uint32_t game_fps_ = 0; + float fps_font_scale_ = 1.0f; + + std::string title_fps_text_; + std::string osd_fps_text_; + bool modifier_shift_pressed_ = false; bool modifier_cntrl_pressed_ = false; bool modifier_alt_pressed_ = false; diff --git a/src/xenia/ui/window_gtk.cc b/src/xenia/ui/window_gtk.cc index a6ca2087b..30e49f491 100644 --- a/src/xenia/ui/window_gtk.cc +++ b/src/xenia/ui/window_gtk.cc @@ -99,8 +99,8 @@ void GTKWindow::OnClose() { super::OnClose(); } -bool GTKWindow::set_title(const std::string& title) { - if (!super::set_title(title)) { +bool GTKWindow::set_title(const std::string& title, bool set_base_title) { + if (!super::set_title(title, set_base_title)) { return false; } gtk_window_set_title(GTK_WINDOW(window_), (gchar*)title.c_str()); diff --git a/src/xenia/ui/window_gtk.h b/src/xenia/ui/window_gtk.h index b0b56f70d..1a49e58ce 100644 --- a/src/xenia/ui/window_gtk.h +++ b/src/xenia/ui/window_gtk.h @@ -38,7 +38,8 @@ class GTKWindow : public Window { void EnableMainMenu() override {} void DisableMainMenu() override {} - bool set_title(const std::string& title) override; + bool set_title(const std::string& title, + bool set_base_title = true) override; bool SetIcon(const void* buffer, size_t size) override; diff --git a/src/xenia/ui/window_win.cc b/src/xenia/ui/window_win.cc index 2e60d2e42..b47729526 100644 --- a/src/xenia/ui/window_win.cc +++ b/src/xenia/ui/window_win.cc @@ -198,8 +198,8 @@ void Win32Window::DisableMainMenu() { } } -bool Win32Window::set_title(const std::string& title) { - if (!super::set_title(title)) { +bool Win32Window::set_title(const std::string& title, bool set_base_title) { + if (!super::set_title(title, set_base_title)) { return false; } SetWindowTextW(hwnd_, reinterpret_cast(xe::to_utf16(title).c_str())); diff --git a/src/xenia/ui/window_win.h b/src/xenia/ui/window_win.h index da638afdc..4c5d1301e 100644 --- a/src/xenia/ui/window_win.h +++ b/src/xenia/ui/window_win.h @@ -34,7 +34,8 @@ class Win32Window : public Window { void EnableMainMenu() override; void DisableMainMenu() override; - bool set_title(const std::string& title) override; + bool set_title(const std::string& title, + bool set_base_title = true) override; bool SetIcon(const void* buffer, size_t size) override;