diff options
Diffstat (limited to 'src')
32 files changed, 1373 insertions, 636 deletions
diff --git a/src/audio_core/stream.cpp b/src/audio_core/stream.cpp index 22a3f8c84..11481a776 100644 --- a/src/audio_core/stream.cpp +++ b/src/audio_core/stream.cpp @@ -57,7 +57,9 @@ Stream::State Stream::GetState() const { s64 Stream::GetBufferReleaseCycles(const Buffer& buffer) const { const std::size_t num_samples{buffer.GetSamples().size() / GetNumChannels()}; - return Core::Timing::usToCycles((static_cast<u64>(num_samples) * 1000000) / sample_rate); + const auto us = + std::chrono::microseconds((static_cast<u64>(num_samples) * 1000000) / sample_rate); + return Core::Timing::usToCycles(us); } static void VolumeAdjustSamples(std::vector<s16>& samples) { diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index a56e526a6..6bf512e12 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -328,6 +328,9 @@ add_library(core STATIC hle/service/nim/nim.h hle/service/npns/npns.cpp hle/service/npns/npns.h + hle/service/ns/errors.h + hle/service/ns/language.cpp + hle/service/ns/language.h hle/service/ns/ns.cpp hle/service/ns/ns.h hle/service/ns/pl_u.cpp diff --git a/src/core/core.cpp b/src/core/core.cpp index 7106151bd..ff0721079 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -18,11 +18,6 @@ #include "core/file_sys/registered_cache.h" #include "core/file_sys/vfs_concat.h" #include "core/file_sys/vfs_real.h" -#include "core/frontend/applets/error.h" -#include "core/frontend/applets/general_frontend.h" -#include "core/frontend/applets/profile_select.h" -#include "core/frontend/applets/software_keyboard.h" -#include "core/frontend/applets/web_browser.h" #include "core/gdbstub/gdbstub.h" #include "core/hle/kernel/client_port.h" #include "core/hle/kernel/kernel.h" @@ -37,9 +32,6 @@ #include "core/settings.h" #include "core/telemetry_session.h" #include "file_sys/cheat_engine.h" -#include "frontend/applets/profile_select.h" -#include "frontend/applets/software_keyboard.h" -#include "frontend/applets/web_browser.h" #include "video_core/debug_utils/debug_utils.h" #include "video_core/renderer_base.h" #include "video_core/video_core.h" @@ -144,20 +136,10 @@ struct System::Impl { ResultStatus Load(System& system, Frontend::EmuWindow& emu_window, const std::string& filepath) { app_loader = Loader::GetLoader(GetGameFileFromPath(virtual_filesystem, filepath)); - if (!app_loader) { LOG_CRITICAL(Core, "Failed to obtain loader for {}!", filepath); return ResultStatus::ErrorGetLoader; } - std::pair<std::optional<u32>, Loader::ResultStatus> system_mode = - app_loader->LoadKernelSystemMode(); - - if (system_mode.second != Loader::ResultStatus::Success) { - LOG_CRITICAL(Core, "Failed to determine system mode (Error {})!", - static_cast<int>(system_mode.second)); - - return ResultStatus::ErrorSystemMode; - } ResultStatus init_result{Init(system, emu_window)}; if (init_result != ResultStatus::Success) { @@ -167,6 +149,7 @@ struct System::Impl { return init_result; } + telemetry_session->AddInitialInfo(*app_loader); auto main_process = Kernel::Process::Create(system, "main"); const auto [load_result, load_parameters] = app_loader->Load(*main_process); if (load_result != Loader::ResultStatus::Success) { diff --git a/src/core/core.h b/src/core/core.h index a9a756a4c..20959de54 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -98,7 +98,6 @@ public: Success, ///< Succeeded ErrorNotInitialized, ///< Error trying to use core prior to initialization ErrorGetLoader, ///< Error finding the correct application loader - ErrorSystemMode, ///< Error determining the system mode ErrorSystemFiles, ///< Error in finding system files ErrorSharedFont, ///< Error in finding shared font ErrorVideoCore, ///< Error in the video core diff --git a/src/core/core_timing_util.cpp b/src/core/core_timing_util.cpp index c0f08cddb..a10472a95 100644 --- a/src/core/core_timing_util.cpp +++ b/src/core/core_timing_util.cpp @@ -13,52 +13,40 @@ namespace Core::Timing { constexpr u64 MAX_VALUE_TO_MULTIPLY = std::numeric_limits<s64>::max() / BASE_CLOCK_RATE; -s64 usToCycles(s64 us) { - if (static_cast<u64>(us / 1000000) > MAX_VALUE_TO_MULTIPLY) { +s64 msToCycles(std::chrono::milliseconds ms) { + if (static_cast<u64>(ms.count() / 1000) > MAX_VALUE_TO_MULTIPLY) { LOG_ERROR(Core_Timing, "Integer overflow, use max value"); return std::numeric_limits<s64>::max(); } - if (static_cast<u64>(us) > MAX_VALUE_TO_MULTIPLY) { + if (static_cast<u64>(ms.count()) > MAX_VALUE_TO_MULTIPLY) { LOG_DEBUG(Core_Timing, "Time very big, do rounding"); - return BASE_CLOCK_RATE * (us / 1000000); + return BASE_CLOCK_RATE * (ms.count() / 1000); } - return (BASE_CLOCK_RATE * us) / 1000000; + return (BASE_CLOCK_RATE * ms.count()) / 1000; } -s64 usToCycles(u64 us) { - if (us / 1000000 > MAX_VALUE_TO_MULTIPLY) { +s64 usToCycles(std::chrono::microseconds us) { + if (static_cast<u64>(us.count() / 1000000) > MAX_VALUE_TO_MULTIPLY) { LOG_ERROR(Core_Timing, "Integer overflow, use max value"); return std::numeric_limits<s64>::max(); } - if (us > MAX_VALUE_TO_MULTIPLY) { + if (static_cast<u64>(us.count()) > MAX_VALUE_TO_MULTIPLY) { LOG_DEBUG(Core_Timing, "Time very big, do rounding"); - return BASE_CLOCK_RATE * static_cast<s64>(us / 1000000); + return BASE_CLOCK_RATE * (us.count() / 1000000); } - return (BASE_CLOCK_RATE * static_cast<s64>(us)) / 1000000; + return (BASE_CLOCK_RATE * us.count()) / 1000000; } -s64 nsToCycles(s64 ns) { - if (static_cast<u64>(ns / 1000000000) > MAX_VALUE_TO_MULTIPLY) { +s64 nsToCycles(std::chrono::nanoseconds ns) { + if (static_cast<u64>(ns.count() / 1000000000) > MAX_VALUE_TO_MULTIPLY) { LOG_ERROR(Core_Timing, "Integer overflow, use max value"); return std::numeric_limits<s64>::max(); } - if (static_cast<u64>(ns) > MAX_VALUE_TO_MULTIPLY) { + if (static_cast<u64>(ns.count()) > MAX_VALUE_TO_MULTIPLY) { LOG_DEBUG(Core_Timing, "Time very big, do rounding"); - return BASE_CLOCK_RATE * (ns / 1000000000); + return BASE_CLOCK_RATE * (ns.count() / 1000000000); } - return (BASE_CLOCK_RATE * ns) / 1000000000; -} - -s64 nsToCycles(u64 ns) { - if (ns / 1000000000 > MAX_VALUE_TO_MULTIPLY) { - LOG_ERROR(Core_Timing, "Integer overflow, use max value"); - return std::numeric_limits<s64>::max(); - } - if (ns > MAX_VALUE_TO_MULTIPLY) { - LOG_DEBUG(Core_Timing, "Time very big, do rounding"); - return BASE_CLOCK_RATE * (static_cast<s64>(ns) / 1000000000); - } - return (BASE_CLOCK_RATE * static_cast<s64>(ns)) / 1000000000; + return (BASE_CLOCK_RATE * ns.count()) / 1000000000; } u64 CpuCyclesToClockCycles(u64 ticks) { diff --git a/src/core/core_timing_util.h b/src/core/core_timing_util.h index 679aa3123..cdd84d70f 100644 --- a/src/core/core_timing_util.h +++ b/src/core/core_timing_util.h @@ -4,6 +4,7 @@ #pragma once +#include <chrono> #include "common/common_types.h" namespace Core::Timing { @@ -13,53 +14,20 @@ namespace Core::Timing { constexpr u64 BASE_CLOCK_RATE = 1019215872; // Switch clock speed is 1020MHz un/docked constexpr u64 CNTFREQ = 19200000; // Value from fusee. -inline s64 msToCycles(int ms) { - // since ms is int there is no way to overflow - return BASE_CLOCK_RATE * static_cast<s64>(ms) / 1000; -} - -inline s64 msToCycles(float ms) { - return static_cast<s64>(BASE_CLOCK_RATE * (0.001f) * ms); -} - -inline s64 msToCycles(double ms) { - return static_cast<s64>(BASE_CLOCK_RATE * (0.001) * ms); -} - -inline s64 usToCycles(float us) { - return static_cast<s64>(BASE_CLOCK_RATE * (0.000001f) * us); -} - -inline s64 usToCycles(int us) { - return (BASE_CLOCK_RATE * static_cast<s64>(us) / 1000000); -} - -s64 usToCycles(s64 us); - -s64 usToCycles(u64 us); - -inline s64 nsToCycles(float ns) { - return static_cast<s64>(BASE_CLOCK_RATE * (0.000000001f) * ns); -} - -inline s64 nsToCycles(int ns) { - return BASE_CLOCK_RATE * static_cast<s64>(ns) / 1000000000; -} - -s64 nsToCycles(s64 ns); - -s64 nsToCycles(u64 ns); +s64 msToCycles(std::chrono::milliseconds ms); +s64 usToCycles(std::chrono::microseconds us); +s64 nsToCycles(std::chrono::nanoseconds ns); -inline u64 cyclesToNs(s64 cycles) { - return cycles * 1000000000 / BASE_CLOCK_RATE; +inline std::chrono::milliseconds CyclesToMs(s64 cycles) { + return std::chrono::milliseconds(cycles * 1000 / BASE_CLOCK_RATE); } -inline s64 cyclesToUs(s64 cycles) { - return cycles * 1000000 / BASE_CLOCK_RATE; +inline std::chrono::nanoseconds CyclesToNs(s64 cycles) { + return std::chrono::nanoseconds(cycles * 1000000000 / BASE_CLOCK_RATE); } -inline u64 cyclesToMs(s64 cycles) { - return cycles * 1000 / BASE_CLOCK_RATE; +inline std::chrono::microseconds CyclesToUs(s64 cycles) { + return std::chrono::microseconds(cycles * 1000000 / BASE_CLOCK_RATE); } u64 CpuCyclesToClockCycles(u64 ticks); diff --git a/src/core/file_sys/control_metadata.cpp b/src/core/file_sys/control_metadata.cpp index 60ea9ad12..04da30825 100644 --- a/src/core/file_sys/control_metadata.cpp +++ b/src/core/file_sys/control_metadata.cpp @@ -87,6 +87,10 @@ u64 NACP::GetDefaultJournalSaveSize() const { return raw.user_account_save_data_journal_size; } +u32 NACP::GetSupportedLanguages() const { + return raw.supported_languages; +} + std::vector<u8> NACP::GetRawBytes() const { std::vector<u8> out(sizeof(RawNACP)); std::memcpy(out.data(), &raw, sizeof(RawNACP)); diff --git a/src/core/file_sys/control_metadata.h b/src/core/file_sys/control_metadata.h index 280710ddf..1be34ed55 100644 --- a/src/core/file_sys/control_metadata.h +++ b/src/core/file_sys/control_metadata.h @@ -109,6 +109,7 @@ public: std::string GetVersionString() const; u64 GetDefaultNormalSaveSize() const; u64 GetDefaultJournalSaveSize() const; + u32 GetSupportedLanguages() const; std::vector<u8> GetRawBytes() const; private: diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 2abf9efca..c73a40977 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -75,9 +75,9 @@ void Thread::WakeAfterDelay(s64 nanoseconds) { // This function might be called from any thread so we have to be cautious and use the // thread-safe version of ScheduleEvent. + const s64 cycles = Core::Timing::nsToCycles(std::chrono::nanoseconds{nanoseconds}); Core::System::GetInstance().CoreTiming().ScheduleEventThreadsafe( - Core::Timing::nsToCycles(nanoseconds), kernel.ThreadWakeupCallbackEventType(), - callback_handle); + cycles, kernel.ThreadWakeupCallbackEventType(), callback_handle); } void Thread::CancelWakeupTimer() { diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index 1a32a109f..3f201c821 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp @@ -8,6 +8,8 @@ #include <cstring> #include "audio_core/audio_renderer.h" #include "core/core.h" +#include "core/file_sys/control_metadata.h" +#include "core/file_sys/patch_manager.h" #include "core/file_sys/savedata_factory.h" #include "core/hle/ipc_helpers.h" #include "core/hle/kernel/kernel.h" @@ -29,9 +31,11 @@ #include "core/hle/service/am/tcap.h" #include "core/hle/service/apm/apm.h" #include "core/hle/service/filesystem/filesystem.h" +#include "core/hle/service/ns/ns.h" #include "core/hle/service/nvflinger/nvflinger.h" #include "core/hle/service/pm/pm.h" #include "core/hle/service/set/set.h" +#include "core/hle/service/sm/sm.h" #include "core/hle/service/vi/vi.h" #include "core/settings.h" @@ -1100,10 +1104,42 @@ void IApplicationFunctions::GetDesiredLanguage(Kernel::HLERequestContext& ctx) { // TODO(bunnei): This should be configurable LOG_DEBUG(Service_AM, "called"); + // Get supported languages from NACP, if possible + // Default to 0 (all languages supported) + u32 supported_languages = 0; + FileSys::PatchManager pm{Core::System::GetInstance().CurrentProcess()->GetTitleID()}; + + const auto res = pm.GetControlMetadata(); + if (res.first != nullptr) { + supported_languages = res.first->GetSupportedLanguages(); + } + + // Call IApplicationManagerInterface implementation. + auto& service_manager = Core::System::GetInstance().ServiceManager(); + auto ns_am2 = service_manager.GetService<Service::NS::NS>("ns:am2"); + auto app_man = ns_am2->GetApplicationManagerInterface(); + + // Get desired application language + const auto res_lang = app_man->GetApplicationDesiredLanguage(supported_languages); + if (res_lang.Failed()) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(res_lang.Code()); + return; + } + + // Convert to settings language code. + const auto res_code = app_man->ConvertApplicationLanguageToLanguageCode(*res_lang); + if (res_code.Failed()) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(res_code.Code()); + return; + } + + LOG_DEBUG(Service_AM, "got desired_language={:016X}", *res_code); + IPC::ResponseBuilder rb{ctx, 4}; rb.Push(RESULT_SUCCESS); - rb.Push( - static_cast<u64>(Service::Set::GetLanguageCodeFromIndex(Settings::values.language_index))); + rb.Push(*res_code); } void IApplicationFunctions::InitializeGamePlayRecording(Kernel::HLERequestContext& ctx) { diff --git a/src/core/hle/service/am/applets/applets.cpp b/src/core/hle/service/am/applets/applets.cpp index e812c66e9..14fa92318 100644 --- a/src/core/hle/service/am/applets/applets.cpp +++ b/src/core/hle/service/am/applets/applets.cpp @@ -121,6 +121,21 @@ void Applet::Initialize() { initialized = true; } +AppletFrontendSet::AppletFrontendSet() = default; + +AppletFrontendSet::AppletFrontendSet(ErrorApplet error, PhotoViewer photo_viewer, + ProfileSelect profile_select, + SoftwareKeyboard software_keyboard, WebBrowser web_browser) + : error{std::move(error)}, photo_viewer{std::move(photo_viewer)}, profile_select{std::move( + profile_select)}, + software_keyboard{std::move(software_keyboard)}, web_browser{std::move(web_browser)} {} + +AppletFrontendSet::~AppletFrontendSet() = default; + +AppletFrontendSet::AppletFrontendSet(AppletFrontendSet&&) noexcept = default; + +AppletFrontendSet& AppletFrontendSet::operator=(AppletFrontendSet&&) noexcept = default; + AppletManager::AppletManager() = default; AppletManager::~AppletManager() = default; diff --git a/src/core/hle/service/am/applets/applets.h b/src/core/hle/service/am/applets/applets.h index 7f932672c..b46e10a4a 100644 --- a/src/core/hle/service/am/applets/applets.h +++ b/src/core/hle/service/am/applets/applets.h @@ -137,11 +137,28 @@ protected: }; struct AppletFrontendSet { - std::unique_ptr<Core::Frontend::ErrorApplet> error; - std::unique_ptr<Core::Frontend::PhotoViewerApplet> photo_viewer; - std::unique_ptr<Core::Frontend::ProfileSelectApplet> profile_select; - std::unique_ptr<Core::Frontend::SoftwareKeyboardApplet> software_keyboard; - std::unique_ptr<Core::Frontend::WebBrowserApplet> web_browser; + using ErrorApplet = std::unique_ptr<Core::Frontend::ErrorApplet>; + using PhotoViewer = std::unique_ptr<Core::Frontend::PhotoViewerApplet>; + using ProfileSelect = std::unique_ptr<Core::Frontend::ProfileSelectApplet>; + using SoftwareKeyboard = std::unique_ptr<Core::Frontend::SoftwareKeyboardApplet>; + using WebBrowser = std::unique_ptr<Core::Frontend::WebBrowserApplet>; + + AppletFrontendSet(); + AppletFrontendSet(ErrorApplet error, PhotoViewer photo_viewer, ProfileSelect profile_select, + SoftwareKeyboard software_keyboard, WebBrowser web_browser); + ~AppletFrontendSet(); + + AppletFrontendSet(const AppletFrontendSet&) = delete; + AppletFrontendSet& operator=(const AppletFrontendSet&) = delete; + + AppletFrontendSet(AppletFrontendSet&&) noexcept; + AppletFrontendSet& operator=(AppletFrontendSet&&) noexcept; + + ErrorApplet error; + PhotoViewer photo_viewer; + ProfileSelect profile_select; + SoftwareKeyboard software_keyboard; + WebBrowser web_browser; }; class AppletManager { diff --git a/src/core/hle/service/ns/errors.h b/src/core/hle/service/ns/errors.h new file mode 100644 index 000000000..f4aea8a65 --- /dev/null +++ b/src/core/hle/service/ns/errors.h @@ -0,0 +1,12 @@ +// Copyright 2019 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/result.h" + +namespace Service::NS { + +constexpr ResultCode ERR_APPLICATION_LANGUAGE_NOT_FOUND{ErrorModule::NS, 300}; +}
\ No newline at end of file diff --git a/src/core/hle/service/ns/language.cpp b/src/core/hle/service/ns/language.cpp new file mode 100644 index 000000000..29c4a820c --- /dev/null +++ b/src/core/hle/service/ns/language.cpp @@ -0,0 +1,392 @@ +// Copyright 2019 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/service/ns/language.h" +#include "core/hle/service/set/set.h" + +namespace Service::NS { + +constexpr ApplicationLanguagePriorityList priority_list_american_english = {{ + ApplicationLanguage::AmericanEnglish, + ApplicationLanguage::BritishEnglish, + ApplicationLanguage::LatinAmericanSpanish, + ApplicationLanguage::CanadianFrench, + ApplicationLanguage::French, + ApplicationLanguage::German, + ApplicationLanguage::Spanish, + ApplicationLanguage::Italian, + ApplicationLanguage::Dutch, + ApplicationLanguage::Portuguese, + ApplicationLanguage::Russian, + ApplicationLanguage::Japanese, + ApplicationLanguage::SimplifiedChinese, + ApplicationLanguage::TraditionalChinese, + ApplicationLanguage::Korean, +}}; + +constexpr ApplicationLanguagePriorityList priority_list_british_english = {{ + ApplicationLanguage::BritishEnglish, + ApplicationLanguage::AmericanEnglish, + ApplicationLanguage::French, + ApplicationLanguage::German, + ApplicationLanguage::Spanish, + ApplicationLanguage::Italian, + ApplicationLanguage::Dutch, + ApplicationLanguage::Portuguese, + ApplicationLanguage::Russian, + ApplicationLanguage::LatinAmericanSpanish, + ApplicationLanguage::CanadianFrench, + ApplicationLanguage::Japanese, + ApplicationLanguage::SimplifiedChinese, + ApplicationLanguage::TraditionalChinese, + ApplicationLanguage::Korean, +}}; + +constexpr ApplicationLanguagePriorityList priority_list_japanese = {{ + ApplicationLanguage::Japanese, + ApplicationLanguage::AmericanEnglish, + ApplicationLanguage::BritishEnglish, + ApplicationLanguage::LatinAmericanSpanish, + ApplicationLanguage::CanadianFrench, + ApplicationLanguage::French, + ApplicationLanguage::German, + ApplicationLanguage::Spanish, + ApplicationLanguage::Italian, + ApplicationLanguage::Dutch, + ApplicationLanguage::Portuguese, + ApplicationLanguage::Russian, + ApplicationLanguage::SimplifiedChinese, + ApplicationLanguage::TraditionalChinese, + ApplicationLanguage::Korean, +}}; + +constexpr ApplicationLanguagePriorityList priority_list_french = {{ + ApplicationLanguage::French, + ApplicationLanguage::CanadianFrench, + ApplicationLanguage::BritishEnglish, + ApplicationLanguage::AmericanEnglish, + ApplicationLanguage::German, + ApplicationLanguage::Spanish, + ApplicationLanguage::Italian, + ApplicationLanguage::Dutch, + ApplicationLanguage::Portuguese, + ApplicationLanguage::Russian, + ApplicationLanguage::LatinAmericanSpanish, + ApplicationLanguage::Japanese, + ApplicationLanguage::SimplifiedChinese, + ApplicationLanguage::TraditionalChinese, + ApplicationLanguage::Korean, +}}; + +constexpr ApplicationLanguagePriorityList priority_list_german = {{ + ApplicationLanguage::German, + ApplicationLanguage::BritishEnglish, + ApplicationLanguage::AmericanEnglish, + ApplicationLanguage::French, + ApplicationLanguage::Spanish, + ApplicationLanguage::Italian, + ApplicationLanguage::Dutch, + ApplicationLanguage::Portuguese, + ApplicationLanguage::Russian, + ApplicationLanguage::LatinAmericanSpanish, + ApplicationLanguage::CanadianFrench, + ApplicationLanguage::Japanese, + ApplicationLanguage::SimplifiedChinese, + ApplicationLanguage::TraditionalChinese, + ApplicationLanguage::Korean, +}}; + +constexpr ApplicationLanguagePriorityList priority_list_latin_american_spanish = {{ + ApplicationLanguage::LatinAmericanSpanish, + ApplicationLanguage::Spanish, + ApplicationLanguage::AmericanEnglish, + ApplicationLanguage::BritishEnglish, + ApplicationLanguage::Portuguese, + ApplicationLanguage::CanadianFrench, + ApplicationLanguage::French, + ApplicationLanguage::Italian, + ApplicationLanguage::German, + ApplicationLanguage::Dutch, + ApplicationLanguage::Russian, + ApplicationLanguage::Japanese, + ApplicationLanguage::SimplifiedChinese, + ApplicationLanguage::TraditionalChinese, + ApplicationLanguage::Korean, +}}; + +constexpr ApplicationLanguagePriorityList priority_list_spanish = {{ + ApplicationLanguage::Spanish, + ApplicationLanguage::LatinAmericanSpanish, + ApplicationLanguage::BritishEnglish, + ApplicationLanguage::AmericanEnglish, + ApplicationLanguage::French, + ApplicationLanguage::German, + ApplicationLanguage::Italian, + ApplicationLanguage::Dutch, + ApplicationLanguage::Portuguese, + ApplicationLanguage::Russian, + ApplicationLanguage::CanadianFrench, + ApplicationLanguage::Japanese, + ApplicationLanguage::SimplifiedChinese, + ApplicationLanguage::TraditionalChinese, + ApplicationLanguage::Korean, +}}; + +constexpr ApplicationLanguagePriorityList priority_list_italian = {{ + ApplicationLanguage::Italian, + ApplicationLanguage::BritishEnglish, + ApplicationLanguage::AmericanEnglish, + ApplicationLanguage::French, + ApplicationLanguage::German, + ApplicationLanguage::Spanish, + ApplicationLanguage::Dutch, + ApplicationLanguage::Portuguese, + ApplicationLanguage::Russian, + ApplicationLanguage::LatinAmericanSpanish, + ApplicationLanguage::CanadianFrench, + ApplicationLanguage::Japanese, + ApplicationLanguage::SimplifiedChinese, + ApplicationLanguage::TraditionalChinese, + ApplicationLanguage::Korean, +}}; + +constexpr ApplicationLanguagePriorityList priority_list_dutch = {{ + ApplicationLanguage::Dutch, + ApplicationLanguage::BritishEnglish, + ApplicationLanguage::AmericanEnglish, + ApplicationLanguage::French, + ApplicationLanguage::German, + ApplicationLanguage::Spanish, + ApplicationLanguage::Italian, + ApplicationLanguage::Portuguese, + ApplicationLanguage::Russian, + ApplicationLanguage::LatinAmericanSpanish, + ApplicationLanguage::CanadianFrench, + ApplicationLanguage::Japanese, + ApplicationLanguage::SimplifiedChinese, + ApplicationLanguage::TraditionalChinese, + ApplicationLanguage::Korean, +}}; + +constexpr ApplicationLanguagePriorityList priority_list_canadian_french = {{ + ApplicationLanguage::CanadianFrench, + ApplicationLanguage::French, + ApplicationLanguage::AmericanEnglish, + ApplicationLanguage::BritishEnglish, + ApplicationLanguage::LatinAmericanSpanish, + ApplicationLanguage::Spanish, + ApplicationLanguage::German, + ApplicationLanguage::Italian, + ApplicationLanguage::Dutch, + ApplicationLanguage::Portuguese, + ApplicationLanguage::Russian, + ApplicationLanguage::Japanese, + ApplicationLanguage::SimplifiedChinese, + ApplicationLanguage::TraditionalChinese, + ApplicationLanguage::Korean, +}}; + +constexpr ApplicationLanguagePriorityList priority_list_portuguese = {{ + ApplicationLanguage::Portuguese, + ApplicationLanguage::BritishEnglish, + ApplicationLanguage::AmericanEnglish, + ApplicationLanguage::French, + ApplicationLanguage::German, + ApplicationLanguage::Spanish, + ApplicationLanguage::Italian, + ApplicationLanguage::Dutch, + ApplicationLanguage::Russian, + ApplicationLanguage::LatinAmericanSpanish, + ApplicationLanguage::CanadianFrench, + ApplicationLanguage::Japanese, + ApplicationLanguage::SimplifiedChinese, + ApplicationLanguage::TraditionalChinese, + ApplicationLanguage::Korean, +}}; + +constexpr ApplicationLanguagePriorityList priority_list_russian = {{ + ApplicationLanguage::Russian, + ApplicationLanguage::BritishEnglish, + ApplicationLanguage::AmericanEnglish, + ApplicationLanguage::French, + ApplicationLanguage::German, + ApplicationLanguage::Spanish, + ApplicationLanguage::Italian, + ApplicationLanguage::Dutch, + ApplicationLanguage::Portuguese, + ApplicationLanguage::LatinAmericanSpanish, + ApplicationLanguage::CanadianFrench, + ApplicationLanguage::Japanese, + ApplicationLanguage::SimplifiedChinese, + ApplicationLanguage::TraditionalChinese, + ApplicationLanguage::Korean, +}}; + +constexpr ApplicationLanguagePriorityList priority_list_korean = {{ + ApplicationLanguage::Korean, + ApplicationLanguage::AmericanEnglish, + ApplicationLanguage::BritishEnglish, + ApplicationLanguage::LatinAmericanSpanish, + ApplicationLanguage::CanadianFrench, + ApplicationLanguage::French, + ApplicationLanguage::German, + ApplicationLanguage::Spanish, + ApplicationLanguage::Italian, + ApplicationLanguage::Dutch, + ApplicationLanguage::Portuguese, + ApplicationLanguage::Russian, + ApplicationLanguage::Japanese, + ApplicationLanguage::SimplifiedChinese, + ApplicationLanguage::TraditionalChinese, +}}; + +constexpr ApplicationLanguagePriorityList priority_list_traditional_chinese = {{ + ApplicationLanguage::TraditionalChinese, + ApplicationLanguage::SimplifiedChinese, + ApplicationLanguage::AmericanEnglish, + ApplicationLanguage::BritishEnglish, + ApplicationLanguage::Japanese, + ApplicationLanguage::LatinAmericanSpanish, + ApplicationLanguage::CanadianFrench, + ApplicationLanguage::French, + ApplicationLanguage::German, + ApplicationLanguage::Spanish, + ApplicationLanguage::Italian, + ApplicationLanguage::Dutch, + ApplicationLanguage::Portuguese, + ApplicationLanguage::Russian, + ApplicationLanguage::Korean, +}}; + +constexpr ApplicationLanguagePriorityList priority_list_simplified_chinese = {{ + ApplicationLanguage::SimplifiedChinese, + ApplicationLanguage::TraditionalChinese, + ApplicationLanguage::AmericanEnglish, + ApplicationLanguage::BritishEnglish, + ApplicationLanguage::Japanese, + ApplicationLanguage::LatinAmericanSpanish, + ApplicationLanguage::CanadianFrench, + ApplicationLanguage::French, + ApplicationLanguage::German, + ApplicationLanguage::Spanish, + ApplicationLanguage::Italian, + ApplicationLanguage::Dutch, + ApplicationLanguage::Portuguese, + ApplicationLanguage::Russian, + ApplicationLanguage::Korean, +}}; + +const ApplicationLanguagePriorityList* GetApplicationLanguagePriorityList( + const ApplicationLanguage lang) { + switch (lang) { + case ApplicationLanguage::AmericanEnglish: + return &priority_list_american_english; + case ApplicationLanguage::BritishEnglish: + return &priority_list_british_english; + case ApplicationLanguage::Japanese: + return &priority_list_japanese; + case ApplicationLanguage::French: + return &priority_list_french; + case ApplicationLanguage::German: + return &priority_list_german; + case ApplicationLanguage::LatinAmericanSpanish: + return &priority_list_latin_american_spanish; + case ApplicationLanguage::Spanish: + return &priority_list_spanish; + case ApplicationLanguage::Italian: + return &priority_list_italian; + case ApplicationLanguage::Dutch: + return &priority_list_dutch; + case ApplicationLanguage::CanadianFrench: + return &priority_list_canadian_french; + case ApplicationLanguage::Portuguese: + return &priority_list_portuguese; + case ApplicationLanguage::Russian: + return &priority_list_russian; + case ApplicationLanguage::Korean: + return &priority_list_korean; + case ApplicationLanguage::TraditionalChinese: + return &priority_list_traditional_chinese; + case ApplicationLanguage::SimplifiedChinese: + return &priority_list_simplified_chinese; + default: + return nullptr; + } +} + +std::optional<ApplicationLanguage> ConvertToApplicationLanguage( + const Set::LanguageCode language_code) { + switch (language_code) { + case Set::LanguageCode::EN_US: + return ApplicationLanguage::AmericanEnglish; + case Set::LanguageCode::EN_GB: + return ApplicationLanguage::BritishEnglish; + case Set::LanguageCode::JA: + return ApplicationLanguage::Japanese; + case Set::LanguageCode::FR: + return ApplicationLanguage::French; + case Set::LanguageCode::DE: + return ApplicationLanguage::German; + case Set::LanguageCode::ES_419: + return ApplicationLanguage::LatinAmericanSpanish; + case Set::LanguageCode::ES: + return ApplicationLanguage::Spanish; + case Set::LanguageCode::IT: + return ApplicationLanguage::Italian; + case Set::LanguageCode::NL: + return ApplicationLanguage::Dutch; + case Set::LanguageCode::FR_CA: + return ApplicationLanguage::CanadianFrench; + case Set::LanguageCode::PT: + return ApplicationLanguage::Portuguese; + case Set::LanguageCode::RU: + return ApplicationLanguage::Russian; + case Set::LanguageCode::KO: + return ApplicationLanguage::Korean; + case Set::LanguageCode::ZH_HANT: + return ApplicationLanguage::TraditionalChinese; + case Set::LanguageCode::ZH_HANS: + return ApplicationLanguage::SimplifiedChinese; + default: + return std::nullopt; + } +} + +std::optional<Set::LanguageCode> ConvertToLanguageCode(const ApplicationLanguage lang) { + switch (lang) { + case ApplicationLanguage::AmericanEnglish: + return Set::LanguageCode::EN_US; + case ApplicationLanguage::BritishEnglish: + return Set::LanguageCode::EN_GB; + case ApplicationLanguage::Japanese: + return Set::LanguageCode::JA; + case ApplicationLanguage::French: + return Set::LanguageCode::FR; + case ApplicationLanguage::German: + return Set::LanguageCode::DE; + case ApplicationLanguage::LatinAmericanSpanish: + return Set::LanguageCode::ES_419; + case ApplicationLanguage::Spanish: + return Set::LanguageCode::ES; + case ApplicationLanguage::Italian: + return Set::LanguageCode::IT; + case ApplicationLanguage::Dutch: + return Set::LanguageCode::NL; + case ApplicationLanguage::CanadianFrench: + return Set::LanguageCode::FR_CA; + case ApplicationLanguage::Portuguese: + return Set::LanguageCode::PT; + case ApplicationLanguage::Russian: + return Set::LanguageCode::RU; + case ApplicationLanguage::Korean: + return Set::LanguageCode::KO; + case ApplicationLanguage::TraditionalChinese: + return Set::LanguageCode::ZH_HANT; + case ApplicationLanguage::SimplifiedChinese: + return Set::LanguageCode::ZH_HANS; + default: + return std::nullopt; + } +} +} // namespace Service::NS
\ No newline at end of file diff --git a/src/core/hle/service/ns/language.h b/src/core/hle/service/ns/language.h new file mode 100644 index 000000000..e9829f9d2 --- /dev/null +++ b/src/core/hle/service/ns/language.h @@ -0,0 +1,45 @@ +// Copyright 2019 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <optional> +#include <string> +#include "common/common_types.h" + +namespace Service::Set { +enum class LanguageCode : u64; +} + +namespace Service::NS { +/// This is nn::ns::detail::ApplicationLanguage +enum class ApplicationLanguage : u8 { + AmericanEnglish = 0, + BritishEnglish, + Japanese, + French, + German, + LatinAmericanSpanish, + Spanish, + Italian, + Dutch, + CanadianFrench, + Portuguese, + Russian, + Korean, + TraditionalChinese, + SimplifiedChinese, + Count +}; +using ApplicationLanguagePriorityList = + const std::array<ApplicationLanguage, static_cast<std::size_t>(ApplicationLanguage::Count)>; + +constexpr u32 GetSupportedLanguageFlag(const ApplicationLanguage lang) { + return 1U << static_cast<u32>(lang); +} + +const ApplicationLanguagePriorityList* GetApplicationLanguagePriorityList(ApplicationLanguage lang); +std::optional<ApplicationLanguage> ConvertToApplicationLanguage(Set::LanguageCode language_code); +std::optional<Set::LanguageCode> ConvertToLanguageCode(ApplicationLanguage lang); +} // namespace Service::NS
\ No newline at end of file diff --git a/src/core/hle/service/ns/ns.cpp b/src/core/hle/service/ns/ns.cpp index 0eb04037a..ce88a2941 100644 --- a/src/core/hle/service/ns/ns.cpp +++ b/src/core/hle/service/ns/ns.cpp @@ -7,445 +7,507 @@ #include "core/file_sys/patch_manager.h" #include "core/hle/ipc_helpers.h" #include "core/hle/kernel/hle_ipc.h" +#include "core/hle/service/ns/errors.h" +#include "core/hle/service/ns/language.h" #include "core/hle/service/ns/ns.h" #include "core/hle/service/ns/pl_u.h" +#include "core/hle/service/set/set.h" +#include "core/settings.h" namespace Service::NS { -class IAccountProxyInterface final : public ServiceFramework<IAccountProxyInterface> { -public: - explicit IAccountProxyInterface() : ServiceFramework{"IAccountProxyInterface"} { - // clang-format off - static const FunctionInfo functions[] = { - {0, nullptr, "CreateUserAccount"}, - }; - // clang-format on +IAccountProxyInterface::IAccountProxyInterface() : ServiceFramework{"IAccountProxyInterface"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, nullptr, "CreateUserAccount"}, + }; + // clang-format on - RegisterHandlers(functions); - } -}; + RegisterHandlers(functions); +} -class IApplicationManagerInterface final : public ServiceFramework<IApplicationManagerInterface> { -public: - explicit IApplicationManagerInterface() : ServiceFramework{"IApplicationManagerInterface"} { - // clang-format off - static const FunctionInfo functions[] = { - {0, nullptr, "ListApplicationRecord"}, - {1, nullptr, "GenerateApplicationRecordCount"}, - {2, nullptr, "GetApplicationRecordUpdateSystemEvent"}, - {3, nullptr, "GetApplicationViewDeprecated"}, - {4, nullptr, "DeleteApplicationEntity"}, - {5, nullptr, "DeleteApplicationCompletely"}, - {6, nullptr, "IsAnyApplicationEntityRedundant"}, - {7, nullptr, "DeleteRedundantApplicationEntity"}, - {8, nullptr, "IsApplicationEntityMovable"}, - {9, nullptr, "MoveApplicationEntity"}, - {11, nullptr, "CalculateApplicationOccupiedSize"}, - {16, nullptr, "PushApplicationRecord"}, - {17, nullptr, "ListApplicationRecordContentMeta"}, - {19, nullptr, "LaunchApplicationOld"}, - {21, nullptr, "GetApplicationContentPath"}, - {22, nullptr, "TerminateApplication"}, - {23, nullptr, "ResolveApplicationContentPath"}, - {26, nullptr, "BeginInstallApplication"}, - {27, nullptr, "DeleteApplicationRecord"}, - {30, nullptr, "RequestApplicationUpdateInfo"}, - {32, nullptr, "CancelApplicationDownload"}, - {33, nullptr, "ResumeApplicationDownload"}, - {35, nullptr, "UpdateVersionList"}, - {36, nullptr, "PushLaunchVersion"}, - {37, nullptr, "ListRequiredVersion"}, - {38, nullptr, "CheckApplicationLaunchVersion"}, - {39, nullptr, "CheckApplicationLaunchRights"}, - {40, nullptr, "GetApplicationLogoData"}, - {41, nullptr, "CalculateApplicationDownloadRequiredSize"}, - {42, nullptr, "CleanupSdCard"}, - {43, nullptr, "CheckSdCardMountStatus"}, - {44, nullptr, "GetSdCardMountStatusChangedEvent"}, - {45, nullptr, "GetGameCardAttachmentEvent"}, - {46, nullptr, "GetGameCardAttachmentInfo"}, - {47, nullptr, "GetTotalSpaceSize"}, - {48, nullptr, "GetFreeSpaceSize"}, - {49, nullptr, "GetSdCardRemovedEvent"}, - {52, nullptr, "GetGameCardUpdateDetectionEvent"}, - {53, nullptr, "DisableApplicationAutoDelete"}, - {54, nullptr, "EnableApplicationAutoDelete"}, - {55, nullptr, "GetApplicationDesiredLanguage"}, - {56, nullptr, "SetApplicationTerminateResult"}, - {57, nullptr, "ClearApplicationTerminateResult"}, - {58, nullptr, "GetLastSdCardMountUnexpectedResult"}, - {59, nullptr, "ConvertApplicationLanguageToLanguageCode"}, - {60, nullptr, "ConvertLanguageCodeToApplicationLanguage"}, - {61, nullptr, "GetBackgroundDownloadStressTaskInfo"}, - {62, nullptr, "GetGameCardStopper"}, - {63, nullptr, "IsSystemProgramInstalled"}, - {64, nullptr, "StartApplyDeltaTask"}, - {65, nullptr, "GetRequestServerStopper"}, - {66, nullptr, "GetBackgroundApplyDeltaStressTaskInfo"}, - {67, nullptr, "CancelApplicationApplyDelta"}, - {68, nullptr, "ResumeApplicationApplyDelta"}, - {69, nullptr, "CalculateApplicationApplyDeltaRequiredSize"}, - {70, nullptr, "ResumeAll"}, - {71, nullptr, "GetStorageSize"}, - {80, nullptr, "RequestDownloadApplication"}, - {81, nullptr, "RequestDownloadAddOnContent"}, - {82, nullptr, "DownloadApplication"}, - {83, nullptr, "CheckApplicationResumeRights"}, - {84, nullptr, "GetDynamicCommitEvent"}, - {85, nullptr, "RequestUpdateApplication2"}, - {86, nullptr, "EnableApplicationCrashReport"}, - {87, nullptr, "IsApplicationCrashReportEnabled"}, - {90, nullptr, "BoostSystemMemoryResourceLimit"}, - {91, nullptr, "DeprecatedLaunchApplication"}, - {92, nullptr, "GetRunningApplicationProgramId"}, - {93, nullptr, "GetMainApplicationProgramIndex"}, - {94, nullptr, "LaunchApplication"}, - {95, nullptr, "GetApplicationLaunchInfo"}, - {96, nullptr, "AcquireApplicationLaunchInfo"}, - {97, nullptr, "GetMainApplicationProgramIndex2"}, - {98, nullptr, "EnableApplicationAllThreadDumpOnCrash"}, - {100, nullptr, "ResetToFactorySettings"}, - {101, nullptr, "ResetToFactorySettingsWithoutUserSaveData"}, - {102, nullptr, "ResetToFactorySettingsForRefurbishment"}, - {200, nullptr, "CalculateUserSaveDataStatistics"}, - {201, nullptr, "DeleteUserSaveDataAll"}, - {210, nullptr, "DeleteUserSystemSaveData"}, - {211, nullptr, "DeleteSaveData"}, - {220, nullptr, "UnregisterNetworkServiceAccount"}, - {221, nullptr, "UnregisterNetworkServiceAccountWithUserSaveDataDeletion"}, - {300, nullptr, "GetApplicationShellEvent"}, - {301, nullptr, "PopApplicationShellEventInfo"}, - {302, nullptr, "LaunchLibraryApplet"}, - {303, nullptr, "TerminateLibraryApplet"}, - {304, nullptr, "LaunchSystemApplet"}, - {305, nullptr, "TerminateSystemApplet"}, - {306, nullptr, "LaunchOverlayApplet"}, - {307, nullptr, "TerminateOverlayApplet"}, - {400, &IApplicationManagerInterface::GetApplicationControlData, "GetApplicationControlData"}, - {401, nullptr, "InvalidateAllApplicationControlCache"}, - {402, nullptr, "RequestDownloadApplicationControlData"}, - {403, nullptr, "GetMaxApplicationControlCacheCount"}, - {404, nullptr, "InvalidateApplicationControlCache"}, - {405, nullptr, "ListApplicationControlCacheEntryInfo"}, - {406, nullptr, "GetApplicationControlProperty"}, - {502, nullptr, "RequestCheckGameCardRegistration"}, - {503, nullptr, "RequestGameCardRegistrationGoldPoint"}, - {504, nullptr, "RequestRegisterGameCard"}, - {505, nullptr, "GetGameCardMountFailureEvent"}, - {506, nullptr, "IsGameCardInserted"}, - {507, nullptr, "EnsureGameCardAccess"}, - {508, nullptr, "GetLastGameCardMountFailureResult"}, - {509, nullptr, "ListApplicationIdOnGameCard"}, - {600, nullptr, "CountApplicationContentMeta"}, - {601, nullptr, "ListApplicationContentMetaStatus"}, - {602, nullptr, "ListAvailableAddOnContent"}, - {603, nullptr, "GetOwnedApplicationContentMetaStatus"}, - {604, nullptr, "RegisterContentsExternalKey"}, - {605, nullptr, "ListApplicationContentMetaStatusWithRightsCheck"}, - {606, nullptr, "GetContentMetaStorage"}, - {607, nullptr, "ListAvailableAddOnContent"}, - {700, nullptr, "PushDownloadTaskList"}, - {701, nullptr, "ClearTaskStatusList"}, - {702, nullptr, "RequestDownloadTaskList"}, - {703, nullptr, "RequestEnsureDownloadTask"}, - {704, nullptr, "ListDownloadTaskStatus"}, - {705, nullptr, "RequestDownloadTaskListData"}, - {800, nullptr, "RequestVersionList"}, - {801, nullptr, "ListVersionList"}, - {802, nullptr, "RequestVersionListData"}, - {900, nullptr, "GetApplicationRecord"}, - {901, nullptr, "GetApplicationRecordProperty"}, - {902, nullptr, "EnableApplicationAutoUpdate"}, - {903, nullptr, "DisableApplicationAutoUpdate"}, - {904, nullptr, "TouchApplication"}, - {905, nullptr, "RequestApplicationUpdate"}, - {906, nullptr, "IsApplicationUpdateRequested"}, - {907, nullptr, "WithdrawApplicationUpdateRequest"}, - {908, nullptr, "ListApplicationRecordInstalledContentMeta"}, - {909, nullptr, "WithdrawCleanupAddOnContentsWithNoRightsRecommendation"}, - {910, nullptr, "HasApplicationRecord"}, - {911, nullptr, "SetPreInstalledApplication"}, - {912, nullptr, "ClearPreInstalledApplicationFlag"}, - {1000, nullptr, "RequestVerifyApplicationDeprecated"}, - {1001, nullptr, "CorruptApplicationForDebug"}, - {1002, nullptr, "RequestVerifyAddOnContentsRights"}, - {1003, nullptr, "RequestVerifyApplication"}, - {1004, nullptr, "CorruptContentForDebug"}, - {1200, nullptr, "NeedsUpdateVulnerability"}, - {1300, nullptr, "IsAnyApplicationEntityInstalled"}, - {1301, nullptr, "DeleteApplicationContentEntities"}, - {1302, nullptr, "CleanupUnrecordedApplicationEntity"}, - {1303, nullptr, "CleanupAddOnContentsWithNoRights"}, - {1304, nullptr, "DeleteApplicationContentEntity"}, - {1305, nullptr, "TryDeleteRunningApplicationEntity"}, - {1306, nullptr, "TryDeleteRunningApplicationCompletely"}, - {1307, nullptr, "TryDeleteRunningApplicationContentEntities"}, - {1308, nullptr, "DeleteApplicationCompletelyForDebug"}, - {1309, nullptr, "CleanupUnavailableAddOnContents"}, - {1400, nullptr, "PrepareShutdown"}, - {1500, nullptr, "FormatSdCard"}, - {1501, nullptr, "NeedsSystemUpdateToFormatSdCard"}, - {1502, nullptr, "GetLastSdCardFormatUnexpectedResult"}, - {1504, nullptr, "InsertSdCard"}, - {1505, nullptr, "RemoveSdCard"}, - {1600, nullptr, "GetSystemSeedForPseudoDeviceId"}, - {1601, nullptr, "ResetSystemSeedForPseudoDeviceId"}, - {1700, nullptr, "ListApplicationDownloadingContentMeta"}, - {1701, nullptr, "GetApplicationView"}, - {1702, nullptr, "GetApplicationDownloadTaskStatus"}, - {1703, nullptr, "GetApplicationViewDownloadErrorContext"}, - {1800, nullptr, "IsNotificationSetupCompleted"}, - {1801, nullptr, "GetLastNotificationInfoCount"}, - {1802, nullptr, "ListLastNotificationInfo"}, - {1803, nullptr, "ListNotificationTask"}, - {1900, nullptr, "IsActiveAccount"}, - {1901, nullptr, "RequestDownloadApplicationPrepurchasedRights"}, - {1902, nullptr, "GetApplicationTicketInfo"}, - {2000, nullptr, "GetSystemDeliveryInfo"}, - {2001, nullptr, "SelectLatestSystemDeliveryInfo"}, - {2002, nullptr, "VerifyDeliveryProtocolVersion"}, - {2003, nullptr, "GetApplicationDeliveryInfo"}, - {2004, nullptr, "HasAllContentsToDeliver"}, - {2005, nullptr, "CompareApplicationDeliveryInfo"}, - {2006, nullptr, "CanDeliverApplication"}, - {2007, nullptr, "ListContentMetaKeyToDeliverApplication"}, - {2008, nullptr, "NeedsSystemUpdateToDeliverApplication"}, - {2009, nullptr, "EstimateRequiredSize"}, - {2010, nullptr, "RequestReceiveApplication"}, - {2011, nullptr, "CommitReceiveApplication"}, - {2012, nullptr, "GetReceiveApplicationProgress"}, - {2013, nullptr, "RequestSendApplication"}, - {2014, nullptr, "GetSendApplicationProgress"}, - {2015, nullptr, "CompareSystemDeliveryInfo"}, - {2016, nullptr, "ListNotCommittedContentMeta"}, - {2017, nullptr, "CreateDownloadTask"}, - {2018, nullptr, "GetApplicationDeliveryInfoHash"}, - {2050, nullptr, "GetApplicationRightsOnClient"}, - {2100, nullptr, "GetApplicationTerminateResult"}, - {2101, nullptr, "GetRawApplicationTerminateResult"}, - {2150, nullptr, "CreateRightsEnvironment"}, - {2151, nullptr, "DestroyRightsEnvironment"}, - {2152, nullptr, "ActivateRightsEnvironment"}, - {2153, nullptr, "DeactivateRightsEnvironment"}, - {2154, nullptr, "ForceActivateRightsContextForExit"}, - {2160, nullptr, "AddTargetApplicationToRightsEnvironment"}, - {2161, nullptr, "SetUsersToRightsEnvironment"}, - {2170, nullptr, "GetRightsEnvironmentStatus"}, - {2171, nullptr, "GetRightsEnvironmentStatusChangedEvent"}, - {2180, nullptr, "RequestExtendRightsInRightsEnvironment"}, - {2181, nullptr, "GetLastResultOfExtendRightsInRightsEnvironment"}, - {2182, nullptr, "SetActiveRightsContextUsingStateToRightsEnvironment"}, - {2190, nullptr, "GetRightsEnvironmentHandleForApplication"}, - {2199, nullptr, "GetRightsEnvironmentCountForDebug"}, - {2200, nullptr, "GetGameCardApplicationCopyIdentifier"}, - {2201, nullptr, "GetInstalledApplicationCopyIdentifier"}, - {2250, nullptr, "RequestReportActiveELicence"}, - {2300, nullptr, "ListEventLog"}, - }; - // clang-format on +IAccountProxyInterface::~IAccountProxyInterface() = default; + +IApplicationManagerInterface::IApplicationManagerInterface() + : ServiceFramework{"IApplicationManagerInterface"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, nullptr, "ListApplicationRecord"}, + {1, nullptr, "GenerateApplicationRecordCount"}, + {2, nullptr, "GetApplicationRecordUpdateSystemEvent"}, + {3, nullptr, "GetApplicationViewDeprecated"}, + {4, nullptr, "DeleteApplicationEntity"}, + {5, nullptr, "DeleteApplicationCompletely"}, + {6, nullptr, "IsAnyApplicationEntityRedundant"}, + {7, nullptr, "DeleteRedundantApplicationEntity"}, + {8, nullptr, "IsApplicationEntityMovable"}, + {9, nullptr, "MoveApplicationEntity"}, + {11, nullptr, "CalculateApplicationOccupiedSize"}, + {16, nullptr, "PushApplicationRecord"}, + {17, nullptr, "ListApplicationRecordContentMeta"}, + {19, nullptr, "LaunchApplicationOld"}, + {21, nullptr, "GetApplicationContentPath"}, + {22, nullptr, "TerminateApplication"}, + {23, nullptr, "ResolveApplicationContentPath"}, + {26, nullptr, "BeginInstallApplication"}, + {27, nullptr, "DeleteApplicationRecord"}, + {30, nullptr, "RequestApplicationUpdateInfo"}, + {32, nullptr, "CancelApplicationDownload"}, + {33, nullptr, "ResumeApplicationDownload"}, + {35, nullptr, "UpdateVersionList"}, + {36, nullptr, "PushLaunchVersion"}, + {37, nullptr, "ListRequiredVersion"}, + {38, nullptr, "CheckApplicationLaunchVersion"}, + {39, nullptr, "CheckApplicationLaunchRights"}, + {40, nullptr, "GetApplicationLogoData"}, + {41, nullptr, "CalculateApplicationDownloadRequiredSize"}, + {42, nullptr, "CleanupSdCard"}, + {43, nullptr, "CheckSdCardMountStatus"}, + {44, nullptr, "GetSdCardMountStatusChangedEvent"}, + {45, nullptr, "GetGameCardAttachmentEvent"}, + {46, nullptr, "GetGameCardAttachmentInfo"}, + {47, nullptr, "GetTotalSpaceSize"}, + {48, nullptr, "GetFreeSpaceSize"}, + {49, nullptr, "GetSdCardRemovedEvent"}, + {52, nullptr, "GetGameCardUpdateDetectionEvent"}, + {53, nullptr, "DisableApplicationAutoDelete"}, + {54, nullptr, "EnableApplicationAutoDelete"}, + {55, &IApplicationManagerInterface::GetApplicationDesiredLanguage, "GetApplicationDesiredLanguage"}, + {56, nullptr, "SetApplicationTerminateResult"}, + {57, nullptr, "ClearApplicationTerminateResult"}, + {58, nullptr, "GetLastSdCardMountUnexpectedResult"}, + {59, &IApplicationManagerInterface::ConvertApplicationLanguageToLanguageCode, "ConvertApplicationLanguageToLanguageCode"}, + {60, nullptr, "ConvertLanguageCodeToApplicationLanguage"}, + {61, nullptr, "GetBackgroundDownloadStressTaskInfo"}, + {62, nullptr, "GetGameCardStopper"}, + {63, nullptr, "IsSystemProgramInstalled"}, + {64, nullptr, "StartApplyDeltaTask"}, + {65, nullptr, "GetRequestServerStopper"}, + {66, nullptr, "GetBackgroundApplyDeltaStressTaskInfo"}, + {67, nullptr, "CancelApplicationApplyDelta"}, + {68, nullptr, "ResumeApplicationApplyDelta"}, + {69, nullptr, "CalculateApplicationApplyDeltaRequiredSize"}, + {70, nullptr, "ResumeAll"}, + {71, nullptr, "GetStorageSize"}, + {80, nullptr, "RequestDownloadApplication"}, + {81, nullptr, "RequestDownloadAddOnContent"}, + {82, nullptr, "DownloadApplication"}, + {83, nullptr, "CheckApplicationResumeRights"}, + {84, nullptr, "GetDynamicCommitEvent"}, + {85, nullptr, "RequestUpdateApplication2"}, + {86, nullptr, "EnableApplicationCrashReport"}, + {87, nullptr, "IsApplicationCrashReportEnabled"}, + {90, nullptr, "BoostSystemMemoryResourceLimit"}, + {91, nullptr, "DeprecatedLaunchApplication"}, + {92, nullptr, "GetRunningApplicationProgramId"}, + {93, nullptr, "GetMainApplicationProgramIndex"}, + {94, nullptr, "LaunchApplication"}, + {95, nullptr, "GetApplicationLaunchInfo"}, + {96, nullptr, "AcquireApplicationLaunchInfo"}, + {97, nullptr, "GetMainApplicationProgramIndex2"}, + {98, nullptr, "EnableApplicationAllThreadDumpOnCrash"}, + {100, nullptr, "ResetToFactorySettings"}, + {101, nullptr, "ResetToFactorySettingsWithoutUserSaveData"}, + {102, nullptr, "ResetToFactorySettingsForRefurbishment"}, + {200, nullptr, "CalculateUserSaveDataStatistics"}, + {201, nullptr, "DeleteUserSaveDataAll"}, + {210, nullptr, "DeleteUserSystemSaveData"}, + {211, nullptr, "DeleteSaveData"}, + {220, nullptr, "UnregisterNetworkServiceAccount"}, + {221, nullptr, "UnregisterNetworkServiceAccountWithUserSaveDataDeletion"}, + {300, nullptr, "GetApplicationShellEvent"}, + {301, nullptr, "PopApplicationShellEventInfo"}, + {302, nullptr, "LaunchLibraryApplet"}, + {303, nullptr, "TerminateLibraryApplet"}, + {304, nullptr, "LaunchSystemApplet"}, + {305, nullptr, "TerminateSystemApplet"}, + {306, nullptr, "LaunchOverlayApplet"}, + {307, nullptr, "TerminateOverlayApplet"}, + {400, &IApplicationManagerInterface::GetApplicationControlData, "GetApplicationControlData"}, + {401, nullptr, "InvalidateAllApplicationControlCache"}, + {402, nullptr, "RequestDownloadApplicationControlData"}, + {403, nullptr, "GetMaxApplicationControlCacheCount"}, + {404, nullptr, "InvalidateApplicationControlCache"}, + {405, nullptr, "ListApplicationControlCacheEntryInfo"}, + {406, nullptr, "GetApplicationControlProperty"}, + {502, nullptr, "RequestCheckGameCardRegistration"}, + {503, nullptr, "RequestGameCardRegistrationGoldPoint"}, + {504, nullptr, "RequestRegisterGameCard"}, + {505, nullptr, "GetGameCardMountFailureEvent"}, + {506, nullptr, "IsGameCardInserted"}, + {507, nullptr, "EnsureGameCardAccess"}, + {508, nullptr, "GetLastGameCardMountFailureResult"}, + {509, nullptr, "ListApplicationIdOnGameCard"}, + {600, nullptr, "CountApplicationContentMeta"}, + {601, nullptr, "ListApplicationContentMetaStatus"}, + {602, nullptr, "ListAvailableAddOnContent"}, + {603, nullptr, "GetOwnedApplicationContentMetaStatus"}, + {604, nullptr, "RegisterContentsExternalKey"}, + {605, nullptr, "ListApplicationContentMetaStatusWithRightsCheck"}, + {606, nullptr, "GetContentMetaStorage"}, + {607, nullptr, "ListAvailableAddOnContent"}, + {700, nullptr, "PushDownloadTaskList"}, + {701, nullptr, "ClearTaskStatusList"}, + {702, nullptr, "RequestDownloadTaskList"}, + {703, nullptr, "RequestEnsureDownloadTask"}, + {704, nullptr, "ListDownloadTaskStatus"}, + {705, nullptr, "RequestDownloadTaskListData"}, + {800, nullptr, "RequestVersionList"}, + {801, nullptr, "ListVersionList"}, + {802, nullptr, "RequestVersionListData"}, + {900, nullptr, "GetApplicationRecord"}, + {901, nullptr, "GetApplicationRecordProperty"}, + {902, nullptr, "EnableApplicationAutoUpdate"}, + {903, nullptr, "DisableApplicationAutoUpdate"}, + {904, nullptr, "TouchApplication"}, + {905, nullptr, "RequestApplicationUpdate"}, + {906, nullptr, "IsApplicationUpdateRequested"}, + {907, nullptr, "WithdrawApplicationUpdateRequest"}, + {908, nullptr, "ListApplicationRecordInstalledContentMeta"}, + {909, nullptr, "WithdrawCleanupAddOnContentsWithNoRightsRecommendation"}, + {910, nullptr, "HasApplicationRecord"}, + {911, nullptr, "SetPreInstalledApplication"}, + {912, nullptr, "ClearPreInstalledApplicationFlag"}, + {1000, nullptr, "RequestVerifyApplicationDeprecated"}, + {1001, nullptr, "CorruptApplicationForDebug"}, + {1002, nullptr, "RequestVerifyAddOnContentsRights"}, + {1003, nullptr, "RequestVerifyApplication"}, + {1004, nullptr, "CorruptContentForDebug"}, + {1200, nullptr, "NeedsUpdateVulnerability"}, + {1300, nullptr, "IsAnyApplicationEntityInstalled"}, + {1301, nullptr, "DeleteApplicationContentEntities"}, + {1302, nullptr, "CleanupUnrecordedApplicationEntity"}, + {1303, nullptr, "CleanupAddOnContentsWithNoRights"}, + {1304, nullptr, "DeleteApplicationContentEntity"}, + {1305, nullptr, "TryDeleteRunningApplicationEntity"}, + {1306, nullptr, "TryDeleteRunningApplicationCompletely"}, + {1307, nullptr, "TryDeleteRunningApplicationContentEntities"}, + {1308, nullptr, "DeleteApplicationCompletelyForDebug"}, + {1309, nullptr, "CleanupUnavailableAddOnContents"}, + {1400, nullptr, "PrepareShutdown"}, + {1500, nullptr, "FormatSdCard"}, + {1501, nullptr, "NeedsSystemUpdateToFormatSdCard"}, + {1502, nullptr, "GetLastSdCardFormatUnexpectedResult"}, + {1504, nullptr, "InsertSdCard"}, + {1505, nullptr, "RemoveSdCard"}, + {1600, nullptr, "GetSystemSeedForPseudoDeviceId"}, + {1601, nullptr, "ResetSystemSeedForPseudoDeviceId"}, + {1700, nullptr, "ListApplicationDownloadingContentMeta"}, + {1701, nullptr, "GetApplicationView"}, + {1702, nullptr, "GetApplicationDownloadTaskStatus"}, + {1703, nullptr, "GetApplicationViewDownloadErrorContext"}, + {1800, nullptr, "IsNotificationSetupCompleted"}, + {1801, nullptr, "GetLastNotificationInfoCount"}, + {1802, nullptr, "ListLastNotificationInfo"}, + {1803, nullptr, "ListNotificationTask"}, + {1900, nullptr, "IsActiveAccount"}, + {1901, nullptr, "RequestDownloadApplicationPrepurchasedRights"}, + {1902, nullptr, "GetApplicationTicketInfo"}, + {2000, nullptr, "GetSystemDeliveryInfo"}, + {2001, nullptr, "SelectLatestSystemDeliveryInfo"}, + {2002, nullptr, "VerifyDeliveryProtocolVersion"}, + {2003, nullptr, "GetApplicationDeliveryInfo"}, + {2004, nullptr, "HasAllContentsToDeliver"}, + {2005, nullptr, "CompareApplicationDeliveryInfo"}, + {2006, nullptr, "CanDeliverApplication"}, + {2007, nullptr, "ListContentMetaKeyToDeliverApplication"}, + {2008, nullptr, "NeedsSystemUpdateToDeliverApplication"}, + {2009, nullptr, "EstimateRequiredSize"}, + {2010, nullptr, "RequestReceiveApplication"}, + {2011, nullptr, "CommitReceiveApplication"}, + {2012, nullptr, "GetReceiveApplicationProgress"}, + {2013, nullptr, "RequestSendApplication"}, + {2014, nullptr, "GetSendApplicationProgress"}, + {2015, nullptr, "CompareSystemDeliveryInfo"}, + {2016, nullptr, "ListNotCommittedContentMeta"}, + {2017, nullptr, "CreateDownloadTask"}, + {2018, nullptr, "GetApplicationDeliveryInfoHash"}, + {2050, nullptr, "GetApplicationRightsOnClient"}, + {2100, nullptr, "GetApplicationTerminateResult"}, + {2101, nullptr, "GetRawApplicationTerminateResult"}, + {2150, nullptr, "CreateRightsEnvironment"}, + {2151, nullptr, "DestroyRightsEnvironment"}, + {2152, nullptr, "ActivateRightsEnvironment"}, + {2153, nullptr, "DeactivateRightsEnvironment"}, + {2154, nullptr, "ForceActivateRightsContextForExit"}, + {2160, nullptr, "AddTargetApplicationToRightsEnvironment"}, + {2161, nullptr, "SetUsersToRightsEnvironment"}, + {2170, nullptr, "GetRightsEnvironmentStatus"}, + {2171, nullptr, "GetRightsEnvironmentStatusChangedEvent"}, + {2180, nullptr, "RequestExtendRightsInRightsEnvironment"}, + {2181, nullptr, "GetLastResultOfExtendRightsInRightsEnvironment"}, + {2182, nullptr, "SetActiveRightsContextUsingStateToRightsEnvironment"}, + {2190, nullptr, "GetRightsEnvironmentHandleForApplication"}, + {2199, nullptr, "GetRightsEnvironmentCountForDebug"}, + {2200, nullptr, "GetGameCardApplicationCopyIdentifier"}, + {2201, nullptr, "GetInstalledApplicationCopyIdentifier"}, + {2250, nullptr, "RequestReportActiveELicence"}, + {2300, nullptr, "ListEventLog"}, + }; + // clang-format on + + RegisterHandlers(functions); +} - RegisterHandlers(functions); - } +IApplicationManagerInterface::~IApplicationManagerInterface() = default; + +void IApplicationManagerInterface::GetApplicationControlData(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto flag = rp.PopRaw<u64>(); + LOG_DEBUG(Service_NS, "called with flag={:016X}", flag); - void GetApplicationControlData(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto flag = rp.PopRaw<u64>(); - LOG_DEBUG(Service_NS, "called with flag={:016X}", flag); - - const auto title_id = rp.PopRaw<u64>(); - - const auto size = ctx.GetWriteBufferSize(); - - const FileSys::PatchManager pm{title_id}; - const auto control = pm.GetControlMetadata(); - - std::vector<u8> out; - - if (control.first != nullptr) { - if (size < 0x4000) { - LOG_ERROR(Service_NS, - "output buffer is too small! (actual={:016X}, expected_min=0x4000)", - size); - IPC::ResponseBuilder rb{ctx, 2}; - // TODO(DarkLordZach): Find a better error code for this. - rb.Push(ResultCode(-1)); - return; - } - - out.resize(0x4000); - const auto bytes = control.first->GetRawBytes(); - std::memcpy(out.data(), bytes.data(), bytes.size()); - } else { - LOG_WARNING(Service_NS, "missing NACP data for title_id={:016X}, defaulting to zeros.", - title_id); - out.resize(std::min<u64>(0x4000, size)); + const auto title_id = rp.PopRaw<u64>(); + + const auto size = ctx.GetWriteBufferSize(); + + const FileSys::PatchManager pm{title_id}; + const auto control = pm.GetControlMetadata(); + + std::vector<u8> out; + + if (control.first != nullptr) { + if (size < 0x4000) { + LOG_ERROR(Service_NS, + "output buffer is too small! (actual={:016X}, expected_min=0x4000)", size); + IPC::ResponseBuilder rb{ctx, 2}; + // TODO(DarkLordZach): Find a better error code for this. + rb.Push(ResultCode(-1)); + return; } - if (control.second != nullptr) { - if (size < 0x4000 + control.second->GetSize()) { - LOG_ERROR(Service_NS, - "output buffer is too small! (actual={:016X}, expected_min={:016X})", - size, 0x4000 + control.second->GetSize()); - IPC::ResponseBuilder rb{ctx, 2}; - // TODO(DarkLordZach): Find a better error code for this. - rb.Push(ResultCode(-1)); - return; - } - - out.resize(0x4000 + control.second->GetSize()); - control.second->Read(out.data() + 0x4000, control.second->GetSize()); - } else { - LOG_WARNING(Service_NS, "missing icon data for title_id={:016X}, defaulting to zeros.", - title_id); + out.resize(0x4000); + const auto bytes = control.first->GetRawBytes(); + std::memcpy(out.data(), bytes.data(), bytes.size()); + } else { + LOG_WARNING(Service_NS, "missing NACP data for title_id={:016X}, defaulting to zeros.", + title_id); + out.resize(std::min<u64>(0x4000, size)); + } + + if (control.second != nullptr) { + if (size < 0x4000 + control.second->GetSize()) { + LOG_ERROR(Service_NS, + "output buffer is too small! (actual={:016X}, expected_min={:016X})", size, + 0x4000 + control.second->GetSize()); + IPC::ResponseBuilder rb{ctx, 2}; + // TODO(DarkLordZach): Find a better error code for this. + rb.Push(ResultCode(-1)); + return; } - ctx.WriteBuffer(out); + out.resize(0x4000 + control.second->GetSize()); + control.second->Read(out.data() + 0x4000, control.second->GetSize()); + } else { + LOG_WARNING(Service_NS, "missing icon data for title_id={:016X}, defaulting to zeros.", + title_id); + } + + ctx.WriteBuffer(out); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(RESULT_SUCCESS); + rb.Push<u32>(static_cast<u32>(out.size())); +} + +void IApplicationManagerInterface::GetApplicationDesiredLanguage(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto supported_languages = rp.Pop<u32>(); + const auto res = GetApplicationDesiredLanguage(supported_languages); + if (res.Succeeded()) { IPC::ResponseBuilder rb{ctx, 3}; rb.Push(RESULT_SUCCESS); - rb.Push<u32>(static_cast<u32>(out.size())); + rb.Push<u32>(*res); + } else { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(res.Code()); } -}; +} -class IApplicationVersionInterface final : public ServiceFramework<IApplicationVersionInterface> { -public: - explicit IApplicationVersionInterface() : ServiceFramework{"IApplicationVersionInterface"} { - // clang-format off - static const FunctionInfo functions[] = { - {0, nullptr, "GetLaunchRequiredVersion"}, - {1, nullptr, "UpgradeLaunchRequiredVersion"}, - {35, nullptr, "UpdateVersionList"}, - {36, nullptr, "PushLaunchVersion"}, - {37, nullptr, "ListRequiredVersion"}, - {800, nullptr, "RequestVersionList"}, - {801, nullptr, "ListVersionList"}, - {802, nullptr, "RequestVersionListData"}, - {1000, nullptr, "PerformAutoUpdate"}, - }; - // clang-format on +ResultVal<u8> IApplicationManagerInterface::GetApplicationDesiredLanguage( + const u32 supported_languages) { + LOG_DEBUG(Service_NS, "called with supported_languages={:08X}", supported_languages); - RegisterHandlers(functions); - } -}; + // Get language code from settings + const auto language_code = Set::GetLanguageCodeFromIndex(Settings::values.language_index); -class IContentManagerInterface final : public ServiceFramework<IContentManagerInterface> { -public: - explicit IContentManagerInterface() : ServiceFramework{"IContentManagerInterface"} { - // clang-format off - static const FunctionInfo functions[] = { - {11, nullptr, "CalculateApplicationOccupiedSize"}, - {43, nullptr, "CheckSdCardMountStatus"}, - {47, nullptr, "GetTotalSpaceSize"}, - {48, nullptr, "GetFreeSpaceSize"}, - {600, nullptr, "CountApplicationContentMeta"}, - {601, nullptr, "ListApplicationContentMetaStatus"}, - {605, nullptr, "ListApplicationContentMetaStatusWithRightsCheck"}, - {607, nullptr, "IsAnyApplicationRunning"}, - }; - // clang-format on + // Convert to application language, get priority list + const auto application_language = ConvertToApplicationLanguage(language_code); + if (application_language == std::nullopt) { + return ERR_APPLICATION_LANGUAGE_NOT_FOUND; + } + const auto priority_list = GetApplicationLanguagePriorityList(*application_language); + if (!priority_list) { + return ERR_APPLICATION_LANGUAGE_NOT_FOUND; + } - RegisterHandlers(functions); + // Try to find a valid language. + for (const auto lang : *priority_list) { + const auto supported_flag = GetSupportedLanguageFlag(lang); + if (supported_languages == 0 || (supported_languages & supported_flag) == supported_flag) { + return MakeResult(static_cast<u8>(lang)); + } } -}; -class IDocumentInterface final : public ServiceFramework<IDocumentInterface> { -public: - explicit IDocumentInterface() : ServiceFramework{"IDocumentInterface"} { - // clang-format off - static const FunctionInfo functions[] = { - {21, nullptr, "GetApplicationContentPath"}, - {23, nullptr, "ResolveApplicationContentPath"}, - {93, nullptr, "GetRunningApplicationProgramId"}, - }; - // clang-format on + return ERR_APPLICATION_LANGUAGE_NOT_FOUND; +} - RegisterHandlers(functions); - } -}; +void IApplicationManagerInterface::ConvertApplicationLanguageToLanguageCode( + Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto application_language = rp.Pop<u8>(); -class IDownloadTaskInterface final : public ServiceFramework<IDownloadTaskInterface> { -public: - explicit IDownloadTaskInterface() : ServiceFramework{"IDownloadTaskInterface"} { - // clang-format off - static const FunctionInfo functions[] = { - {701, nullptr, "ClearTaskStatusList"}, - {702, nullptr, "RequestDownloadTaskList"}, - {703, nullptr, "RequestEnsureDownloadTask"}, - {704, nullptr, "ListDownloadTaskStatus"}, - {705, nullptr, "RequestDownloadTaskListData"}, - {706, nullptr, "TryCommitCurrentApplicationDownloadTask"}, - {707, nullptr, "EnableAutoCommit"}, - {708, nullptr, "DisableAutoCommit"}, - {709, nullptr, "TriggerDynamicCommitEvent"}, - }; - // clang-format on + const auto res = ConvertApplicationLanguageToLanguageCode(application_language); + if (res.Succeeded()) { + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(RESULT_SUCCESS); + rb.Push(*res); + } else { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(res.Code()); + } +} - RegisterHandlers(functions); +ResultVal<u64> IApplicationManagerInterface::ConvertApplicationLanguageToLanguageCode( + u8 application_language) { + const auto language_code = + ConvertToLanguageCode(static_cast<ApplicationLanguage>(application_language)); + if (language_code == std::nullopt) { + return ERR_APPLICATION_LANGUAGE_NOT_FOUND; } -}; -class IECommerceInterface final : public ServiceFramework<IECommerceInterface> { -public: - explicit IECommerceInterface() : ServiceFramework{"IECommerceInterface"} { - // clang-format off - static const FunctionInfo functions[] = { - {0, nullptr, "RequestLinkDevice"}, - {1, nullptr, "RequestCleanupAllPreInstalledApplications"}, - {2, nullptr, "RequestCleanupPreInstalledApplication"}, - {3, nullptr, "RequestSyncRights"}, - {4, nullptr, "RequestUnlinkDevice"}, - {5, nullptr, "RequestRevokeAllELicense"}, - }; - // clang-format on + return MakeResult(static_cast<u64>(*language_code)); +} - RegisterHandlers(functions); - } -}; +IApplicationVersionInterface::IApplicationVersionInterface() + : ServiceFramework{"IApplicationVersionInterface"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, nullptr, "GetLaunchRequiredVersion"}, + {1, nullptr, "UpgradeLaunchRequiredVersion"}, + {35, nullptr, "UpdateVersionList"}, + {36, nullptr, "PushLaunchVersion"}, + {37, nullptr, "ListRequiredVersion"}, + {800, nullptr, "RequestVersionList"}, + {801, nullptr, "ListVersionList"}, + {802, nullptr, "RequestVersionListData"}, + {1000, nullptr, "PerformAutoUpdate"}, + }; + // clang-format on + + RegisterHandlers(functions); +} -class IFactoryResetInterface final : public ServiceFramework<IFactoryResetInterface> { -public: - explicit IFactoryResetInterface() : ServiceFramework{"IFactoryResetInterface"} { - // clang-format off +IApplicationVersionInterface::~IApplicationVersionInterface() = default; + +IContentManagerInterface::IContentManagerInterface() + : ServiceFramework{"IContentManagerInterface"} { + // clang-format off + static const FunctionInfo functions[] = { + {11, nullptr, "CalculateApplicationOccupiedSize"}, + {43, nullptr, "CheckSdCardMountStatus"}, + {47, nullptr, "GetTotalSpaceSize"}, + {48, nullptr, "GetFreeSpaceSize"}, + {600, nullptr, "CountApplicationContentMeta"}, + {601, nullptr, "ListApplicationContentMetaStatus"}, + {605, nullptr, "ListApplicationContentMetaStatusWithRightsCheck"}, + {607, nullptr, "IsAnyApplicationRunning"}, + }; + // clang-format on + + RegisterHandlers(functions); +} + +IContentManagerInterface::~IContentManagerInterface() = default; + +IDocumentInterface::IDocumentInterface() : ServiceFramework{"IDocumentInterface"} { + // clang-format off + static const FunctionInfo functions[] = { + {21, nullptr, "GetApplicationContentPath"}, + {23, nullptr, "ResolveApplicationContentPath"}, + {93, nullptr, "GetRunningApplicationProgramId"}, + }; + // clang-format on + + RegisterHandlers(functions); +} + +IDocumentInterface::~IDocumentInterface() = default; + +IDownloadTaskInterface::IDownloadTaskInterface() : ServiceFramework{"IDownloadTaskInterface"} { + // clang-format off + static const FunctionInfo functions[] = { + {701, nullptr, "ClearTaskStatusList"}, + {702, nullptr, "RequestDownloadTaskList"}, + {703, nullptr, "RequestEnsureDownloadTask"}, + {704, nullptr, "ListDownloadTaskStatus"}, + {705, nullptr, "RequestDownloadTaskListData"}, + {706, nullptr, "TryCommitCurrentApplicationDownloadTask"}, + {707, nullptr, "EnableAutoCommit"}, + {708, nullptr, "DisableAutoCommit"}, + {709, nullptr, "TriggerDynamicCommitEvent"}, + }; + // clang-format on + + RegisterHandlers(functions); +} + +IDownloadTaskInterface::~IDownloadTaskInterface() = default; + +IECommerceInterface::IECommerceInterface() : ServiceFramework{"IECommerceInterface"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, nullptr, "RequestLinkDevice"}, + {1, nullptr, "RequestCleanupAllPreInstalledApplications"}, + {2, nullptr, "RequestCleanupPreInstalledApplication"}, + {3, nullptr, "RequestSyncRights"}, + {4, nullptr, "RequestUnlinkDevice"}, + {5, nullptr, "RequestRevokeAllELicense"}, + }; + // clang-format on + + RegisterHandlers(functions); +} + +IECommerceInterface::~IECommerceInterface() = default; + +IFactoryResetInterface::IFactoryResetInterface::IFactoryResetInterface() + : ServiceFramework{"IFactoryResetInterface"} { + // clang-format off static const FunctionInfo functions[] = { {100, nullptr, "ResetToFactorySettings"}, {101, nullptr, "ResetToFactorySettingsWithoutUserSaveData"}, {102, nullptr, "ResetToFactorySettingsForRefurbishment"}, }; - // clang-format on + // clang-format on - RegisterHandlers(functions); - } -}; - -class NS final : public ServiceFramework<NS> { -public: - explicit NS(const char* name) : ServiceFramework{name} { - // clang-format off - static const FunctionInfo functions[] = { - {7992, &NS::PushInterface<IECommerceInterface>, "GetECommerceInterface"}, - {7993, &NS::PushInterface<IApplicationVersionInterface>, "GetApplicationVersionInterface"}, - {7994, &NS::PushInterface<IFactoryResetInterface>, "GetFactoryResetInterface"}, - {7995, &NS::PushInterface<IAccountProxyInterface>, "GetAccountProxyInterface"}, - {7996, &NS::PushInterface<IApplicationManagerInterface>, "GetApplicationManagerInterface"}, - {7997, &NS::PushInterface<IDownloadTaskInterface>, "GetDownloadTaskInterface"}, - {7998, &NS::PushInterface<IContentManagerInterface>, "GetContentManagementInterface"}, - {7999, &NS::PushInterface<IDocumentInterface>, "GetDocumentInterface"}, - }; - // clang-format on + RegisterHandlers(functions); +} - RegisterHandlers(functions); - } +IFactoryResetInterface::~IFactoryResetInterface() = default; + +NS::NS(const char* name) : ServiceFramework{name} { + // clang-format off + static const FunctionInfo functions[] = { + {7992, &NS::PushInterface<IECommerceInterface>, "GetECommerceInterface"}, + {7993, &NS::PushInterface<IApplicationVersionInterface>, "GetApplicationVersionInterface"}, + {7994, &NS::PushInterface<IFactoryResetInterface>, "GetFactoryResetInterface"}, + {7995, &NS::PushInterface<IAccountProxyInterface>, "GetAccountProxyInterface"}, + {7996, &NS::PushInterface<IApplicationManagerInterface>, "GetApplicationManagerInterface"}, + {7997, &NS::PushInterface<IDownloadTaskInterface>, "GetDownloadTaskInterface"}, + {7998, &NS::PushInterface<IContentManagerInterface>, "GetContentManagementInterface"}, + {7999, &NS::PushInterface<IDocumentInterface>, "GetDocumentInterface"}, + }; + // clang-format on + + RegisterHandlers(functions); +} -private: - template <typename T> - void PushInterface(Kernel::HLERequestContext& ctx) { - LOG_DEBUG(Service_NS, "called"); +NS::~NS() = default; - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(RESULT_SUCCESS); - rb.PushIpcInterface<T>(); - } -}; +std::shared_ptr<IApplicationManagerInterface> NS::GetApplicationManagerInterface() const { + return GetInterface<IApplicationManagerInterface>(); +} class NS_DEV final : public ServiceFramework<NS_DEV> { public: diff --git a/src/core/hle/service/ns/ns.h b/src/core/hle/service/ns/ns.h index b81ca8f1e..0f4bab4cb 100644 --- a/src/core/hle/service/ns/ns.h +++ b/src/core/hle/service/ns/ns.h @@ -8,6 +8,88 @@ namespace Service::NS { +class IAccountProxyInterface final : public ServiceFramework<IAccountProxyInterface> { +public: + explicit IAccountProxyInterface(); + ~IAccountProxyInterface(); +}; + +class IApplicationManagerInterface final : public ServiceFramework<IApplicationManagerInterface> { +public: + explicit IApplicationManagerInterface(); + ~IApplicationManagerInterface(); + + ResultVal<u8> GetApplicationDesiredLanguage(u32 supported_languages); + ResultVal<u64> ConvertApplicationLanguageToLanguageCode(u8 application_language); + +private: + void GetApplicationControlData(Kernel::HLERequestContext& ctx); + void GetApplicationDesiredLanguage(Kernel::HLERequestContext& ctx); + void ConvertApplicationLanguageToLanguageCode(Kernel::HLERequestContext& ctx); +}; + +class IApplicationVersionInterface final : public ServiceFramework<IApplicationVersionInterface> { +public: + explicit IApplicationVersionInterface(); + ~IApplicationVersionInterface(); +}; + +class IContentManagerInterface final : public ServiceFramework<IContentManagerInterface> { +public: + explicit IContentManagerInterface(); + ~IContentManagerInterface(); +}; + +class IDocumentInterface final : public ServiceFramework<IDocumentInterface> { +public: + explicit IDocumentInterface(); + ~IDocumentInterface(); +}; + +class IDownloadTaskInterface final : public ServiceFramework<IDownloadTaskInterface> { +public: + explicit IDownloadTaskInterface(); + ~IDownloadTaskInterface(); +}; + +class IECommerceInterface final : public ServiceFramework<IECommerceInterface> { +public: + explicit IECommerceInterface(); + ~IECommerceInterface(); +}; + +class IFactoryResetInterface final : public ServiceFramework<IFactoryResetInterface> { +public: + explicit IFactoryResetInterface(); + ~IFactoryResetInterface(); +}; + +class NS final : public ServiceFramework<NS> { +public: + explicit NS(const char* name); + ~NS(); + + std::shared_ptr<IApplicationManagerInterface> GetApplicationManagerInterface() const; + +private: + template <typename T> + void PushInterface(Kernel::HLERequestContext& ctx) { + LOG_DEBUG(Service_NS, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(RESULT_SUCCESS); + rb.PushIpcInterface<T>(); + } + + template <typename T> + std::shared_ptr<T> GetInterface() const { + static_assert(std::is_base_of_v<Kernel::SessionRequestHandler, T>, + "Not a base of ServiceFrameworkBase"); + + return std::make_shared<T>(); + } +}; + /// Registers all NS services with the specified service manager. void InstallInterfaces(SM::ServiceManager& service_manager); diff --git a/src/core/hle/service/ns/ns_language.h b/src/core/hle/service/ns/ns_language.h new file mode 100644 index 000000000..59ac85a19 --- /dev/null +++ b/src/core/hle/service/ns/ns_language.h @@ -0,0 +1,42 @@ +// Copyright 2019 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once +#include <optional> +#include <string> +#include "common/common_types.h" +#include "core/hle/service/set/set.h" + +namespace Service::NS { +/// This is nn::ns::detail::ApplicationLanguage +enum class ApplicationLanguage : u8 { + AmericanEnglish = 0, + BritishEnglish, + Japanese, + French, + German, + LatinAmericanSpanish, + Spanish, + Italian, + Dutch, + CanadianFrench, + Portuguese, + Russian, + Korean, + TraditionalChinese, + SimplifiedChinese, + Count +}; +using ApplicationLanguagePriorityList = + const std::array<ApplicationLanguage, static_cast<std::size_t>(ApplicationLanguage::Count)>; + +constexpr u32 GetSupportedLanguageFlag(const ApplicationLanguage lang) { + return 1U << static_cast<u32>(lang); +} + +const ApplicationLanguagePriorityList* GetApplicationLanguagePriorityList(ApplicationLanguage lang); +std::optional<ApplicationLanguage> ConvertToApplicationLanguage( + Service::Set::LanguageCode language_code); +std::optional<Service::Set::LanguageCode> ConvertToLanguageCode(ApplicationLanguage lang); +} // namespace Service::NS
\ No newline at end of file diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp index 45812d238..0e28755bd 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp @@ -185,7 +185,8 @@ u32 nvhost_ctrl_gpu::GetGpuTime(const std::vector<u8>& input, std::vector<u8>& o IoctlGetGpuTime params{}; std::memcpy(¶ms, input.data(), input.size()); - params.gpu_time = Core::Timing::cyclesToNs(Core::System::GetInstance().CoreTiming().GetTicks()); + const auto ns = Core::Timing::CyclesToNs(Core::System::GetInstance().CoreTiming().GetTicks()); + params.gpu_time = static_cast<u64_le>(ns.count()); std::memcpy(output.data(), ¶ms, output.size()); return 0; } diff --git a/src/core/hle/service/time/time.cpp b/src/core/hle/service/time/time.cpp index aa115935d..346bad80d 100644 --- a/src/core/hle/service/time/time.cpp +++ b/src/core/hle/service/time/time.cpp @@ -108,8 +108,9 @@ private: LOG_DEBUG(Service_Time, "called"); const auto& core_timing = Core::System::GetInstance().CoreTiming(); - const SteadyClockTimePoint steady_clock_time_point{ - Core::Timing::cyclesToMs(core_timing.GetTicks()) / 1000}; + const auto ms = Core::Timing::CyclesToMs(core_timing.GetTicks()); + const SteadyClockTimePoint steady_clock_time_point{static_cast<u64_le>(ms.count() / 1000), + {}}; IPC::ResponseBuilder rb{ctx, (sizeof(SteadyClockTimePoint) / 4) + 2}; rb.Push(RESULT_SUCCESS); rb.PushRaw(steady_clock_time_point); @@ -284,8 +285,8 @@ void Module::Interface::GetClockSnapshot(Kernel::HLERequestContext& ctx) { } const auto& core_timing = Core::System::GetInstance().CoreTiming(); - const SteadyClockTimePoint steady_clock_time_point{ - Core::Timing::cyclesToMs(core_timing.GetTicks()) / 1000, {}}; + const auto ms = Core::Timing::CyclesToMs(core_timing.GetTicks()); + const SteadyClockTimePoint steady_clock_time_point{static_cast<u64_le>(ms.count() / 1000), {}}; CalendarTime calendar_time{}; calendar_time.year = tm->tm_year + 1900; diff --git a/src/core/loader/loader.h b/src/core/loader/loader.h index f7846db52..869406b75 100644 --- a/src/core/loader/loader.h +++ b/src/core/loader/loader.h @@ -154,17 +154,6 @@ public: virtual LoadResult Load(Kernel::Process& process) = 0; /** - * Loads the system mode that this application needs. - * This function defaults to 2 (96MB allocated to the application) if it can't read the - * information. - * @returns A pair with the optional system mode, and and the status. - */ - virtual std::pair<std::optional<u32>, ResultStatus> LoadKernelSystemMode() { - // 96MB allocated to the application. - return std::make_pair(2, ResultStatus::Success); - } - - /** * Get the code (typically .code section) of the application * @param buffer Reference to buffer to store data * @return ResultStatus result of function diff --git a/src/core/telemetry_session.cpp b/src/core/telemetry_session.cpp index 4b17bada5..90d06830f 100644 --- a/src/core/telemetry_session.cpp +++ b/src/core/telemetry_session.cpp @@ -12,7 +12,6 @@ #include "common/file_util.h" #include "common/logging/log.h" -#include "core/core.h" #include "core/file_sys/control_metadata.h" #include "core/file_sys/patch_manager.h" #include "core/loader/loader.h" @@ -101,7 +100,30 @@ bool VerifyLogin(const std::string& username, const std::string& token) { #endif } -TelemetrySession::TelemetrySession() { +TelemetrySession::TelemetrySession() = default; + +TelemetrySession::~TelemetrySession() { + // Log one-time session end information + const s64 shutdown_time{std::chrono::duration_cast<std::chrono::milliseconds>( + std::chrono::system_clock::now().time_since_epoch()) + .count()}; + AddField(Telemetry::FieldType::Session, "Shutdown_Time", shutdown_time); + +#ifdef ENABLE_WEB_SERVICE + auto backend = std::make_unique<WebService::TelemetryJson>( + Settings::values.web_api_url, Settings::values.yuzu_username, Settings::values.yuzu_token); +#else + auto backend = std::make_unique<Telemetry::NullVisitor>(); +#endif + + // Complete the session, submitting to the web service backend if necessary + field_collection.Accept(*backend); + if (Settings::values.enable_telemetry) { + backend->Complete(); + } +} + +void TelemetrySession::AddInitialInfo(Loader::AppLoader& app_loader) { // Log one-time top-level information AddField(Telemetry::FieldType::None, "TelemetryId", GetTelemetryId()); @@ -112,26 +134,28 @@ TelemetrySession::TelemetrySession() { AddField(Telemetry::FieldType::Session, "Init_Time", init_time); u64 program_id{}; - const Loader::ResultStatus res{System::GetInstance().GetAppLoader().ReadProgramId(program_id)}; + const Loader::ResultStatus res{app_loader.ReadProgramId(program_id)}; if (res == Loader::ResultStatus::Success) { const std::string formatted_program_id{fmt::format("{:016X}", program_id)}; AddField(Telemetry::FieldType::Session, "ProgramId", formatted_program_id); std::string name; - System::GetInstance().GetAppLoader().ReadTitle(name); + app_loader.ReadTitle(name); if (name.empty()) { auto [nacp, icon_file] = FileSys::PatchManager(program_id).GetControlMetadata(); - if (nacp != nullptr) + if (nacp != nullptr) { name = nacp->GetApplicationName(); + } } - if (!name.empty()) + if (!name.empty()) { AddField(Telemetry::FieldType::Session, "ProgramName", name); + } } AddField(Telemetry::FieldType::Session, "ProgramFormat", - static_cast<u8>(System::GetInstance().GetAppLoader().GetFileType())); + static_cast<u8>(app_loader.GetFileType())); // Log application information Telemetry::AppendBuildInfo(field_collection); @@ -162,27 +186,6 @@ TelemetrySession::TelemetrySession() { Settings::values.use_docked_mode); } -TelemetrySession::~TelemetrySession() { - // Log one-time session end information - const s64 shutdown_time{std::chrono::duration_cast<std::chrono::milliseconds>( - std::chrono::system_clock::now().time_since_epoch()) - .count()}; - AddField(Telemetry::FieldType::Session, "Shutdown_Time", shutdown_time); - -#ifdef ENABLE_WEB_SERVICE - auto backend = std::make_unique<WebService::TelemetryJson>( - Settings::values.web_api_url, Settings::values.yuzu_username, Settings::values.yuzu_token); -#else - auto backend = std::make_unique<Telemetry::NullVisitor>(); -#endif - - // Complete the session, submitting to web service if necessary - field_collection.Accept(*backend); - if (Settings::values.enable_telemetry) - backend->Complete(); - backend = nullptr; -} - bool TelemetrySession::SubmitTestcase() { #ifdef ENABLE_WEB_SERVICE auto backend = std::make_unique<WebService::TelemetryJson>( diff --git a/src/core/telemetry_session.h b/src/core/telemetry_session.h index cae5a45a0..17ac22377 100644 --- a/src/core/telemetry_session.h +++ b/src/core/telemetry_session.h @@ -4,10 +4,13 @@ #pragma once -#include <memory> #include <string> #include "common/telemetry.h" +namespace Loader { +class AppLoader; +} + namespace Core { /** @@ -15,11 +18,33 @@ namespace Core { * session, logging any one-time fields. Interfaces with the telemetry backend used for submitting * data to the web service. Submits session data on close. */ -class TelemetrySession : NonCopyable { +class TelemetrySession { public: - TelemetrySession(); + explicit TelemetrySession(); ~TelemetrySession(); + TelemetrySession(const TelemetrySession&) = delete; + TelemetrySession& operator=(const TelemetrySession&) = delete; + + TelemetrySession(TelemetrySession&&) = delete; + TelemetrySession& operator=(TelemetrySession&&) = delete; + + /** + * Adds the initial telemetry info necessary when starting up a title. + * + * This includes information such as: + * - Telemetry ID + * - Initialization time + * - Title ID + * - Title name + * - Title file format + * - Miscellaneous settings values. + * + * @param app_loader The application loader to use to retrieve + * title-specific information. + */ + void AddInitialInfo(Loader::AppLoader& app_loader); + /** * Wrapper around the Telemetry::FieldCollection::AddField method. * @param type Type of the field to add. diff --git a/src/input_common/sdl/sdl.h b/src/input_common/sdl/sdl.h index d7f24c68a..5306daa70 100644 --- a/src/input_common/sdl/sdl.h +++ b/src/input_common/sdl/sdl.h @@ -6,15 +6,8 @@ #include <memory> #include <vector> -#include "core/frontend/input.h" #include "input_common/main.h" -union SDL_Event; - -namespace Common { -class ParamPackage; -} // namespace Common - namespace InputCommon::Polling { class DevicePoller; enum class DeviceType; diff --git a/src/input_common/sdl/sdl_impl.cpp b/src/input_common/sdl/sdl_impl.cpp index 0b69bfede..d2e9d278f 100644 --- a/src/input_common/sdl/sdl_impl.cpp +++ b/src/input_common/sdl/sdl_impl.cpp @@ -6,7 +6,6 @@ #include <atomic> #include <cmath> #include <functional> -#include <iterator> #include <mutex> #include <string> #include <thread> @@ -15,7 +14,6 @@ #include <utility> #include <vector> #include <SDL.h> -#include "common/assert.h" #include "common/logging/log.h" #include "common/math_util.h" #include "common/param_package.h" @@ -23,12 +21,10 @@ #include "core/frontend/input.h" #include "input_common/sdl/sdl_impl.h" -namespace InputCommon { - -namespace SDL { +namespace InputCommon::SDL { static std::string GetGUID(SDL_Joystick* joystick) { - SDL_JoystickGUID guid = SDL_JoystickGetGUID(joystick); + const SDL_JoystickGUID guid = SDL_JoystickGetGUID(joystick); char guid_str[33]; SDL_JoystickGetGUIDString(guid, guid_str, sizeof(guid_str)); return guid_str; @@ -37,26 +33,27 @@ static std::string GetGUID(SDL_Joystick* joystick) { /// Creates a ParamPackage from an SDL_Event that can directly be used to create a ButtonDevice static Common::ParamPackage SDLEventToButtonParamPackage(SDLState& state, const SDL_Event& event); -static int SDLEventWatcher(void* userdata, SDL_Event* event) { - SDLState* sdl_state = reinterpret_cast<SDLState*>(userdata); +static int SDLEventWatcher(void* user_data, SDL_Event* event) { + auto* const sdl_state = static_cast<SDLState*>(user_data); + // Don't handle the event if we are configuring if (sdl_state->polling) { sdl_state->event_queue.Push(*event); } else { sdl_state->HandleGameControllerEvent(*event); } + return 0; } class SDLJoystick { public: - SDLJoystick(std::string guid_, int port_, SDL_Joystick* joystick, - decltype(&SDL_JoystickClose) deleter = &SDL_JoystickClose) - : guid{std::move(guid_)}, port{port_}, sdl_joystick{joystick, deleter} {} + SDLJoystick(std::string guid_, int port_, SDL_Joystick* joystick) + : guid{std::move(guid_)}, port{port_}, sdl_joystick{joystick, &SDL_JoystickClose} {} void SetButton(int button, bool value) { std::lock_guard lock{mutex}; - state.buttons[button] = value; + state.buttons.insert_or_assign(button, value); } bool GetButton(int button) const { @@ -66,7 +63,7 @@ public: void SetAxis(int axis, Sint16 value) { std::lock_guard lock{mutex}; - state.axes[axis] = value; + state.axes.insert_or_assign(axis, value); } float GetAxis(int axis) const { @@ -93,7 +90,7 @@ public: void SetHat(int hat, Uint8 direction) { std::lock_guard lock{mutex}; - state.hats[hat] = direction; + state.hats.insert_or_assign(hat, direction); } bool GetHatDirection(int hat, Uint8 direction) const { @@ -118,10 +115,8 @@ public: return sdl_joystick.get(); } - void SetSDLJoystick(SDL_Joystick* joystick, - decltype(&SDL_JoystickClose) deleter = &SDL_JoystickClose) { - sdl_joystick = - std::unique_ptr<SDL_Joystick, decltype(&SDL_JoystickClose)>(joystick, deleter); + void SetSDLJoystick(SDL_Joystick* joystick) { + sdl_joystick.reset(joystick); } private: @@ -136,59 +131,57 @@ private: mutable std::mutex mutex; }; -/** - * Get the nth joystick with the corresponding GUID - */ std::shared_ptr<SDLJoystick> SDLState::GetSDLJoystickByGUID(const std::string& guid, int port) { std::lock_guard lock{joystick_map_mutex}; const auto it = joystick_map.find(guid); if (it != joystick_map.end()) { while (it->second.size() <= static_cast<std::size_t>(port)) { - auto joystick = std::make_shared<SDLJoystick>(guid, static_cast<int>(it->second.size()), - nullptr, [](SDL_Joystick*) {}); + auto joystick = + std::make_shared<SDLJoystick>(guid, static_cast<int>(it->second.size()), nullptr); it->second.emplace_back(std::move(joystick)); } return it->second[port]; } - auto joystick = std::make_shared<SDLJoystick>(guid, 0, nullptr, [](SDL_Joystick*) {}); + auto joystick = std::make_shared<SDLJoystick>(guid, 0, nullptr); return joystick_map[guid].emplace_back(std::move(joystick)); } -/** - * Check how many identical joysticks (by guid) were connected before the one with sdl_id and so tie - * it to a SDLJoystick with the same guid and that port - */ std::shared_ptr<SDLJoystick> SDLState::GetSDLJoystickBySDLID(SDL_JoystickID sdl_id) { auto sdl_joystick = SDL_JoystickFromInstanceID(sdl_id); const std::string guid = GetGUID(sdl_joystick); std::lock_guard lock{joystick_map_mutex}; - auto map_it = joystick_map.find(guid); + const auto map_it = joystick_map.find(guid); if (map_it != joystick_map.end()) { - auto vec_it = std::find_if(map_it->second.begin(), map_it->second.end(), - [&sdl_joystick](const std::shared_ptr<SDLJoystick>& joystick) { - return sdl_joystick == joystick->GetSDLJoystick(); - }); + const auto vec_it = + std::find_if(map_it->second.begin(), map_it->second.end(), + [&sdl_joystick](const std::shared_ptr<SDLJoystick>& joystick) { + return sdl_joystick == joystick->GetSDLJoystick(); + }); if (vec_it != map_it->second.end()) { // This is the common case: There is already an existing SDL_Joystick maped to a // SDLJoystick. return the SDLJoystick return *vec_it; } + // Search for a SDLJoystick without a mapped SDL_Joystick... - auto nullptr_it = std::find_if(map_it->second.begin(), map_it->second.end(), - [](const std::shared_ptr<SDLJoystick>& joystick) { - return !joystick->GetSDLJoystick(); - }); + const auto nullptr_it = std::find_if(map_it->second.begin(), map_it->second.end(), + [](const std::shared_ptr<SDLJoystick>& joystick) { + return !joystick->GetSDLJoystick(); + }); if (nullptr_it != map_it->second.end()) { // ... and map it (*nullptr_it)->SetSDLJoystick(sdl_joystick); return *nullptr_it; } + // There is no SDLJoystick without a mapped SDL_Joystick // Create a new SDLJoystick - auto joystick = std::make_shared<SDLJoystick>(guid, map_it->second.size(), sdl_joystick); + const int port = static_cast<int>(map_it->second.size()); + auto joystick = std::make_shared<SDLJoystick>(guid, port, sdl_joystick); return map_it->second.emplace_back(std::move(joystick)); } + auto joystick = std::make_shared<SDLJoystick>(guid, 0, sdl_joystick); return joystick_map[guid].emplace_back(std::move(joystick)); } @@ -215,17 +208,19 @@ void SDLState::InitJoystick(int joystick_index) { (*it)->SetSDLJoystick(sdl_joystick); return; } - auto joystick = std::make_shared<SDLJoystick>(guid, joystick_guid_list.size(), sdl_joystick); + const int port = static_cast<int>(joystick_guid_list.size()); + auto joystick = std::make_shared<SDLJoystick>(guid, port, sdl_joystick); joystick_guid_list.emplace_back(std::move(joystick)); } void SDLState::CloseJoystick(SDL_Joystick* sdl_joystick) { - std::string guid = GetGUID(sdl_joystick); + const std::string guid = GetGUID(sdl_joystick); + std::shared_ptr<SDLJoystick> joystick; { std::lock_guard lock{joystick_map_mutex}; // This call to guid is safe since the joystick is guaranteed to be in the map - auto& joystick_guid_list = joystick_map[guid]; + const auto& joystick_guid_list = joystick_map[guid]; const auto joystick_it = std::find_if(joystick_guid_list.begin(), joystick_guid_list.end(), [&sdl_joystick](const std::shared_ptr<SDLJoystick>& joystick) { @@ -233,9 +228,10 @@ void SDLState::CloseJoystick(SDL_Joystick* sdl_joystick) { }); joystick = *joystick_it; } - // Destruct SDL_Joystick outside the lock guard because SDL can internally call event calback - // which locks the mutex again - joystick->SetSDLJoystick(nullptr, [](SDL_Joystick*) {}); + + // Destruct SDL_Joystick outside the lock guard because SDL can internally call the + // event callback which locks the mutex again. + joystick->SetSDLJoystick(nullptr); } void SDLState::HandleGameControllerEvent(const SDL_Event& event) { @@ -317,9 +313,10 @@ public: trigger_if_greater(trigger_if_greater_) {} bool GetStatus() const override { - float axis_value = joystick->GetAxis(axis); - if (trigger_if_greater) + const float axis_value = joystick->GetAxis(axis); + if (trigger_if_greater) { return axis_value > threshold; + } return axis_value < threshold; } @@ -444,7 +441,7 @@ public: const int port = params.Get("port", 0); const int axis_x = params.Get("axis_x", 0); const int axis_y = params.Get("axis_y", 1); - float deadzone = std::clamp(params.Get("deadzone", 0.0f), 0.0f, .99f); + const float deadzone = std::clamp(params.Get("deadzone", 0.0f), 0.0f, .99f); auto joystick = state.GetSDLJoystickByGUID(guid, port); @@ -470,7 +467,7 @@ SDLState::SDLState() { return; } if (SDL_SetHint(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, "1") == SDL_FALSE) { - LOG_ERROR(Input, "Failed to set Hint for background events", SDL_GetError()); + LOG_ERROR(Input, "Failed to set hint for background events with: {}", SDL_GetError()); } SDL_AddEventWatch(&SDLEventWatcher, this); @@ -507,12 +504,12 @@ SDLState::~SDLState() { } } -Common::ParamPackage SDLEventToButtonParamPackage(SDLState& state, const SDL_Event& event) { +static Common::ParamPackage SDLEventToButtonParamPackage(SDLState& state, const SDL_Event& event) { Common::ParamPackage params({{"engine", "sdl"}}); switch (event.type) { case SDL_JOYAXISMOTION: { - auto joystick = state.GetSDLJoystickBySDLID(event.jaxis.which); + const auto joystick = state.GetSDLJoystickBySDLID(event.jaxis.which); params.Set("port", joystick->GetPort()); params.Set("guid", joystick->GetGUID()); params.Set("axis", event.jaxis.axis); @@ -526,14 +523,14 @@ Common::ParamPackage SDLEventToButtonParamPackage(SDLState& state, const SDL_Eve break; } case SDL_JOYBUTTONUP: { - auto joystick = state.GetSDLJoystickBySDLID(event.jbutton.which); + const auto joystick = state.GetSDLJoystickBySDLID(event.jbutton.which); params.Set("port", joystick->GetPort()); params.Set("guid", joystick->GetGUID()); params.Set("button", event.jbutton.button); break; } case SDL_JOYHATMOTION: { - auto joystick = state.GetSDLJoystickBySDLID(event.jhat.which); + const auto joystick = state.GetSDLJoystickBySDLID(event.jhat.which); params.Set("port", joystick->GetPort()); params.Set("guid", joystick->GetGUID()); params.Set("hat", event.jhat.hat); @@ -607,8 +604,8 @@ public: SDLPoller::Start(); // Reset stored axes - analog_xaxis = -1; - analog_yaxis = -1; + analog_x_axis = -1; + analog_y_axis = -1; analog_axes_joystick = -1; } @@ -620,25 +617,25 @@ public: } // An analog device needs two axes, so we need to store the axis for later and wait for // a second SDL event. The axes also must be from the same joystick. - int axis = event.jaxis.axis; - if (analog_xaxis == -1) { - analog_xaxis = axis; + const int axis = event.jaxis.axis; + if (analog_x_axis == -1) { + analog_x_axis = axis; analog_axes_joystick = event.jaxis.which; - } else if (analog_yaxis == -1 && analog_xaxis != axis && + } else if (analog_y_axis == -1 && analog_x_axis != axis && analog_axes_joystick == event.jaxis.which) { - analog_yaxis = axis; + analog_y_axis = axis; } } Common::ParamPackage params; - if (analog_xaxis != -1 && analog_yaxis != -1) { - auto joystick = state.GetSDLJoystickBySDLID(event.jaxis.which); + if (analog_x_axis != -1 && analog_y_axis != -1) { + const auto joystick = state.GetSDLJoystickBySDLID(event.jaxis.which); params.Set("engine", "sdl"); params.Set("port", joystick->GetPort()); params.Set("guid", joystick->GetGUID()); - params.Set("axis_x", analog_xaxis); - params.Set("axis_y", analog_yaxis); - analog_xaxis = -1; - analog_yaxis = -1; + params.Set("axis_x", analog_x_axis); + params.Set("axis_y", analog_y_axis); + analog_x_axis = -1; + analog_y_axis = -1; analog_axes_joystick = -1; return params; } @@ -646,8 +643,8 @@ public: } private: - int analog_xaxis = -1; - int analog_yaxis = -1; + int analog_x_axis = -1; + int analog_y_axis = -1; SDL_JoystickID analog_axes_joystick = -1; }; } // namespace Polling @@ -667,5 +664,4 @@ SDLState::Pollers SDLState::GetPollers(InputCommon::Polling::DeviceType type) { return pollers; } -} // namespace SDL -} // namespace InputCommon +} // namespace InputCommon::SDL diff --git a/src/input_common/sdl/sdl_impl.h b/src/input_common/sdl/sdl_impl.h index 2579741d6..606a32c5b 100644 --- a/src/input_common/sdl/sdl_impl.h +++ b/src/input_common/sdl/sdl_impl.h @@ -6,7 +6,10 @@ #include <atomic> #include <memory> +#include <mutex> #include <thread> +#include <unordered_map> +#include "common/common_types.h" #include "common/threadsafe_queue.h" #include "input_common/sdl/sdl.h" @@ -16,9 +19,9 @@ using SDL_JoystickID = s32; namespace InputCommon::SDL { -class SDLJoystick; -class SDLButtonFactory; class SDLAnalogFactory; +class SDLButtonFactory; +class SDLJoystick; class SDLState : public State { public: @@ -31,7 +34,13 @@ public: /// Handle SDL_Events for joysticks from SDL_PollEvent void HandleGameControllerEvent(const SDL_Event& event); + /// Get the nth joystick with the corresponding GUID std::shared_ptr<SDLJoystick> GetSDLJoystickBySDLID(SDL_JoystickID sdl_id); + + /** + * Check how many identical joysticks (by guid) were connected before the one with sdl_id and so + * tie it to a SDLJoystick with the same guid and that port + */ std::shared_ptr<SDLJoystick> GetSDLJoystickByGUID(const std::string& guid, int port); /// Get all DevicePoller that use the SDL backend for a specific device type diff --git a/src/video_core/gpu_thread.cpp b/src/video_core/gpu_thread.cpp index 1e2ff46b0..3f0939ec9 100644 --- a/src/video_core/gpu_thread.cpp +++ b/src/video_core/gpu_thread.cpp @@ -75,7 +75,7 @@ void ThreadManager::StartThread(VideoCore::RendererBase& renderer, Tegra::DmaPus void ThreadManager::SubmitList(Tegra::CommandList&& entries) { const u64 fence{PushCommand(SubmitListCommand(std::move(entries)))}; - const s64 synchronization_ticks{Core::Timing::usToCycles(9000)}; + const s64 synchronization_ticks{Core::Timing::usToCycles(std::chrono::microseconds{9000})}; system.CoreTiming().ScheduleEvent(synchronization_ticks, synchronization_event, fence); } diff --git a/src/video_core/renderer_opengl/gl_device.cpp b/src/video_core/renderer_opengl/gl_device.cpp index 1d1581f49..65a88b06c 100644 --- a/src/video_core/renderer_opengl/gl_device.cpp +++ b/src/video_core/renderer_opengl/gl_device.cpp @@ -2,11 +2,14 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include <array> #include <cstddef> #include <glad/glad.h> #include "common/logging/log.h" +#include "common/scope_exit.h" #include "video_core/renderer_opengl/gl_device.h" +#include "video_core/renderer_opengl/gl_resource_manager.h" namespace OpenGL { @@ -24,6 +27,7 @@ Device::Device() { max_vertex_attributes = GetInteger<u32>(GL_MAX_VERTEX_ATTRIBS); max_varyings = GetInteger<u32>(GL_MAX_VARYING_VECTORS); has_variable_aoffi = TestVariableAoffi(); + has_component_indexing_bug = TestComponentIndexingBug(); } Device::Device(std::nullptr_t) { @@ -31,6 +35,7 @@ Device::Device(std::nullptr_t) { max_vertex_attributes = 16; max_varyings = 15; has_variable_aoffi = true; + has_component_indexing_bug = false; } bool Device::TestVariableAoffi() { @@ -52,4 +57,53 @@ void main() { return supported; } +bool Device::TestComponentIndexingBug() { + constexpr char log_message[] = "Renderer_ComponentIndexingBug: {}"; + const GLchar* COMPONENT_TEST = R"(#version 430 core +layout (std430, binding = 0) buffer OutputBuffer { + uint output_value; +}; +layout (std140, binding = 0) uniform InputBuffer { + uvec4 input_value[4096]; +}; +layout (location = 0) uniform uint idx; +void main() { + output_value = input_value[idx >> 2][idx & 3]; +})"; + const GLuint shader{glCreateShaderProgramv(GL_VERTEX_SHADER, 1, &COMPONENT_TEST)}; + SCOPE_EXIT({ glDeleteProgram(shader); }); + glUseProgram(shader); + + OGLVertexArray vao; + vao.Create(); + glBindVertexArray(vao.handle); + + constexpr std::array<GLuint, 8> values{0, 0, 0, 0, 0x1236327, 0x985482, 0x872753, 0x2378432}; + OGLBuffer ubo; + ubo.Create(); + glNamedBufferData(ubo.handle, sizeof(values), values.data(), GL_STATIC_DRAW); + glBindBufferBase(GL_UNIFORM_BUFFER, 0, ubo.handle); + + OGLBuffer ssbo; + ssbo.Create(); + glNamedBufferStorage(ssbo.handle, sizeof(GLuint), nullptr, GL_CLIENT_STORAGE_BIT); + + for (GLuint index = 4; index < 8; ++index) { + glInvalidateBufferData(ssbo.handle); + glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, ssbo.handle); + + glProgramUniform1ui(shader, 0, index); + glDrawArrays(GL_POINTS, 0, 1); + + GLuint result; + glGetNamedBufferSubData(ssbo.handle, 0, sizeof(result), &result); + if (result != values.at(index)) { + LOG_INFO(Render_OpenGL, log_message, true); + return true; + } + } + LOG_INFO(Render_OpenGL, log_message, false); + return false; +} + } // namespace OpenGL diff --git a/src/video_core/renderer_opengl/gl_device.h b/src/video_core/renderer_opengl/gl_device.h index de8490682..8c8c93760 100644 --- a/src/video_core/renderer_opengl/gl_device.h +++ b/src/video_core/renderer_opengl/gl_device.h @@ -30,13 +30,19 @@ public: return has_variable_aoffi; } + bool HasComponentIndexingBug() const { + return has_component_indexing_bug; + } + private: static bool TestVariableAoffi(); + static bool TestComponentIndexingBug(); std::size_t uniform_buffer_alignment{}; u32 max_vertex_attributes{}; u32 max_varyings{}; bool has_variable_aoffi{}; + bool has_component_indexing_bug{}; }; } // namespace OpenGL diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp index e9f8d40db..3b61bf77f 100644 --- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp +++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp @@ -577,9 +577,26 @@ private: if (std::holds_alternative<OperationNode>(*offset)) { // Indirect access const std::string final_offset = code.GenerateTemporary(); - code.AddLine("uint {} = (ftou({}) / 4);", final_offset, Visit(offset)); - return fmt::format("{}[{} / 4][{} % 4]", GetConstBuffer(cbuf->GetIndex()), - final_offset, final_offset); + code.AddLine("uint {} = ftou({}) >> 2;", final_offset, Visit(offset)); + + if (!device.HasComponentIndexingBug()) { + return fmt::format("{}[{} >> 2][{} & 3]", GetConstBuffer(cbuf->GetIndex()), + final_offset, final_offset); + } + + // AMD's proprietary GLSL compiler emits ill code for variable component access. + // To bypass this driver bug generate 4 ifs, one per each component. + const std::string pack = code.GenerateTemporary(); + code.AddLine("vec4 {} = {}[{} >> 2];", pack, GetConstBuffer(cbuf->GetIndex()), + final_offset); + + const std::string result = code.GenerateTemporary(); + code.AddLine("float {};", result); + for (u32 swizzle = 0; swizzle < 4; ++swizzle) { + code.AddLine("if (({} & 3) == {}) {} = {}{};", final_offset, swizzle, result, + pack, GetSwizzle(swizzle)); + } + return result; } UNREACHABLE_MSG("Unmanaged offset node type"); diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index d2258a487..cd32623b4 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -847,11 +847,6 @@ bool GMainWindow::LoadROM(const QString& filename) { QMessageBox::critical(this, tr("Error while loading ROM!"), tr("The ROM format is not supported.")); break; - case Core::System::ResultStatus::ErrorSystemMode: - LOG_CRITICAL(Frontend, "Failed to load ROM!"); - QMessageBox::critical(this, tr("Error while loading ROM!"), - tr("Could not determine the system mode.")); - break; case Core::System::ResultStatus::ErrorVideoCore: QMessageBox::critical( this, tr("An error occurred initializing the video core."), diff --git a/src/yuzu_cmd/yuzu.cpp b/src/yuzu_cmd/yuzu.cpp index 5d9442646..129d8ca73 100644 --- a/src/yuzu_cmd/yuzu.cpp +++ b/src/yuzu_cmd/yuzu.cpp @@ -192,7 +192,7 @@ int main(int argc, char** argv) { switch (load_result) { case Core::System::ResultStatus::ErrorGetLoader: - LOG_CRITICAL(Frontend, "Failed to obtain loader for %s!", filepath.c_str()); + LOG_CRITICAL(Frontend, "Failed to obtain loader for {}!", filepath); return -1; case Core::System::ResultStatus::ErrorLoader: LOG_CRITICAL(Frontend, "Failed to load ROM!"); @@ -200,9 +200,6 @@ int main(int argc, char** argv) { case Core::System::ResultStatus::ErrorNotInitialized: LOG_CRITICAL(Frontend, "CPUCore not initialized"); return -1; - case Core::System::ResultStatus::ErrorSystemMode: - LOG_CRITICAL(Frontend, "Failed to determine system mode!"); - return -1; case Core::System::ResultStatus::ErrorVideoCore: LOG_CRITICAL(Frontend, "Failed to initialize VideoCore!"); return -1; |