Misc: Post-refactor cleanups
This commit is contained in:
@ -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)
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
@ -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
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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();
|
||||
}
|
||||
@ -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" />
|
||||
|
||||
@ -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>
|
||||
@ -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(),
|
||||
|
||||
@ -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"
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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);
|
||||
}
|
||||
@ -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
|
||||
@ -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>(
|
||||
@ -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();
|
||||
|
||||
@ -7,8 +7,9 @@
|
||||
|
||||
namespace ImGuiManager {
|
||||
void RenderTextOverlays();
|
||||
void RenderDebugWindows();
|
||||
void RenderOverlayWindows();
|
||||
}
|
||||
} // namespace ImGuiManager
|
||||
|
||||
namespace SaveStateSelectorUI {
|
||||
|
||||
|
||||
@ -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 = {
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
Reference in New Issue
Block a user