Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Merge pull request #12242 from AdmiralCurtiss/osd-icons
VideoCommon: Add support for icons in OSD messages.
  • Loading branch information
AdmiralCurtiss committed Oct 17, 2023
2 parents 53ea7ae + cb13ad7 commit c87b2e4
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 13 deletions.
10 changes: 6 additions & 4 deletions Source/Core/Core/Core.cpp
Expand Up @@ -579,9 +579,6 @@ static void EmuThread(std::unique_ptr<BootParameters> boot, WindowSystemInfo wsi
HW::Shutdown(system);
INFO_LOG_FMT(CONSOLE, "{}", StopMessage(false, "HW shutdown"));

// Clear on screen messages that haven't expired
OSD::ClearMessages();

// The config must be restored only after the whole HW has shut down,
// not when it is still running.
BootManager::RestoreConfig();
Expand All @@ -600,7 +597,12 @@ static void EmuThread(std::unique_ptr<BootParameters> boot, WindowSystemInfo wsi
PanicAlertFmt("Failed to initialize video backend!");
return;
}
Common::ScopeGuard video_guard{[] { g_video_backend->Shutdown(); }};
Common::ScopeGuard video_guard{[] {
// Clear on screen messages that haven't expired
OSD::ClearMessages();

g_video_backend->Shutdown();
}};

if (cpu_info.HTT)
Config::SetBaseOrCurrent(Config::MAIN_DSP_THREAD, cpu_info.num_cores > 4);
Expand Down
62 changes: 55 additions & 7 deletions Source/Core/VideoCommon/OnScreenDisplay.cpp
Expand Up @@ -18,6 +18,10 @@

#include "Core/Config/MainSettings.h"

#include "VideoCommon/AbstractGfx.h"
#include "VideoCommon/AbstractTexture.h"
#include "VideoCommon/TextureConfig.h"

namespace OSD
{
constexpr float LEFT_MARGIN = 10.0f; // Pixels to the left of OSD messages.
Expand All @@ -32,8 +36,8 @@ static std::atomic<int> s_obscured_pixels_top = 0;
struct Message
{
Message() = default;
Message(std::string text_, u32 duration_, u32 color_)
: text(std::move(text_)), duration(duration_), color(color_)
Message(std::string text_, u32 duration_, u32 color_, std::unique_ptr<Icon> icon_ = nullptr)
: text(std::move(text_)), duration(duration_), color(color_), icon(std::move(icon_))
{
timer.Start();
}
Expand All @@ -42,7 +46,10 @@ struct Message
Common::Timer timer;
u32 duration = 0;
bool ever_drawn = false;
bool should_discard = false;
u32 color = 0;
std::unique_ptr<Icon> icon;
std::unique_ptr<AbstractTexture> texture;
};
static std::multimap<MessageType, Message> s_messages;
static std::mutex s_messages_mutex;
Expand Down Expand Up @@ -77,6 +84,33 @@ static float DrawMessage(int index, Message& msg, const ImVec2& position, int ti
ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoNav |
ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoFocusOnAppearing))
{
if (msg.icon)
{
if (!msg.texture)
{
const u32 width = msg.icon->width;
const u32 height = msg.icon->height;
TextureConfig tex_config(width, height, 1, 1, 1, AbstractTextureFormat::RGBA8, 0);
msg.texture = g_gfx->CreateTexture(tex_config);
if (msg.texture)
{
msg.texture->Load(0, width, height, width, msg.icon->rgba_data.data(),
sizeof(u32) * width * height);
}
else
{
// don't try again next time
msg.icon.reset();
}
}

if (msg.texture)
{
ImGui::Image(msg.texture.get(), ImVec2(static_cast<float>(msg.icon->width),
static_cast<float>(msg.icon->height)));
}
}

// Use %s in case message contains %.
ImGui::TextColored(ARGBToImVec4(msg.color), "%s", msg.text.c_str());
window_height =
Expand All @@ -91,17 +125,25 @@ static float DrawMessage(int index, Message& msg, const ImVec2& position, int ti
return window_height;
}

void AddTypedMessage(MessageType type, std::string message, u32 ms, u32 argb)
void AddTypedMessage(MessageType type, std::string message, u32 ms, u32 argb,
std::unique_ptr<Icon> icon)
{
std::lock_guard lock{s_messages_mutex};
s_messages.erase(type);
s_messages.emplace(type, Message(std::move(message), ms, argb));

// A message may hold a reference to a texture that can only be destroyed on the video thread, so
// only mark the old typed message (if any) for removal. It will be discarded on the next call to
// DrawMessages().
auto range = s_messages.equal_range(type);
for (auto it = range.first; it != range.second; ++it)
it->second.should_discard = true;

s_messages.emplace(type, Message(std::move(message), ms, argb, std::move(icon)));
}

void AddMessage(std::string message, u32 ms, u32 argb)
void AddMessage(std::string message, u32 ms, u32 argb, std::unique_ptr<Icon> icon)
{
std::lock_guard lock{s_messages_mutex};
s_messages.emplace(MessageType::Typeless, Message(std::move(message), ms, argb));
s_messages.emplace(MessageType::Typeless, Message(std::move(message), ms, argb, std::move(icon)));
}

void DrawMessages()
Expand All @@ -117,6 +159,12 @@ void DrawMessages()
for (auto it = s_messages.begin(); it != s_messages.end();)
{
Message& msg = it->second;
if (msg.should_discard)
{
it = s_messages.erase(it);
continue;
}

const s64 time_left = msg.TimeRemaining();

// Make sure we draw them at least once if they were printed with 0ms,
Expand Down
14 changes: 12 additions & 2 deletions Source/Core/VideoCommon/OnScreenDisplay.h
Expand Up @@ -4,7 +4,9 @@
#pragma once

#include <functional>
#include <memory>
#include <string>
#include <vector>

#include "Common/CommonTypes.h"

Expand Down Expand Up @@ -35,10 +37,18 @@ constexpr u32 NORMAL = 5000;
constexpr u32 VERY_LONG = 10000;
}; // namespace Duration

struct Icon
{
std::vector<u8> rgba_data;
u32 width = 0;
u32 height = 0;
}; // struct Icon

// On-screen message display (colored yellow by default)
void AddMessage(std::string message, u32 ms = Duration::SHORT, u32 argb = Color::YELLOW);
void AddMessage(std::string message, u32 ms = Duration::SHORT, u32 argb = Color::YELLOW,
std::unique_ptr<Icon> icon = nullptr);
void AddTypedMessage(MessageType type, std::string message, u32 ms = Duration::SHORT,
u32 argb = Color::YELLOW);
u32 argb = Color::YELLOW, std::unique_ptr<Icon> icon = nullptr);

// Draw the current messages on the screen. Only call once per frame.
void DrawMessages();
Expand Down

0 comments on commit c87b2e4

Please sign in to comment.