ImGuiManager: Run idle when OSD messages are present

So we don't miss them.
This commit is contained in:
Stenzek
2026-01-12 18:25:31 +10:00
parent 56cbbb1323
commit 5637fc7804
3 changed files with 78 additions and 15 deletions

View File

@@ -1485,6 +1485,22 @@ void GPUThread::SetRunIdleReason(RunIdleReason reason, bool enabled)
if (((s_state.run_idle_reasons & bit) != 0) == enabled)
return;
if (Log::IsLogVisible(Log::Level::Dev, Log::Channel::GPUThread))
{
static constexpr const std::array reason_strings = {
"NoGPUBackend", "SystemPaused", "OSDMessagesActive", "FullscreenUIActive",
"NotificationsActive", "LoadingScreenActive", "AchievementOverlaysActive",
};
for (u32 i = 0; i < reason_strings.size(); ++i)
{
if (static_cast<RunIdleReason>(1u << i) == reason)
{
DEV_COLOR_LOG(StrongYellow, "Setting run idle reason '{}' to {}", reason_strings[i], enabled);
break;
}
}
}
s_state.run_idle_reasons = enabled ? (s_state.run_idle_reasons | bit) : (s_state.run_idle_reasons & ~bit);
UpdateRunIdle();
}
@@ -1508,8 +1524,9 @@ void GPUThread::UpdateRunIdle()
static_cast<u8>(RunIdleReason::SystemPaused) |
static_cast<u8>(RunIdleReason::LoadingScreenActive);
static constexpr u8 ACTIVATE_MASK =
static_cast<u8>(RunIdleReason::FullscreenUIActive) | static_cast<u8>(RunIdleReason::NotificationsActive) |
static_cast<u8>(RunIdleReason::LoadingScreenActive) | static_cast<u8>(RunIdleReason::AchievementOverlaysActive);
static_cast<u8>(RunIdleReason::OSDMessagesActive) | static_cast<u8>(RunIdleReason::FullscreenUIActive) |
static_cast<u8>(RunIdleReason::NotificationsActive) | static_cast<u8>(RunIdleReason::LoadingScreenActive) |
static_cast<u8>(RunIdleReason::AchievementOverlaysActive);
const bool new_flag = (g_gpu_device && ((s_state.run_idle_reasons & REQUIRE_MASK) != 0) &&
((s_state.run_idle_reasons & ACTIVATE_MASK) != 0));

View File

@@ -36,10 +36,11 @@ enum class RunIdleReason : u8
{
NoGPUBackend = (1 << 0),
SystemPaused = (1 << 1),
FullscreenUIActive = (1 << 2),
NotificationsActive = (1 << 3),
LoadingScreenActive = (1 << 4),
AchievementOverlaysActive = (1 << 5),
OSDMessagesActive = (1 << 2),
FullscreenUIActive = (1 << 3),
NotificationsActive = (1 << 4),
LoadingScreenActive = (1 << 5),
AchievementOverlaysActive = (1 << 6),
};
/// Starts Big Picture UI.

View File

@@ -15,6 +15,7 @@
#include "core/gpu_thread.h"
#include "core/host.h"
#include "core/settings.h"
#include "core/system_private.h"
#include "common/assert.h"
#include "common/bitutils.h"
@@ -24,6 +25,7 @@
#include "common/log.h"
#include "common/string_util.h"
#include "common/thirdparty/usb_key_code_data.h"
#include "common/threading.h"
#include "common/timer.h"
#include "IconsEmoji.h"
@@ -101,6 +103,7 @@ static void AddOSDMessage(OSDMessageType type, std::string key, std::string icon
std::string message);
static void RemoveKeyedOSDMessage(std::string key);
static void ClearOSDMessages();
static void UpdateOSDMessageRunIdle(const std::unique_lock<std::mutex>& lock);
static void AcquirePendingOSDMessages(Timer::Value current_time);
static void DrawOSDMessages(Timer::Value current_time);
static void CreateSoftwareCursorTextures();
@@ -868,6 +871,41 @@ void ImGuiManager::AddOSDMessage(OSDMessageType type, std::string key, std::stri
.text = std::move(message),
.type = type,
});
// trigger run idle on first message
if (s_state.osd_posted_messages.size() == 1)
UpdateOSDMessageRunIdle(lock);
}
void ImGuiManager::UpdateOSDMessageRunIdle(const std::unique_lock<std::mutex>& lock)
{
static constexpr auto cb = []() {
GPUThread::SetRunIdleReason(GPUThread::RunIdleReason::OSDMessagesActive,
(!s_state.osd_active_messages.empty() || !s_state.osd_posted_messages.empty()));
};
if (GPUThread::IsOnThread())
{
cb();
return;
}
if (System::GetCoreThreadHandle().IsCallingThread())
{
GPUThread::RunOnThread([]() {
const std::unique_lock lock(s_state.osd_messages_lock);
cb();
});
}
else
{
Host::RunOnCoreThread([]() {
GPUThread::RunOnThread([]() {
const std::unique_lock lock(s_state.osd_messages_lock);
cb();
});
});
}
}
void ImGuiManager::RemoveKeyedOSDMessage(std::string key)
@@ -880,6 +918,8 @@ void ImGuiManager::RemoveKeyedOSDMessage(std::string key)
.text = {},
.type = OSDMessageType::MaxCount,
});
if (s_state.osd_posted_messages.size() == 1)
UpdateOSDMessageRunIdle(lock);
}
void ImGuiManager::ClearOSDMessages()
@@ -894,16 +934,8 @@ void ImGuiManager::ClearOSDMessages()
void ImGuiManager::AcquirePendingOSDMessages(Timer::Value current_time)
{
std::atomic_thread_fence(std::memory_order_acquire);
if (s_state.osd_posted_messages.empty())
return;
std::unique_lock lock(s_state.osd_messages_lock);
for (;;)
while (!s_state.osd_posted_messages.empty())
{
if (s_state.osd_posted_messages.empty())
break;
PostedOSDMessage& new_msg = s_state.osd_posted_messages.front();
// MaxCount is used to indicate removal of a message.
@@ -1151,9 +1183,22 @@ void ImGuiManager::DrawOSDMessages(Timer::Value current_time)
void ImGuiManager::RenderOSDMessages()
{
s_state.osd_messages_lock.lock();
if (s_state.osd_posted_messages.empty() && s_state.osd_active_messages.empty())
{
s_state.osd_messages_lock.unlock();
return;
}
const Timer::Value current_time = Timer::GetCurrentValue();
AcquirePendingOSDMessages(current_time);
s_state.osd_messages_lock.unlock();
DrawOSDMessages(current_time);
// last one displayed?
if (s_state.osd_active_messages.empty())
GPUThread::SetRunIdleReason(GPUThread::RunIdleReason::OSDMessagesActive, false);
}
void Host::AddOSDMessage(OSDMessageType type, std::string message)