Renderer: Use imgui for drawing debug text and OSD

This commit is contained in:
Stenzek 2018-10-10 01:26:31 +11:00
parent d1868d9475
commit 600d1fc0bc
13 changed files with 268 additions and 324 deletions

View File

@ -595,9 +595,6 @@ static void Run(const std::vector<std::string>& paths, bool first_open,
ASSERT(!paths.empty()); ASSERT(!paths.empty());
__android_log_print(ANDROID_LOG_INFO, DOLPHIN_TAG, "Running : %s", paths[0].c_str()); __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); RegisterMsgAlertHandler(&MsgAlert);
Common::AndroidSetReportHandler(&ReportSend); Common::AndroidSetReportHandler(&ReportSend);
DolphinAnalytics::AndroidSetGetValFunc(&GetAnalyticValue); DolphinAnalytics::AndroidSetGetValFunc(&GetAnalyticValue);
@ -639,6 +636,7 @@ static void Run(const std::vector<std::string>& paths, bool first_open,
} }
Core::Shutdown(); Core::Shutdown();
ButtonManager::Shutdown();
UICommon::Shutdown(); UICommon::Shutdown();
guard.unlock(); guard.unlock();

View File

@ -5,6 +5,7 @@
#include "DolphinQt/HotkeyScheduler.h" #include "DolphinQt/HotkeyScheduler.h"
#include <algorithm> #include <algorithm>
#include <cmath>
#include <thread> #include <thread>
#include <QCoreApplication> #include <QCoreApplication>
@ -26,6 +27,7 @@
#include "InputCommon/ControllerInterface/ControllerInterface.h" #include "InputCommon/ControllerInterface/ControllerInterface.h"
#include "VideoCommon/OnScreenDisplay.h"
#include "VideoCommon/RenderBase.h" #include "VideoCommon/RenderBase.h"
#include "VideoCommon/VertexShaderManager.h" #include "VideoCommon/VertexShaderManager.h"
#include "VideoCommon/VideoConfig.h" #include "VideoCommon/VideoConfig.h"
@ -286,43 +288,62 @@ void HotkeyScheduler::Run()
else if (IsHotkey(HK_NEXT_GAME_WIIMOTE_PROFILE_4)) else if (IsHotkey(HK_NEXT_GAME_WIIMOTE_PROFILE_4))
m_profile_cycler.NextWiimoteProfileForGame(3); m_profile_cycler.NextWiimoteProfileForGame(3);
const auto show_msg = [](OSDMessage message) { auto ShowVolume = []() {
if (g_renderer) OSD::AddMessage(std::string("Volume: ") +
g_renderer->ShowOSDMessage(message); (SConfig::GetInstance().m_IsMuted ?
"Muted" :
std::to_string(SConfig::GetInstance().m_Volume)) +
"%");
}; };
// Volume // Volume
if (IsHotkey(HK_VOLUME_DOWN)) if (IsHotkey(HK_VOLUME_DOWN))
{ {
show_msg(OSDMessage::VolumeChanged);
settings.DecreaseVolume(3); settings.DecreaseVolume(3);
ShowVolume();
} }
if (IsHotkey(HK_VOLUME_UP)) if (IsHotkey(HK_VOLUME_UP))
{ {
show_msg(OSDMessage::VolumeChanged);
settings.IncreaseVolume(3); settings.IncreaseVolume(3);
ShowVolume();
} }
if (IsHotkey(HK_VOLUME_TOGGLE_MUTE)) if (IsHotkey(HK_VOLUME_TOGGLE_MUTE))
{ {
show_msg(OSDMessage::VolumeChanged);
AudioCommon::ToggleMuteVolume(); AudioCommon::ToggleMuteVolume();
ShowVolume();
} }
// Graphics // Graphics
const auto efb_scale = Config::Get(Config::GFX_EFB_SCALE); 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)) if (IsHotkey(HK_INCREASE_IR))
{ {
show_msg(OSDMessage::IRChanged);
Config::SetCurrent(Config::GFX_EFB_SCALE, efb_scale + 1); Config::SetCurrent(Config::GFX_EFB_SCALE, efb_scale + 1);
ShowEFBScale();
} }
if (IsHotkey(HK_DECREASE_IR)) if (IsHotkey(HK_DECREASE_IR))
{ {
show_msg(OSDMessage::IRChanged);
if (efb_scale > EFB_SCALE_AUTO_INTEGRAL) if (efb_scale > EFB_SCALE_AUTO_INTEGRAL)
{
Config::SetCurrent(Config::GFX_EFB_SCALE, efb_scale - 1); Config::SetCurrent(Config::GFX_EFB_SCALE, efb_scale - 1);
ShowEFBScale();
}
} }
if (IsHotkey(HK_TOGGLE_CROP)) if (IsHotkey(HK_TOGGLE_CROP))
@ -330,34 +351,55 @@ void HotkeyScheduler::Run()
if (IsHotkey(HK_TOGGLE_AR)) if (IsHotkey(HK_TOGGLE_AR))
{ {
show_msg(OSDMessage::ARToggled);
const int aspect_ratio = (static_cast<int>(Config::Get(Config::GFX_ASPECT_RATIO)) + 1) & 3; const int aspect_ratio = (static_cast<int>(Config::Get(Config::GFX_ASPECT_RATIO)) + 1) & 3;
Config::SetCurrent(Config::GFX_ASPECT_RATIO, static_cast<AspectMode>(aspect_ratio)); Config::SetCurrent(Config::GFX_ASPECT_RATIO, static_cast<AspectMode>(aspect_ratio));
switch (static_cast<AspectMode>(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)) if (IsHotkey(HK_TOGGLE_EFBCOPIES))
{ {
show_msg(OSDMessage::EFBCopyToggled); const bool new_value = !Config::Get(Config::GFX_HACK_SKIP_EFB_COPY_TO_RAM);
Config::SetCurrent(Config::GFX_HACK_SKIP_EFB_COPY_TO_RAM, Config::SetCurrent(Config::GFX_HACK_SKIP_EFB_COPY_TO_RAM, new_value);
!Config::Get(Config::GFX_HACK_SKIP_EFB_COPY_TO_RAM)); 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)) if (IsHotkey(HK_TOGGLE_XFBCOPIES))
{ {
show_msg(OSDMessage::XFBChanged);
Config::SetCurrent(Config::GFX_HACK_SKIP_XFB_COPY_TO_RAM, Config::SetCurrent(Config::GFX_HACK_SKIP_XFB_COPY_TO_RAM,
!Config::Get(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)) if (IsHotkey(HK_TOGGLE_IMMEDIATE_XFB))
{ {
show_msg(OSDMessage::XFBChanged);
Config::SetCurrent(Config::GFX_HACK_IMMEDIATE_XFB, Config::SetCurrent(Config::GFX_HACK_IMMEDIATE_XFB,
!Config::Get(Config::GFX_HACK_IMMEDIATE_XFB)); !Config::Get(Config::GFX_HACK_IMMEDIATE_XFB));
ShowXFBCopies();
} }
if (IsHotkey(HK_TOGGLE_FOG)) if (IsHotkey(HK_TOGGLE_FOG))
{ {
show_msg(OSDMessage::FogToggled); const bool new_value = !Config::Get(Config::GFX_DISABLE_FOG);
Config::SetCurrent(Config::GFX_DISABLE_FOG, !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)) if (IsHotkey(HK_TOGGLE_DUMPTEXTURES))
@ -368,22 +410,28 @@ void HotkeyScheduler::Run()
Core::SetIsThrottlerTempDisabled(IsHotkey(HK_TOGGLE_THROTTLE, true)); 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)) if (IsHotkey(HK_DECREASE_EMULATION_SPEED))
{ {
show_msg(OSDMessage::SpeedChanged);
auto speed = SConfig::GetInstance().m_EmulationSpeed - 0.1; auto speed = SConfig::GetInstance().m_EmulationSpeed - 0.1;
speed = (speed <= 0 || (speed >= 0.95 && speed <= 1.05)) ? 1.0 : speed; speed = (speed <= 0 || (speed >= 0.95 && speed <= 1.05)) ? 1.0 : speed;
SConfig::GetInstance().m_EmulationSpeed = speed; SConfig::GetInstance().m_EmulationSpeed = speed;
ShowEmulationSpeed();
} }
if (IsHotkey(HK_INCREASE_EMULATION_SPEED)) if (IsHotkey(HK_INCREASE_EMULATION_SPEED))
{ {
show_msg(OSDMessage::SpeedChanged);
auto speed = SConfig::GetInstance().m_EmulationSpeed + 0.1; auto speed = SConfig::GetInstance().m_EmulationSpeed + 0.1;
speed = (speed >= 0.95 && speed <= 1.05) ? 1.0 : speed; speed = (speed >= 0.95 && speed <= 1.05) ? 1.0 : speed;
SConfig::GetInstance().m_EmulationSpeed = speed; SConfig::GetInstance().m_EmulationSpeed = speed;
ShowEmulationSpeed();
} }
// Slot Saving / Loading // Slot Saving / Loading

View File

@ -595,10 +595,6 @@ void Renderer::SwapImpl(AbstractTexture* texture, const EFBRectangle& xfb_region
D3D11_VIEWPORT vp = CD3D11_VIEWPORT(0.0f, 0.0f, static_cast<float>(m_backbuffer_width), D3D11_VIEWPORT vp = CD3D11_VIEWPORT(0.0f, 0.0f, static_cast<float>(m_backbuffer_width),
static_cast<float>(m_backbuffer_height)); static_cast<float>(m_backbuffer_height));
D3D::context->RSSetViewports(1, &vp); D3D::context->RSSetViewports(1, &vp);
Renderer::DrawDebugText();
OSD::DrawMessages();
DrawImGui(); DrawImGui();
g_texture_cache->Cleanup(frameCount); g_texture_cache->Cleanup(frameCount);

View File

@ -1424,9 +1424,6 @@ void Renderer::SwapImpl(AbstractTexture* texture, const EFBRectangle& xfb_region
ResetAPIState(); ResetAPIState();
// Do our OSD callbacks
OSD::DoCallbacks(OSD::CallbackType::OnFrame);
// Check if we need to render to a new surface. // Check if we need to render to a new surface.
CheckForSurfaceChange(); CheckForSurfaceChange();
CheckForSurfaceResize(); CheckForSurfaceResize();
@ -1451,10 +1448,6 @@ void Renderer::SwapImpl(AbstractTexture* texture, const EFBRectangle& xfb_region
// Render OSD messages. // Render OSD messages.
glViewport(0, 0, m_backbuffer_width, m_backbuffer_height); 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(); DrawImGui();
// Swap the back and front buffers, presenting the image. // Swap the back and front buffers, presenting the image.

View File

@ -97,13 +97,8 @@ std::unique_ptr<AbstractPipeline> SWRenderer::CreatePipeline(const AbstractPipel
// Called on the GPU thread // Called on the GPU thread
void SWRenderer::SwapImpl(AbstractTexture* texture, const EFBRectangle& xfb_region, u64 ticks) void SWRenderer::SwapImpl(AbstractTexture* texture, const EFBRectangle& xfb_region, u64 ticks)
{ {
OSD::DoCallbacks(OSD::CallbackType::OnFrame);
if (!IsHeadless()) if (!IsHeadless())
{
DrawDebugText();
m_window->ShowImage(texture, xfb_region); m_window->ShowImage(texture, xfb_region);
}
UpdateActiveConfig(); UpdateActiveConfig();
} }

View File

@ -704,9 +704,6 @@ void Renderer::DrawScreen(VKTexture* xfb_texture, const EFBRectangle& xfb_region
// Draw OSD // Draw OSD
SetViewport(0.0f, 0.0f, static_cast<float>(backbuffer->GetWidth()), SetViewport(0.0f, 0.0f, static_cast<float>(backbuffer->GetWidth()),
static_cast<float>(backbuffer->GetHeight()), 0.0f, 1.0f); static_cast<float>(backbuffer->GetHeight()), 0.0f, 1.0f);
DrawDebugText();
OSD::DoCallbacks(OSD::CallbackType::OnFrame);
OSD::DrawMessages();
StateTracker::GetInstance()->SetPendingRebind(); StateTracker::GetInstance()->SetPendingRebind();
DrawImGui(); DrawImGui();

View File

@ -5,22 +5,79 @@
#include <algorithm> #include <algorithm>
#include <list> #include <list>
#include <map> #include <map>
#include <mutex>
#include <string> #include <string>
#include "imgui.h"
#include "Common/CommonTypes.h" #include "Common/CommonTypes.h"
#include "Common/Timer.h" #include "Common/Timer.h"
#include "Core/ConfigManager.h" #include "Core/ConfigManager.h"
#include "VideoCommon/OnScreenDisplay.h" #include "VideoCommon/OnScreenDisplay.h"
#include "VideoCommon/RenderBase.h"
namespace OSD namespace OSD
{ {
static std::multimap<CallbackType, Callback> 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<MessageType, Message> s_messages; static std::multimap<MessageType, Message> s_messages;
static std::mutex s_messages_mutex; static std::mutex s_messages_mutex;
static ImVec4 RGBAToImVec4(const u32 rgba)
{
return ImVec4(static_cast<float>((rgba >> 16) & 0xFF) / 255.0f,
static_cast<float>((rgba >> 8) & 0xFF) / 255.0f,
static_cast<float>((rgba >> 0) & 0xFF) / 255.0f,
static_cast<float>((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) void AddTypedMessage(MessageType type, const std::string& message, u32 ms, u32 rgba)
{ {
std::lock_guard<std::mutex> lock(s_messages_mutex); std::lock_guard<std::mutex> 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)); 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() void DrawMessages()
{ {
if (!SConfig::GetInstance().bOnScreenDisplayMessages) if (!SConfig::GetInstance().bOnScreenDisplayMessages)
@ -51,21 +100,22 @@ void DrawMessages()
{ {
std::lock_guard<std::mutex> lock(s_messages_mutex); std::lock_guard<std::mutex> lock(s_messages_mutex);
u32 now = Common::Timer::GetTimeMs(); const u32 now = Common::Timer::GetTimeMs();
int left = 20, top = 35; 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(); auto it = s_messages.begin();
while (it != s_messages.end()) while (it != s_messages.end())
{ {
const Message& msg = it->second; const Message& msg = it->second;
int time_left = (int)(msg.m_timestamp - now); const int time_left = static_cast<int>(msg.timestamp - now);
DrawMessage(msg, top, left, time_left); current_y += DrawMessage(index++, msg, ImVec2(current_x, current_y), time_left);
if (time_left <= 0) if (time_left <= 0)
it = s_messages.erase(it); it = s_messages.erase(it);
else else
++it; ++it;
top += 15;
} }
} }
} }
@ -75,24 +125,4 @@ void ClearMessages()
std::lock_guard<std::mutex> lock(s_messages_mutex); std::lock_guard<std::mutex> lock(s_messages_mutex);
s_messages.clear(); 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

View File

@ -11,15 +11,6 @@
namespace OSD 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 enum class MessageType
{ {
NetPlayPing, 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 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, void AddTypedMessage(MessageType type, const std::string& message, u32 ms = Duration::SHORT,
u32 rgba = Color::YELLOW); 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 void DrawMessages(); // draw the current messages on the screen. Only call once
// per frame. // per frame.
void ClearMessages(); void ClearMessages();
// On-screen callbacks
enum class CallbackType
{
Initialization,
OnFrame,
Shutdown
};
using Callback = std::function<void()>;
void AddCallback(CallbackType type, Callback cb);
void DoCallbacks(CallbackType type);
} // namespace OSD } // namespace OSD

View File

@ -65,6 +65,7 @@
#include "VideoCommon/Statistics.h" #include "VideoCommon/Statistics.h"
#include "VideoCommon/TextureCacheBase.h" #include "VideoCommon/TextureCacheBase.h"
#include "VideoCommon/TextureDecoder.h" #include "VideoCommon/TextureDecoder.h"
#include "VideoCommon/VertexLoaderManager.h"
#include "VideoCommon/VertexManagerBase.h" #include "VideoCommon/VertexManagerBase.h"
#include "VideoCommon/VertexShaderManager.h" #include "VideoCommon/VertexShaderManager.h"
#include "VideoCommon/VideoConfig.h" #include "VideoCommon/VideoConfig.h"
@ -261,139 +262,64 @@ bool Renderer::CheckForHostConfigChanges()
// Create On-Screen-Messages // Create On-Screen-Messages
void Renderer::DrawDebugText() 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) // Position in the top-right corner of the screen.
final_cyan += StringFromFormat("FPS: %.2f", m_fps_counter.GetFPS()); 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) if (ImGui::Begin("FPS", nullptr,
final_cyan += " - "; ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoInputs |
if (SConfig::GetInstance().m_ShowFrameCount) 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()) 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());
} }
ImGui::End();
final_cyan += "\n";
final_yellow += "\n";
} }
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<u32>(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) if (g_ActiveConfig.bOverlayStats)
final_cyan += Statistics::ToString(); Statistics::Display();
if (g_ActiveConfig.bOverlayProjStats) if (g_ActiveConfig.bOverlayProjStats)
final_cyan += Statistics::ToStringProj(); Statistics::DisplayProj();
// and then the text
RenderText(final_cyan, 20, 20, 0xFF00FFFF);
RenderText(final_yellow, 20, 20, 0xFFFFFF00);
} }
float Renderer::CalculateDrawAspectRatio() const 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 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. // draw calls don't get issued until DrawImGui is called, which happens in SwapImpl.
DrawDebugText();
OSD::DrawMessages();
ImGui::Render(); ImGui::Render();
// TODO: merge more generic parts into VideoCommon // TODO: merge more generic parts into VideoCommon
@ -1332,8 +1260,3 @@ std::unique_ptr<VideoCommon::AsyncShaderCompiler> Renderer::CreateAsyncShaderCom
{ {
return std::make_unique<VideoCommon::AsyncShaderCompiler>(); return std::make_unique<VideoCommon::AsyncShaderCompiler>();
} }
void Renderer::ShowOSDMessage(OSDMessage message)
{
m_osd_message = static_cast<s32>(message);
}

View File

@ -57,17 +57,6 @@ struct EfbPokeData
extern int frameCount; 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". // 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 // The long term goal is to get rid of this class and replace it with others that make
// more sense. // more sense.
@ -201,8 +190,6 @@ public:
virtual std::unique_ptr<VideoCommon::AsyncShaderCompiler> CreateAsyncShaderCompiler(); virtual std::unique_ptr<VideoCommon::AsyncShaderCompiler> CreateAsyncShaderCompiler();
void ShowOSDMessage(OSDMessage message);
protected: protected:
std::tuple<int, int> CalculateTargetScale(int x, int y) const; std::tuple<int, int> CalculateTargetScale(int x, int y) const;
bool CalculateTargetSize(); bool CalculateTargetSize();
@ -303,9 +290,6 @@ private:
u32 m_last_xfb_width = MAX_XFB_WIDTH; u32 m_last_xfb_width = MAX_XFB_WIDTH;
u32 m_last_xfb_height = MAX_XFB_HEIGHT; 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. // NOTE: The methods below are called on the framedumping thread.
bool StartFrameDumpToAVI(const FrameDumpConfig& config); bool StartFrameDumpToAVI(const FrameDumpConfig& config);
void DumpFrameToAVI(const FrameDumpConfig& config); void DumpFrameToAVI(const FrameDumpConfig& config);

View File

@ -6,6 +6,8 @@
#include <string> #include <string>
#include <utility> #include <utility>
#include "imgui.h"
#include "Common/StringUtil.h" #include "Common/StringUtil.h"
#include "VideoCommon/Statistics.h" #include "VideoCommon/Statistics.h"
#include "VideoCommon/VertexLoaderManager.h" #include "VideoCommon/VertexLoaderManager.h"
@ -26,91 +28,98 @@ void Statistics::SwapDL()
std::swap(stats.thisFrame.numBPLoadsInDL, stats.thisFrame.numBPLoads); 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) if (g_ActiveConfig.backend_info.api_type == APIType::Nothing)
{ {
str += StringFromFormat("Objects: %i\n", stats.thisFrame.numDrawnObjects); DRAW_STAT("Objects", "%d", stats.thisFrame.numDrawnObjects);
str += StringFromFormat("Vertices Loaded: %i\n", stats.thisFrame.numVerticesLoaded); DRAW_STAT("Vertices Loaded", "%d", stats.thisFrame.numVerticesLoaded);
str += StringFromFormat("Triangles Input: %i\n", stats.thisFrame.numTrianglesIn); DRAW_STAT("Triangles Input", "%d", stats.thisFrame.numTrianglesIn);
str += StringFromFormat("Triangles Rejected: %i\n", stats.thisFrame.numTrianglesRejected); DRAW_STAT("Triangles Rejected", "%d", stats.thisFrame.numTrianglesRejected);
str += StringFromFormat("Triangles Culled: %i\n", stats.thisFrame.numTrianglesCulled); DRAW_STAT("Triangles Culled", "%d", stats.thisFrame.numTrianglesCulled);
str += StringFromFormat("Triangles Clipped: %i\n", stats.thisFrame.numTrianglesClipped); DRAW_STAT("Triangles Clipped", "%d", stats.thisFrame.numTrianglesClipped);
str += StringFromFormat("Triangles Drawn: %i\n", stats.thisFrame.numTrianglesDrawn); DRAW_STAT("Triangles Drawn", "%d", stats.thisFrame.numTrianglesDrawn);
str += StringFromFormat("Rasterized Pix: %i\n", stats.thisFrame.rasterizedPixels); DRAW_STAT("Rasterized Pix", "%d", stats.thisFrame.rasterizedPixels);
str += StringFromFormat("TEV Pix In: %i\n", stats.thisFrame.tevPixelsIn); DRAW_STAT("TEV Pix In", "%d", stats.thisFrame.tevPixelsIn);
str += StringFromFormat("TEV Pix Out: %i\n", stats.thisFrame.tevPixelsOut); DRAW_STAT("TEV Pix Out", "%d", stats.thisFrame.tevPixelsOut);
} }
str += StringFromFormat("Textures created: %i\n", stats.numTexturesCreated); DRAW_STAT("Textures created", "%d", stats.numTexturesCreated);
str += StringFromFormat("Textures uploaded: %i\n", stats.numTexturesUploaded); DRAW_STAT("Textures uploaded", "%d", stats.numTexturesUploaded);
str += StringFromFormat("Textures alive: %i\n", stats.numTexturesAlive); DRAW_STAT("Textures alive", "%d", stats.numTexturesAlive);
str += StringFromFormat("pshaders created: %i\n", stats.numPixelShadersCreated); DRAW_STAT("pshaders created", "%d", stats.numPixelShadersCreated);
str += StringFromFormat("pshaders alive: %i\n", stats.numPixelShadersAlive); DRAW_STAT("pshaders alive", "%d", stats.numPixelShadersAlive);
str += StringFromFormat("vshaders created: %i\n", stats.numVertexShadersCreated); DRAW_STAT("vshaders created", "%d", stats.numVertexShadersCreated);
str += StringFromFormat("vshaders alive: %i\n", stats.numVertexShadersAlive); DRAW_STAT("vshaders alive", "%d", stats.numVertexShadersAlive);
str += StringFromFormat("shaders changes: %i\n", stats.thisFrame.numShaderChanges); DRAW_STAT("shaders changes", "%d", stats.thisFrame.numShaderChanges);
str += StringFromFormat("dlists called: %i\n", stats.thisFrame.numDListsCalled); DRAW_STAT("dlists called", "%d", stats.thisFrame.numDListsCalled);
str += StringFromFormat("Primitive joins: %i\n", stats.thisFrame.numPrimitiveJoins); DRAW_STAT("Primitive joins", "%d", stats.thisFrame.numPrimitiveJoins);
str += StringFromFormat("Draw calls: %i\n", stats.thisFrame.numDrawCalls); DRAW_STAT("Draw calls", "%d", stats.thisFrame.numDrawCalls);
str += StringFromFormat("Primitives: %i\n", stats.thisFrame.numPrims); DRAW_STAT("Primitives", "%d", stats.thisFrame.numPrims);
str += StringFromFormat("Primitives (DL): %i\n", stats.thisFrame.numDLPrims); DRAW_STAT("Primitives (DL)", "%d", stats.thisFrame.numDLPrims);
str += StringFromFormat("XF loads: %i\n", stats.thisFrame.numXFLoads); DRAW_STAT("XF loads", "%d", stats.thisFrame.numXFLoads);
str += StringFromFormat("XF loads (DL): %i\n", stats.thisFrame.numXFLoadsInDL); DRAW_STAT("XF loads (DL)", "%d", stats.thisFrame.numXFLoadsInDL);
str += StringFromFormat("CP loads: %i\n", stats.thisFrame.numCPLoads); DRAW_STAT("CP loads", "%d", stats.thisFrame.numCPLoads);
str += StringFromFormat("CP loads (DL): %i\n", stats.thisFrame.numCPLoadsInDL); DRAW_STAT("CP loads (DL)", "%d", stats.thisFrame.numCPLoadsInDL);
str += StringFromFormat("BP loads: %i\n", stats.thisFrame.numBPLoads); DRAW_STAT("BP loads", "%d", stats.thisFrame.numBPLoads);
str += StringFromFormat("BP loads (DL): %i\n", stats.thisFrame.numBPLoadsInDL); DRAW_STAT("BP loads (DL)", "%d", stats.thisFrame.numBPLoadsInDL);
str += StringFromFormat("Vertex streamed: %i kB\n", stats.thisFrame.bytesVertexStreamed / 1024); DRAW_STAT("Vertex streamed", "%i kB", stats.thisFrame.bytesVertexStreamed / 1024);
str += StringFromFormat("Index streamed: %i kB\n", stats.thisFrame.bytesIndexStreamed / 1024); DRAW_STAT("Index streamed", "%i kB", stats.thisFrame.bytesIndexStreamed / 1024);
str += StringFromFormat("Uniform streamed: %i kB\n", stats.thisFrame.bytesUniformStreamed / 1024); DRAW_STAT("Uniform streamed", "%i kB", stats.thisFrame.bytesUniformStreamed / 1024);
str += StringFromFormat("Vertex Loaders: %i\n", stats.numVertexLoaders); 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 ImGui::Columns(1);
// 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());
str += vertex_list; ImGui::End();
return str;
} }
// Is this really needed? // 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"; ImGui::Text("Projection #: X for Raw 6=0 (X for Raw 6!=0)");
projections += StringFromFormat("Projection 0: %f (%f) Raw 0: %f\n", stats.gproj_0, ImGui::NewLine();
stats.g2proj_0, stats.proj_0); ImGui::Text("Projection 0: %f (%f) Raw 0: %f", stats.gproj_0, stats.g2proj_0, stats.proj_0);
projections += StringFromFormat("Projection 1: %f (%f)\n", stats.gproj_1, stats.g2proj_1); ImGui::Text("Projection 1: %f (%f)", stats.gproj_1, stats.g2proj_1);
projections += StringFromFormat("Projection 2: %f (%f) Raw 1: %f\n", stats.gproj_2, ImGui::Text("Projection 2: %f (%f) Raw 1: %f", stats.gproj_2, stats.g2proj_2, stats.proj_1);
stats.g2proj_2, stats.proj_1); ImGui::Text("Projection 3: %f (%f)", stats.gproj_3, stats.g2proj_3);
projections += StringFromFormat("Projection 3: %f (%f)\n\n", stats.gproj_3, stats.g2proj_3); ImGui::Text("Projection 4: %f (%f)", stats.gproj_4, stats.g2proj_4);
projections += StringFromFormat("Projection 4: %f (%f)\n", stats.gproj_4, stats.g2proj_4); ImGui::Text("Projection 5: %f (%f) Raw 2: %f", stats.gproj_5, stats.g2proj_5, stats.proj_2);
projections += StringFromFormat("Projection 5: %f (%f) Raw 2: %f\n", stats.gproj_5, ImGui::Text("Projection 6: %f (%f) Raw 3: %f", stats.gproj_6, stats.g2proj_6, stats.proj_3);
stats.g2proj_5, stats.proj_2); ImGui::Text("Projection 7: %f (%f)", stats.gproj_7, stats.g2proj_7);
projections += StringFromFormat("Projection 6: %f (%f) Raw 3: %f\n", stats.gproj_6, ImGui::Text("Projection 8: %f (%f)", stats.gproj_8, stats.g2proj_8);
stats.g2proj_6, stats.proj_3); ImGui::Text("Projection 9: %f (%f)", stats.gproj_9, stats.g2proj_9);
projections += StringFromFormat("Projection 7: %f (%f)\n\n", stats.gproj_7, stats.g2proj_7); ImGui::Text("Projection 10: %f (%f) Raw 4: %f", stats.gproj_10, stats.g2proj_10, stats.proj_4);
projections += StringFromFormat("Projection 8: %f (%f)\n", stats.gproj_8, stats.g2proj_8); ImGui::Text("Projection 11: %f (%f) Raw 5: %f", stats.gproj_11, stats.g2proj_11, stats.proj_5);
projections += StringFromFormat("Projection 9: %f (%f)\n", stats.gproj_9, stats.g2proj_9); ImGui::Text("Projection 12: %f (%f)", stats.gproj_12, stats.g2proj_12);
projections += StringFromFormat("Projection 10: %f (%f) Raw 4: %f\n\n", stats.gproj_10, ImGui::Text("Projection 13: %f (%f)", stats.gproj_13, stats.g2proj_13);
stats.g2proj_10, stats.proj_4); ImGui::Text("Projection 14: %f (%f)", stats.gproj_14, stats.g2proj_14);
projections += StringFromFormat("Projection 11: %f (%f) Raw 5: %f\n\n", stats.gproj_11, ImGui::Text("Projection 15: %f (%f)", stats.gproj_15, stats.g2proj_15);
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);
return projections; ImGui::End();
} }

View File

@ -65,9 +65,8 @@ struct Statistics
ThisFrame thisFrame; ThisFrame thisFrame;
void ResetFrame(); void ResetFrame();
static void SwapDL(); static void SwapDL();
static void Display();
static std::string ToString(); static void DisplayProj();
static std::string ToStringProj();
}; };
extern Statistics stats; extern Statistics stats;

View File

@ -278,9 +278,6 @@ void VideoBackendBase::InitializeShared()
memset(&g_preprocess_cp_state, 0, sizeof(g_preprocess_cp_state)); memset(&g_preprocess_cp_state, 0, sizeof(g_preprocess_cp_state));
memset(texMem, 0, TMEM_SIZE); memset(texMem, 0, TMEM_SIZE);
// Do our OSD callbacks
OSD::DoCallbacks(OSD::CallbackType::Initialization);
// do not initialize again for the config window // do not initialize again for the config window
m_initialized = true; m_initialized = true;
@ -303,9 +300,6 @@ void VideoBackendBase::InitializeShared()
void VideoBackendBase::ShutdownShared() void VideoBackendBase::ShutdownShared()
{ {
// Do our OSD callbacks
OSD::DoCallbacks(OSD::CallbackType::Shutdown);
m_initialized = false; m_initialized = false;
VertexLoaderManager::Clear(); VertexLoaderManager::Clear();