Misc: Post-refactor cleanups

This commit is contained in:
Stenzek 2023-08-23 22:06:48 +10:00
parent 82cdef45b3
commit dc9c99438b
55 changed files with 1243 additions and 1396 deletions

View file

@ -16,8 +16,6 @@ add_library(core
cheats.h
controller.cpp
controller.h
common_host.cpp
common_host.h
cpu_code_cache.cpp
cpu_code_cache.h
cpu_core.cpp
@ -62,8 +60,7 @@ add_library(core
host.h
host_interface_progress_callback.cpp
host_interface_progress_callback.h
host_settings.cpp
host_settings.h
hotkeys.cpp
input_types.h
imgui_overlays.cpp
imgui_overlays.h
@ -157,7 +154,6 @@ endif()
if(ENABLE_CHEEVOS)
target_sources(core PRIVATE
achievements.cpp
achievements_private.h
)
target_compile_definitions(core PUBLIC -DWITH_CHEEVOS=1)
target_link_libraries(core PRIVATE rcheevos rapidjson)

View file

@ -1,13 +1,12 @@
// SPDX-FileCopyrightText: 2019-2022 Connor McLaughlin <stenzek@gmail.com>
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
#include "achievements_private.h"
#include "achievements.h"
#include "bios.h"
#include "bus.h"
#include "cpu_core.h"
#include "fullscreen_ui.h"
#include "host.h"
#include "host_settings.h"
#include "system.h"
#include "scmversion/scmversion.h"
@ -682,8 +681,7 @@ void Achievements::FrameUpdate()
#ifdef WITH_RAINTEGRATION
if (IsUsingRAIntegration())
{
if (!System::IsPaused())
RA_DoAchievementsFrame();
RA_DoAchievementsFrame();
return;
}
#endif
@ -693,17 +691,8 @@ void Achievements::FrameUpdate()
if (HasActiveGame())
{
std::unique_lock lock(s_achievements_mutex);
if (!System::IsPaused())
rc_runtime_do_frame(&s_rcheevos_runtime, &CheevosEventHandler, &PeekMemory, nullptr, nullptr);
rc_runtime_do_frame(&s_rcheevos_runtime, &CheevosEventHandler, &PeekMemory, nullptr, nullptr);
UpdateRichPresence();
if (!IsTestModeActive())
{
const s32 ping_frequency =
g_settings.achievements_rich_presence ? RICH_PRESENCE_PING_FREQUENCY : NO_RICH_PRESENCE_PING_FREQUENCY;
if (static_cast<s32>(s_last_ping_time.GetTimeSeconds()) >= ping_frequency)
SendPing();
}
}
}
@ -714,7 +703,18 @@ void Achievements::ProcessPendingHTTPRequests()
return;
#endif
if (!s_http_downloader)
return;
s_http_downloader->PollRequests();
if (HasActiveGame() && !IsTestModeActive())
{
const s32 ping_frequency =
g_settings.achievements_rich_presence ? RICH_PRESENCE_PING_FREQUENCY : NO_RICH_PRESENCE_PING_FREQUENCY;
if (static_cast<s32>(s_last_ping_time.GetTimeSeconds()) >= ping_frequency)
SendPing();
}
}
bool Achievements::DoState(StateWrapper& sw)
@ -1029,7 +1029,7 @@ void Achievements::DisplayAchievementSummary()
// Technically not going through the resource API, but since we're passing this to something else, we can't.
if (g_settings.achievements_sound_effects)
FrontendCommon::PlaySoundAsync(Path::Combine(EmuFolders::Resources, INFO_SOUND_NAME).c_str());
PlatformMisc::PlaySoundAsync(Path::Combine(EmuFolders::Resources, INFO_SOUND_NAME).c_str());
});
}
@ -1773,7 +1773,7 @@ void Achievements::SubmitLeaderboardCallback(s32 status_code, std::string conten
// Technically not going through the resource API, but since we're passing this to something else, we can't.
if (g_settings.achievements_sound_effects)
FrontendCommon::PlaySoundAsync(Path::Combine(EmuFolders::Resources, LBSUBMIT_SOUND_NAME).c_str());
PlatformMisc::PlaySoundAsync(Path::Combine(EmuFolders::Resources, LBSUBMIT_SOUND_NAME).c_str());
}
void Achievements::UnlockAchievement(u32 achievement_id, bool add_notification /* = true*/)
@ -1818,7 +1818,7 @@ void Achievements::UnlockAchievement(u32 achievement_id, bool add_notification /
GetAchievementBadgePath(*achievement));
}
if (g_settings.achievements_sound_effects)
FrontendCommon::PlaySoundAsync(Path::Combine(EmuFolders::Resources, UNLOCK_SOUND_NAME).c_str());
PlatformMisc::PlaySoundAsync(Path::Combine(EmuFolders::Resources, UNLOCK_SOUND_NAME).c_str());
if (IsMastered())
DisplayMasteredNotification();

View file

@ -1,10 +1,19 @@
// 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)
#pragma once
#include "settings.h"
#include "types.h"
#include "common/string.h"
#include "common/types.h"
#include <functional>
#include <optional>
#include <string>
#include <utility>
#include <vector>
class StateWrapper;
class CDImage;
@ -13,23 +22,157 @@ namespace Achievements {
#ifdef WITH_CHEEVOS
// Implemented in Host.
extern bool ConfirmSystemReset();
extern void ResetRuntime();
extern bool DoState(StateWrapper& sw);
extern void GameChanged(const std::string& path, CDImage* image);
enum class AchievementCategory : u8
{
Local = 0,
Core = 3,
Unofficial = 5
};
struct Achievement
{
u32 id;
std::string title;
std::string description;
std::string memaddr;
std::string badge_name;
// badge paths are mutable because they're resolved when they're needed.
mutable std::string locked_badge_path;
mutable std::string unlocked_badge_path;
u32 points;
AchievementCategory category;
bool locked;
bool active;
bool primed;
};
struct Leaderboard
{
u32 id;
std::string title;
std::string description;
int format;
};
struct LeaderboardEntry
{
std::string user;
std::string formatted_score;
time_t submitted;
u32 rank;
bool is_self;
};
// RAIntegration only exists for Windows, so no point checking it on other platforms.
#ifdef WITH_RAINTEGRATION
bool IsUsingRAIntegration();
#else
static ALWAYS_INLINE bool IsUsingRAIntegration()
{
return false;
}
#endif
bool IsActive();
bool IsLoggedIn();
bool ChallengeModeActive();
bool LeaderboardsActive();
bool IsTestModeActive();
bool IsUnofficialTestModeActive();
bool IsRichPresenceEnabled();
bool HasActiveGame();
u32 GetGameID();
/// Acquires the achievements lock. Must be held when accessing any achievement state from another thread.
std::unique_lock<std::recursive_mutex> GetLock();
void Initialize();
void UpdateSettings(const Settings& old_config);
void ResetRuntime();
/// Called when the system is being reset. If it returns false, the reset should be aborted.
bool ConfirmSystemReset();
/// Called when the system is being shut down. If Shutdown() returns false, the shutdown should be aborted.
bool Shutdown();
/// Called when the system is being paused and resumed.
void OnSystemPaused(bool paused);
/// Called once a frame at vsync time on the CPU thread.
void FrameUpdate();
/// Called when the system is paused, because FrameUpdate() won't be getting called.
void ProcessPendingHTTPRequests();
/// Saves/loads state.
bool DoState(StateWrapper& sw);
/// Returns true if the current game has any achievements or leaderboards.
/// Does not need to have the lock held.
bool SafeHasAchievementsOrLeaderboards();
const std::string& GetUsername();
const std::string& GetRichPresenceString();
bool LoginAsync(const char* username, const char* password);
bool Login(const char* username, const char* password);
void Logout();
void GameChanged(const std::string& path, CDImage* image);
/// Re-enables hardcode mode if it is enabled in the settings.
extern bool ResetChallengeMode();
bool ResetChallengeMode();
/// Forces hardcore mode off until next reset.
extern void DisableChallengeMode();
void DisableChallengeMode();
/// Prompts the user to disable hardcore mode, if they agree, returns true.
extern bool ConfirmChallengeModeDisable(const char* trigger);
bool ConfirmChallengeModeDisable(const char* trigger);
/// Returns true if features such as save states should be disabled.
extern bool ChallengeModeActive();
bool ChallengeModeActive();
const std::string& GetGameTitle();
const std::string& GetGameIcon();
bool EnumerateAchievements(std::function<bool(const Achievement&)> callback);
u32 GetUnlockedAchiementCount();
u32 GetAchievementCount();
u32 GetMaximumPointsForGame();
u32 GetCurrentPointsForGame();
bool EnumerateLeaderboards(std::function<bool(const Leaderboard&)> callback);
std::optional<bool> TryEnumerateLeaderboardEntries(u32 id, std::function<bool(const LeaderboardEntry&)> callback);
const Leaderboard* GetLeaderboardByID(u32 id);
u32 GetLeaderboardCount();
bool IsLeaderboardTimeType(const Leaderboard& leaderboard);
u32 GetPrimedAchievementCount();
const Achievement* GetAchievementByID(u32 id);
std::pair<u32, u32> GetAchievementProgress(const Achievement& achievement);
TinyString GetAchievementProgressText(const Achievement& achievement);
const std::string& GetAchievementBadgePath(const Achievement& achievement, bool download_if_missing = true,
bool force_unlocked_icon = false);
std::string GetAchievementBadgeURL(const Achievement& achievement);
#ifdef WITH_RAINTEGRATION
void SwitchToRAIntegration();
namespace RAIntegration {
void MainWindowChanged(void* new_handle);
void GameChanged();
std::vector<std::tuple<int, std::string, bool>> GetMenuItems();
void ActivateMenuItem(int item);
} // namespace RAIntegration
#endif
#else
@ -38,7 +181,9 @@ static inline bool ConfirmSystemReset()
{
return true;
}
static inline void ResetRuntime() {}
static inline void ResetRuntime()
{
}
static inline bool DoState(StateWrapper& sw)
{
return true;
@ -53,7 +198,9 @@ static inline bool ResetChallengeMode()
return false;
}
static inline void DisableChallengeMode() {}
static inline void DisableChallengeMode()
{
}
static inline bool ConfirmChallengeModeDisable(const char* trigger)
{
@ -63,3 +210,9 @@ static inline bool ConfirmChallengeModeDisable(const char* trigger)
#endif
} // namespace Achievements
/// Functions implemented in the frontend.
namespace Host {
void OnAchievementsRefreshed();
void OnAchievementsChallengeModeChanged();
} // namespace Host

View file

@ -1,178 +0,0 @@
// SPDX-FileCopyrightText: 2019-2022 Connor McLaughlin <stenzek@gmail.com>
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
#pragma once
#include "achievements.h"
#include "settings.h"
#include "types.h"
#include "common/string.h"
#include <functional>
#include <optional>
#include <string>
#include <utility>
#include <vector>
class CDImage;
class StateWrapper;
namespace Achievements {
enum class AchievementCategory : u8
{
Local = 0,
Core = 3,
Unofficial = 5
};
struct Achievement
{
u32 id;
std::string title;
std::string description;
std::string memaddr;
std::string badge_name;
// badge paths are mutable because they're resolved when they're needed.
mutable std::string locked_badge_path;
mutable std::string unlocked_badge_path;
u32 points;
AchievementCategory category;
bool locked;
bool active;
bool primed;
};
struct Leaderboard
{
u32 id;
std::string title;
std::string description;
int format;
};
struct LeaderboardEntry
{
std::string user;
std::string formatted_score;
time_t submitted;
u32 rank;
bool is_self;
};
// RAIntegration only exists for Windows, so no point checking it on other platforms.
#ifdef WITH_RAINTEGRATION
bool IsUsingRAIntegration();
#else
static ALWAYS_INLINE bool IsUsingRAIntegration()
{
return false;
}
#endif
bool IsActive();
bool IsLoggedIn();
bool ChallengeModeActive();
bool LeaderboardsActive();
bool IsTestModeActive();
bool IsUnofficialTestModeActive();
bool IsRichPresenceEnabled();
bool HasActiveGame();
u32 GetGameID();
/// Acquires the achievements lock. Must be held when accessing any achievement state from another thread.
std::unique_lock<std::recursive_mutex> GetLock();
void Initialize();
void UpdateSettings(const Settings& old_config);
/// Called when the system is being reset. If it returns false, the reset should be aborted.
bool ConfirmSystemReset();
/// Called when the system is being shut down. If Shutdown() returns false, the shutdown should be aborted.
bool Shutdown();
/// Called when the system is being paused and resumed.
void OnSystemPaused(bool paused);
/// Called once a frame at vsync time on the CPU thread.
void FrameUpdate();
/// Called when the system is paused, because FrameUpdate() won't be getting called.
void ProcessPendingHTTPRequests();
/// Saves/loads state.
bool DoState(StateWrapper& sw);
/// Returns true if the current game has any achievements or leaderboards.
/// Does not need to have the lock held.
bool SafeHasAchievementsOrLeaderboards();
const std::string& GetUsername();
const std::string& GetRichPresenceString();
bool LoginAsync(const char* username, const char* password);
bool Login(const char* username, const char* password);
void Logout();
void GameChanged(const std::string& path, CDImage* image);
/// Re-enables hardcode mode if it is enabled in the settings.
bool ResetChallengeMode();
/// Forces hardcore mode off until next reset.
void DisableChallengeMode();
/// Prompts the user to disable hardcore mode, if they agree, returns true.
bool ConfirmChallengeModeDisable(const char* trigger);
/// Returns true if features such as save states should be disabled.
bool ChallengeModeActive();
const std::string& GetGameTitle();
const std::string& GetGameIcon();
bool EnumerateAchievements(std::function<bool(const Achievement&)> callback);
u32 GetUnlockedAchiementCount();
u32 GetAchievementCount();
u32 GetMaximumPointsForGame();
u32 GetCurrentPointsForGame();
bool EnumerateLeaderboards(std::function<bool(const Leaderboard&)> callback);
std::optional<bool> TryEnumerateLeaderboardEntries(u32 id, std::function<bool(const LeaderboardEntry&)> callback);
const Leaderboard* GetLeaderboardByID(u32 id);
u32 GetLeaderboardCount();
bool IsLeaderboardTimeType(const Leaderboard& leaderboard);
u32 GetPrimedAchievementCount();
const Achievement* GetAchievementByID(u32 id);
std::pair<u32, u32> GetAchievementProgress(const Achievement& achievement);
TinyString GetAchievementProgressText(const Achievement& achievement);
const std::string& GetAchievementBadgePath(const Achievement& achievement, bool download_if_missing = true,
bool force_unlocked_icon = false);
std::string GetAchievementBadgeURL(const Achievement& achievement);
#ifdef WITH_RAINTEGRATION
void SwitchToRAIntegration();
namespace RAIntegration {
void MainWindowChanged(void* new_handle);
void GameChanged();
std::vector<std::tuple<int, std::string, bool>> GetMenuItems();
void ActivateMenuItem(int item);
} // namespace RAIntegration
#endif
} // namespace Achievements
/// Functions implemented in the frontend.
namespace Host {
void OnAchievementsRefreshed();
void OnAchievementsChallengeModeChanged();
} // namespace Host

View file

@ -8,6 +8,7 @@
#include "host.h"
#include "settings.h"
#include "system.h"
#include "util/input_manager.h"
#include "util/state_wrapper.h"
#include <cmath>
Log_SetChannel(AnalogController);
@ -348,7 +349,7 @@ void AnalogController::UpdateHostVibration()
hvalues[motor] = (state != 0) ? static_cast<float>(strength / 65535.0) : 0.0f;
}
Host::SetPadVibrationIntensity(m_index, hvalues[0], hvalues[1]);
InputManager::SetPadVibrationIntensity(m_index, hvalues[0], hvalues[1]);
}
u8 AnalogController::GetExtraButtonMaskLSB() const
@ -820,7 +821,7 @@ static const Controller::ControllerBindingInfo s_binding_info[] = {
AXIS("RRight", TRANSLATE_NOOP("AnalogController", "Right Stick Right"), AnalogController::HalfAxis::RRight, GenericInputBinding::RightStickRight),
AXIS("RDown", TRANSLATE_NOOP("AnalogController", "Right Stick Down"), AnalogController::HalfAxis::RDown, GenericInputBinding::RightStickDown),
AXIS("RUp", TRANSLATE_NOOP("AnalogController", "Right Stick Up"), AnalogController::HalfAxis::RUp, GenericInputBinding::RightStickUp),
// clang-format on
// clang-format on
#undef AXIS
#undef BUTTON

View file

@ -9,7 +9,6 @@
#include "common/path.h"
#include "cpu_disasm.h"
#include "host.h"
#include "host_settings.h"
#include "settings.h"
#include <cerrno>
Log_SetChannel(BIOS);

View file

@ -1,46 +0,0 @@
// SPDX-FileCopyrightText: 2019-2022 Connor McLaughlin <stenzek@gmail.com>
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
#pragma once
#include "system.h"
#include <memory>
#include <mutex>
#include <string>
#include <utility>
#include <vector>
class SettingsInterface;
class AudioStream;
enum class AudioStretchMode : u8;
namespace CommonHost {
/// Initializes configuration.
void UpdateLogSettings();
void Initialize();
void Shutdown();
void SetDefaultSettings(SettingsInterface& si);
void SetDefaultControllerSettings(SettingsInterface& si);
void SetDefaultHotkeyBindings(SettingsInterface& si);
void LoadSettings(SettingsInterface& si, std::unique_lock<std::mutex>& lock);
void CheckForSettingsChanges(const Settings& old_settings);
void OnSystemStarting();
void OnSystemStarted();
void OnSystemDestroyed();
void OnSystemPaused();
void OnSystemResumed();
void OnGameChanged(const std::string& disc_path, const std::string& game_serial, const std::string& game_name);
void PumpMessagesOnCPUThread();
/// Returns the time elapsed in the current play session.
u64 GetSessionPlayedTime();
} // namespace CommonHost
namespace ImGuiManager {
void RenderDebugWindows();
}

View file

@ -10,7 +10,6 @@
<ClCompile Include="cdrom.cpp" />
<ClCompile Include="cdrom_async_reader.cpp" />
<ClCompile Include="cheats.cpp" />
<ClCompile Include="common_host.cpp" />
<ClCompile Include="cpu_core.cpp" />
<ClCompile Include="cpu_disasm.cpp" />
<ClCompile Include="cpu_code_cache.cpp" />
@ -49,7 +48,7 @@
<ClCompile Include="gpu_hw.cpp" />
<ClCompile Include="host.cpp" />
<ClCompile Include="host_interface_progress_callback.cpp" />
<ClCompile Include="host_settings.cpp" />
<ClCompile Include="hotkeys.cpp" />
<ClCompile Include="imgui_overlays.cpp" />
<ClCompile Include="interrupt_controller.cpp" />
<ClCompile Include="mdec.cpp" />
@ -74,7 +73,6 @@
<ClCompile Include="timing_event.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="achievements_private.h" />
<ClInclude Include="analog_controller.h" />
<ClInclude Include="analog_joystick.h" />
<ClInclude Include="bios.h" />
@ -83,7 +81,6 @@
<ClInclude Include="cdrom_async_reader.h" />
<ClInclude Include="cheats.h" />
<ClInclude Include="achievements.h" />
<ClInclude Include="common_host.h" />
<ClInclude Include="cpu_core.h" />
<ClInclude Include="cpu_core_private.h" />
<ClInclude Include="cpu_disasm.h" />
@ -118,7 +115,6 @@
<ClInclude Include="gte_types.h" />
<ClInclude Include="host.h" />
<ClInclude Include="host_interface_progress_callback.h" />
<ClInclude Include="host_settings.h" />
<ClInclude Include="imgui_overlays.h" />
<ClInclude Include="input_types.h" />
<ClInclude Include="interrupt_controller.h" />

View file

@ -54,11 +54,10 @@
<ClCompile Include="game_database.cpp" />
<ClCompile Include="pcdrv.cpp" />
<ClCompile Include="game_list.cpp" />
<ClCompile Include="host_settings.cpp" />
<ClCompile Include="imgui_overlays.cpp" />
<ClCompile Include="fullscreen_ui.cpp" />
<ClCompile Include="common_host.cpp" />
<ClCompile Include="achievements.cpp" />
<ClCompile Include="hotkeys.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="types.h" />
@ -113,7 +112,6 @@
<ClInclude Include="multitap.h" />
<ClInclude Include="gdb_protocol.h" />
<ClInclude Include="host.h" />
<ClInclude Include="host_settings.h" />
<ClInclude Include="achievements.h" />
<ClInclude Include="game_database.h" />
<ClInclude Include="input_types.h" />
@ -121,8 +119,6 @@
<ClInclude Include="game_list.h" />
<ClInclude Include="imgui_overlays.h" />
<ClInclude Include="fullscreen_ui.h" />
<ClInclude Include="common_host.h" />
<ClInclude Include="achievements_private.h" />
<ClInclude Include="shader_cache_version.h" />
</ItemGroup>
</Project>

View file

@ -7,14 +7,12 @@
#include "achievements.h"
#include "bios.h"
#include "cheats.h"
#include "common_host.h"
#include "controller.h"
#include "core/memory_card_image.h"
#include "cpu_core.h"
#include "game_list.h"
#include "gpu.h"
#include "host.h"
#include "host_settings.h"
#include "resources.h"
#include "settings.h"
#include "system.h"
@ -53,10 +51,6 @@
Log_SetChannel(FullscreenUI);
#ifdef WITH_CHEEVOS
#include "achievements_private.h"
#endif
#define TR_CONTEXT "FullscreenUI"
namespace {
@ -3170,7 +3164,7 @@ void FullscreenUI::ResetControllerSettings()
{
SettingsInterface* dsi = GetEditingSettingsInterface();
CommonHost::SetDefaultControllerSettings(*dsi);
Settings::SetDefaultControllerConfig(*dsi);
ShowToast(std::string(), FSUI_STR("Controller settings reset to default."));
}
@ -4831,7 +4825,7 @@ void FullscreenUI::DrawPauseMenu(MainWindowType type)
if (!serial.empty())
{
const std::time_t cached_played_time = GameList::GetCachedPlayedTimeForSerial(serial);
const std::time_t session_time = static_cast<std::time_t>(CommonHost::GetSessionPlayedTime());
const std::time_t session_time = static_cast<std::time_t>(System::GetSessionPlayedTime());
buffer.Fmt(FSUI_FSTR("Session: {}"), GameList::FormatTimespan(session_time, true).GetStringView());
const ImVec2 session_size(g_medium_font->CalcTextSizeA(g_medium_font->FontSize, std::numeric_limits<float>::max(),

View file

@ -4,7 +4,6 @@
#include "game_list.h"
#include "bios.h"
#include "host.h"
#include "host_settings.h"
#include "psf_loader.h"
#include "settings.h"
#include "system.h"

View file

@ -4,17 +4,19 @@
#include "gdb_protocol.h"
#include "bus.h"
#include "cpu_core_private.h"
#include "cpu_core.h"
#include "system.h"
#include "common/log.h"
#include "common/string_util.h"
#include "cpu_core.h"
#include "common_host.h"
#include "system.h"
#include <functional>
#include <iomanip>
#include <map>
#include <optional>
#include <sstream>
#include <string>
Log_SetChannel(GDBProtocol);
namespace GDBProtocol

View file

@ -2,15 +2,17 @@
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
#include "host.h"
#include "common_host.h"
#include "fullscreen_ui.h"
#include "imgui_overlays.h"
#include "shader_cache_version.h"
#include "system.h"
#include "util/gpu_device.h"
#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"
@ -23,6 +25,9 @@ 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>;
@ -32,6 +37,196 @@ static std::vector<char> s_translation_string_cache;
static u32 s_translation_string_cache_pos;
} // namespace Host
std::unique_lock<std::mutex> Host::GetSettingsLock()
{
return std::unique_lock<std::mutex>(s_settings_mutex);
}
SettingsInterface* Host::GetSettingsInterface()
{
return &s_layered_settings_interface;
}
SettingsInterface* Host::GetSettingsInterfaceForBindings()
{
SettingsInterface* input_layer = s_layered_settings_interface.GetLayer(LayeredSettingsInterface::LAYER_INPUT);
return input_layer ? input_layer : &s_layered_settings_interface;
}
std::string Host::GetBaseStringSettingValue(const char* section, const char* key, const char* default_value /*= ""*/)
{
std::unique_lock lock(s_settings_mutex);
return s_layered_settings_interface.GetLayer(LayeredSettingsInterface::LAYER_BASE)
->GetStringValue(section, key, default_value);
}
bool Host::GetBaseBoolSettingValue(const char* section, const char* key, bool default_value /*= false*/)
{
std::unique_lock lock(s_settings_mutex);
return s_layered_settings_interface.GetLayer(LayeredSettingsInterface::LAYER_BASE)
->GetBoolValue(section, key, default_value);
}
s32 Host::GetBaseIntSettingValue(const char* section, const char* key, s32 default_value /*= 0*/)
{
std::unique_lock lock(s_settings_mutex);
return s_layered_settings_interface.GetLayer(LayeredSettingsInterface::LAYER_BASE)
->GetIntValue(section, key, default_value);
}
u32 Host::GetBaseUIntSettingValue(const char* section, const char* key, u32 default_value /*= 0*/)
{
std::unique_lock lock(s_settings_mutex);
return s_layered_settings_interface.GetLayer(LayeredSettingsInterface::LAYER_BASE)
->GetUIntValue(section, key, default_value);
}
float Host::GetBaseFloatSettingValue(const char* section, const char* key, float default_value /*= 0.0f*/)
{
std::unique_lock lock(s_settings_mutex);
return s_layered_settings_interface.GetLayer(LayeredSettingsInterface::LAYER_BASE)
->GetFloatValue(section, key, default_value);
}
double Host::GetBaseDoubleSettingValue(const char* section, const char* key, double default_value /* = 0.0f */)
{
std::unique_lock lock(s_settings_mutex);
return s_layered_settings_interface.GetLayer(LayeredSettingsInterface::LAYER_BASE)
->GetDoubleValue(section, key, default_value);
}
std::vector<std::string> Host::GetBaseStringListSetting(const char* section, const char* key)
{
std::unique_lock lock(s_settings_mutex);
return s_layered_settings_interface.GetLayer(LayeredSettingsInterface::LAYER_BASE)->GetStringList(section, key);
}
std::string Host::GetStringSettingValue(const char* section, const char* key, const char* default_value /*= ""*/)
{
std::unique_lock lock(s_settings_mutex);
return s_layered_settings_interface.GetStringValue(section, key, default_value);
}
bool Host::GetBoolSettingValue(const char* section, const char* key, bool default_value /*= false*/)
{
std::unique_lock lock(s_settings_mutex);
return s_layered_settings_interface.GetBoolValue(section, key, default_value);
}
s32 Host::GetIntSettingValue(const char* section, const char* key, s32 default_value /*= 0*/)
{
std::unique_lock lock(s_settings_mutex);
return s_layered_settings_interface.GetIntValue(section, key, default_value);
}
u32 Host::GetUIntSettingValue(const char* section, const char* key, u32 default_value /*= 0*/)
{
std::unique_lock lock(s_settings_mutex);
return s_layered_settings_interface.GetUIntValue(section, key, default_value);
}
float Host::GetFloatSettingValue(const char* section, const char* key, float default_value /*= 0.0f*/)
{
std::unique_lock lock(s_settings_mutex);
return s_layered_settings_interface.GetFloatValue(section, key, default_value);
}
double Host::GetDoubleSettingValue(const char* section, const char* key, double default_value /*= 0.0f*/)
{
std::unique_lock lock(s_settings_mutex);
return s_layered_settings_interface.GetDoubleValue(section, key, default_value);
}
std::vector<std::string> Host::GetStringListSetting(const char* section, const char* key)
{
std::unique_lock lock(s_settings_mutex);
return s_layered_settings_interface.GetStringList(section, key);
}
void Host::SetBaseBoolSettingValue(const char* section, const char* key, bool value)
{
std::unique_lock lock(s_settings_mutex);
s_layered_settings_interface.GetLayer(LayeredSettingsInterface::LAYER_BASE)->SetBoolValue(section, key, value);
}
void Host::SetBaseIntSettingValue(const char* section, const char* key, int value)
{
std::unique_lock lock(s_settings_mutex);
s_layered_settings_interface.GetLayer(LayeredSettingsInterface::LAYER_BASE)->SetIntValue(section, key, value);
}
void Host::SetBaseFloatSettingValue(const char* section, const char* key, float value)
{
std::unique_lock lock(s_settings_mutex);
s_layered_settings_interface.GetLayer(LayeredSettingsInterface::LAYER_BASE)->SetFloatValue(section, key, value);
}
void Host::SetBaseStringSettingValue(const char* section, const char* key, const char* value)
{
std::unique_lock lock(s_settings_mutex);
s_layered_settings_interface.GetLayer(LayeredSettingsInterface::LAYER_BASE)->SetStringValue(section, key, value);
}
void Host::SetBaseStringListSettingValue(const char* section, const char* key, const std::vector<std::string>& values)
{
std::unique_lock lock(s_settings_mutex);
s_layered_settings_interface.GetLayer(LayeredSettingsInterface::LAYER_BASE)->SetStringList(section, key, values);
}
bool Host::AddValueToBaseStringListSetting(const char* section, const char* key, const char* value)
{
std::unique_lock lock(s_settings_mutex);
return s_layered_settings_interface.GetLayer(LayeredSettingsInterface::LAYER_BASE)
->AddToStringList(section, key, value);
}
bool Host::RemoveValueFromBaseStringListSetting(const char* section, const char* key, const char* value)
{
std::unique_lock lock(s_settings_mutex);
return s_layered_settings_interface.GetLayer(LayeredSettingsInterface::LAYER_BASE)
->RemoveFromStringList(section, key, value);
}
void Host::DeleteBaseSettingValue(const char* section, const char* key)
{
std::unique_lock lock(s_settings_mutex);
s_layered_settings_interface.GetLayer(LayeredSettingsInterface::LAYER_BASE)->DeleteValue(section, key);
}
SettingsInterface* Host::Internal::GetBaseSettingsLayer()
{
return s_layered_settings_interface.GetLayer(LayeredSettingsInterface::LAYER_BASE);
}
SettingsInterface* Host::Internal::GetGameSettingsLayer()
{
return s_layered_settings_interface.GetLayer(LayeredSettingsInterface::LAYER_GAME);
}
SettingsInterface* Host::Internal::GetInputSettingsLayer()
{
return s_layered_settings_interface.GetLayer(LayeredSettingsInterface::LAYER_INPUT);
}
void Host::Internal::SetBaseSettingsLayer(SettingsInterface* sif)
{
AssertMsg(s_layered_settings_interface.GetLayer(LayeredSettingsInterface::LAYER_BASE) == nullptr,
"Base layer has not been set");
s_layered_settings_interface.SetLayer(LayeredSettingsInterface::LAYER_BASE, sif);
}
void Host::Internal::SetGameSettingsLayer(SettingsInterface* sif)
{
std::unique_lock lock(s_settings_mutex);
s_layered_settings_interface.SetLayer(LayeredSettingsInterface::LAYER_GAME, sif);
}
void Host::Internal::SetInputSettingsLayer(SettingsInterface* sif)
{
std::unique_lock lock(s_settings_mutex);
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.
@ -162,6 +357,118 @@ void Host::ReportFormattedDebuggerMessage(const char* format, ...)
ReportDebuggerMessage(message);
}
bool Host::CreateGPUDevice(RenderAPI api)
{
DebugAssert(!g_gpu_device);
Log_InfoPrintf("Trying to create a %s GPU device...", GPUDevice::RenderAPIToString(api));
g_gpu_device = GPUDevice::CreateDeviceForAPI(api);
// TODO: FSUI should always use vsync..
const bool vsync = System::IsValid() ? System::ShouldUseVSync() : g_settings.video_sync_enabled;
if (!g_gpu_device || !g_gpu_device->Create(g_settings.gpu_adapter,
g_settings.gpu_disable_shader_cache ? std::string_view() :
std::string_view(EmuFolders::Cache),
SHADER_CACHE_VERSION, g_settings.gpu_use_debug_device, vsync,
g_settings.gpu_threaded_presentation))
{
Log_ErrorPrintf("Failed to initialize GPU device.");
if (g_gpu_device)
g_gpu_device->Destroy();
g_gpu_device.reset();
return false;
}
if (!ImGuiManager::Initialize())
{
Log_ErrorPrintf("Failed to initialize ImGuiManager.");
g_gpu_device->Destroy();
g_gpu_device.reset();
return false;
}
return true;
}
void Host::UpdateDisplayWindow()
{
if (!g_gpu_device)
return;
if (!g_gpu_device->UpdateWindow())
{
Host::ReportErrorAsync("Error", "Failed to change window after update. The log may contain more information.");
return;
}
ImGuiManager::WindowResized();
// If we're paused, re-present the current frame at the new window size.
if (System::IsValid() && System::IsPaused())
RenderDisplay(false);
}
void Host::ResizeDisplayWindow(s32 width, s32 height, float scale)
{
if (!g_gpu_device)
return;
Log_DevPrintf("Display window resized to %dx%d", width, height);
g_gpu_device->ResizeWindow(width, height, scale);
ImGuiManager::WindowResized();
// If we're paused, re-present the current frame at the new window size.
if (System::IsValid())
{
if (System::IsPaused())
RenderDisplay(false);
System::HostDisplayResized();
}
}
void Host::ReleaseGPUDevice()
{
if (!g_gpu_device)
return;
SaveStateSelectorUI::DestroyTextures();
FullscreenUI::Shutdown();
ImGuiManager::Shutdown();
Log_InfoPrintf("Destroying %s GPU device...", GPUDevice::RenderAPIToString(g_gpu_device->GetRenderAPI()));
g_gpu_device->Destroy();
g_gpu_device.reset();
}
#ifndef __ANDROID__
std::unique_ptr<AudioStream> Host::CreateAudioStream(AudioBackend backend, u32 sample_rate, u32 channels, u32 buffer_ms,
u32 latency_ms, AudioStretchMode stretch)
{
switch (backend)
{
#ifdef WITH_CUBEB
case AudioBackend::Cubeb:
return AudioStream::CreateCubebAudioStream(sample_rate, channels, buffer_ms, latency_ms, stretch);
#endif
#ifdef _WIN32
case AudioBackend::XAudio2:
return AudioStream::CreateXAudio2Stream(sample_rate, channels, buffer_ms, latency_ms, stretch);
#endif
case AudioBackend::Null:
return AudioStream::CreateNullStream(sample_rate, channels, buffer_ms);
default:
return nullptr;
}
}
#endif
void Host::RenderDisplay(bool skip_present)
{
Host::BeginPresentFrame();

View file

@ -9,14 +9,17 @@
#include <ctime>
#include <functional>
#include <memory>
#include <mutex>
#include <optional>
#include <string>
#include <string_view>
#include <vector>
class SettingsInterface;
struct WindowInfo;
enum class AudioBackend : u8;
enum class AudioStretchMode : u8;
enum class RenderAPI : u32;
class AudioStream;
class CDImage;
@ -38,6 +41,46 @@ 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);
s32 GetBaseIntSettingValue(const char* section, const char* key, s32 default_value = 0);
u32 GetBaseUIntSettingValue(const char* section, const char* key, u32 default_value = 0);
float GetBaseFloatSettingValue(const char* section, const char* key, float default_value = 0.0f);
double GetBaseDoubleSettingValue(const char* section, const char* key, double default_value = 0.0);
std::vector<std::string> GetBaseStringListSetting(const char* section, const char* key);
// Allows the emucore to write settings back to the frontend. Use with care.
// You should call CommitBaseSettingChanges() if you directly write to the layer (i.e. not these functions), or it may
// not be written to disk.
void SetBaseBoolSettingValue(const char* section, const char* key, bool value);
void SetBaseIntSettingValue(const char* section, const char* key, s32 value);
void SetBaseUIntSettingValue(const char* section, const char* key, u32 value);
void SetBaseFloatSettingValue(const char* section, const char* key, float value);
void SetBaseStringSettingValue(const char* section, const char* key, const char* value);
void SetBaseStringListSettingValue(const char* section, const char* key, const std::vector<std::string>& values);
bool AddValueToBaseStringListSetting(const char* section, const char* key, const char* value);
bool RemoveValueFromBaseStringListSetting(const char* section, const char* key, const char* value);
void DeleteBaseSettingValue(const char* section, const char* key);
void CommitBaseSettingChanges();
// Settings access, thread-safe.
std::string GetStringSettingValue(const char* section, const char* key, const char* default_value = "");
bool GetBoolSettingValue(const char* section, const char* key, bool default_value = false);
int GetIntSettingValue(const char* section, const char* key, s32 default_value = 0);
u32 GetUIntSettingValue(const char* section, const char* key, u32 default_value = 0);
float GetFloatSettingValue(const char* section, const char* key, float default_value = 0.0f);
double GetDoubleSettingValue(const char* section, const char* key, double default_value = 0.0);
std::vector<std::string> GetStringListSetting(const char* section, const char* key);
/// Direct access to settings interface. Must hold the lock when calling GetSettingsInterface() and while using it.
std::unique_lock<std::mutex> GetSettingsLock();
SettingsInterface* GetSettingsInterface();
/// Returns the settings interface that controller bindings should be loaded from.
/// 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);
@ -85,10 +128,6 @@ void ReportFormattedDebuggerMessage(const char* format, ...);
/// such as compiling shaders when starting up.
void DisplayLoadingScreen(const char* message, int progress_min = -1, int progress_max = -1, int progress_value = -1);
/// Internal method used by pads to dispatch vibration updates to input sources.
/// Intensity is normalized from 0 to 1.
void SetPadVibrationIntensity(u32 pad_index, float large_or_single_motor_intensity, float small_motor_intensity);
/// Enables "relative" mouse mode, locking the cursor position and returning relative coordinates.
void SetMouseMode(bool relative, bool hide_cursor);
@ -105,6 +144,18 @@ bool CopyTextToClipboard(const std::string_view& text);
/// if the user cancels the shutdown confirmation.
void RequestExit(bool allow_confirm);
/// Attempts to create the rendering device backend.
bool CreateGPUDevice(RenderAPI api);
/// Handles fullscreen transitions and such.
void UpdateDisplayWindow();
/// Called when the window is resized.
void ResizeDisplayWindow(s32 width, s32 height, float scale);
/// Destroys any active rendering device.
void ReleaseGPUDevice();
/// Called before drawing the OSD and other display elements.
void BeginPresentFrame();
@ -113,6 +164,24 @@ void RenderDisplay(bool skip_present);
void InvalidateDisplay();
namespace Internal {
/// Retrieves the base settings layer. Must call with lock held.
SettingsInterface* GetBaseSettingsLayer();
/// Retrieves the game settings layer, if present. Must call with lock held.
SettingsInterface* GetGameSettingsLayer();
/// Retrieves the input settings layer, if present. Must call with lock held.
SettingsInterface* GetInputSettingsLayer();
/// Sets the base settings layer. Should be called by the host at initialization time.
void SetBaseSettingsLayer(SettingsInterface* sif);
/// Sets the game settings layer. Called by VMManager when the game changes.
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);

View file

@ -1,192 +0,0 @@
// SPDX-FileCopyrightText: 2019-2022 Connor McLaughlin <stenzek@gmail.com>
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
#include "core/host.h"
#include "core/host_settings.h"
#include "common/assert.h"
#include "common/layered_settings_interface.h"
static std::mutex s_settings_mutex;
static LayeredSettingsInterface s_layered_settings_interface;
std::unique_lock<std::mutex> Host::GetSettingsLock()
{
return std::unique_lock<std::mutex>(s_settings_mutex);
}
SettingsInterface* Host::GetSettingsInterface()
{
return &s_layered_settings_interface;
}
SettingsInterface* Host::GetSettingsInterfaceForBindings()
{
SettingsInterface* input_layer = s_layered_settings_interface.GetLayer(LayeredSettingsInterface::LAYER_INPUT);
return input_layer ? input_layer : &s_layered_settings_interface;
}
std::string Host::GetBaseStringSettingValue(const char* section, const char* key, const char* default_value /*= ""*/)
{
std::unique_lock lock(s_settings_mutex);
return s_layered_settings_interface.GetLayer(LayeredSettingsInterface::LAYER_BASE)->GetStringValue(section, key, default_value);
}
bool Host::GetBaseBoolSettingValue(const char* section, const char* key, bool default_value /*= false*/)
{
std::unique_lock lock(s_settings_mutex);
return s_layered_settings_interface.GetLayer(LayeredSettingsInterface::LAYER_BASE)->GetBoolValue(section, key, default_value);
}
s32 Host::GetBaseIntSettingValue(const char* section, const char* key, s32 default_value /*= 0*/)
{
std::unique_lock lock(s_settings_mutex);
return s_layered_settings_interface.GetLayer(LayeredSettingsInterface::LAYER_BASE)->GetIntValue(section, key, default_value);
}
u32 Host::GetBaseUIntSettingValue(const char* section, const char* key, u32 default_value /*= 0*/)
{
std::unique_lock lock(s_settings_mutex);
return s_layered_settings_interface.GetLayer(LayeredSettingsInterface::LAYER_BASE)->GetUIntValue(section, key, default_value);
}
float Host::GetBaseFloatSettingValue(const char* section, const char* key, float default_value /*= 0.0f*/)
{
std::unique_lock lock(s_settings_mutex);
return s_layered_settings_interface.GetLayer(LayeredSettingsInterface::LAYER_BASE)->GetFloatValue(section, key, default_value);
}
double Host::GetBaseDoubleSettingValue(const char* section, const char* key, double default_value /* = 0.0f */)
{
std::unique_lock lock(s_settings_mutex);
return s_layered_settings_interface.GetLayer(LayeredSettingsInterface::LAYER_BASE)->GetDoubleValue(section, key, default_value);
}
std::vector<std::string> Host::GetBaseStringListSetting(const char* section, const char* key)
{
std::unique_lock lock(s_settings_mutex);
return s_layered_settings_interface.GetLayer(LayeredSettingsInterface::LAYER_BASE)->GetStringList(section, key);
}
std::string Host::GetStringSettingValue(const char* section, const char* key, const char* default_value /*= ""*/)
{
std::unique_lock lock(s_settings_mutex);
return s_layered_settings_interface.GetStringValue(section, key, default_value);
}
bool Host::GetBoolSettingValue(const char* section, const char* key, bool default_value /*= false*/)
{
std::unique_lock lock(s_settings_mutex);
return s_layered_settings_interface.GetBoolValue(section, key, default_value);
}
s32 Host::GetIntSettingValue(const char* section, const char* key, s32 default_value /*= 0*/)
{
std::unique_lock lock(s_settings_mutex);
return s_layered_settings_interface.GetIntValue(section, key, default_value);
}
u32 Host::GetUIntSettingValue(const char* section, const char* key, u32 default_value /*= 0*/)
{
std::unique_lock lock(s_settings_mutex);
return s_layered_settings_interface.GetUIntValue(section, key, default_value);
}
float Host::GetFloatSettingValue(const char* section, const char* key, float default_value /*= 0.0f*/)
{
std::unique_lock lock(s_settings_mutex);
return s_layered_settings_interface.GetFloatValue(section, key, default_value);
}
double Host::GetDoubleSettingValue(const char* section, const char* key, double default_value /*= 0.0f*/)
{
std::unique_lock lock(s_settings_mutex);
return s_layered_settings_interface.GetDoubleValue(section, key, default_value);
}
std::vector<std::string> Host::GetStringListSetting(const char* section, const char* key)
{
std::unique_lock lock(s_settings_mutex);
return s_layered_settings_interface.GetStringList(section, key);
}
void Host::SetBaseBoolSettingValue(const char* section, const char* key, bool value)
{
std::unique_lock lock(s_settings_mutex);
s_layered_settings_interface.GetLayer(LayeredSettingsInterface::LAYER_BASE)->SetBoolValue(section, key, value);
}
void Host::SetBaseIntSettingValue(const char* section, const char* key, int value)
{
std::unique_lock lock(s_settings_mutex);
s_layered_settings_interface.GetLayer(LayeredSettingsInterface::LAYER_BASE)->SetIntValue(section, key, value);
}
void Host::SetBaseFloatSettingValue(const char* section, const char* key, float value)
{
std::unique_lock lock(s_settings_mutex);
s_layered_settings_interface.GetLayer(LayeredSettingsInterface::LAYER_BASE)->SetFloatValue(section, key, value);
}
void Host::SetBaseStringSettingValue(const char* section, const char* key, const char* value)
{
std::unique_lock lock(s_settings_mutex);
s_layered_settings_interface.GetLayer(LayeredSettingsInterface::LAYER_BASE)->SetStringValue(section, key, value);
}
void Host::SetBaseStringListSettingValue(const char* section, const char* key, const std::vector<std::string>& values)
{
std::unique_lock lock(s_settings_mutex);
s_layered_settings_interface.GetLayer(LayeredSettingsInterface::LAYER_BASE)->SetStringList(section, key, values);
}
bool Host::AddValueToBaseStringListSetting(const char* section, const char* key, const char* value)
{
std::unique_lock lock(s_settings_mutex);
return s_layered_settings_interface.GetLayer(LayeredSettingsInterface::LAYER_BASE)->AddToStringList(section, key, value);
}
bool Host::RemoveValueFromBaseStringListSetting(const char* section, const char* key, const char* value)
{
std::unique_lock lock(s_settings_mutex);
return s_layered_settings_interface.GetLayer(LayeredSettingsInterface::LAYER_BASE)
->RemoveFromStringList(section, key, value);
}
void Host::DeleteBaseSettingValue(const char* section, const char* key)
{
std::unique_lock lock(s_settings_mutex);
s_layered_settings_interface.GetLayer(LayeredSettingsInterface::LAYER_BASE)->DeleteValue(section, key);
}
SettingsInterface* Host::Internal::GetBaseSettingsLayer()
{
return s_layered_settings_interface.GetLayer(LayeredSettingsInterface::LAYER_BASE);
}
SettingsInterface* Host::Internal::GetGameSettingsLayer()
{
return s_layered_settings_interface.GetLayer(LayeredSettingsInterface::LAYER_GAME);
}
SettingsInterface* Host::Internal::GetInputSettingsLayer()
{
return s_layered_settings_interface.GetLayer(LayeredSettingsInterface::LAYER_INPUT);
}
void Host::Internal::SetBaseSettingsLayer(SettingsInterface* sif)
{
AssertMsg(s_layered_settings_interface.GetLayer(LayeredSettingsInterface::LAYER_BASE) == nullptr, "Base layer has not been set");
s_layered_settings_interface.SetLayer(LayeredSettingsInterface::LAYER_BASE, sif);
}
void Host::Internal::SetGameSettingsLayer(SettingsInterface* sif)
{
std::unique_lock lock(s_settings_mutex);
s_layered_settings_interface.SetLayer(LayeredSettingsInterface::LAYER_GAME, sif);
}
void Host::Internal::SetInputSettingsLayer(SettingsInterface* sif)
{
std::unique_lock lock(s_settings_mutex);
s_layered_settings_interface.SetLayer(LayeredSettingsInterface::LAYER_INPUT, sif);
}

View file

@ -1,73 +0,0 @@
// SPDX-FileCopyrightText: 2019-2022 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 <mutex>
#include <string>
#include <vector>
class SettingsInterface;
namespace Host {
// 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);
s32 GetBaseIntSettingValue(const char* section, const char* key, s32 default_value = 0);
u32 GetBaseUIntSettingValue(const char* section, const char* key, u32 default_value = 0);
float GetBaseFloatSettingValue(const char* section, const char* key, float default_value = 0.0f);
double GetBaseDoubleSettingValue(const char* section, const char* key, double default_value = 0.0);
std::vector<std::string> GetBaseStringListSetting(const char* section, const char* key);
// Allows the emucore to write settings back to the frontend. Use with care.
// You should call CommitBaseSettingChanges() if you directly write to the layer (i.e. not these functions), or it may
// not be written to disk.
void SetBaseBoolSettingValue(const char* section, const char* key, bool value);
void SetBaseIntSettingValue(const char* section, const char* key, s32 value);
void SetBaseUIntSettingValue(const char* section, const char* key, u32 value);
void SetBaseFloatSettingValue(const char* section, const char* key, float value);
void SetBaseStringSettingValue(const char* section, const char* key, const char* value);
void SetBaseStringListSettingValue(const char* section, const char* key, const std::vector<std::string>& values);
bool AddValueToBaseStringListSetting(const char* section, const char* key, const char* value);
bool RemoveValueFromBaseStringListSetting(const char* section, const char* key, const char* value);
void DeleteBaseSettingValue(const char* section, const char* key);
void CommitBaseSettingChanges();
// Settings access, thread-safe.
std::string GetStringSettingValue(const char* section, const char* key, const char* default_value = "");
bool GetBoolSettingValue(const char* section, const char* key, bool default_value = false);
int GetIntSettingValue(const char* section, const char* key, s32 default_value = 0);
u32 GetUIntSettingValue(const char* section, const char* key, u32 default_value = 0);
float GetFloatSettingValue(const char* section, const char* key, float default_value = 0.0f);
double GetDoubleSettingValue(const char* section, const char* key, double default_value = 0.0);
std::vector<std::string> GetStringListSetting(const char* section, const char* key);
/// Direct access to settings interface. Must hold the lock when calling GetSettingsInterface() and while using it.
std::unique_lock<std::mutex> GetSettingsLock();
SettingsInterface* GetSettingsInterface();
/// Returns the settings interface that controller bindings should be loaded from.
/// If an input profile is being used, this will be the input layer, otherwise the layered interface.
SettingsInterface* GetSettingsInterfaceForBindings();
namespace Internal {
/// Retrieves the base settings layer. Must call with lock held.
SettingsInterface* GetBaseSettingsLayer();
/// Retrieves the game settings layer, if present. Must call with lock held.
SettingsInterface* GetGameSettingsLayer();
/// Retrieves the input settings layer, if present. Must call with lock held.
SettingsInterface* GetInputSettingsLayer();
/// Sets the base settings layer. Should be called by the host at initialization time.
void SetBaseSettingsLayer(SettingsInterface* sif);
/// Sets the game settings layer. Called by VMManager when the game changes.
void SetGameSettingsLayer(SettingsInterface* sif);
/// Sets the input profile settings layer. Called by VMManager when the game changes.
void SetInputSettingsLayer(SettingsInterface* sif);
} // namespace Internal
} // namespace Host

View file

@ -1,375 +1,28 @@
// 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 "common_host.h"
#include "cdrom.h"
#include "cheats.h"
#include "controller.h"
#include "cpu_code_cache.h"
#include "dma.h"
#include "cpu_core.h"
#include "fullscreen_ui.h"
#include "game_list.h"
#include "gpu.h"
#include "gte.h"
#include "host.h"
#include "host_settings.h"
#include "imgui_overlays.h"
#include "mdec.h"
#include "pgxp.h"
#include "resources.h"
#include "save_state_version.h"
#include "settings.h"
#include "shader_cache_version.h"
#include "spu.h"
#include "system.h"
#include "texture_replacements.h"
#include "timers.h"
#include "scmversion/scmversion.h"
#include "util/audio_stream.h"
#include "util/gpu_device.h"
#include "util/imgui_fullscreen.h"
#include "util/imgui_manager.h"
#include "util/ini_settings_interface.h"
#include "util/input_manager.h"
#include "util/platform_misc.h"
#include "common/assert.h"
#include "common/byte_stream.h"
#include "common/crash_handler.h"
#include "common/file_system.h"
#include "common/log.h"
#include "common/path.h"
#include "common/string_util.h"
#include "IconsFontAwesome5.h"
#include "imgui.h"
#include <cmath>
#include <cstdio>
#include <cstring>
#include <ctime>
#ifdef WITH_DISCORD_PRESENCE
#include "discord_rpc.h"
#endif
#ifdef WITH_CHEEVOS
#include "achievements_private.h"
#endif
#ifdef _WIN32
#include "common/windows_headers.h"
#include <KnownFolders.h>
#include <ShlObj.h>
#include <mmsystem.h>
#endif
Log_SetChannel(CommonHostInterface);
namespace CommonHost {
static void UpdateSessionTime(const std::string& new_serial);
#ifdef WITH_DISCORD_PRESENCE
static void SetDiscordPresenceEnabled(bool enabled);
static void InitializeDiscordPresence();
static void ShutdownDiscordPresence();
static void UpdateDiscordPresence(bool rich_presence_only);
static void PollDiscordPresence();
#endif
} // namespace CommonHost
// Used to track play time. We use a monotonic timer here, in case of clock changes.
static u64 s_session_start_time = 0;
static std::string s_session_serial;
#ifdef WITH_DISCORD_PRESENCE
// discord rich presence
bool m_discord_presence_enabled = false;
bool m_discord_presence_active = false;
#ifdef WITH_CHEEVOS
std::string m_discord_presence_cheevos_string;
#endif
#endif
void CommonHost::Initialize()
{
// This will call back to Host::LoadSettings() -> ReloadSources().
System::LoadSettings(false);
#ifdef WITH_CHEEVOS
#ifdef WITH_RAINTEGRATION
if (Host::GetBaseBoolSettingValue("Cheevos", "UseRAIntegration", false))
Achievements::SwitchToRAIntegration();
#endif
if (g_settings.achievements_enabled)
Achievements::Initialize();
#endif
}
void CommonHost::Shutdown()
{
#ifdef WITH_DISCORD_PRESENCE
CommonHost::ShutdownDiscordPresence();
#endif
#ifdef WITH_CHEEVOS
Achievements::Shutdown();
#endif
InputManager::CloseSources();
}
void CommonHost::PumpMessagesOnCPUThread()
{
InputManager::PollSources();
#ifdef WITH_DISCORD_PRESENCE
PollDiscordPresence();
#endif
#ifdef WITH_CHEEVOS
if (Achievements::IsActive())
Achievements::FrameUpdate();
#endif
}
bool Host::CreateGPUDevice(RenderAPI api)
{
DebugAssert(!g_gpu_device);
Log_InfoPrintf("Trying to create a %s GPU device...", GPUDevice::RenderAPIToString(api));
g_gpu_device = GPUDevice::CreateDeviceForAPI(api);
// TODO: FSUI should always use vsync..
const bool vsync = System::IsValid() ? System::ShouldUseVSync() : g_settings.video_sync_enabled;
if (!g_gpu_device || !g_gpu_device->Create(g_settings.gpu_adapter,
g_settings.gpu_disable_shader_cache ? std::string_view() :
std::string_view(EmuFolders::Cache),
SHADER_CACHE_VERSION, g_settings.gpu_use_debug_device, vsync,
g_settings.gpu_threaded_presentation))
{
Log_ErrorPrintf("Failed to initialize GPU device.");
if (g_gpu_device)
g_gpu_device->Destroy();
g_gpu_device.reset();
return false;
}
if (!ImGuiManager::Initialize())
{
Log_ErrorPrintf("Failed to initialize ImGuiManager.");
g_gpu_device->Destroy();
g_gpu_device.reset();
return false;
}
return true;
}
void Host::UpdateDisplayWindow()
{
if (!g_gpu_device)
return;
if (!g_gpu_device->UpdateWindow())
{
Host::ReportErrorAsync("Error", "Failed to change window after update. The log may contain more information.");
return;
}
ImGuiManager::WindowResized();
// If we're paused, re-present the current frame at the new window size.
if (System::IsValid() && System::IsPaused())
RenderDisplay(false);
}
void Host::ResizeDisplayWindow(s32 width, s32 height, float scale)
{
if (!g_gpu_device)
return;
Log_DevPrintf("Display window resized to %dx%d", width, height);
g_gpu_device->ResizeWindow(width, height, scale);
ImGuiManager::WindowResized();
// If we're paused, re-present the current frame at the new window size.
if (System::IsValid())
{
if (System::IsPaused())
RenderDisplay(false);
System::HostDisplayResized();
}
}
void Host::ReleaseGPUDevice()
{
if (!g_gpu_device)
return;
SaveStateSelectorUI::DestroyTextures();
FullscreenUI::Shutdown();
ImGuiManager::Shutdown();
Log_InfoPrintf("Destroying %s GPU device...", GPUDevice::RenderAPIToString(g_gpu_device->GetRenderAPI()));
g_gpu_device->Destroy();
g_gpu_device.reset();
}
#ifndef __ANDROID__
std::unique_ptr<AudioStream> Host::CreateAudioStream(AudioBackend backend, u32 sample_rate, u32 channels, u32 buffer_ms,
u32 latency_ms, AudioStretchMode stretch)
{
switch (backend)
{
#ifdef WITH_CUBEB
case AudioBackend::Cubeb:
return AudioStream::CreateCubebAudioStream(sample_rate, channels, buffer_ms, latency_ms, stretch);
#endif
#ifdef _WIN32
case AudioBackend::XAudio2:
return AudioStream::CreateXAudio2Stream(sample_rate, channels, buffer_ms, latency_ms, stretch);
#endif
case AudioBackend::Null:
return AudioStream::CreateNullStream(sample_rate, channels, buffer_ms);
default:
return nullptr;
}
}
#endif
void CommonHost::UpdateLogSettings()
{
Log::SetFilterLevel(g_settings.log_level);
Log::SetConsoleOutputParams(g_settings.log_to_console,
g_settings.log_filter.empty() ? nullptr : g_settings.log_filter.c_str(),
g_settings.log_level);
Log::SetDebugOutputParams(g_settings.log_to_debug,
g_settings.log_filter.empty() ? nullptr : g_settings.log_filter.c_str(),
g_settings.log_level);
if (g_settings.log_to_file)
{
Log::SetFileOutputParams(g_settings.log_to_file, Path::Combine(EmuFolders::DataRoot, "duckstation.log").c_str(),
true, g_settings.log_filter.empty() ? nullptr : g_settings.log_filter.c_str(),
g_settings.log_level);
}
else
{
Log::SetFileOutputParams(false, nullptr);
}
}
void CommonHost::OnSystemStarting()
{
//
}
void CommonHost::OnSystemStarted()
{
FullscreenUI::OnSystemStarted();
if (g_settings.inhibit_screensaver)
FrontendCommon::SuspendScreensaver();
}
void CommonHost::OnSystemPaused()
{
FullscreenUI::OnSystemPaused();
InputManager::PauseVibration();
#ifdef WITH_CHEEVOS
Achievements::OnSystemPaused(true);
#endif
if (g_settings.inhibit_screensaver)
FrontendCommon::ResumeScreensaver();
}
void CommonHost::OnSystemResumed()
{
FullscreenUI::OnSystemResumed();
#ifdef WITH_CHEEVOS
Achievements::OnSystemPaused(false);
#endif
if (g_settings.inhibit_screensaver)
FrontendCommon::SuspendScreensaver();
}
void CommonHost::OnSystemDestroyed()
{
Host::ClearOSDMessages();
SaveStateSelectorUI::Close(true);
FullscreenUI::OnSystemDestroyed();
InputManager::PauseVibration();
if (g_settings.inhibit_screensaver)
FrontendCommon::ResumeScreensaver();
}
void CommonHost::OnGameChanged(const std::string& disc_path, const std::string& game_serial,
const std::string& game_name)
{
#ifdef WITH_DISCORD_PRESENCE
UpdateDiscordPresence(false);
#endif
UpdateSessionTime(game_serial);
SaveStateSelectorUI::RefreshList();
}
void CommonHost::SetDefaultSettings(SettingsInterface& si)
{
#ifdef WITH_DISCORD_PRESENCE
si.SetBoolValue("Main", "EnableDiscordPresence", false);
#endif
#if defined(WITH_CHEEVOS) && defined(WITH_RAINTEGRATION)
si.SetBoolValue("Cheevos", "UseRAIntegration", false);
#endif
}
void CommonHost::SetDefaultControllerSettings(SettingsInterface& si)
{
InputManager::SetDefaultConfig(si);
// Global Settings
si.SetStringValue("ControllerPorts", "MultitapMode", Settings::GetMultitapModeName(Settings::DEFAULT_MULTITAP_MODE));
si.SetFloatValue("ControllerPorts", "PointerXScale", 8.0f);
si.SetFloatValue("ControllerPorts", "PointerYScale", 8.0f);
si.SetBoolValue("ControllerPorts", "PointerXInvert", false);
si.SetBoolValue("ControllerPorts", "PointerYInvert", false);
// Default pad types and parameters.
for (u32 i = 0; i < NUM_CONTROLLER_AND_CARD_PORTS; i++)
{
const std::string section(Controller::GetSettingsSection(i));
si.ClearSection(section.c_str());
si.SetStringValue(section.c_str(), "Type", Controller::GetDefaultPadType(i));
}
#ifndef __ANDROID__
// Use the automapper to set this up.
InputManager::MapController(si, 0, InputManager::GetGenericBindingMapping("Keyboard"));
#endif
}
void CommonHost::SetDefaultHotkeyBindings(SettingsInterface& si)
void Settings::SetDefaultHotkeyConfig(SettingsInterface& si)
{
si.ClearSection("Hotkeys");
@ -387,276 +40,6 @@ void CommonHost::SetDefaultHotkeyBindings(SettingsInterface& si)
#endif
}
void CommonHost::LoadSettings(SettingsInterface& si, std::unique_lock<std::mutex>& lock)
{
UpdateLogSettings();
InputManager::ReloadSources(si, lock);
InputManager::ReloadBindings(si, *Host::GetSettingsInterfaceForBindings());
#ifdef WITH_DISCORD_PRESENCE
SetDiscordPresenceEnabled(si.GetBoolValue("Main", "EnableDiscordPresence", false));
#endif
}
void CommonHost::CheckForSettingsChanges(const Settings& old_settings)
{
if (System::IsValid())
{
if (g_settings.inhibit_screensaver != old_settings.inhibit_screensaver)
{
if (g_settings.inhibit_screensaver)
FrontendCommon::SuspendScreensaver();
else
FrontendCommon::ResumeScreensaver();
}
}
#ifdef WITH_CHEEVOS
Achievements::UpdateSettings(old_settings);
#endif
FullscreenUI::CheckForConfigChanges(old_settings);
if (g_settings.log_level != old_settings.log_level || g_settings.log_filter != old_settings.log_filter ||
g_settings.log_to_console != old_settings.log_to_console ||
g_settings.log_to_debug != old_settings.log_to_debug || g_settings.log_to_window != old_settings.log_to_window ||
g_settings.log_to_file != old_settings.log_to_file)
{
UpdateLogSettings();
}
}
void CommonHost::UpdateSessionTime(const std::string& new_serial)
{
if (s_session_serial == new_serial)
return;
const u64 ctime = Common::Timer::GetCurrentValue();
if (!s_session_serial.empty())
{
// round up to seconds
const std::time_t etime =
static_cast<std::time_t>(std::round(Common::Timer::ConvertValueToSeconds(ctime - s_session_start_time)));
const std::time_t wtime = std::time(nullptr);
GameList::AddPlayedTimeForSerial(s_session_serial, wtime, etime);
}
s_session_serial = new_serial;
s_session_start_time = ctime;
}
u64 CommonHost::GetSessionPlayedTime()
{
const u64 ctime = Common::Timer::GetCurrentValue();
return static_cast<u64>(std::round(Common::Timer::ConvertValueToSeconds(ctime - s_session_start_time)));
}
void Host::SetPadVibrationIntensity(u32 pad_index, float large_or_single_motor_intensity, float small_motor_intensity)
{
InputManager::SetPadVibrationIntensity(pad_index, large_or_single_motor_intensity, small_motor_intensity);
}
void Host::DisplayLoadingScreen(const char* message, int progress_min /*= -1*/, int progress_max /*= -1*/,
int progress_value /*= -1*/)
{
const auto& io = ImGui::GetIO();
const float scale = ImGuiManager::GetGlobalScale();
const float width = (400.0f * scale);
const bool has_progress = (progress_min < progress_max);
// eat the last imgui frame, it might've been partially rendered by the caller.
ImGui::EndFrame();
ImGui::NewFrame();
const float logo_width = 260.0f * scale;
const float logo_height = 260.0f * scale;
ImGui::SetNextWindowSize(ImVec2(logo_width, logo_height), ImGuiCond_Always);
ImGui::SetNextWindowPos(ImVec2(io.DisplaySize.x * 0.5f, (io.DisplaySize.y * 0.5f) - (50.0f * scale)),
ImGuiCond_Always, ImVec2(0.5f, 0.5f));
if (ImGui::Begin("LoadingScreenLogo", nullptr,
ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_NoMove |
ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoNav |
ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoFocusOnAppearing |
ImGuiWindowFlags_NoBackground))
{
GPUTexture* tex = ImGuiFullscreen::GetCachedTexture("images/duck.png");
if (tex)
ImGui::Image(tex, ImVec2(logo_width, logo_height));
}
ImGui::End();
const float padding_and_rounding = 15.0f * scale;
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, padding_and_rounding);
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(padding_and_rounding, padding_and_rounding));
ImGui::SetNextWindowSize(ImVec2(width, (has_progress ? 80.0f : 50.0f) * scale), ImGuiCond_Always);
ImGui::SetNextWindowPos(ImVec2(io.DisplaySize.x * 0.5f, (io.DisplaySize.y * 0.5f) + (100.0f * scale)),
ImGuiCond_Always, ImVec2(0.5f, 0.0f));
if (ImGui::Begin("LoadingScreen", nullptr,
ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_NoMove |
ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoNav |
ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoFocusOnAppearing))
{
if (has_progress)
{
ImGui::TextUnformatted(message);
TinyString buf;
buf.Fmt("{}/{}", progress_value, progress_max);
const ImVec2 prog_size = ImGui::CalcTextSize(buf.GetCharArray(), buf.GetCharArray() + buf.GetLength());
ImGui::SameLine();
ImGui::SetCursorPosX(width - padding_and_rounding - prog_size.x);
ImGui::TextUnformatted(buf.GetCharArray(), buf.GetCharArray() + buf.GetLength());
ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 5.0f);
ImGui::ProgressBar(static_cast<float>(progress_value) / static_cast<float>(progress_max - progress_min),
ImVec2(-1.0f, 0.0f), "");
Log_InfoPrintf("%s: %d/%d", message, progress_value, progress_max);
}
else
{
const ImVec2 text_size(ImGui::CalcTextSize(message));
ImGui::SetCursorPosX((width - text_size.x) / 2.0f);
ImGui::TextUnformatted(message);
Log_InfoPrintf("%s", message);
}
}
ImGui::End();
ImGui::PopStyleVar(2);
ImGui::EndFrame();
g_gpu_device->Render(false);
ImGui::NewFrame();
}
void ImGuiManager::RenderDebugWindows()
{
if (System::IsValid())
{
if (g_settings.debugging.show_gpu_state)
g_gpu->DrawDebugStateWindow();
if (g_settings.debugging.show_cdrom_state)
CDROM::DrawDebugWindow();
if (g_settings.debugging.show_timers_state)
Timers::DrawDebugStateWindow();
if (g_settings.debugging.show_spu_state)
SPU::DrawDebugStateWindow();
if (g_settings.debugging.show_mdec_state)
MDEC::DrawDebugStateWindow();
if (g_settings.debugging.show_dma_state)
DMA::DrawDebugStateWindow();
}
}
#ifdef WITH_DISCORD_PRESENCE
void CommonHost::SetDiscordPresenceEnabled(bool enabled)
{
if (m_discord_presence_enabled == enabled)
return;
m_discord_presence_enabled = enabled;
if (enabled)
InitializeDiscordPresence();
else
ShutdownDiscordPresence();
}
void CommonHost::InitializeDiscordPresence()
{
if (m_discord_presence_active)
return;
DiscordEventHandlers handlers = {};
Discord_Initialize("705325712680288296", &handlers, 0, nullptr);
m_discord_presence_active = true;
UpdateDiscordPresence(false);
}
void CommonHost::ShutdownDiscordPresence()
{
if (!m_discord_presence_active)
return;
Discord_ClearPresence();
Discord_Shutdown();
m_discord_presence_active = false;
#ifdef WITH_CHEEVOS
m_discord_presence_cheevos_string.clear();
#endif
}
void CommonHost::UpdateDiscordPresence(bool rich_presence_only)
{
if (!m_discord_presence_active)
return;
#ifdef WITH_CHEEVOS
// Update only if RetroAchievements rich presence has changed
const std::string& new_rich_presence = Achievements::GetRichPresenceString();
if (new_rich_presence == m_discord_presence_cheevos_string && rich_presence_only)
{
return;
}
m_discord_presence_cheevos_string = new_rich_presence;
#else
if (rich_presence_only)
{
return;
}
#endif
// https://discord.com/developers/docs/rich-presence/how-to#updating-presence-update-presence-payload-fields
DiscordRichPresence rp = {};
rp.largeImageKey = "duckstation_logo";
rp.largeImageText = "DuckStation PS1/PSX Emulator";
rp.startTimestamp = std::time(nullptr);
SmallString details_string;
if (!System::IsShutdown())
{
details_string.AppendFormattedString("%s (%s)", System::GetGameTitle().c_str(), System::GetGameSerial().c_str());
}
else
{
details_string.AppendString("No Game Running");
}
#ifdef WITH_CHEEVOS
SmallString state_string;
// Trim to 128 bytes as per Discord-RPC requirements
if (m_discord_presence_cheevos_string.length() >= 128)
{
// 124 characters + 3 dots + null terminator
state_string = m_discord_presence_cheevos_string.substr(0, 124);
state_string.AppendString("...");
}
else
{
state_string = m_discord_presence_cheevos_string;
}
rp.state = state_string;
#endif
rp.details = details_string;
Discord_UpdatePresence(&rp);
}
void CommonHost::PollDiscordPresence()
{
if (!m_discord_presence_active)
return;
UpdateDiscordPresence(true);
Discord_RunCallbacks();
}
#endif
static void HotkeyModifyResolutionScale(s32 increment)
{
const u32 new_resolution_scale = std::clamp<u32>(

View file

@ -1,12 +1,14 @@
// 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_overlays.h"
#include "cdrom.h"
#include "controller.h"
#include "dma.h"
#include "fullscreen_ui.h"
#include "gpu.h"
#include "host.h"
#include "host_settings.h"
#include "mdec.h"
#include "resources.h"
#include "settings.h"
#include "spu.h"
@ -131,6 +133,99 @@ static std::tuple<float, float> GetMinMax(gsl::span<const float> values)
static bool s_save_state_selector_ui_open = false;
void Host::DisplayLoadingScreen(const char* message, int progress_min /*= -1*/, int progress_max /*= -1*/,
int progress_value /*= -1*/)
{
const auto& io = ImGui::GetIO();
const float scale = ImGuiManager::GetGlobalScale();
const float width = (400.0f * scale);
const bool has_progress = (progress_min < progress_max);
// eat the last imgui frame, it might've been partially rendered by the caller.
ImGui::EndFrame();
ImGui::NewFrame();
const float logo_width = 260.0f * scale;
const float logo_height = 260.0f * scale;
ImGui::SetNextWindowSize(ImVec2(logo_width, logo_height), ImGuiCond_Always);
ImGui::SetNextWindowPos(ImVec2(io.DisplaySize.x * 0.5f, (io.DisplaySize.y * 0.5f) - (50.0f * scale)),
ImGuiCond_Always, ImVec2(0.5f, 0.5f));
if (ImGui::Begin("LoadingScreenLogo", nullptr,
ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_NoMove |
ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoNav |
ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoFocusOnAppearing |
ImGuiWindowFlags_NoBackground))
{
GPUTexture* tex = ImGuiFullscreen::GetCachedTexture("images/duck.png");
if (tex)
ImGui::Image(tex, ImVec2(logo_width, logo_height));
}
ImGui::End();
const float padding_and_rounding = 15.0f * scale;
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, padding_and_rounding);
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(padding_and_rounding, padding_and_rounding));
ImGui::SetNextWindowSize(ImVec2(width, (has_progress ? 80.0f : 50.0f) * scale), ImGuiCond_Always);
ImGui::SetNextWindowPos(ImVec2(io.DisplaySize.x * 0.5f, (io.DisplaySize.y * 0.5f) + (100.0f * scale)),
ImGuiCond_Always, ImVec2(0.5f, 0.0f));
if (ImGui::Begin("LoadingScreen", nullptr,
ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_NoMove |
ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoNav |
ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoFocusOnAppearing))
{
if (has_progress)
{
ImGui::TextUnformatted(message);
TinyString buf;
buf.Fmt("{}/{}", progress_value, progress_max);
const ImVec2 prog_size = ImGui::CalcTextSize(buf.GetCharArray(), buf.GetCharArray() + buf.GetLength());
ImGui::SameLine();
ImGui::SetCursorPosX(width - padding_and_rounding - prog_size.x);
ImGui::TextUnformatted(buf.GetCharArray(), buf.GetCharArray() + buf.GetLength());
ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 5.0f);
ImGui::ProgressBar(static_cast<float>(progress_value) / static_cast<float>(progress_max - progress_min),
ImVec2(-1.0f, 0.0f), "");
Log_InfoPrintf("%s: %d/%d", message, progress_value, progress_max);
}
else
{
const ImVec2 text_size(ImGui::CalcTextSize(message));
ImGui::SetCursorPosX((width - text_size.x) / 2.0f);
ImGui::TextUnformatted(message);
Log_InfoPrintf("%s", message);
}
}
ImGui::End();
ImGui::PopStyleVar(2);
ImGui::EndFrame();
g_gpu_device->Render(false);
ImGui::NewFrame();
}
void ImGuiManager::RenderDebugWindows()
{
if (System::IsValid())
{
if (g_settings.debugging.show_gpu_state)
g_gpu->DrawDebugStateWindow();
if (g_settings.debugging.show_cdrom_state)
CDROM::DrawDebugWindow();
if (g_settings.debugging.show_timers_state)
Timers::DrawDebugStateWindow();
if (g_settings.debugging.show_spu_state)
SPU::DrawDebugStateWindow();
if (g_settings.debugging.show_mdec_state)
MDEC::DrawDebugStateWindow();
if (g_settings.debugging.show_dma_state)
DMA::DrawDebugStateWindow();
}
}
void ImGuiManager::RenderTextOverlays()
{
const System::State state = System::GetState();

View file

@ -7,8 +7,9 @@
namespace ImGuiManager {
void RenderTextOverlays();
void RenderDebugWindows();
void RenderOverlayWindows();
}
} // namespace ImGuiManager
namespace SaveStateSelectorUI {

View file

@ -5,10 +5,10 @@
#include "achievements.h"
#include "controller.h"
#include "host.h"
#include "host_settings.h"
#include "system.h"
#include "util/gpu_device.h"
#include "util/input_manager.h"
#include "common/assert.h"
#include "common/file_system.h"
@ -182,6 +182,7 @@ void Settings::Load(SettingsInterface& si)
apply_game_settings = si.GetBoolValue("Main", "ApplyGameSettings", true);
auto_load_cheats = si.GetBoolValue("Main", "AutoLoadCheats", true);
disable_all_enhancements = si.GetBoolValue("Main", "DisableAllEnhancements", false);
enable_discord_presence = si.GetBoolValue("Main", "EnableDiscordPresence", false);
rewind_enable = si.GetBoolValue("Main", "RewindEnable", false);
rewind_save_frequency = si.GetFloatValue("Main", "RewindFrequency", 10.0f);
rewind_save_slots = static_cast<u32>(si.GetIntValue("Main", "RewindSaveSlots", 10));
@ -369,6 +370,7 @@ void Settings::Load(SettingsInterface& si)
achievements_notifications = si.GetBoolValue("Cheevos", "Notifications", true);
achievements_sound_effects = si.GetBoolValue("Cheevos", "SoundEffects", true);
achievements_primed_indicators = si.GetBoolValue("Cheevos", "PrimedIndicators", true);
achievements_use_raintegration = si.GetBoolValue("Cheevos", "UseRAIntegration", false);
log_level = ParseLogLevelName(si.GetStringValue("Logging", "LogLevel", GetLogLevelName(DEFAULT_LOG_LEVEL)).c_str())
.value_or(DEFAULT_LOG_LEVEL);
@ -426,6 +428,7 @@ void Settings::Save(SettingsInterface& si) const
si.SetBoolValue("Main", "ApplyGameSettings", apply_game_settings);
si.SetBoolValue("Main", "AutoLoadCheats", auto_load_cheats);
si.SetBoolValue("Main", "DisableAllEnhancements", disable_all_enhancements);
si.SetBoolValue("Main", "EnableDiscordPresence", enable_discord_presence);
si.SetBoolValue("Main", "RewindEnable", rewind_enable);
si.SetFloatValue("Main", "RewindFrequency", rewind_save_frequency);
si.SetIntValue("Main", "RewindSaveSlots", rewind_save_slots);
@ -565,6 +568,7 @@ void Settings::Save(SettingsInterface& si) const
si.SetBoolValue("Cheevos", "Notifications", achievements_notifications);
si.SetBoolValue("Cheevos", "SoundEffects", achievements_sound_effects);
si.SetBoolValue("Cheevos", "PrimedIndicators", achievements_primed_indicators);
si.SetBoolValue("Cheevos", "UseRAIntegration", achievements_use_raintegration);
si.SetStringValue("Logging", "LogLevel", GetLogLevelName(log_level));
si.SetStringValue("Logging", "LogFilter", log_filter.c_str());
@ -726,6 +730,46 @@ void Settings::FixIncompatibleSettings(bool display_osd_messages)
}
}
void Settings::UpdateLogSettings()
{
Log::SetFilterLevel(log_level);
Log::SetConsoleOutputParams(log_to_console, log_filter.empty() ? nullptr : log_filter.c_str(), log_level);
Log::SetDebugOutputParams(log_to_debug, log_filter.empty() ? nullptr : log_filter.c_str(), log_level);
if (log_to_file)
{
Log::SetFileOutputParams(log_to_file, Path::Combine(EmuFolders::DataRoot, "duckstation.log").c_str(), true,
log_filter.empty() ? nullptr : log_filter.c_str(), log_level);
}
else
{
Log::SetFileOutputParams(false, nullptr);
}
}
void Settings::SetDefaultControllerConfig(SettingsInterface& si)
{
// Global Settings
si.SetStringValue("ControllerPorts", "MultitapMode", GetMultitapModeName(Settings::DEFAULT_MULTITAP_MODE));
si.SetFloatValue("ControllerPorts", "PointerXScale", 8.0f);
si.SetFloatValue("ControllerPorts", "PointerYScale", 8.0f);
si.SetBoolValue("ControllerPorts", "PointerXInvert", false);
si.SetBoolValue("ControllerPorts", "PointerYInvert", false);
// Default pad types and parameters.
for (u32 i = 0; i < NUM_CONTROLLER_AND_CARD_PORTS; i++)
{
const std::string section(Controller::GetSettingsSection(i));
si.ClearSection(section.c_str());
si.SetStringValue(section.c_str(), "Type", Controller::GetDefaultPadType(i));
}
#ifndef __ANDROID__
// Use the automapper to set this up.
InputManager::MapController(si, 0, InputManager::GetGenericBindingMapping("Keyboard"));
#endif
}
static std::array<const char*, LOGLEVEL_COUNT> s_log_level_names = {
{"None", "Error", "Warning", "Perf", "Info", "Verbose", "Dev", "Profile", "Debug", "Trace"}};
static std::array<const char*, LOGLEVEL_COUNT> s_log_level_display_names = {

View file

@ -85,6 +85,7 @@ struct Settings
bool apply_game_settings = true;
bool auto_load_cheats = true;
bool disable_all_enhancements = false;
bool enable_discord_presence = false;
bool rewind_enable = false;
float rewind_save_frequency = 10.0f;
@ -190,6 +191,7 @@ struct Settings
bool achievements_notifications = true;
bool achievements_sound_effects = true;
bool achievements_primed_indicators = true;
bool achievements_use_raintegration = false;
struct DebugSettings
{
@ -336,6 +338,12 @@ struct Settings
void FixIncompatibleSettings(bool display_osd_messages);
/// Initializes configuration.
void UpdateLogSettings();
static void SetDefaultControllerConfig(SettingsInterface& si);
static void SetDefaultHotkeyConfig(SettingsInterface& si);
static std::optional<LOGLEVEL> ParseLogLevelName(const char* str);
static const char* GetLogLevelName(LOGLEVEL level);
static const char* GetLogLevelDisplayName(LOGLEVEL level);

View file

@ -12,14 +12,14 @@
#include "cpu_code_cache.h"
#include "cpu_core.h"
#include "dma.h"
#include "fmt/chrono.h"
#include "fmt/format.h"
#include "fullscreen_ui.h"
#include "game_database.h"
#include "game_list.h"
#include "gpu.h"
#include "gte.h"
#include "host.h"
#include "host_interface_progress_callback.h"
#include "host_settings.h"
#include "imgui_overlays.h"
#include "interrupt_controller.h"
#include "mdec.h"
#include "memory_card.h"
@ -38,7 +38,9 @@
#include "util/cd_image.h"
#include "util/gpu_device.h"
#include "util/ini_settings_interface.h"
#include "util/input_manager.h"
#include "util/iso_reader.h"
#include "util/platform_misc.h"
#include "util/state_wrapper.h"
#include "common/error.h"
@ -49,6 +51,8 @@
#include "common/string_util.h"
#include "common/threading.h"
#include "fmt/chrono.h"
#include "fmt/format.h"
#include "xxhash.h"
#include <cctype>
@ -67,6 +71,10 @@ Log_SetChannel(System);
#include <mmsystem.h>
#endif
#ifdef WITH_DISCORD_PRESENCE
#include "discord_rpc.h"
#endif
// #define PROFILE_MEMORY_SAVE_STATES 1
SystemBootParameters::SystemBootParameters() = default;
@ -130,7 +138,16 @@ static void UpdateRunningGame(const char* path, CDImage* image, bool booting);
static bool CheckForSBIFile(CDImage* image);
static std::unique_ptr<MemoryCard> GetMemoryCardForSlot(u32 slot, MemoryCardType type);
static void UpdateSessionTime(const std::string& prev_serial);
static void SetTimerResolutionIncreased(bool enabled);
#ifdef WITH_DISCORD_PRESENCE
static void InitializeDiscordPresence();
static void ShutdownDiscordPresence();
static void UpdateDiscordPresence(bool rich_presence_only);
static void PollDiscordPresence();
#endif
} // namespace System
static constexpr const float PERFORMANCE_COUNTER_UPDATE_INTERVAL = 1.0f;
@ -222,11 +239,63 @@ static bool s_runahead_replay_pending = false;
static u32 s_runahead_frames = 0;
static u32 s_runahead_replay_frames = 0;
// Used to track play time. We use a monotonic timer here, in case of clock changes.
static u64 s_session_start_time = 0;
#ifdef WITH_DISCORD_PRESENCE
// discord rich presence
static bool s_discord_presence_active = false;
#ifdef WITH_CHEEVOS
static std::string s_discord_presence_cheevos_string;
#endif
#endif
static TinyString GetTimestampStringForFileName()
{
return TinyString::FromFmt("{:%Y-%m-%d_%H-%M-%S}", fmt::localtime(std::time(nullptr)));
}
void System::Internal::ProcessStartup()
{
// This will call back to Host::LoadSettings() -> ReloadSources().
LoadSettings(false);
#ifdef WITH_CHEEVOS
#ifdef WITH_RAINTEGRATION
if (Host::GetBaseBoolSettingValue("Cheevos", "UseRAIntegration", false))
Achievements::SwitchToRAIntegration();
#endif
if (g_settings.achievements_enabled)
Achievements::Initialize();
#endif
}
void System::Internal::ProcessShutdown()
{
#ifdef WITH_DISCORD_PRESENCE
ShutdownDiscordPresence();
#endif
#ifdef WITH_CHEEVOS
Achievements::Shutdown();
#endif
InputManager::CloseSources();
}
void System::Internal::IdlePollUpdate()
{
InputManager::PollSources();
#ifdef WITH_DISCORD_PRESENCE
PollDiscordPresence();
#endif
#ifdef WITH_CHEEVOS
Achievements::ProcessPendingHTTPRequests();
#endif
}
System::State System::GetState()
{
return s_state;
@ -845,7 +914,11 @@ void System::LoadSettings(bool display_osd_messages)
std::unique_lock<std::mutex> lock = Host::GetSettingsLock();
SettingsInterface& si = *Host::GetSettingsInterface();
g_settings.Load(si);
g_settings.UpdateLogSettings();
Host::LoadSettings(si, lock);
InputManager::ReloadSources(si, lock);
InputManager::ReloadBindings(si, *Host::GetSettingsInterfaceForBindings());
// apply compatibility settings
if (g_settings.apply_compatibility_settings && !s_running_game_serial.empty())
@ -1017,12 +1090,34 @@ void System::PauseSystem(bool paused)
if (paused)
{
FullscreenUI::OnSystemPaused();
InputManager::PauseVibration();
#ifdef WITH_CHEEVOS
Achievements::OnSystemPaused(true);
#endif
if (g_settings.inhibit_screensaver)
PlatformMisc::ResumeScreensaver();
Host::OnSystemPaused();
}
else
{
Host::OnSystemResumed();
FullscreenUI::OnSystemResumed();
#ifdef WITH_CHEEVOS
Achievements::OnSystemPaused(false);
#endif
if (g_settings.inhibit_screensaver)
PlatformMisc::SuspendScreensaver();
UpdateDisplaySync();
Host::OnSystemResumed();
ResetPerformanceCounters();
ResetThrottler();
}
@ -1330,16 +1425,16 @@ bool System::BootSystem(SystemBootParameters parameters)
}
// Good to go.
s_state =
(g_settings.start_paused || parameters.override_start_paused.value_or(false)) ? State::Paused : State::Running;
s_state = State::Running;
UpdateSoftwareCursor();
SPU::GetOutputStream()->SetPaused(false);
Host::OnSystemStarted();
if (s_state == State::Paused)
Host::OnSystemPaused();
else
Host::OnSystemResumed();
FullscreenUI::OnSystemStarted();
if (g_settings.inhibit_screensaver)
PlatformMisc::SuspendScreensaver();
Host::OnSystemStarted();
// try to load the state, if it fails, bail out
if (!parameters.save_state.empty())
@ -1371,6 +1466,9 @@ bool System::BootSystem(SystemBootParameters parameters)
if (g_settings.audio_dump_on_boot)
StartDumpingAudio();
if (g_settings.start_paused || parameters.override_start_paused.value_or(false))
PauseSystem(true);
ResetPerformanceCounters();
if (IsRunning())
UpdateSpeedLimiterState();
@ -1520,6 +1618,16 @@ void System::DestroySystem()
if (s_state == State::Shutdown)
return;
Host::ClearOSDMessages();
SaveStateSelectorUI::Close(true);
FullscreenUI::OnSystemDestroyed();
InputManager::PauseVibration();
if (g_settings.inhibit_screensaver)
PlatformMisc::ResumeScreensaver();
SetTimerResolutionIncreased(false);
s_cpu_thread_usage = {};
@ -1569,6 +1677,8 @@ void System::DestroySystem()
void System::ClearRunningGame()
{
UpdateSessionTime(s_running_game_serial);
s_running_game_serial.clear();
s_running_game_path.clear();
s_running_game_title.clear();
@ -1580,6 +1690,10 @@ void System::ClearRunningGame()
#ifdef WITH_CHEEVOS
Achievements::GameChanged(s_running_game_path, nullptr);
#endif
#ifdef WITH_DISCORD_PRESENCE
UpdateDiscordPresence(false);
#endif
}
bool System::FastForwardToFirstFrame()
@ -1644,6 +1758,7 @@ void System::FrameDone()
g_gpu->FlushRender();
// Generate any pending samples from the SPU before sleeping, this way we reduce the chances of underruns.
// TODO: when running ahead, we can skip this (and the flush above)
SPU::GeneratePendingSamples();
if (s_cheat_list)
@ -1677,6 +1792,8 @@ void System::FrameDone()
// *technically* this means higher input latency (by less than a frame), but runahead itself
// counter-acts that.
Host::PumpMessagesOnCPUThread();
InputManager::PollSources();
if (IsExecutionInterrupted())
{
s_system_interrupted = false;
@ -1694,6 +1811,15 @@ void System::FrameDone()
SaveRunaheadState();
}
#ifdef WITH_CHEEVOS
if (Achievements::IsActive())
Achievements::FrameUpdate();
#endif
#ifdef WITH_DISCORD_PRESENCE
PollDiscordPresence();
#endif
const Common::Timer::Value current_time = Common::Timer::GetCurrentValue();
if (current_time < s_next_frame_time || s_display_all_frames || s_last_frame_skipped)
{
@ -1722,6 +1848,7 @@ void System::FrameDone()
if (s_runahead_frames == 0)
{
Host::PumpMessagesOnCPUThread();
InputManager::PollSources();
if (IsExecutionInterrupted())
{
@ -3150,8 +3277,10 @@ void System::UpdateRunningGame(const char* path, CDImage* image, bool booting)
if (!booting && s_running_game_path == path)
return;
const std::string prev_serial = std::move(s_running_game_serial);
s_running_game_path.clear();
s_running_game_serial.clear();
s_running_game_serial = {};
s_running_game_title.clear();
s_running_game_entry = nullptr;
s_running_game_hash = 0;
@ -3207,6 +3336,15 @@ void System::UpdateRunningGame(const char* path, CDImage* image, bool booting)
if (g_settings.auto_load_cheats && !Achievements::ChallengeModeActive())
LoadCheatListFromGameTitle();
if (s_running_game_serial != prev_serial)
UpdateSessionTime(prev_serial);
SaveStateSelectorUI::RefreshList();
#ifdef WITH_DISCORD_PRESENCE
UpdateDiscordPresence(false);
#endif
Host::OnGameChanged(s_running_game_path, s_running_game_serial, s_running_game_title);
}
@ -3541,6 +3679,14 @@ void System::CheckForSettingsChanges(const Settings& old_settings)
g_gpu_device->SetPostProcessingChain({});
}
}
if (g_settings.inhibit_screensaver != old_settings.inhibit_screensaver)
{
if (g_settings.inhibit_screensaver)
PlatformMisc::SuspendScreensaver();
else
PlatformMisc::ResumeScreensaver();
}
}
bool controllers_updated = false;
@ -3566,6 +3712,28 @@ void System::CheckForSettingsChanges(const Settings& old_settings)
if (g_settings.multitap_mode != old_settings.multitap_mode)
UpdateMultitaps();
#ifdef WITH_CHEEVOS
Achievements::UpdateSettings(old_settings);
#endif
FullscreenUI::CheckForConfigChanges(old_settings);
if (g_settings.enable_discord_presence != old_settings.enable_discord_presence)
{
if (g_settings.enable_discord_presence)
InitializeDiscordPresence();
else
ShutdownDiscordPresence();
}
if (g_settings.log_level != old_settings.log_level || g_settings.log_filter != old_settings.log_filter ||
g_settings.log_to_console != old_settings.log_to_console ||
g_settings.log_to_debug != old_settings.log_to_debug || g_settings.log_to_window != old_settings.log_to_window ||
g_settings.log_to_file != old_settings.log_to_file)
{
g_settings.UpdateLogSettings();
}
}
void System::CalculateRewindMemoryUsage(u32 num_saves, u64* ram_usage, u64* vram_usage)
@ -4538,3 +4706,120 @@ void System::SetTimerResolutionIncreased(bool enabled)
timeEndPeriod(1);
#endif
}
void System::UpdateSessionTime(const std::string& prev_serial)
{
const u64 ctime = Common::Timer::GetCurrentValue();
if (!prev_serial.empty())
{
// round up to seconds
const std::time_t etime =
static_cast<std::time_t>(std::round(Common::Timer::ConvertValueToSeconds(ctime - s_session_start_time)));
const std::time_t wtime = std::time(nullptr);
GameList::AddPlayedTimeForSerial(prev_serial, wtime, etime);
}
s_session_start_time = ctime;
}
u64 System::GetSessionPlayedTime()
{
const u64 ctime = Common::Timer::GetCurrentValue();
return static_cast<u64>(std::round(Common::Timer::ConvertValueToSeconds(ctime - s_session_start_time)));
}
#ifdef WITH_DISCORD_PRESENCE
void System::InitializeDiscordPresence()
{
if (s_discord_presence_active)
return;
DiscordEventHandlers handlers = {};
Discord_Initialize("705325712680288296", &handlers, 0, nullptr);
s_discord_presence_active = true;
UpdateDiscordPresence(false);
}
void System::ShutdownDiscordPresence()
{
if (!s_discord_presence_active)
return;
Discord_ClearPresence();
Discord_Shutdown();
s_discord_presence_active = false;
#ifdef WITH_CHEEVOS
s_discord_presence_cheevos_string.clear();
#endif
}
void System::UpdateDiscordPresence(bool rich_presence_only)
{
if (!s_discord_presence_active)
return;
#ifdef WITH_CHEEVOS
// Update only if RetroAchievements rich presence has changed
const std::string& new_rich_presence = Achievements::GetRichPresenceString();
if (new_rich_presence == s_discord_presence_cheevos_string && rich_presence_only)
{
return;
}
s_discord_presence_cheevos_string = new_rich_presence;
#else
if (rich_presence_only)
{
return;
}
#endif
// https://discord.com/developers/docs/rich-presence/how-to#updating-presence-update-presence-payload-fields
DiscordRichPresence rp = {};
rp.largeImageKey = "duckstation_logo";
rp.largeImageText = "DuckStation PS1/PSX Emulator";
rp.startTimestamp = std::time(nullptr);
SmallString details_string;
if (!System::IsShutdown())
{
details_string.AppendFormattedString("%s (%s)", System::GetGameTitle().c_str(), System::GetGameSerial().c_str());
}
else
{
details_string.AppendString("No Game Running");
}
#ifdef WITH_CHEEVOS
SmallString state_string;
// Trim to 128 bytes as per Discord-RPC requirements
if (s_discord_presence_cheevos_string.length() >= 128)
{
// 124 characters + 3 dots + null terminator
state_string = s_discord_presence_cheevos_string.substr(0, 124);
state_string.AppendString("...");
}
else
{
state_string = s_discord_presence_cheevos_string;
}
rp.state = state_string;
#endif
rp.details = details_string;
Discord_UpdatePresence(&rp);
}
void System::PollDiscordPresence()
{
if (!s_discord_presence_active)
return;
UpdateDiscordPresence(true);
Discord_RunCallbacks();
}
#endif

View file

@ -194,6 +194,9 @@ GameHash GetGameHash();
bool IsRunningUnknownGame();
bool WasFastBooted();
/// Returns the time elapsed in the current play session.
u64 GetSessionPlayedTime();
const BIOS::ImageInfo* GetBIOSImageInfo();
const BIOS::Hash& GetBIOSHash();
@ -459,6 +462,18 @@ void UpdateMemorySaveStateSettings();
bool LoadRewindState(u32 skip_saves = 0, bool consume_state = true);
void SetRunaheadReplayFlag();
namespace Internal
{
/// Called on process startup.
void ProcessStartup();
/// Called on process shutdown.
void ProcessShutdown();
/// Polls input, updates subsystems which are present while paused/inactive.
void IdlePollUpdate();
}
} // namespace System
namespace Host {
@ -497,16 +512,4 @@ void RequestResizeHostDisplay(s32 width, s32 height);
/// Requests shut down of the current virtual machine.
void RequestSystemShutdown(bool allow_confirm, bool save_state);
/// Attempts to create the rendering device backend.
bool CreateGPUDevice(RenderAPI api);
/// Handles fullscreen transitions and such.
void UpdateDisplayWindow();
/// Called when the window is resized.
void ResizeDisplayWindow(s32 width, s32 height, float scale);
/// Destroys any active rendering device.
void ReleaseGPUDevice();
} // namespace Host

View file

@ -6,7 +6,6 @@
#include "nogui_host.h"
#include "core/host.h"
#include "core/host_settings.h"
#include "util/cocoa_tools.h"
#include "util/imgui_manager.h"
@ -28,9 +27,6 @@ constexpr NSWindowStyleMask WINDOWED_STYLE = NSWindowStyleMaskTitled | NSWindowS
- (BOOL)canBecomeKeyView {
return YES;
}
- (void)viewDidEndLiveResize:(NSEvent *)event {
[super viewDidEndLiveResize:event];
}
- (void)mouseDown:(NSEvent *)event {
NoGUIHost::ProcessPlatformMouseButtonEvent(0, true);
}

View file

@ -6,13 +6,12 @@
#include "scmversion/scmversion.h"
#include "core/common_host.h"
#include "core/achievements.h"
#include "core/controller.h"
#include "core/fullscreen_ui.h"
#include "core/game_list.h"
#include "core/gpu.h"
#include "core/host.h"
#include "core/host_settings.h"
#include "core/imgui_overlays.h"
#include "core/settings.h"
#include "core/system.h"
@ -21,6 +20,7 @@
#include "util/imgui_manager.h"
#include "util/ini_settings_interface.h"
#include "util/input_manager.h"
#include "util/platform_misc.h"
#include "imgui.h"
#include "imgui_internal.h"
@ -43,10 +43,6 @@
Log_SetChannel(NoGUIHost);
#ifdef WITH_CHEEVOS
#include "core/achievements_private.h"
#endif
#ifdef _WIN32
#include "common/windows_headers.h"
#include <ShlObj.h>
@ -278,15 +274,15 @@ void NoGUIHost::SetDefaultSettings(SettingsInterface& si, bool system, bool cont
if (system)
{
System::SetDefaultSettings(si);
CommonHost::SetDefaultSettings(si);
EmuFolders::SetDefaults();
EmuFolders::Save(si);
}
if (controller)
{
CommonHost::SetDefaultControllerSettings(si);
CommonHost::SetDefaultHotkeyBindings(si);
InputManager::SetDefaultSourceConfig(si);
Settings::SetDefaultControllerConfig(si);
Settings::SetDefaultHotkeyConfig(si);
}
g_nogui_window->SetDefaultConfig(si);
@ -384,12 +380,10 @@ std::optional<std::time_t> Host::GetResourceFileTimestamp(const char* filename)
void Host::LoadSettings(SettingsInterface& si, std::unique_lock<std::mutex>& lock)
{
CommonHost::LoadSettings(si, lock);
}
void Host::CheckForSettingsChanges(const Settings& old_settings)
{
CommonHost::CheckForSettingsChanges(old_settings);
}
void Host::CommitBaseSettingChanges()
@ -614,7 +608,7 @@ void NoGUIHost::CPUThreadEntryPoint()
Threading::SetNameOfCurrentThread("CPU Thread");
// input source setup must happen on emu thread
CommonHost::Initialize();
System::Internal::ProcessStartup();
// start the fullscreen UI and get it going
if (Host::CreateGPUDevice(Settings::GetRenderAPIForRenderer(g_settings.gpu_renderer)) && FullscreenUI::Initialize())
@ -640,7 +634,7 @@ void NoGUIHost::CPUThreadEntryPoint()
Host::ReleaseGPUDevice();
Host::ReleaseRenderWindow();
CommonHost::Shutdown();
System::Internal::ProcessShutdown();
g_nogui_window->QuitMessageLoop();
}
@ -655,6 +649,7 @@ void NoGUIHost::CPUThreadMainLoop()
}
Host::PumpMessagesOnCPUThread();
System::Internal::IdlePollUpdate();
Host::RenderDisplay(false);
if (!g_gpu_device->IsVsyncEnabled())
g_gpu_device->ThrottlePresentation();
@ -708,34 +703,24 @@ void Host::ReleaseRenderWindow()
void Host::OnSystemStarting()
{
CommonHost::OnSystemStarting();
Log_VerbosePrintf("Host::OnSystemStarting()");
s_save_state_on_shutdown = false;
s_was_paused_by_focus_loss = false;
}
void Host::OnSystemStarted()
{
CommonHost::OnSystemStarted();
Log_VerbosePrintf("Host::OnSystemStarted()");
}
void Host::OnSystemPaused()
{
CommonHost::OnSystemPaused();
Log_VerbosePrintf("Host::OnSystemPaused()");
}
void Host::OnSystemResumed()
{
CommonHost::OnSystemResumed();
Log_VerbosePrintf("Host::OnSystemResumed()");
}
void Host::OnSystemDestroyed()
{
CommonHost::OnSystemDestroyed();
Log_VerbosePrintf("Host::OnSystemDestroyed()");
}
void Host::BeginPresentFrame()
@ -764,18 +749,15 @@ void Host::OnPerformanceCountersUpdated()
void Host::OnGameChanged(const std::string& disc_path, const std::string& game_serial, const std::string& game_name)
{
CommonHost::OnGameChanged(disc_path, game_serial, game_name);
Log_VerbosePrintf("Host::OnGameChanged(\"%s\", \"%s\", \"%s\")", disc_path.c_str(), game_serial.c_str(),
game_name.c_str());
NoGUIHost::UpdateWindowTitle(game_name);
}
#ifdef WITH_CHEEVOS
void Host::OnAchievementsRefreshed()
{
// noop
}
#endif
void Host::SetMouseMode(bool relative, bool hide_cursor)
{
@ -793,7 +775,6 @@ void Host::PumpMessagesOnCPUThread()
{
NoGUIHost::ProcessCPUThreadPlatformMessages();
NoGUIHost::ProcessCPUThreadEvents(false);
CommonHost::PumpMessagesOnCPUThread(); // calls InputManager::PollSources()
}
std::unique_ptr<NoGUIPlatform> NoGUIHost::CreatePlatform()

View file

@ -7,7 +7,6 @@
#include "common/string_util.h"
#include "common/threading.h"
#include "core/host.h"
#include "core/host_settings.h"
#include "util/imgui_manager.h"
#include "nogui_host.h"
#include "resource.h"

View file

@ -2,7 +2,7 @@
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
#include "achievementlogindialog.h"
#include "core/achievements_private.h"
#include "core/achievements.h"
#include "qthost.h"
#include <QtWidgets/QMessageBox>

View file

@ -8,7 +8,7 @@
#include "settingsdialog.h"
#include "settingwidgetbinder.h"
#include "core/achievements_private.h"
#include "core/achievements.h"
#include "core/system.h"
#include "common/string_util.h"

View file

@ -5,7 +5,6 @@
#include "settingsdialog.h"
#include "settingwidgetbinder.h"
#include "core/common_host.h"
#include "core/spu.h"
#include "util/audio_stream.h"

View file

@ -2,17 +2,21 @@
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
#include "controllerbindingwidgets.h"
#include "common/log.h"
#include "common/string_util.h"
#include "controllersettingsdialog.h"
#include "controllersettingwidgetbinder.h"
#include "core/controller.h"
#include "core/host_settings.h"
#include "util/input_manager.h"
#include "qthost.h"
#include "qtutils.h"
#include "settingsdialog.h"
#include "settingwidgetbinder.h"
#include "core/controller.h"
#include "core/host.h"
#include "util/input_manager.h"
#include "common/log.h"
#include "common/string_util.h"
#include <QtWidgets/QCheckBox>
#include <QtWidgets/QDoubleSpinBox>
#include <QtWidgets/QInputDialog>
@ -519,7 +523,9 @@ ControllerCustomSettingsWidget::ControllerCustomSettingsWidget(ControllerBinding
layout->addStretch(1);
}
ControllerCustomSettingsWidget::~ControllerCustomSettingsWidget() {}
ControllerCustomSettingsWidget::~ControllerCustomSettingsWidget()
{
}
void ControllerCustomSettingsWidget::createSettingWidgets(ControllerBindingWidget* parent, QWidget* parent_widget,
QGridLayout* layout, const Controller::ControllerInfo* cinfo)
@ -720,9 +726,13 @@ void ControllerCustomSettingsWidget::restoreDefaults()
//////////////////////////////////////////////////////////////////////////
ControllerBindingWidget_Base::ControllerBindingWidget_Base(ControllerBindingWidget* parent) : QWidget(parent) {}
ControllerBindingWidget_Base::ControllerBindingWidget_Base(ControllerBindingWidget* parent) : QWidget(parent)
{
}
ControllerBindingWidget_Base::~ControllerBindingWidget_Base() {}
ControllerBindingWidget_Base::~ControllerBindingWidget_Base()
{
}
QIcon ControllerBindingWidget_Base::getIcon() const
{
@ -792,7 +802,9 @@ ControllerBindingWidget_DigitalController::ControllerBindingWidget_DigitalContro
initBindingWidgets();
}
ControllerBindingWidget_DigitalController::~ControllerBindingWidget_DigitalController() {}
ControllerBindingWidget_DigitalController::~ControllerBindingWidget_DigitalController()
{
}
QIcon ControllerBindingWidget_DigitalController::getIcon() const
{
@ -813,7 +825,9 @@ ControllerBindingWidget_AnalogController::ControllerBindingWidget_AnalogControll
initBindingWidgets();
}
ControllerBindingWidget_AnalogController::~ControllerBindingWidget_AnalogController() {}
ControllerBindingWidget_AnalogController::~ControllerBindingWidget_AnalogController()
{
}
QIcon ControllerBindingWidget_AnalogController::getIcon() const
{
@ -834,7 +848,9 @@ ControllerBindingWidget_AnalogJoystick::ControllerBindingWidget_AnalogJoystick(C
initBindingWidgets();
}
ControllerBindingWidget_AnalogJoystick::~ControllerBindingWidget_AnalogJoystick() {}
ControllerBindingWidget_AnalogJoystick::~ControllerBindingWidget_AnalogJoystick()
{
}
QIcon ControllerBindingWidget_AnalogJoystick::getIcon() const
{
@ -872,7 +888,9 @@ ControllerBindingWidget_NeGcon::ControllerBindingWidget_NeGcon(ControllerBinding
}
}
ControllerBindingWidget_NeGcon::~ControllerBindingWidget_NeGcon() {}
ControllerBindingWidget_NeGcon::~ControllerBindingWidget_NeGcon()
{
}
QIcon ControllerBindingWidget_NeGcon::getIcon() const
{
@ -893,7 +911,9 @@ ControllerBindingWidget_GunCon::ControllerBindingWidget_GunCon(ControllerBinding
initBindingWidgets();
}
ControllerBindingWidget_GunCon::~ControllerBindingWidget_GunCon() {}
ControllerBindingWidget_GunCon::~ControllerBindingWidget_GunCon()
{
}
QIcon ControllerBindingWidget_GunCon::getIcon() const
{
@ -914,7 +934,9 @@ ControllerBindingWidget_Mouse::ControllerBindingWidget_Mouse(ControllerBindingWi
initBindingWidgets();
}
ControllerBindingWidget_Mouse::~ControllerBindingWidget_Mouse() {}
ControllerBindingWidget_Mouse::~ControllerBindingWidget_Mouse()
{
}
QIcon ControllerBindingWidget_Mouse::getIcon() const
{

View file

@ -2,16 +2,19 @@
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
#include "controllersettingsdialog.h"
#include "common/assert.h"
#include "common/file_system.h"
#include "controllerbindingwidgets.h"
#include "controllerglobalsettingswidget.h"
#include "core/controller.h"
#include "core/host_settings.h"
#include "util/input_manager.h"
#include "hotkeysettingswidget.h"
#include "qthost.h"
#include "core/controller.h"
#include "core/host.h"
#include "util/ini_settings_interface.h"
#include "util/input_manager.h"
#include "common/assert.h"
#include "common/file_system.h"
#include <QtWidgets/QInputDialog>
#include <QtWidgets/QMessageBox>

View file

@ -1,7 +1,12 @@
// 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 <optional>
#include <type_traits>
#include "qthost.h"
#include "settingwidgetbinder.h"
#include "core/host.h"
#include <QtCore/QtCore>
#include <QtGui/QAction>
@ -11,10 +16,8 @@
#include <QtWidgets/QLineEdit>
#include <QtWidgets/QSlider>
#include <QtWidgets/QSpinBox>
#include "core/host_settings.h"
#include "qthost.h"
#include "settingwidgetbinder.h"
#include <optional>
#include <type_traits>
/// This nastyness is required because input profiles aren't overlaid settings like the rest of them, it's
/// input profile *or* global, not both.

View file

@ -8,7 +8,7 @@
#include "qtutils.h"
#include "core/game_list.h"
#include "core/host_settings.h"
#include "core/host.h"
#include "core/settings.h"
#include "common/assert.h"
@ -83,7 +83,9 @@ private:
QString m_filter_name;
};
GameListWidget::GameListWidget(QWidget* parent /* = nullptr */) : QWidget(parent) {}
GameListWidget::GameListWidget(QWidget* parent /* = nullptr */) : QWidget(parent)
{
}
GameListWidget::~GameListWidget() = default;
@ -585,7 +587,9 @@ const GameList::Entry* GameListWidget::getSelectedEntry() const
}
}
GameListGridListView::GameListGridListView(QWidget* parent /*= nullptr*/) : QListView(parent) {}
GameListGridListView::GameListGridListView(QWidget* parent /*= nullptr*/) : QListView(parent)
{
}
void GameListGridListView::wheelEvent(QWheelEvent* e)
{

View file

@ -2,12 +2,15 @@
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
#include "inputbindingwidgets.h"
#include "common/bitutils.h"
#include "controllersettingsdialog.h"
#include "core/host_settings.h"
#include "inputbindingdialog.h"
#include "qthost.h"
#include "qtutils.h"
#include "core/host.h"
#include "common/bitutils.h"
#include <QtCore/QTimer>
#include <QtGui/QKeyEvent>
#include <QtGui/QMouseEvent>
@ -408,7 +411,9 @@ InputVibrationBindingWidget::InputVibrationBindingWidget(QWidget* parent, Contro
setKey(dialog, std::move(section_name), std::move(key_name));
}
InputVibrationBindingWidget::~InputVibrationBindingWidget() {}
InputVibrationBindingWidget::~InputVibrationBindingWidget()
{
}
void InputVibrationBindingWidget::setKey(ControllerSettingsDialog* dialog, std::string section_name,
std::string key_name)

View file

@ -25,7 +25,6 @@
#include "util/cd_image.h"
#include "util/gpu_device.h"
#include "util/platform_misc.h"
#include "common/assert.h"
#include "common/file_system.h"
@ -46,15 +45,15 @@
#include <QtWidgets/QStyleFactory>
#include <cmath>
#ifdef WITH_CHEEVOS
#include "core/achievements_private.h"
#endif
#ifdef _WIN32
#include "common/windows_headers.h"
#include <Dbt.h>
#endif
#ifdef __APPLE__
#include "util/cocoa_tools.h"
#endif
Log_SetChannel(MainWindow);
static constexpr char DISC_IMAGE_FILTER[] = QT_TRANSLATE_NOOP(
@ -65,11 +64,7 @@ static constexpr char DISC_IMAGE_FILTER[] = QT_TRANSLATE_NOOP(
"(*.ecm);;Media Descriptor Sidecar Images (*.mds);;PlayStation EBOOTs (*.pbp *.PBP);;PlayStation Executables (*.exe "
"*.psexe *.ps-exe);;Portable Sound Format Files (*.psf *.minipsf);;Playlists (*.m3u)");
#ifdef __APPLE__
const char* DEFAULT_THEME_NAME = "";
#else
const char* DEFAULT_THEME_NAME = "darkfusion";
#endif
MainWindow* g_main_window = nullptr;
static QString s_unthemed_style_name;
@ -123,7 +118,7 @@ MainWindow::~MainWindow()
unregisterForDeviceNotifications();
#endif
#ifdef __APPLE__
FrontendCommon::RemoveThemeChangeHandler(this);
CocoaTools::RemoveThemeChangeHandler(this);
#endif
}
@ -159,8 +154,8 @@ void MainWindow::initialize()
#endif
#ifdef __APPLE__
FrontendCommon::AddThemeChangeHandler(this,
[](void* ctx) { QtHost::RunOnUIThread([] { g_main_window->updateTheme(); }); });
CocoaTools::AddThemeChangeHandler(this,
[](void* ctx) { QtHost::RunOnUIThread([] { g_main_window->updateTheme(); }); });
#endif
}

View file

@ -13,7 +13,7 @@
#include <optional>
#include <string_view>
namespace FrontendCommon {
namespace PlatformMisc {
class PostProcessingChain;
}

View file

@ -7,6 +7,7 @@
#include "qtprogresscallback.h"
#include "qtutils.h"
#include "core/achievements.h"
#include "core/cheats.h"
#include "core/controller.h"
#include "core/fullscreen_ui.h"
@ -14,7 +15,6 @@
#include "core/game_list.h"
#include "core/gpu.h"
#include "core/host.h"
#include "core/host_settings.h"
#include "core/imgui_overlays.h"
#include "core/memory_card.h"
#include "core/spu.h"
@ -32,6 +32,7 @@
#include "util/imgui_manager.h"
#include "util/ini_settings_interface.h"
#include "util/input_manager.h"
#include "util/platform_misc.h"
#include "scmversion/scmversion.h"
@ -62,10 +63,6 @@ Log_SetChannel(QtHost);
#include <ShlObj.h>
#endif
#ifdef WITH_CHEEVOS
#include "core/achievements_private.h"
#endif
static constexpr u32 SETTINGS_VERSION = 3;
static constexpr u32 SETTINGS_SAVE_DELAY = 1000;
@ -321,7 +318,6 @@ void QtHost::SetDataDirectory()
void Host::LoadSettings(SettingsInterface& si, std::unique_lock<std::mutex>& lock)
{
CommonHost::LoadSettings(si, lock);
g_emu_thread->loadSettings(si);
}
@ -358,7 +354,6 @@ void EmuThread::checkForSettingsChanges(const Settings& old_settings)
void Host::CheckForSettingsChanges(const Settings& old_settings)
{
CommonHost::CheckForSettingsChanges(old_settings);
g_emu_thread->checkForSettingsChanges(old_settings);
}
@ -385,15 +380,15 @@ void QtHost::SetDefaultSettings(SettingsInterface& si, bool system, bool control
if (system)
{
System::SetDefaultSettings(si);
CommonHost::SetDefaultSettings(si);
EmuFolders::SetDefaults();
EmuFolders::Save(si);
}
if (controller)
{
CommonHost::SetDefaultControllerSettings(si);
CommonHost::SetDefaultHotkeyBindings(si);
InputManager::SetDefaultSourceConfig(si);
Settings::SetDefaultControllerConfig(si);
Settings::SetDefaultHotkeyConfig(si);
}
}
@ -745,15 +740,11 @@ void EmuThread::connectDisplaySignals(DisplayWidget* widget)
void Host::OnSystemStarting()
{
CommonHost::OnSystemStarting();
emit g_emu_thread->systemStarting();
}
void Host::OnSystemStarted()
{
CommonHost::OnSystemStarted();
g_emu_thread->wakeThread();
g_emu_thread->stopBackgroundControllerPollTimer();
@ -762,8 +753,6 @@ void Host::OnSystemStarted()
void Host::OnSystemPaused()
{
CommonHost::OnSystemPaused();
emit g_emu_thread->systemPaused();
g_emu_thread->startBackgroundControllerPollTimer();
Host::InvalidateDisplay();
@ -771,8 +760,6 @@ void Host::OnSystemPaused()
void Host::OnSystemResumed()
{
CommonHost::OnSystemResumed();
// if we were surfaceless (view->game list, system->unpause), get our display widget back
if (g_emu_thread->isSurfaceless())
g_emu_thread->setSurfaceless(false);
@ -785,8 +772,6 @@ void Host::OnSystemResumed()
void Host::OnSystemDestroyed()
{
CommonHost::OnSystemDestroyed();
g_emu_thread->resetPerformanceCounters();
g_emu_thread->startBackgroundControllerPollTimer();
emit g_emu_thread->systemDestroyed();
@ -1227,10 +1212,9 @@ void EmuThread::saveScreenshot()
System::SaveScreenshot(nullptr, true, true);
}
#ifdef WITH_CHEEVOS
void Host::OnAchievementsRefreshed()
{
#ifdef WITH_CHEEVOS
u32 game_id = 0;
u32 achievement_count = 0;
u32 max_points = 0;
@ -1264,18 +1248,19 @@ void Host::OnAchievementsRefreshed()
}
emit g_emu_thread->achievementsRefreshed(game_id, game_info, achievement_count, max_points);
#endif
}
void Host::OnAchievementsChallengeModeChanged()
{
#ifdef WITH_CHEEVOS
emit g_emu_thread->achievementsChallengeModeChanged();
}
#endif
}
void EmuThread::doBackgroundControllerPoll()
{
InputManager::PollSources();
System::Internal::IdlePollUpdate();
}
void EmuThread::createBackgroundControllerPollTimer()
@ -1346,7 +1331,7 @@ void EmuThread::run()
m_started_semaphore.release();
// input source setup must happen on emu thread
CommonHost::Initialize();
System::Internal::ProcessStartup();
// bind buttons/axises
createBackgroundControllerPollTimer();
@ -1370,7 +1355,7 @@ void EmuThread::run()
}
m_event_loop->processEvents(QEventLoop::AllEvents);
CommonHost::PumpMessagesOnCPUThread();
System::Internal::IdlePollUpdate();
if (g_gpu_device)
{
Host::RenderDisplay(false);
@ -1384,7 +1369,7 @@ void EmuThread::run()
System::ShutdownSystem(false);
destroyBackgroundControllerPollTimer();
CommonHost::Shutdown();
System::Internal::ProcessShutdown();
// move back to UI thread
moveToThread(m_ui_thread);
@ -1585,8 +1570,6 @@ void Host::OnPerformanceCountersUpdated()
void Host::OnGameChanged(const std::string& disc_path, const std::string& game_serial, const std::string& game_name)
{
CommonHost::OnGameChanged(disc_path, game_serial, game_name);
emit g_emu_thread->runningGameChanged(QString::fromStdString(disc_path), QString::fromStdString(game_serial),
QString::fromStdString(game_name));
}
@ -1606,7 +1589,6 @@ void Host::SetMouseMode(bool relative, bool hide_cursor)
void Host::PumpMessagesOnCPUThread()
{
g_emu_thread->getEventLoop()->processEvents(QEventLoop::AllEvents);
CommonHost::PumpMessagesOnCPUThread(); // calls InputManager::PollSources()
}
void QtHost::SaveSettings()

View file

@ -6,12 +6,10 @@
#include "gdbserver.h"
#include "qtutils.h"
#include "core/game_list.h"
#include "core/host.h"
#include "core/host_settings.h"
#include "core/system.h"
#include "core/types.h"
#include "core/common_host.h"
#include "core/game_list.h"
#include "util/gpu_device.h"
#include "util/input_manager.h"

View file

@ -20,7 +20,6 @@
#include "qthost.h"
#include "core/host.h"
#include "core/host_settings.h"
#include "util/ini_settings_interface.h"
@ -32,7 +31,7 @@
#ifdef WITH_CHEEVOS
#include "achievementsettingswidget.h"
#include "core/achievements_private.h"
#include "core/achievements.h"
#endif
static QList<SettingsDialog*> s_open_game_properties_dialogs;

View file

@ -1,10 +1,17 @@
// 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)
#pragma once
#include <optional>
#include <type_traits>
#include "qthost.h"
#include "qtutils.h"
#include "settingsdialog.h"
#include "core/host.h"
#include "core/settings.h"
#include "common/assert.h"
#include "common/path.h"
#include <QtCore/QtCore>
#include <QtGui/QAction>
@ -17,15 +24,8 @@
#include <QtWidgets/QMenu>
#include <QtWidgets/QSlider>
#include <QtWidgets/QSpinBox>
#include "common/assert.h"
#include "common/path.h"
#include "core/host_settings.h"
#include "core/settings.h"
#include "qthost.h"
#include "qtutils.h"
#include "settingsdialog.h"
#include <optional>
#include <type_traits>
namespace SettingWidgetBinder {
static constexpr const char* NULLABLE_PROPERTY = "SettingWidgetBinder_isNullable";

View file

@ -1,6 +1,18 @@
// SPDX-FileCopyrightText: 2019-2022 Connor McLaughlin <stenzek@gmail.com>
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
#include "core/achievements.h"
#include "core/game_list.h"
#include "core/host.h"
#include "core/system.h"
#include "scmversion/scmversion.h"
#include "util/gpu_device.h"
#include "util/imgui_manager.h"
#include "util/input_manager.h"
#include "util/platform_misc.h"
#include "common/assert.h"
#include "common/crash_handler.h"
#include "common/file_system.h"
@ -8,22 +20,11 @@
#include "common/memory_settings_interface.h"
#include "common/path.h"
#include "common/string_util.h"
#include "core/common_host.h"
#include "core/game_list.h"
#include "core/host.h"
#include "core/host_settings.h"
#include "core/system.h"
#include "scmversion/scmversion.h"
#include "util/gpu_device.h"
#include "util/imgui_manager.h"
#include "util/input_manager.h"
#include <csignal>
#include <cstdio>
Log_SetChannel(RegTestHost);
#ifdef WITH_CHEEVOS
#include "core/achievements_private.h"
#endif
Log_SetChannel(RegTestHost);
namespace RegTestHost {
static bool ParseCommandLineParameters(int argc, char* argv[], std::optional<SystemBootParameters>& autoboot);
@ -157,12 +158,10 @@ s32 Host::Internal::GetTranslatedStringImpl(const std::string_view& context, con
void Host::LoadSettings(SettingsInterface& si, std::unique_lock<std::mutex>& lock)
{
CommonHost::LoadSettings(si, lock);
}
void Host::CheckForSettingsChanges(const Settings& old_settings)
{
CommonHost::CheckForSettingsChanges(old_settings);
}
void Host::CommitBaseSettingChanges()

View file

@ -232,7 +232,6 @@ if(WIN32)
elseif(APPLE)
target_sources(util PRIVATE
cocoa_tools.h
cocoa_tools.mm
metal_device.h
metal_device.mm
metal_stream_buffer.h

View file

@ -3,9 +3,23 @@
#include <string_view>
#include <Cocoa/Cocoa.h>
struct WindowInfo;
#ifdef __OBJC__
#import <AppKit/AppKit.h>
#import <Cocoa/Cocoa.h>
namespace CocoaTools {
NSString* StringViewToNSString(const std::string_view& str);
}
#endif
namespace CocoaTools {
/// Add a handler to be run when macOS changes between dark and light themes
void AddThemeChangeHandler(void* ctx, void(handler)(void* ctx));
/// Remove a handler previously added using AddThemeChangeHandler with the given context
void RemoveThemeChangeHandler(void* ctx);
}

View file

@ -1,15 +0,0 @@
// SPDX-FileCopyrightText: 2019-2022 Connor McLaughlin <stenzek@gmail.com>
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
#include "cocoa_tools.h"
NSString* CocoaTools::StringViewToNSString(const std::string_view& str)
{
if (str.empty())
return nil;
return [[[NSString alloc] initWithBytes:str.data()
length:static_cast<NSUInteger>(str.length())
encoding:NSUTF8StringEncoding] autorelease];
}

View file

@ -2,7 +2,7 @@
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
#include "d3d11_device.h"
#include "core/host_settings.h" // TODO: Remove me
#include "core/host.h" // TODO: Remove me
#include "d3d11_pipeline.h"
#include "d3d11_texture.h"
#include "d3d_common.h"

View file

@ -4,13 +4,16 @@
#define INITGUID
#include "dinput_source.h"
#include "input_manager.h"
#include "platform_misc.h"
#include "common/assert.h"
#include "common/log.h"
#include "common/make_array.h"
#include "common/string_util.h"
#include "core/host.h"
#include "fmt/format.h"
#include "input_manager.h"
#include <cmath>
#include <limits>
Log_SetChannel(DInputSource);

View file

@ -2,7 +2,7 @@
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
#include "gpu_device.h"
#include "core/host_settings.h"
#include "core/host.h"
#include "core/settings.h"
#include "core/system.h"
#include "postprocessing_chain.h"

View file

@ -1071,7 +1071,7 @@ bool InputManager::HasPointerAxisBinds()
return false;
}
void InputManager::SetDefaultConfig(SettingsInterface& si)
void InputManager::SetDefaultSourceConfig(SettingsInterface& si)
{
si.ClearSection("InputSources");
si.SetBoolValue("InputSources", "SDL", true);

View file

@ -319,7 +319,7 @@ bool IsUsingRawInput();
bool HasPointerAxisBinds();
/// Restores default configuration.
void SetDefaultConfig(SettingsInterface& si);
void SetDefaultSourceConfig(SettingsInterface& si);
/// Clears all bindings for a given port.
void ClearPortBindings(SettingsInterface& si, u32 port);
@ -343,9 +343,6 @@ void OnInputDeviceDisconnected(const std::string_view& identifier);
} // namespace InputManager
namespace Host {
/// Return the current window handle. Needed for DInput.
std::optional<WindowInfo> GetTopLevelWindowInfo();
/// Called when a new input device is connected.
void OnInputDeviceConnected(const std::string_view& identifier, const std::string_view& device_name);

View file

@ -2,7 +2,6 @@
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
#include "metal_device.h"
#include "core/host_settings.h"
#include "spirv_compiler.h"
#include "common/align.h"

View file

@ -1,18 +1,20 @@
// SPDX-FileCopyrightText: 2019-2022 Connor McLaughlin <stenzek@gmail.com>
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
namespace FrontendCommon {
#include "window_info.h"
#include <optional>
namespace PlatformMisc {
void SuspendScreensaver();
void ResumeScreensaver();
/// Abstracts platform-specific code for asynchronously playing a sound.
/// On Windows, this will use PlaySound(). On Linux, it will shell out to aplay. On MacOS, it uses NSSound.
bool PlaySoundAsync(const char* path);
} // namespace PlatformMisc
#ifdef __APPLE__
/// Add a handler to be run when macOS changes between dark and light themes
void AddThemeChangeHandler(void* ctx, void(handler)(void* ctx));
/// Remove a handler previously added using AddThemeChangeHandler with the given context
void RemoveThemeChangeHandler(void* ctx);
#endif
} // namespace FrontendCommon
namespace Host {
/// Return the current window handle. Needed for DInput.
std::optional<WindowInfo> GetTopLevelWindowInfo();
} // namespace Host

View file

@ -2,16 +2,23 @@
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
#include "platform_misc.h"
#include "window_info.h"
#include "cocoa_tools.h"
#include "common/log.h"
#include "common/string.h"
#include <IOKit/pwr_mgt/IOPMLib.h>
#include <Cocoa/Cocoa.h>
#include <QuartzCore/QuartzCore.h>
#include <cinttypes>
#include <vector>
Log_SetChannel(FrontendCommon);
#import <AppKit/AppKit.h>
Log_SetChannel(PlatformMisc);
#if __has_feature(objc_arc)
#error ARC should not be enabled.
#endif
static IOPMAssertionID s_prevent_idle_assertion = kIOPMNullAssertionID;
@ -39,7 +46,7 @@ static bool SetScreensaverInhibitMacOS(bool inhibit)
static bool s_screensaver_suspended;
void FrontendCommon::SuspendScreensaver()
void PlatformMisc::SuspendScreensaver()
{
if (s_screensaver_suspended)
@ -52,7 +59,7 @@ void FrontendCommon::SuspendScreensaver()
s_screensaver_suspended = true;
}
void FrontendCommon::ResumeScreensaver()
void PlatformMisc::ResumeScreensaver()
{
if (!s_screensaver_suspended)
return;
@ -63,7 +70,7 @@ void FrontendCommon::ResumeScreensaver()
s_screensaver_suspended = false;
}
bool FrontendCommon::PlaySoundAsync(const char* path)
bool PlatformMisc::PlaySoundAsync(const char* path)
{
NSString* nspath = [[NSString alloc] initWithUTF8String:path];
NSSound* sound = [[NSSound alloc] initWithContentsOfFile:nspath byReference:YES];
@ -73,6 +80,16 @@ bool FrontendCommon::PlaySoundAsync(const char* path)
return result;
}
NSString* CocoaTools::StringViewToNSString(const std::string_view& str)
{
if (str.empty())
return nil;
return [[[NSString alloc] initWithBytes:str.data()
length:static_cast<NSUInteger>(str.length())
encoding:NSUTF8StringEncoding] autorelease];
}
// From https://github.com/PCSX2/pcsx2/blob/1b673d9dd0829a48f5f0b6604c1de2108e981399/common/CocoaTools.mm
@interface PCSX2KVOHelper : NSObject
@ -110,7 +127,7 @@ bool FrontendCommon::PlaySoundAsync(const char* path)
static PCSX2KVOHelper* s_themeChangeHandler;
void FrontendCommon::AddThemeChangeHandler(void* ctx, void(handler)(void* ctx))
void CocoaTools::AddThemeChangeHandler(void* ctx, void(handler)(void* ctx))
{
assert([NSThread isMainThread]);
if (!s_themeChangeHandler)
@ -125,7 +142,7 @@ void FrontendCommon::AddThemeChangeHandler(void* ctx, void(handler)(void* ctx))
[s_themeChangeHandler addCallback:ctx run:handler];
}
void FrontendCommon::RemoveThemeChangeHandler(void* ctx)
void CocoaTools::RemoveThemeChangeHandler(void* ctx)
{
assert([NSThread isMainThread]);
[s_themeChangeHandler removeCallback:ctx];

View file

@ -7,7 +7,7 @@
#include "input_manager.h"
#include "platform_misc.h"
#include <cinttypes>
Log_SetChannel(FrontendCommon);
Log_SetChannel(PlatformMisc);
#include <spawn.h>
#include <unistd.h>
@ -146,7 +146,7 @@ static bool SetScreensaverInhibit(bool inhibit)
static bool s_screensaver_suspended;
void FrontendCommon::SuspendScreensaver()
void PlatformMisc::SuspendScreensaver()
{
if (s_screensaver_suspended)
return;
@ -160,7 +160,7 @@ void FrontendCommon::SuspendScreensaver()
s_screensaver_suspended = true;
}
void FrontendCommon::ResumeScreensaver()
void PlatformMisc::ResumeScreensaver()
{
if (!s_screensaver_suspended)
return;
@ -171,7 +171,7 @@ void FrontendCommon::ResumeScreensaver()
s_screensaver_suspended = false;
}
bool FrontendCommon::PlaySoundAsync(const char* path)
bool PlatformMisc::PlaySoundAsync(const char* path)
{
#ifdef __linux__
// This is... pretty awful. But I can't think of a better way without linking to e.g. gstreamer.

View file

@ -6,7 +6,7 @@
#include "common/string_util.h"
#include "platform_misc.h"
#include <cinttypes>
Log_SetChannel(FrontendCommon);
Log_SetChannel(PlatformMisc);
#include "common/windows_headers.h"
#include <mmsystem.h>
@ -24,7 +24,7 @@ static bool SetScreensaverInhibitWin32(bool inhibit)
static bool s_screensaver_suspended;
void FrontendCommon::SuspendScreensaver()
void PlatformMisc::SuspendScreensaver()
{
if (s_screensaver_suspended)
return;
@ -38,7 +38,7 @@ void FrontendCommon::SuspendScreensaver()
s_screensaver_suspended = true;
}
void FrontendCommon::ResumeScreensaver()
void PlatformMisc::ResumeScreensaver()
{
if (!s_screensaver_suspended)
return;
@ -49,7 +49,7 @@ void FrontendCommon::ResumeScreensaver()
s_screensaver_suspended = false;
}
bool FrontendCommon::PlaySoundAsync(const char* path)
bool PlatformMisc::PlaySoundAsync(const char* path)
{
const std::wstring wpath(StringUtil::UTF8StringToWideString(path));
return PlaySoundW(wpath.c_str(), NULL, SND_ASYNC | SND_NODEFAULT);

View file

@ -2,17 +2,21 @@
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
#include "sdl_input_source.h"
#include "input_manager.h"
#include "core/host.h"
#include "common/assert.h"
#include "common/bitutils.h"
#include "common/log.h"
#include "common/string_util.h"
#include "core/host.h"
#include "core/host_settings.h"
#include "input_manager.h"
#include <cmath>
#ifdef __APPLE__
#include <dispatch/dispatch.h>
#endif
Log_SetChannel(SDLInputSource);
static constexpr const char* s_sdl_axis_names[] = {