Misc: Split core and util Host

This commit is contained in:
Stenzek 2023-08-27 16:00:06 +10:00
parent 779e78ae61
commit e23c9875d5
25 changed files with 429 additions and 306 deletions

View File

@ -22,6 +22,7 @@
#include "util/cd_image.h"
#include "util/imgui_fullscreen.h"
#include "util/imgui_manager.h"
#include "util/platform_misc.h"
#include "util/state_wrapper.h"

View File

@ -2,15 +2,21 @@
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
#include "analog_controller.h"
#include "IconsFontAwesome5.h"
#include "common/log.h"
#include "common/string_util.h"
#include "host.h"
#include "settings.h"
#include "system.h"
#include "util/imgui_manager.h"
#include "util/input_manager.h"
#include "util/state_wrapper.h"
#include "common/log.h"
#include "common/string_util.h"
#include "IconsFontAwesome5.h"
#include <cmath>
Log_SetChannel(AnalogController);
AnalogController::AnalogController(u32 index) : Controller(index)

View File

@ -2,12 +2,17 @@
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
#include "analog_joystick.h"
#include "common/log.h"
#include "common/string_util.h"
#include "host.h"
#include "system.h"
#include "util/imgui_manager.h"
#include "util/state_wrapper.h"
#include "common/log.h"
#include "common/string_util.h"
#include <cmath>
Log_SetChannel(AnalogJoystick);
AnalogJoystick::AnalogJoystick(u32 index) : Controller(index)
@ -58,9 +63,8 @@ bool AnalogJoystick::DoState(StateWrapper& sw, bool apply_input_state)
if (sw.IsReading() && (old_analog_mode != m_analog_mode))
{
Host::AddFormattedOSDMessage(5.0f,
m_analog_mode ?
TRANSLATE("AnalogJoystick", "Controller %u switched to analog mode.") :
TRANSLATE("AnalogJoystick", "Controller %u switched to digital mode."),
m_analog_mode ? TRANSLATE("AnalogJoystick", "Controller %u switched to analog mode.") :
TRANSLATE("AnalogJoystick", "Controller %u switched to digital mode."),
m_index + 1u);
}
return true;
@ -234,9 +238,8 @@ void AnalogJoystick::ToggleAnalogMode()
Log_InfoPrintf("Joystick %u switched to %s mode.", m_index + 1u, m_analog_mode ? "analog" : "digital");
Host::AddFormattedOSDMessage(5.0f,
m_analog_mode ?
TRANSLATE("AnalogJoystick", "Controller %u switched to analog mode.") :
TRANSLATE("AnalogJoystick", "Controller %u switched to digital mode."),
m_analog_mode ? TRANSLATE("AnalogJoystick", "Controller %u switched to analog mode.") :
TRANSLATE("AnalogJoystick", "Controller %u switched to digital mode."),
m_index + 1u);
}
@ -370,7 +373,7 @@ static const Controller::ControllerBindingInfo s_binding_info[] = {
AXIS("RRight", TRANSLATE_NOOP("AnalogJoystick", "Right Stick Right"), AnalogJoystick::HalfAxis::RRight, GenericInputBinding::RightStickRight),
AXIS("RDown", TRANSLATE_NOOP("AnalogJoystick", "Right Stick Down"), AnalogJoystick::HalfAxis::RDown, GenericInputBinding::RightStickDown),
AXIS("RUp", TRANSLATE_NOOP("AnalogJoystick", "Right Stick Up"), AnalogJoystick::HalfAxis::RUp, GenericInputBinding::RightStickUp),
// clang-format on
// clang-format on
#undef AXIS
#undef BUTTON
@ -384,7 +387,7 @@ static const char* s_invert_settings[] = {TRANSLATE_NOOP("AnalogJoystick", "Not
static const SettingInfo s_settings[] = {
{SettingInfo::Type::Float, "AnalogDeadzone", TRANSLATE_NOOP("AnalogJoystick", "Analog Deadzone"),
TRANSLATE_NOOP("AnalogJoystick",
"Sets the analog stick deadzone, i.e. the fraction of the stick movement which will be ignored."),
"Sets the analog stick deadzone, i.e. the fraction of the stick movement which will be ignored."),
"1.00f", "0.00f", "1.00f", "0.01f", "%.0f%%", nullptr, 100.0f},
{SettingInfo::Type::Float, "AnalogSensitivity", TRANSLATE_NOOP("AnalogJoystick", "Analog Sensitivity"),
TRANSLATE_NOOP(
@ -396,8 +399,8 @@ static const SettingInfo s_settings[] = {
TRANSLATE_NOOP("AnalogJoystick", "Inverts the direction of the left analog stick."), "0", "0", "3", nullptr, nullptr,
s_invert_settings, 0.0f},
{SettingInfo::Type::IntegerList, "InvertRightStick", TRANSLATE_NOOP("AnalogJoystick", "Invert Right Stick"),
TRANSLATE_NOOP("AnalogJoystick", "Inverts the direction of the right analog stick."), "0", "0", "3", nullptr, nullptr,
s_invert_settings, 0.0f},
TRANSLATE_NOOP("AnalogJoystick", "Inverts the direction of the right analog stick."), "0", "0", "3", nullptr,
nullptr, s_invert_settings, 0.0f},
};
const Controller::ControllerInfo AnalogJoystick::INFO = {ControllerType::AnalogJoystick,

View File

@ -3,6 +3,19 @@
#include "cdrom.h"
#include "cdrom_async_reader.h"
#include "dma.h"
#include "host.h"
#include "host_interface_progress_callback.h"
#include "interrupt_controller.h"
#include "settings.h"
#include "spu.h"
#include "system.h"
#include "util/cd_image.h"
#include "util/cd_xa.h"
#include "util/imgui_manager.h"
#include "util/state_wrapper.h"
#include "common/align.h"
#include "common/bitfield.h"
#include "common/fifo_queue.h"
@ -10,17 +23,9 @@
#include "common/heap_array.h"
#include "common/log.h"
#include "common/platform.h"
#include "dma.h"
#include "host.h"
#include "host_interface_progress_callback.h"
#include "imgui.h"
#include "interrupt_controller.h"
#include "settings.h"
#include "spu.h"
#include "system.h"
#include "util/cd_image.h"
#include "util/cd_xa.h"
#include "util/state_wrapper.h"
#include <cmath>
#include <vector>
Log_SetChannel(CDROM);
@ -719,8 +724,8 @@ void CDROM::InsertMedia(std::unique_ptr<CDImage> media, DiscRegion region)
if (CanReadMedia())
RemoveMedia(true);
Log_InfoPrintf("Inserting new media, disc region: %s, console region: %s",
Settings::GetDiscRegionName(region), Settings::GetConsoleRegionName(System::GetRegion()));
Log_InfoPrintf("Inserting new media, disc region: %s, console region: %s", Settings::GetDiscRegionName(region),
Settings::GetConsoleRegionName(System::GetRegion()));
s_disc_region = region;
m_reader.SetMedia(std::move(media));
@ -779,17 +784,16 @@ bool CDROM::PrecacheMedia()
if (m_reader.GetMedia()->HasSubImages() && m_reader.GetMedia()->GetSubImageCount() > 1)
{
Host::AddFormattedOSDMessage(
15.0f, TRANSLATE("OSDMessage", "CD image preloading not available for multi-disc image '%s'"),
FileSystem::GetDisplayNameFromPath(m_reader.GetMedia()->GetFileName()).c_str());
Host::AddFormattedOSDMessage(15.0f,
TRANSLATE("OSDMessage", "CD image preloading not available for multi-disc image '%s'"),
FileSystem::GetDisplayNameFromPath(m_reader.GetMedia()->GetFileName()).c_str());
return false;
}
HostInterfaceProgressCallback callback;
if (!m_reader.Precache(&callback))
{
Host::AddOSDMessage(TRANSLATE_STR("OSDMessage", "Precaching CD image failed, it may be unreliable."),
15.0f);
Host::AddOSDMessage(TRANSLATE_STR("OSDMessage", "Precaching CD image failed, it may be unreliable."), 15.0f);
return false;
}

View File

@ -4,9 +4,6 @@
#include "dma.h"
#include "bus.h"
#include "cdrom.h"
#include "common/bitfield.h"
#include "common/log.h"
#include "common/string_util.h"
#include "cpu_code_cache.h"
#include "cpu_core.h"
#include "gpu.h"
@ -17,10 +14,18 @@
#include "pad.h"
#include "spu.h"
#include "system.h"
#include "util/imgui_manager.h"
#include "util/state_wrapper.h"
#include "common/bitfield.h"
#include "common/log.h"
#include "common/string_util.h"
#include <array>
#include <memory>
#include <vector>
Log_SetChannel(DMA);
namespace DMA {

View File

@ -2,6 +2,12 @@
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
#include "game_database.h"
#include "host.h"
#include "system.h"
#include "util/cd_image.h"
#include "util/imgui_manager.h"
#include "common/assert.h"
#include "common/byte_stream.h"
#include "common/heterogeneous_containers.h"
@ -9,15 +15,15 @@
#include "common/path.h"
#include "common/string_util.h"
#include "common/timer.h"
#include "host.h"
#include "rapidjson/document.h"
#include "rapidjson/error/en.h"
#include "system.h"
#include "util/cd_image.h"
#include <iomanip>
#include <memory>
#include <optional>
#include <sstream>
Log_SetChannel(GameDatabase);
#ifdef _WIN32

View File

@ -2,21 +2,27 @@
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
#include "gpu.h"
#include "common/file_system.h"
#include "common/heap_array.h"
#include "common/log.h"
#include "common/string_util.h"
#include "dma.h"
#include "host.h"
#include "imgui.h"
#include "interrupt_controller.h"
#include "settings.h"
#include "stb_image_write.h"
#include "system.h"
#include "timers.h"
#include "util/gpu_device.h"
#include "util/imgui_manager.h"
#include "util/state_wrapper.h"
#include "common/file_system.h"
#include "common/heap_array.h"
#include "common/log.h"
#include "common/string_util.h"
#include "stb_image_write.h"
#include <cmath>
Log_SetChannel(GPU);
std::unique_ptr<GPU> g_gpu;

View File

@ -2,23 +2,29 @@
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
#include "gpu_hw.h"
#include "cpu_core.h"
#include "gpu_hw_shadergen.h"
#include "gpu_sw_backend.h"
#include "host.h"
#include "pgxp.h"
#include "settings.h"
#include "system.h"
#include "util/imgui_manager.h"
#include "util/state_wrapper.h"
#include "common/align.h"
#include "common/assert.h"
#include "common/log.h"
#include "common/scoped_guard.h"
#include "common/string_util.h"
#include "cpu_core.h"
#include "gpu_hw_shadergen.h"
#include "gpu_sw_backend.h"
#include "host.h"
#include "imgui.h"
#include "pgxp.h"
#include "settings.h"
#include "system.h"
#include "util/state_wrapper.h"
#include <cmath>
#include <sstream>
#include <tuple>
Log_SetChannel(GPU_HW);
// TODO: instead of full state restore, only restore what changed

View File

@ -12,30 +12,17 @@
#include "util/imgui_manager.h"
#include "common/assert.h"
#include "common/heterogeneous_containers.h"
#include "common/layered_settings_interface.h"
#include "common/log.h"
#include "common/string_util.h"
#include <cstdarg>
#include <shared_mutex>
Log_SetChannel(Host);
namespace Host {
static std::pair<const char*, u32> LookupTranslationString(const std::string_view& context,
const std::string_view& msg);
static std::mutex s_settings_mutex;
static LayeredSettingsInterface s_layered_settings_interface;
static constexpr u32 TRANSLATION_STRING_CACHE_SIZE = 4 * 1024 * 1024;
using TranslationStringMap = UnorderedStringMap<std::pair<u32, u32>>;
using TranslationStringContextMap = UnorderedStringMap<TranslationStringMap>;
static std::shared_mutex s_translation_string_mutex;
static TranslationStringContextMap s_translation_string_map;
static std::vector<char> s_translation_string_cache;
static u32 s_translation_string_cache_pos;
} // namespace Host
std::unique_lock<std::mutex> Host::GetSettingsLock()
@ -228,126 +215,6 @@ void Host::Internal::SetInputSettingsLayer(SettingsInterface* sif)
s_layered_settings_interface.SetLayer(LayeredSettingsInterface::LAYER_INPUT, sif);
}
std::pair<const char*, u32> Host::LookupTranslationString(const std::string_view& context, const std::string_view& msg)
{
// TODO: TranslatableString, compile-time hashing.
TranslationStringContextMap::iterator ctx_it;
TranslationStringMap::iterator msg_it;
std::pair<const char*, u32> ret;
s32 len;
// Shouldn't happen, but just in case someone tries to translate an empty string.
if (UNLIKELY(msg.empty()))
{
ret.first = &s_translation_string_cache[0];
ret.second = 0;
return ret;
}
s_translation_string_mutex.lock_shared();
ctx_it = UnorderedStringMapFind(s_translation_string_map, context);
if (UNLIKELY(ctx_it == s_translation_string_map.end()))
goto add_string;
msg_it = UnorderedStringMapFind(ctx_it->second, msg);
if (UNLIKELY(msg_it == ctx_it->second.end()))
goto add_string;
ret.first = &s_translation_string_cache[msg_it->second.first];
ret.second = msg_it->second.second;
s_translation_string_mutex.unlock_shared();
return ret;
add_string:
s_translation_string_mutex.unlock_shared();
s_translation_string_mutex.lock();
if (UNLIKELY(s_translation_string_cache.empty()))
{
// First element is always an empty string.
s_translation_string_cache.resize(TRANSLATION_STRING_CACHE_SIZE);
s_translation_string_cache[0] = '\0';
s_translation_string_cache_pos = 0;
}
if ((len =
Internal::GetTranslatedStringImpl(context, msg, &s_translation_string_cache[s_translation_string_cache_pos],
TRANSLATION_STRING_CACHE_SIZE - 1 - s_translation_string_cache_pos)) < 0)
{
Log_ErrorPrint("WARNING: Clearing translation string cache, it might need to be larger.");
s_translation_string_cache_pos = 0;
if ((len =
Internal::GetTranslatedStringImpl(context, msg, &s_translation_string_cache[s_translation_string_cache_pos],
TRANSLATION_STRING_CACHE_SIZE - 1 - s_translation_string_cache_pos)) < 0)
{
Panic("Failed to get translated string after clearing cache.");
len = 0;
}
}
// New context?
if (ctx_it == s_translation_string_map.end())
ctx_it = s_translation_string_map.emplace(context, TranslationStringMap()).first;
// Impl doesn't null terminate, we need that for C strings.
// TODO: do we want to consider aligning the buffer?
const u32 insert_pos = s_translation_string_cache_pos;
s_translation_string_cache[insert_pos + static_cast<u32>(len)] = 0;
ctx_it->second.emplace(msg, std::pair<u32, u32>(insert_pos, static_cast<u32>(len)));
s_translation_string_cache_pos = insert_pos + static_cast<u32>(len) + 1;
ret.first = &s_translation_string_cache[insert_pos];
ret.second = static_cast<u32>(len);
s_translation_string_mutex.unlock();
return ret;
}
const char* Host::TranslateToCString(const std::string_view& context, const std::string_view& msg)
{
return LookupTranslationString(context, msg).first;
}
std::string_view Host::TranslateToStringView(const std::string_view& context, const std::string_view& msg)
{
const auto mp = LookupTranslationString(context, msg);
return std::string_view(mp.first, mp.second);
}
std::string Host::TranslateToString(const std::string_view& context, const std::string_view& msg)
{
return std::string(TranslateToStringView(context, msg));
}
void Host::ClearTranslationCache()
{
s_translation_string_mutex.lock();
s_translation_string_map.clear();
s_translation_string_cache_pos = 0;
s_translation_string_mutex.unlock();
}
void Host::ReportFormattedErrorAsync(const std::string_view& title, const char* format, ...)
{
std::va_list ap;
va_start(ap, format);
std::string message(StringUtil::StdStringFromFormatV(format, ap));
va_end(ap);
ReportErrorAsync(title, message);
}
bool Host::ConfirmFormattedMessage(const std::string_view& title, const char* format, ...)
{
std::va_list ap;
va_start(ap, format);
std::string message = StringUtil::StdStringFromFormatV(format, ap);
va_end(ap);
return ConfirmMessage(title, message);
}
void Host::ReportFormattedDebuggerMessage(const char* format, ...)
{
std::va_list ap;
@ -380,7 +247,7 @@ bool Host::CreateGPUDevice(RenderAPI api)
return false;
}
if (!ImGuiManager::Initialize())
if (!ImGuiManager::Initialize(g_settings.display_osd_scale / 100.0f))
{
Log_ErrorPrintf("Failed to initialize ImGuiManager.");
g_gpu_device->Destroy();

View File

@ -3,6 +3,8 @@
#pragma once
#include "util/host.h"
#include "common/string.h"
#include "common/types.h"
@ -24,23 +26,6 @@ class AudioStream;
class CDImage;
namespace Host {
/// Typical durations for OSD messages.
static constexpr float OSD_CRITICAL_ERROR_DURATION = 20.0f;
static constexpr float OSD_ERROR_DURATION = 15.0f;
static constexpr float OSD_WARNING_DURATION = 10.0f;
static constexpr float OSD_INFO_DURATION = 5.0f;
static constexpr float OSD_QUICK_DURATION = 2.5f;
/// Reads a file from the resources directory of the application.
/// This may be outside of the "normal" filesystem on platforms such as Mac.
std::optional<std::vector<u8>> ReadResourceFile(const char* filename);
/// Reads a resource file file from the resources directory as a string.
std::optional<std::string> ReadResourceFileToString(const char* filename);
/// Returns the modified time of a resource.
std::optional<std::time_t> GetResourceFileTimestamp(const char* filename);
// Base setting retrieval, bypasses layers.
std::string GetBaseStringSettingValue(const char* section, const char* key, const char* default_value = "");
bool GetBaseBoolSettingValue(const char* section, const char* key, bool default_value = false);
@ -81,45 +66,11 @@ SettingsInterface* GetSettingsInterface();
/// If an input profile is being used, this will be the input layer, otherwise the layered interface.
SettingsInterface* GetSettingsInterfaceForBindings();
/// Returns a localized version of the specified string within the specified context.
/// The pointer is guaranteed to be valid until the next language change.
const char* TranslateToCString(const std::string_view& context, const std::string_view& msg);
/// Returns a localized version of the specified string within the specified context.
/// The view is guaranteed to be valid until the next language change.
/// NOTE: When passing this to fmt, positional arguments should be used in the base string, as
/// not all locales follow the same word ordering.
std::string_view TranslateToStringView(const std::string_view& context, const std::string_view& msg);
/// Returns a localized version of the specified string within the specified context.
std::string TranslateToString(const std::string_view& context, const std::string_view& msg);
/// Clears the translation cache. All previously used strings should be considered invalid.
void ClearTranslationCache();
std::unique_ptr<AudioStream> CreateAudioStream(AudioBackend backend, u32 sample_rate, u32 channels, u32 buffer_ms,
u32 latency_ms, AudioStretchMode stretch);
/// Returns the scale of OSD elements.
float GetOSDScale();
/// Adds OSD messages, duration is in seconds.
void AddOSDMessage(std::string message, float duration = 2.0f);
void AddKeyedOSDMessage(std::string key, std::string message, float duration = 2.0f);
void AddIconOSDMessage(std::string key, const char* icon, std::string message, float duration = 2.0f);
void AddFormattedOSDMessage(float duration, const char* format, ...);
void AddKeyedFormattedOSDMessage(std::string key, float duration, const char* format, ...);
void RemoveKeyedOSDMessage(std::string key);
void ClearOSDMessages();
/// Displays an asynchronous error on the UI thread, i.e. doesn't block the caller.
void ReportErrorAsync(const std::string_view& title, const std::string_view& message);
void ReportFormattedErrorAsync(const std::string_view& title, const char* format, ...);
/// Displays a synchronous confirmation on the UI thread, i.e. blocks the caller.
bool ConfirmMessage(const std::string_view& title, const std::string_view& message);
bool ConfirmFormattedMessage(const std::string_view& title, const char* format, ...);
/// Debugger feedback.
void ReportDebuggerMessage(const std::string_view& message);
void ReportFormattedDebuggerMessage(const char* format, ...);
@ -134,12 +85,6 @@ void SetMouseMode(bool relative, bool hide_cursor);
/// Safely executes a function on the VM thread.
void RunOnCPUThread(std::function<void()> function, bool block = false);
/// Opens a URL, using the default application.
void OpenURL(const std::string_view& url);
/// Copies the provided text to the host's clipboard, if present.
bool CopyTextToClipboard(const std::string_view& text);
/// Requests shut down and exit of the hosting application. This may not actually exit,
/// if the user cancels the shutdown confirmation.
void RequestExit(bool allow_confirm);
@ -181,18 +126,5 @@ void SetGameSettingsLayer(SettingsInterface* sif);
/// Sets the input profile settings layer. Called by VMManager when the game changes.
void SetInputSettingsLayer(SettingsInterface* sif);
/// Implementation to retrieve a translated string.
s32 GetTranslatedStringImpl(const std::string_view& context, const std::string_view& msg, char* tbuf,
size_t tbuf_space);
} // namespace Internal
} // namespace Host
// Helper macros for retrieving translated strings.
#define TRANSLATE(context, msg) Host::TranslateToCString(context, msg)
#define TRANSLATE_SV(context, msg) Host::TranslateToStringView(context, msg)
#define TRANSLATE_STR(context, msg) Host::TranslateToString(context, msg)
#define TRANSLATE_FS(context, msg) fmt::runtime(Host::TranslateToStringView(context, msg))
// Does not translate the string at runtime, but allows the UI to in its own way.
#define TRANSLATE_NOOP(context, msg) msg

View File

@ -2,16 +2,21 @@
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
#include "mdec.h"
#include "common/bitfield.h"
#include "common/fifo_queue.h"
#include "common/log.h"
#include "cpu_core.h"
#include "dma.h"
#include "host.h"
#include "imgui.h"
#include "interrupt_controller.h"
#include "system.h"
#include "util/imgui_manager.h"
#include "util/state_wrapper.h"
#include "common/bitfield.h"
#include "common/fifo_queue.h"
#include "common/log.h"
#include "imgui.h"
#include <array>
#include <memory>

View File

@ -2,16 +2,22 @@
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
#include "memory_card.h"
#include "IconsFontAwesome5.h"
#include "host.h"
#include "system.h"
#include "util/imgui_manager.h"
#include "util/state_wrapper.h"
#include "common/byte_stream.h"
#include "common/file_system.h"
#include "common/log.h"
#include "common/path.h"
#include "common/string_util.h"
#include "host.h"
#include "system.h"
#include "util/state_wrapper.h"
#include "IconsFontAwesome5.h"
#include <cstdio>
Log_SetChannel(MemoryCard);
MemoryCard::MemoryCard()

View File

@ -2,9 +2,6 @@
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
#include "pad.h"
#include "common/bitfield.h"
#include "common/fifo_queue.h"
#include "common/log.h"
#include "controller.h"
#include "host.h"
#include "interrupt_controller.h"
@ -13,9 +10,17 @@
#include "save_state_version.h"
#include "system.h"
#include "types.h"
#include "util/imgui_manager.h"
#include "util/state_wrapper.h"
#include "common/bitfield.h"
#include "common/fifo_queue.h"
#include "common/log.h"
#include <array>
#include <memory>
Log_SetChannel(Pad);
namespace Pad {

View File

@ -8,6 +8,7 @@
#include "system.h"
#include "util/gpu_device.h"
#include "util/imgui_manager.h"
#include "util/input_manager.h"
#include "common/assert.h"

View File

@ -3,19 +3,24 @@
#include "spu.h"
#include "cdrom.h"
#include "common/bitfield.h"
#include "common/fifo_queue.h"
#include "common/log.h"
#include "common/path.h"
#include "dma.h"
#include "host.h"
#include "imgui.h"
#include "interrupt_controller.h"
#include "system.h"
#include "util/audio_stream.h"
#include "util/imgui_manager.h"
#include "util/state_wrapper.h"
#include "util/wav_writer.h"
#include "common/bitfield.h"
#include "common/fifo_queue.h"
#include "common/log.h"
#include "common/path.h"
#include <memory>
Log_SetChannel(SPU);
// Enable to dump all voices of the SPU audio individually.

View File

@ -3684,6 +3684,9 @@ void System::CheckForSettingsChanges(const Settings& old_settings)
}
}
if (g_gpu_device && g_settings.display_osd_scale != old_settings.display_osd_scale)
ImGuiManager::SetGlobalScale(g_settings.display_osd_scale / 100.0f);
bool controllers_updated = false;
for (u32 i = 0; i < NUM_CONTROLLER_AND_CARD_PORTS; i++)
{

View File

@ -2,16 +2,22 @@
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
#include "timers.h"
#include "common/bitfield.h"
#include "common/log.h"
#include "gpu.h"
#include "host.h"
#include "imgui.h"
#include "interrupt_controller.h"
#include "system.h"
#include "util/imgui_manager.h"
#include "util/state_wrapper.h"
#include "common/bitfield.h"
#include "common/log.h"
#include "imgui.h"
#include <array>
#include <memory>
Log_SetChannel(Timers);
namespace Timers {

View File

@ -27,6 +27,8 @@ add_library(util
gpu_shader_cache.h
gpu_texture.cpp
gpu_texture.h
host.cpp
host.h
imgui_fullscreen.cpp
imgui_fullscreen.h
imgui_manager.cpp

View File

@ -2,21 +2,26 @@
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
#include "cubeb_audio_stream.h"
#include "host.h"
#include "imgui_manager.h"
#include "core/settings.h"
#include "common/assert.h"
#include "common/log.h"
#include "common/scoped_guard.h"
#include "common/string_util.h"
#include "core/host.h"
#include "core/settings.h"
#include "cubeb/cubeb.h"
#include "fmt/format.h"
Log_SetChannel(CubebAudioStream);
#ifdef _WIN32
#include "common/windows_headers.h"
#include <objbase.h>
#endif
Log_SetChannel(CubebAudioStream);
static void StateCallback(cubeb_stream* stream, void* user_ptr, cubeb_state state);
CubebAudioStream::CubebAudioStream(u32 sample_rate, u32 channels, u32 buffer_ms, AudioStretchMode stretch)

147
src/util/host.cpp Normal file
View File

@ -0,0 +1,147 @@
// SPDX-FileCopyrightText: 2019-2023 Connor McLaughlin <stenzek@gmail.com>
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
#include "host.h"
#include "common/assert.h"
#include "common/heterogeneous_containers.h"
#include "common/log.h"
#include "common/string_util.h"
#include <cstdarg>
#include <shared_mutex>
Log_SetChannel(Host);
namespace Host {
static std::pair<const char*, u32> LookupTranslationString(const std::string_view& context,
const std::string_view& msg);
static constexpr u32 TRANSLATION_STRING_CACHE_SIZE = 4 * 1024 * 1024;
using TranslationStringMap = UnorderedStringMap<std::pair<u32, u32>>;
using TranslationStringContextMap = UnorderedStringMap<TranslationStringMap>;
static std::shared_mutex s_translation_string_mutex;
static TranslationStringContextMap s_translation_string_map;
static std::vector<char> s_translation_string_cache;
static u32 s_translation_string_cache_pos;
} // namespace Host
std::pair<const char*, u32> Host::LookupTranslationString(const std::string_view& context, const std::string_view& msg)
{
// TODO: TranslatableString, compile-time hashing.
TranslationStringContextMap::iterator ctx_it;
TranslationStringMap::iterator msg_it;
std::pair<const char*, u32> ret;
s32 len;
// Shouldn't happen, but just in case someone tries to translate an empty string.
if (UNLIKELY(msg.empty()))
{
ret.first = &s_translation_string_cache[0];
ret.second = 0;
return ret;
}
s_translation_string_mutex.lock_shared();
ctx_it = UnorderedStringMapFind(s_translation_string_map, context);
if (UNLIKELY(ctx_it == s_translation_string_map.end()))
goto add_string;
msg_it = UnorderedStringMapFind(ctx_it->second, msg);
if (UNLIKELY(msg_it == ctx_it->second.end()))
goto add_string;
ret.first = &s_translation_string_cache[msg_it->second.first];
ret.second = msg_it->second.second;
s_translation_string_mutex.unlock_shared();
return ret;
add_string:
s_translation_string_mutex.unlock_shared();
s_translation_string_mutex.lock();
if (UNLIKELY(s_translation_string_cache.empty()))
{
// First element is always an empty string.
s_translation_string_cache.resize(TRANSLATION_STRING_CACHE_SIZE);
s_translation_string_cache[0] = '\0';
s_translation_string_cache_pos = 0;
}
if ((len =
Internal::GetTranslatedStringImpl(context, msg, &s_translation_string_cache[s_translation_string_cache_pos],
TRANSLATION_STRING_CACHE_SIZE - 1 - s_translation_string_cache_pos)) < 0)
{
Log_ErrorPrint("WARNING: Clearing translation string cache, it might need to be larger.");
s_translation_string_cache_pos = 0;
if ((len =
Internal::GetTranslatedStringImpl(context, msg, &s_translation_string_cache[s_translation_string_cache_pos],
TRANSLATION_STRING_CACHE_SIZE - 1 - s_translation_string_cache_pos)) < 0)
{
Panic("Failed to get translated string after clearing cache.");
len = 0;
}
}
// New context?
if (ctx_it == s_translation_string_map.end())
ctx_it = s_translation_string_map.emplace(context, TranslationStringMap()).first;
// Impl doesn't null terminate, we need that for C strings.
// TODO: do we want to consider aligning the buffer?
const u32 insert_pos = s_translation_string_cache_pos;
s_translation_string_cache[insert_pos + static_cast<u32>(len)] = 0;
ctx_it->second.emplace(msg, std::pair<u32, u32>(insert_pos, static_cast<u32>(len)));
s_translation_string_cache_pos = insert_pos + static_cast<u32>(len) + 1;
ret.first = &s_translation_string_cache[insert_pos];
ret.second = static_cast<u32>(len);
s_translation_string_mutex.unlock();
return ret;
}
const char* Host::TranslateToCString(const std::string_view& context, const std::string_view& msg)
{
return LookupTranslationString(context, msg).first;
}
std::string_view Host::TranslateToStringView(const std::string_view& context, const std::string_view& msg)
{
const auto mp = LookupTranslationString(context, msg);
return std::string_view(mp.first, mp.second);
}
std::string Host::TranslateToString(const std::string_view& context, const std::string_view& msg)
{
return std::string(TranslateToStringView(context, msg));
}
void Host::ClearTranslationCache()
{
s_translation_string_mutex.lock();
s_translation_string_map.clear();
s_translation_string_cache_pos = 0;
s_translation_string_mutex.unlock();
}
void Host::ReportFormattedErrorAsync(const std::string_view& title, const char* format, ...)
{
std::va_list ap;
va_start(ap, format);
std::string message(StringUtil::StdStringFromFormatV(format, ap));
va_end(ap);
ReportErrorAsync(title, message);
}
bool Host::ConfirmFormattedMessage(const std::string_view& title, const char* format, ...)
{
std::va_list ap;
va_start(ap, format);
std::string message = StringUtil::StdStringFromFormatV(format, ap);
va_end(ap);
return ConfirmMessage(title, message);
}

69
src/util/host.h Normal file
View File

@ -0,0 +1,69 @@
// SPDX-FileCopyrightText: 2019-2023 Connor McLaughlin <stenzek@gmail.com>
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
#pragma once
#include "common/types.h"
#include <ctime>
#include <optional>
#include <string>
#include <string_view>
#include <vector>
namespace Host {
/// Reads a file from the resources directory of the application.
/// This may be outside of the "normal" filesystem on platforms such as Mac.
std::optional<std::vector<u8>> ReadResourceFile(const char* filename);
/// Reads a resource file file from the resources directory as a string.
std::optional<std::string> ReadResourceFileToString(const char* filename);
/// Returns the modified time of a resource.
std::optional<std::time_t> GetResourceFileTimestamp(const char* filename);
/// Displays an asynchronous error on the UI thread, i.e. doesn't block the caller.
void ReportErrorAsync(const std::string_view& title, const std::string_view& message);
void ReportFormattedErrorAsync(const std::string_view& title, const char* format, ...);
/// Displays a synchronous confirmation on the UI thread, i.e. blocks the caller.
bool ConfirmMessage(const std::string_view& title, const std::string_view& message);
bool ConfirmFormattedMessage(const std::string_view& title, const char* format, ...);
/// Opens a URL, using the default application.
void OpenURL(const std::string_view& url);
/// Copies the provided text to the host's clipboard, if present.
bool CopyTextToClipboard(const std::string_view& text);
/// Returns a localized version of the specified string within the specified context.
/// The pointer is guaranteed to be valid until the next language change.
const char* TranslateToCString(const std::string_view& context, const std::string_view& msg);
/// Returns a localized version of the specified string within the specified context.
/// The view is guaranteed to be valid until the next language change.
/// NOTE: When passing this to fmt, positional arguments should be used in the base string, as
/// not all locales follow the same word ordering.
std::string_view TranslateToStringView(const std::string_view& context, const std::string_view& msg);
/// Returns a localized version of the specified string within the specified context.
std::string TranslateToString(const std::string_view& context, const std::string_view& msg);
/// Clears the translation cache. All previously used strings should be considered invalid.
void ClearTranslationCache();
namespace Internal {
/// Implementation to retrieve a translated string.
s32 GetTranslatedStringImpl(const std::string_view& context, const std::string_view& msg, char* tbuf,
size_t tbuf_space);
} // namespace Internal
} // namespace Host
// Helper macros for retrieving translated strings.
#define TRANSLATE(context, msg) Host::TranslateToCString(context, msg)
#define TRANSLATE_SV(context, msg) Host::TranslateToStringView(context, msg)
#define TRANSLATE_STR(context, msg) Host::TranslateToString(context, msg)
#define TRANSLATE_FS(context, msg) fmt::runtime(Host::TranslateToStringView(context, msg))
// Does not translate the string at runtime, but allows the UI to in its own way.
#define TRANSLATE_NOOP(context, msg) msg

View File

@ -1,21 +1,23 @@
// SPDX-FileCopyrightText: 2019-2022 Connor McLaughlin <stenzek@gmail.com>
// SPDX-FileCopyrightText: 2019-2023 Connor McLaughlin <stenzek@gmail.com>
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
#include "imgui_manager.h"
#include "IconsFontAwesome5.h"
#include "gpu_device.h"
#include "host.h"
#include "imgui_fullscreen.h"
#include "input_manager.h"
#include "common/assert.h"
#include "common/file_system.h"
#include "common/log.h"
#include "common/string_util.h"
#include "common/timer.h"
#include "gpu_device.h"
#include "core/host.h"
#include "core/system.h"
#include "IconsFontAwesome5.h"
#include "fmt/format.h"
#include "imgui.h"
#include "imgui_fullscreen.h"
#include "imgui_internal.h"
#include "input_manager.h"
#include <atomic>
#include <chrono>
#include <cmath>
@ -37,6 +39,7 @@ static void AcquirePendingOSDMessages();
static void DrawOSDMessages();
} // namespace ImGuiManager
static float s_global_prescale = 1.0f; // before window scale
static float s_global_scale = 1.0f;
static std::string s_font_path;
@ -72,7 +75,13 @@ void ImGuiManager::SetFontRange(const u16* range)
s_standard_font_data = {};
}
bool ImGuiManager::Initialize()
void ImGuiManager::SetGlobalScale(float global_scale)
{
s_global_prescale = global_scale;
UpdateScale();
}
bool ImGuiManager::Initialize(float global_scale)
{
if (!LoadFontData())
{
@ -80,8 +89,8 @@ bool ImGuiManager::Initialize()
return false;
}
s_global_scale =
std::max(g_gpu_device->GetWindowScale() * static_cast<float>(g_settings.display_osd_scale / 100.0f), 1.0f);
s_global_prescale = global_scale;
s_global_scale = std::max(g_gpu_device->GetWindowScale() * global_scale, 1.0f);
ImGui::CreateContext();
@ -105,7 +114,6 @@ bool ImGuiManager::Initialize()
SetKeyMap();
SetStyle();
if (!AddImGuiFonts(false) || !g_gpu_device->UpdateImGuiFontTexture())
{
Panic("Failed to create ImGui font text");
@ -149,7 +157,7 @@ void ImGuiManager::WindowResized()
void ImGuiManager::UpdateScale()
{
const float window_scale = g_gpu_device ? g_gpu_device->GetWindowScale() : 1.0f;
const float scale = std::max(window_scale * static_cast<float>(g_settings.display_osd_scale / 100.0f), 1.0f);
const float scale = std::max(window_scale * s_global_prescale, 1.0f);
if (scale == s_global_scale && (!HasFullscreenFonts() || !ImGuiFullscreen::UpdateLayoutScale()))
return;
@ -623,23 +631,20 @@ void ImGuiManager::AcquirePendingOSDMessages()
if (s_osd_posted_messages.empty())
break;
if (g_settings.display_show_osd_messages)
OSDMessage& new_msg = s_osd_posted_messages.front();
std::deque<OSDMessage>::iterator iter;
if (!new_msg.key.empty() && (iter = std::find_if(s_osd_active_messages.begin(), s_osd_active_messages.end(),
[&new_msg](const OSDMessage& other) {
return new_msg.key == other.key;
})) != s_osd_active_messages.end())
{
OSDMessage& new_msg = s_osd_posted_messages.front();
std::deque<OSDMessage>::iterator iter;
if (!new_msg.key.empty() && (iter = std::find_if(s_osd_active_messages.begin(), s_osd_active_messages.end(),
[&new_msg](const OSDMessage& other) {
return new_msg.key == other.key;
})) != s_osd_active_messages.end())
{
iter->text = std::move(new_msg.text);
iter->duration = new_msg.duration;
iter->time = new_msg.time;
}
else
{
s_osd_active_messages.push_back(std::move(new_msg));
}
iter->text = std::move(new_msg.text);
iter->duration = new_msg.duration;
iter->time = new_msg.time;
}
else
{
s_osd_active_messages.push_back(std::move(new_msg));
}
s_osd_posted_messages.pop_front();

View File

@ -18,8 +18,11 @@ void SetFontPath(std::string path);
/// Sets the glyph range to use when loading fonts.
void SetFontRange(const u16* range);
/// Changes the global scale.
void SetGlobalScale(float global_scale);
/// Initializes ImGui, creates fonts, etc.
bool Initialize();
bool Initialize(float global_scale);
/// Frees all ImGui resources.
void Shutdown();
@ -83,3 +86,24 @@ bool ProcessHostKeyEvent(InputBindingKey key, float value);
/// Called on the CPU thread when any input event fires. Allows imgui to take over controller navigation.
bool ProcessGenericInputEvent(GenericInputBinding key, float value);
} // namespace ImGuiManager
namespace Host {
/// Typical durations for OSD messages.
static constexpr float OSD_CRITICAL_ERROR_DURATION = 20.0f;
static constexpr float OSD_ERROR_DURATION = 15.0f;
static constexpr float OSD_WARNING_DURATION = 10.0f;
static constexpr float OSD_INFO_DURATION = 5.0f;
static constexpr float OSD_QUICK_DURATION = 2.5f;
/// Returns the scale of OSD elements.
float GetOSDScale();
/// Adds OSD messages, duration is in seconds.
void AddOSDMessage(std::string message, float duration = 2.0f);
void AddKeyedOSDMessage(std::string key, std::string message, float duration = 2.0f);
void AddIconOSDMessage(std::string key, const char* icon, std::string message, float duration = 2.0f);
void AddFormattedOSDMessage(float duration, const char* format, ...);
void AddKeyedFormattedOSDMessage(std::string key, float duration, const char* format, ...);
void RemoveKeyedOSDMessage(std::string key);
void ClearOSDMessages();
} // namespace Host

View File

@ -28,6 +28,7 @@
<ClInclude Include="gpu_device.h" />
<ClInclude Include="gpu_shader_cache.h" />
<ClInclude Include="gpu_texture.h" />
<ClInclude Include="host.h" />
<ClInclude Include="imgui_fullscreen.h" />
<ClInclude Include="imgui_manager.h" />
<ClInclude Include="ini_settings_interface.h" />
@ -139,6 +140,7 @@
<ClCompile Include="gpu_device.cpp" />
<ClCompile Include="gpu_shader_cache.cpp" />
<ClCompile Include="gpu_texture.cpp" />
<ClCompile Include="host.cpp" />
<ClCompile Include="imgui_fullscreen.cpp" />
<ClCompile Include="imgui_manager.cpp" />
<ClCompile Include="ini_settings_interface.cpp" />

View File

@ -68,6 +68,7 @@
<ClInclude Include="d3d11_pipeline.h" />
<ClInclude Include="d3d11_stream_buffer.h" />
<ClInclude Include="d3d11_texture.h" />
<ClInclude Include="host.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="jit_code_buffer.cpp" />
@ -142,10 +143,11 @@
<ClCompile Include="d3d11_pipeline.cpp" />
<ClCompile Include="d3d11_stream_buffer.cpp" />
<ClCompile Include="d3d11_texture.cpp" />
<ClCompile Include="host.cpp" />
</ItemGroup>
<ItemGroup>
<Filter Include="gl">
<UniqueIdentifier>{e637fc5b-2483-4a31-abc3-89a16d45c223}</UniqueIdentifier>
</Filter>
</ItemGroup>
</Project>
</Project>