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

@ -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>