Compare commits

...

34 Commits

Author SHA1 Message Date
bunnei
62c6c9f6a6 service: time: Update current time with changes to RTC setting.
- This can be used to advance time, e.g. for Pokemon Sword/Shield pokejobs.
2020-10-12 18:09:15 -07:00
bunnei
4c348f4069 Merge pull request #4766 from ReinUsesLisp/tmml-cube
shader/texture: Implement CUBE texture type for TMML and fix arrays
2020-10-12 12:53:57 -07:00
bunnei
419a59a7b1 Merge pull request #4775 from ReinUsesLisp/enforce-class-memaccess
video_core: Enforce -Wclass-memaccess
2020-10-09 23:38:02 -07:00
bunnei
f250011ba0 Merge pull request #4757 from german77/BetterMotion
InputCommon: Add compatibility with only accelerometer and auto calibrate for drift
2020-10-09 23:37:08 -07:00
ReinUsesLisp
e1600b0962 video_core: Enforce -Wclass-memaccess 2020-10-09 16:46:11 -03:00
LC
61b246a3a9 Merge pull request #4771 from ReinUsesLisp/warn-unused-var
video_core: Enforce -Wunused-variable and -Wunused-but-set-variable
2020-10-08 21:10:31 -04:00
bunnei
06e65de93c Merge pull request #4677 from german77/ShakeFromButton
InputCommon: Add random motion input for buttons
2020-10-08 10:18:39 -07:00
Rodrigo Locatti
7a99226785 Merge pull request #4765 from ReinUsesLisp/fix-sort-devices
renderer_vulkan/wrapper: Fix physical device sorting
2020-10-08 00:54:44 -03:00
ReinUsesLisp
dffaffaac1 shader/texture: Implement CUBE texture type for TMML and fix arrays
TMML takes an array argument that has no known meaning, this one appears
as the first component in gpr8 followed by s, t and r. Skip this
component when arrays are being used. Also implement CUBE texture types.

- Used by Pikmin 3: Deluxe Demo.
2020-10-07 23:17:46 -03:00
bunnei
3446eb79b5 Merge pull request #4731 from lat9nq/mingw-zstd-fix
common: Use system zstd on Linux
2020-10-07 17:57:14 -07:00
bunnei
92adb69fa7 Merge pull request #4736 from Morph1984/home-button-input-protection-stub
hid: Stub HomeButtonInputProtection service commands
2020-10-07 14:54:05 -07:00
ReinUsesLisp
cd3e959f23 renderer_vulkan/wrapper: Fix physical device sorting
The old code had a sort function that was invalid and it didn't work as
expected when the base vector had a different order (e.g. renderdoc was
attached).

This sorts devices as expected and fixes a debug assert on MSVC.
2020-10-07 17:13:22 -03:00
bunnei
cc0dc3280d Merge pull request #4710 from Morph1984/fix-integrated-updates
submission_package: Fix updates integrated into cartridge images.
2020-10-06 22:27:52 -07:00
bunnei
32b4627a9c Merge pull request #4737 from Morph1984/setshimlibraryversion-stub
capsrv: Stub 3 variants of SetShimLibraryVersion
2020-10-06 21:39:38 -07:00
bunnei
e9b81e9f01 Merge pull request #4727 from FrogTheFrog/patch-1
Reduce the "shake" requirements when configuring UDP.
2020-10-06 15:29:28 -07:00
bunnei
614bd0ee8c Merge pull request #4742 from german77/InputFilter
HID: Only use inputs corresponding to controller type
2020-10-05 21:40:09 -07:00
german
a54aee290f Address comments 2020-10-04 18:15:53 -05:00
bunnei
de4cadca1f Merge pull request #4648 from zhaobot/tx-update-20200911153748
Update translations (2020-09-11)
2020-10-03 22:30:38 -07:00
german
a220d8799e Add compatibility with only accelerometer and auto calibrate for drift 2020-10-03 22:22:01 -05:00
ReinUsesLisp
2a24b1c973 video_core: Enforce -Wunused-variable and -Wunused-but-set-variable 2020-10-02 21:19:35 -03:00
bunnei
182cf7d631 Merge pull request #4734 from german77/motionfusion
HID: Add Stub for EnableSixAxisSensorFusion
2020-10-01 22:39:39 -07:00
german
2f47b27654 Only use inputs corresponding to controller type 2020-10-01 19:39:53 -05:00
german
283616dbd8 Stubbed EnableSixAxisSensorFusion 2020-09-30 10:00:24 -05:00
Morph
91bd2281bf caps_c: Stub SetShimLibraryVersion
- Used by caps_su SetShimLibraryVersion
2020-09-30 07:19:46 -04:00
Morph
7d287a6fb0 caps_u: Stub SetShimLibraryVersion
- Used in Super Smash Bros. Ultimate
2020-09-30 07:19:46 -04:00
Morph
9a251339dc caps_su: Properly stub SetShimLibraryVersion 2020-09-30 07:19:46 -04:00
Morph
6380731486 hid: Stub HomeButtonInputProtection service commands
- Used in 1-2 Switch. Given that we do not emulate the functionality of the home button yet, we can stub this for now.
2020-09-30 06:38:24 -04:00
Lukas Senionis
6ee1a784b8 Reduce the "shake" requirements when configuring UDP. 2020-09-30 10:30:33 +03:00
lat9nq
2cbce77b92 CMakeLists: use system zstd on Linux
From what I understand, this tells CMake to use the system, not conan,
version of zstd. Required to build on the coming MinGW Docker container.
2020-09-28 21:11:39 -04:00
lat9nq
9d665cb8db CMakeLists: fix for finding zstd on linux-mingw 2020-09-28 20:28:47 -04:00
german
2978232390 Add random motion input to keyboard 2020-09-25 17:59:52 -05:00
german
03b574ae22 Add random motion input to SDL 2020-09-25 17:59:52 -05:00
Morph
3602df7f1f submission_package: Fix updates integrated into cartridge images. 2020-09-24 17:23:14 -04:00
The yuzu Community
b5784e9af2 Update translations (2020-09-11) 2020-09-11 15:38:10 +00:00
46 changed files with 53107 additions and 324 deletions

4749
dist/languages/de.ts vendored Normal file

File diff suppressed because it is too large Load Diff

4757
dist/languages/es.ts vendored Normal file

File diff suppressed because it is too large Load Diff

4732
dist/languages/fr.ts vendored Normal file

File diff suppressed because it is too large Load Diff

4724
dist/languages/it.ts vendored Normal file

File diff suppressed because it is too large Load Diff

4752
dist/languages/ja_JP.ts vendored Normal file

File diff suppressed because it is too large Load Diff

4719
dist/languages/nl.ts vendored Normal file

File diff suppressed because it is too large Load Diff

4713
dist/languages/pl.ts vendored Normal file

File diff suppressed because it is too large Load Diff

4757
dist/languages/pt_BR.ts vendored Normal file

File diff suppressed because it is too large Load Diff

4725
dist/languages/pt_PT.ts vendored Normal file

File diff suppressed because it is too large Load Diff

4720
dist/languages/ru_RU.ts vendored Normal file

File diff suppressed because it is too large Load Diff

4747
dist/languages/zh_CN.ts vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -192,4 +192,9 @@ create_target_directory_groups(common)
find_package(Boost 1.71 COMPONENTS context headers REQUIRED)
target_link_libraries(common PUBLIC ${Boost_LIBRARIES} fmt::fmt microprofile)
target_link_libraries(common PRIVATE lz4::lz4 zstd::zstd xbyak)
target_link_libraries(common PRIVATE lz4::lz4 xbyak)
if (MSVC)
target_link_libraries(common PRIVATE zstd::zstd)
else()
target_link_libraries(common PRIVATE zstd)
endif()

View File

@@ -40,6 +40,7 @@
#include "core/hle/service/lm/manager.h"
#include "core/hle/service/service.h"
#include "core/hle/service/sm/sm.h"
#include "core/hle/service/time/time_manager.h"
#include "core/loader/loader.h"
#include "core/memory.h"
#include "core/memory/cheat_engine.h"
@@ -121,7 +122,7 @@ FileSys::VirtualFile GetGameFileFromPath(const FileSys::VirtualFilesystem& vfs,
struct System::Impl {
explicit Impl(System& system)
: kernel{system}, fs_controller{system}, memory{system},
cpu_manager{system}, reporter{system}, applet_manager{system} {}
cpu_manager{system}, reporter{system}, applet_manager{system}, time_manager{system} {}
ResultStatus Run() {
status = ResultStatus::Success;
@@ -189,6 +190,9 @@ struct System::Impl {
return ResultStatus::ErrorVideoCore;
}
// Initialize time manager, which must happen after kernel is created
time_manager.Initialize();
is_powered_on = true;
exit_lock = false;
@@ -387,6 +391,7 @@ struct System::Impl {
/// Service State
Service::Glue::ARPManager arp_manager;
Service::LM::Manager lm_manager{reporter};
Service::Time::TimeManager time_manager;
/// Service manager
std::shared_ptr<Service::SM::ServiceManager> service_manager;
@@ -717,6 +722,14 @@ const Service::LM::Manager& System::GetLogManager() const {
return impl->lm_manager;
}
Service::Time::TimeManager& System::GetTimeManager() {
return impl->time_manager;
}
const Service::Time::TimeManager& System::GetTimeManager() const {
return impl->time_manager;
}
void System::SetExitLock(bool locked) {
impl->exit_lock = locked;
}

View File

@@ -69,6 +69,10 @@ namespace SM {
class ServiceManager;
} // namespace SM
namespace Time {
class TimeManager;
} // namespace Time
} // namespace Service
namespace Tegra {
@@ -361,6 +365,10 @@ public:
const Service::LM::Manager& GetLogManager() const;
Service::Time::TimeManager& GetTimeManager();
const Service::Time::TimeManager& GetTimeManager() const;
void SetExitLock(bool locked);
bool GetExitLock() const;

View File

@@ -286,12 +286,31 @@ void NSP::ReadNCAs(const std::vector<VirtualFile>& files) {
}
auto next_nca = std::make_shared<NCA>(std::move(next_file), nullptr, 0);
if (next_nca->GetType() == NCAContentType::Program) {
program_status[next_nca->GetTitleId()] = next_nca->GetStatus();
}
if (next_nca->GetStatus() == Loader::ResultStatus::Success ||
(next_nca->GetStatus() == Loader::ResultStatus::ErrorMissingBKTRBaseRomFS &&
(next_nca->GetTitleId() & 0x800) != 0)) {
if (next_nca->GetStatus() != Loader::ResultStatus::Success &&
next_nca->GetStatus() != Loader::ResultStatus::ErrorMissingBKTRBaseRomFS) {
continue;
}
// If the last 3 hexadecimal digits of the CNMT TitleID is 0x800 or is missing the
// BKTRBaseRomFS, this is an update NCA. Otherwise, this is a base NCA.
if ((cnmt.GetTitleID() & 0x800) != 0 ||
next_nca->GetStatus() == Loader::ResultStatus::ErrorMissingBKTRBaseRomFS) {
// If the last 3 hexadecimal digits of the NCA's TitleID is between 0x1 and
// 0x7FF, this is a multi-program update NCA. Otherwise, this is a regular
// update NCA.
if ((next_nca->GetTitleId() & 0x7FF) != 0 &&
(next_nca->GetTitleId() & 0x800) == 0) {
ncas[next_nca->GetTitleId()][{cnmt.GetType(), rec.type}] =
std::move(next_nca);
} else {
ncas[cnmt.GetTitleID()][{cnmt.GetType(), rec.type}] = std::move(next_nca);
}
} else {
ncas[next_nca->GetTitleId()][{cnmt.GetType(), rec.type}] = std::move(next_nca);
}
}

View File

@@ -2,6 +2,8 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include "common/logging/log.h"
#include "core/hle/ipc_helpers.h"
#include "core/hle/service/caps/caps_c.h"
namespace Service::Capture {
@@ -47,7 +49,7 @@ CAPS_C::CAPS_C() : ServiceFramework("caps:c") {
static const FunctionInfo functions[] = {
{1, nullptr, "CaptureRawImage"},
{2, nullptr, "CaptureRawImageWithTimeout"},
{33, nullptr, "Unknown33"},
{33, &CAPS_C::SetShimLibraryVersion, "SetShimLibraryVersion"},
{1001, nullptr, "RequestTakingScreenShot"},
{1002, nullptr, "RequestTakingScreenShotWithTimeout"},
{1011, nullptr, "NotifyTakingScreenShotRefused"},
@@ -72,4 +74,16 @@ CAPS_C::CAPS_C() : ServiceFramework("caps:c") {
CAPS_C::~CAPS_C() = default;
void CAPS_C::SetShimLibraryVersion(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto library_version{rp.Pop<u64>()};
const auto applet_resource_user_id{rp.Pop<u64>()};
LOG_WARNING(Service_Capture, "(STUBBED) called. library_version={}, applet_resource_user_id={}",
library_version, applet_resource_user_id);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
}
} // namespace Service::Capture

View File

@@ -16,6 +16,9 @@ class CAPS_C final : public ServiceFramework<CAPS_C> {
public:
explicit CAPS_C();
~CAPS_C() override;
private:
void SetShimLibraryVersion(Kernel::HLERequestContext& ctx);
};
} // namespace Service::Capture

View File

@@ -25,7 +25,12 @@ CAPS_SU::CAPS_SU() : ServiceFramework("caps:su") {
CAPS_SU::~CAPS_SU() = default;
void CAPS_SU::SetShimLibraryVersion(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_Capture, "(STUBBED) called");
IPC::RequestParser rp{ctx};
const auto library_version{rp.Pop<u64>()};
const auto applet_resource_user_id{rp.Pop<u64>()};
LOG_WARNING(Service_Capture, "(STUBBED) called. library_version={}, applet_resource_user_id={}",
library_version, applet_resource_user_id);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);

View File

@@ -31,8 +31,7 @@ public:
CAPS_U::CAPS_U() : ServiceFramework("caps:u") {
// clang-format off
static const FunctionInfo functions[] = {
{31, nullptr, "GetShimLibraryVersion"},
{32, nullptr, "SetShimLibraryVersion"},
{32, &CAPS_U::SetShimLibraryVersion, "SetShimLibraryVersion"},
{102, &CAPS_U::GetAlbumContentsFileListForApplication, "GetAlbumContentsFileListForApplication"},
{103, nullptr, "DeleteAlbumContentsFileForApplication"},
{104, nullptr, "GetAlbumContentsFileSizeForApplication"},
@@ -53,6 +52,18 @@ CAPS_U::CAPS_U() : ServiceFramework("caps:u") {
CAPS_U::~CAPS_U() = default;
void CAPS_U::SetShimLibraryVersion(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto library_version{rp.Pop<u64>()};
const auto applet_resource_user_id{rp.Pop<u64>()};
LOG_WARNING(Service_Capture, "(STUBBED) called. library_version={}, applet_resource_user_id={}",
library_version, applet_resource_user_id);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
}
void CAPS_U::GetAlbumContentsFileListForApplication(Kernel::HLERequestContext& ctx) {
// Takes a type-0x6 output buffer containing an array of ApplicationAlbumFileEntry, a PID, an
// u8 ContentType, two s64s, and an u64 AppletResourceUserId. Returns an output u64 for total

View File

@@ -18,6 +18,7 @@ public:
~CAPS_U() override;
private:
void SetShimLibraryVersion(Kernel::HLERequestContext& ctx);
void GetAlbumContentsFileListForApplication(Kernel::HLERequestContext& ctx);
};

View File

@@ -260,7 +260,7 @@ void Controller_NPad::OnRelease() {}
void Controller_NPad::RequestPadStateUpdate(u32 npad_id) {
const auto controller_idx = NPadIdToIndex(npad_id);
[[maybe_unused]] const auto controller_type = connected_controllers[controller_idx].type;
const auto controller_type = connected_controllers[controller_idx].type;
if (!connected_controllers[controller_idx].is_connected) {
return;
}
@@ -276,54 +276,63 @@ void Controller_NPad::RequestPadStateUpdate(u32 npad_id) {
analog_state[static_cast<std::size_t>(JoystickId::Joystick_Right)]->GetStatus();
using namespace Settings::NativeButton;
pad_state.a.Assign(button_state[A - BUTTON_HID_BEGIN]->GetStatus());
pad_state.b.Assign(button_state[B - BUTTON_HID_BEGIN]->GetStatus());
pad_state.x.Assign(button_state[X - BUTTON_HID_BEGIN]->GetStatus());
pad_state.y.Assign(button_state[Y - BUTTON_HID_BEGIN]->GetStatus());
pad_state.l_stick.Assign(button_state[LStick - BUTTON_HID_BEGIN]->GetStatus());
pad_state.r_stick.Assign(button_state[RStick - BUTTON_HID_BEGIN]->GetStatus());
pad_state.l.Assign(button_state[L - BUTTON_HID_BEGIN]->GetStatus());
pad_state.r.Assign(button_state[R - BUTTON_HID_BEGIN]->GetStatus());
pad_state.zl.Assign(button_state[ZL - BUTTON_HID_BEGIN]->GetStatus());
pad_state.zr.Assign(button_state[ZR - BUTTON_HID_BEGIN]->GetStatus());
pad_state.plus.Assign(button_state[Plus - BUTTON_HID_BEGIN]->GetStatus());
pad_state.minus.Assign(button_state[Minus - BUTTON_HID_BEGIN]->GetStatus());
if (controller_type != NPadControllerType::JoyLeft) {
pad_state.a.Assign(button_state[A - BUTTON_HID_BEGIN]->GetStatus());
pad_state.b.Assign(button_state[B - BUTTON_HID_BEGIN]->GetStatus());
pad_state.x.Assign(button_state[X - BUTTON_HID_BEGIN]->GetStatus());
pad_state.y.Assign(button_state[Y - BUTTON_HID_BEGIN]->GetStatus());
pad_state.r_stick.Assign(button_state[RStick - BUTTON_HID_BEGIN]->GetStatus());
pad_state.r.Assign(button_state[R - BUTTON_HID_BEGIN]->GetStatus());
pad_state.zr.Assign(button_state[ZR - BUTTON_HID_BEGIN]->GetStatus());
pad_state.plus.Assign(button_state[Plus - BUTTON_HID_BEGIN]->GetStatus());
pad_state.d_left.Assign(button_state[DLeft - BUTTON_HID_BEGIN]->GetStatus());
pad_state.d_up.Assign(button_state[DUp - BUTTON_HID_BEGIN]->GetStatus());
pad_state.d_right.Assign(button_state[DRight - BUTTON_HID_BEGIN]->GetStatus());
pad_state.d_down.Assign(button_state[DDown - BUTTON_HID_BEGIN]->GetStatus());
pad_state.r_stick_right.Assign(
analog_state[static_cast<std::size_t>(JoystickId::Joystick_Right)]
->GetAnalogDirectionStatus(Input::AnalogDirection::RIGHT));
pad_state.r_stick_left.Assign(
analog_state[static_cast<std::size_t>(JoystickId::Joystick_Right)]
->GetAnalogDirectionStatus(Input::AnalogDirection::LEFT));
pad_state.r_stick_up.Assign(
analog_state[static_cast<std::size_t>(JoystickId::Joystick_Right)]
->GetAnalogDirectionStatus(Input::AnalogDirection::UP));
pad_state.r_stick_down.Assign(
analog_state[static_cast<std::size_t>(JoystickId::Joystick_Right)]
->GetAnalogDirectionStatus(Input::AnalogDirection::DOWN));
rstick_entry.x = static_cast<s32>(stick_r_x_f * HID_JOYSTICK_MAX);
rstick_entry.y = static_cast<s32>(stick_r_y_f * HID_JOYSTICK_MAX);
}
pad_state.l_stick_right.Assign(
analog_state[static_cast<std::size_t>(JoystickId::Joystick_Left)]->GetAnalogDirectionStatus(
Input::AnalogDirection::RIGHT));
pad_state.l_stick_left.Assign(
analog_state[static_cast<std::size_t>(JoystickId::Joystick_Left)]->GetAnalogDirectionStatus(
Input::AnalogDirection::LEFT));
pad_state.l_stick_up.Assign(
analog_state[static_cast<std::size_t>(JoystickId::Joystick_Left)]->GetAnalogDirectionStatus(
Input::AnalogDirection::UP));
pad_state.l_stick_down.Assign(
analog_state[static_cast<std::size_t>(JoystickId::Joystick_Left)]->GetAnalogDirectionStatus(
Input::AnalogDirection::DOWN));
if (controller_type != NPadControllerType::JoyRight) {
pad_state.d_left.Assign(button_state[DLeft - BUTTON_HID_BEGIN]->GetStatus());
pad_state.d_up.Assign(button_state[DUp - BUTTON_HID_BEGIN]->GetStatus());
pad_state.d_right.Assign(button_state[DRight - BUTTON_HID_BEGIN]->GetStatus());
pad_state.d_down.Assign(button_state[DDown - BUTTON_HID_BEGIN]->GetStatus());
pad_state.l_stick.Assign(button_state[LStick - BUTTON_HID_BEGIN]->GetStatus());
pad_state.l.Assign(button_state[L - BUTTON_HID_BEGIN]->GetStatus());
pad_state.zl.Assign(button_state[ZL - BUTTON_HID_BEGIN]->GetStatus());
pad_state.minus.Assign(button_state[Minus - BUTTON_HID_BEGIN]->GetStatus());
pad_state.r_stick_right.Assign(
analog_state[static_cast<std::size_t>(JoystickId::Joystick_Right)]
->GetAnalogDirectionStatus(Input::AnalogDirection::RIGHT));
pad_state.r_stick_left.Assign(analog_state[static_cast<std::size_t>(JoystickId::Joystick_Right)]
->GetAnalogDirectionStatus(Input::AnalogDirection::LEFT));
pad_state.r_stick_up.Assign(analog_state[static_cast<std::size_t>(JoystickId::Joystick_Right)]
->GetAnalogDirectionStatus(Input::AnalogDirection::UP));
pad_state.r_stick_down.Assign(analog_state[static_cast<std::size_t>(JoystickId::Joystick_Right)]
->GetAnalogDirectionStatus(Input::AnalogDirection::DOWN));
pad_state.l_stick_right.Assign(
analog_state[static_cast<std::size_t>(JoystickId::Joystick_Left)]
->GetAnalogDirectionStatus(Input::AnalogDirection::RIGHT));
pad_state.l_stick_left.Assign(
analog_state[static_cast<std::size_t>(JoystickId::Joystick_Left)]
->GetAnalogDirectionStatus(Input::AnalogDirection::LEFT));
pad_state.l_stick_up.Assign(
analog_state[static_cast<std::size_t>(JoystickId::Joystick_Left)]
->GetAnalogDirectionStatus(Input::AnalogDirection::UP));
pad_state.l_stick_down.Assign(
analog_state[static_cast<std::size_t>(JoystickId::Joystick_Left)]
->GetAnalogDirectionStatus(Input::AnalogDirection::DOWN));
lstick_entry.x = static_cast<s32>(stick_l_x_f * HID_JOYSTICK_MAX);
lstick_entry.y = static_cast<s32>(stick_l_y_f * HID_JOYSTICK_MAX);
}
pad_state.left_sl.Assign(button_state[SL - BUTTON_HID_BEGIN]->GetStatus());
pad_state.left_sr.Assign(button_state[SR - BUTTON_HID_BEGIN]->GetStatus());
lstick_entry.x = static_cast<s32>(stick_l_x_f * HID_JOYSTICK_MAX);
lstick_entry.y = static_cast<s32>(stick_l_y_f * HID_JOYSTICK_MAX);
rstick_entry.x = static_cast<s32>(stick_r_x_f * HID_JOYSTICK_MAX);
rstick_entry.y = static_cast<s32>(stick_r_y_f * HID_JOYSTICK_MAX);
if (controller_type == NPadControllerType::JoyLeft ||
controller_type == NPadControllerType::JoyRight) {
pad_state.left_sl.Assign(button_state[SL - BUTTON_HID_BEGIN]->GetStatus());
pad_state.left_sr.Assign(button_state[SR - BUTTON_HID_BEGIN]->GetStatus());
}
}
void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data,
@@ -837,6 +846,15 @@ Controller_NPad::LedPattern Controller_NPad::GetLedPattern(u32 npad_id) {
}
}
bool Controller_NPad::IsUnintendedHomeButtonInputProtectionEnabled(u32 npad_id) const {
return unintended_home_button_input_protection[NPadIdToIndex(npad_id)];
}
void Controller_NPad::SetUnintendedHomeButtonInputProtectionEnabled(bool is_protection_enabled,
u32 npad_id) {
unintended_home_button_input_protection[NPadIdToIndex(npad_id)] = is_protection_enabled;
}
void Controller_NPad::SetVibrationEnabled(bool can_vibrate) {
can_controllers_vibrate = can_vibrate;
}

View File

@@ -146,6 +146,8 @@ public:
bool IsSixAxisSensorAtRest() const;
void SetSixAxisEnabled(bool six_axis_status);
LedPattern GetLedPattern(u32 npad_id);
bool IsUnintendedHomeButtonInputProtectionEnabled(u32 npad_id) const;
void SetUnintendedHomeButtonInputProtectionEnabled(bool is_protection_enabled, u32 npad_id);
void SetVibrationEnabled(bool can_vibrate);
bool IsVibrationEnabled() const;
void ClearAllConnectedControllers();
@@ -387,6 +389,7 @@ private:
std::array<Kernel::EventPair, 10> styleset_changed_events;
Vibration last_processed_vibration{};
std::array<ControllerHolder, 10> connected_controllers{};
std::array<bool, 10> unintended_home_button_input_protection{};
GyroscopeZeroDriftMode gyroscope_zero_drift_mode{GyroscopeZeroDriftMode::Standard};
bool can_controllers_vibrate{true};
bool sixaxis_sensors_enabled{true};

View File

@@ -188,7 +188,7 @@ Hid::Hid(Core::System& system) : ServiceFramework("hid"), system(system) {
{66, &Hid::StartSixAxisSensor, "StartSixAxisSensor"},
{67, &Hid::StopSixAxisSensor, "StopSixAxisSensor"},
{68, nullptr, "IsSixAxisSensorFusionEnabled"},
{69, nullptr, "EnableSixAxisSensorFusion"},
{69, &Hid::EnableSixAxisSensorFusion, "EnableSixAxisSensorFusion"},
{70, nullptr, "SetSixAxisSensorFusionParameters"},
{71, nullptr, "GetSixAxisSensorFusionParameters"},
{72, nullptr, "ResetSixAxisSensorFusionParameters"},
@@ -224,8 +224,8 @@ Hid::Hid(Core::System& system) : ServiceFramework("hid"), system(system) {
{128, &Hid::SetNpadHandheldActivationMode, "SetNpadHandheldActivationMode"},
{129, &Hid::GetNpadHandheldActivationMode, "GetNpadHandheldActivationMode"},
{130, &Hid::SwapNpadAssignment, "SwapNpadAssignment"},
{131, nullptr, "IsUnintendedHomeButtonInputProtectionEnabled"},
{132, nullptr, "EnableUnintendedHomeButtonInputProtection"},
{131, &Hid::IsUnintendedHomeButtonInputProtectionEnabled, "IsUnintendedHomeButtonInputProtectionEnabled"},
{132, &Hid::EnableUnintendedHomeButtonInputProtection, "EnableUnintendedHomeButtonInputProtection"},
{133, nullptr, "SetNpadJoyAssignmentModeSingleWithDestination"},
{134, nullptr, "SetNpadAnalogStickUseCenterClamp"},
{135, nullptr, "SetNpadCaptureButtonAssignment"},
@@ -473,6 +473,19 @@ void Hid::StopSixAxisSensor(Kernel::HLERequestContext& ctx) {
rb.Push(RESULT_SUCCESS);
}
void Hid::EnableSixAxisSensorFusion(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto enable{rp.Pop<bool>()};
const auto handle{rp.Pop<u32>()};
const auto applet_resource_user_id{rp.Pop<u64>()};
LOG_WARNING(Service_HID, "(STUBBED) called, handle={}, applet_resource_user_id={}", handle,
applet_resource_user_id);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
}
void Hid::SetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto handle{rp.Pop<u32>()};
@@ -796,6 +809,40 @@ void Hid::SwapNpadAssignment(Kernel::HLERequestContext& ctx) {
}
}
void Hid::IsUnintendedHomeButtonInputProtectionEnabled(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto npad_id{rp.Pop<u32>()};
const auto applet_resource_user_id{rp.Pop<u64>()};
LOG_WARNING(Service_HID, "(STUBBED) called, npad_id={}, applet_resource_user_id={}", npad_id,
applet_resource_user_id);
auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
rb.Push<bool>(controller.IsUnintendedHomeButtonInputProtectionEnabled(npad_id));
}
void Hid::EnableUnintendedHomeButtonInputProtection(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto unintended_home_button_input_protection{rp.Pop<bool>()};
const auto npad_id{rp.Pop<u32>()};
const auto applet_resource_user_id{rp.Pop<u64>()};
LOG_WARNING(Service_HID,
"(STUBBED) called, unintended_home_button_input_protection={}, npad_id={},"
"applet_resource_user_id={}",
npad_id, unintended_home_button_input_protection, applet_resource_user_id);
auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad);
controller.SetUnintendedHomeButtonInputProtectionEnabled(
unintended_home_button_input_protection, npad_id);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
}
void Hid::BeginPermitVibrationSession(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto applet_resource_user_id{rp.Pop<u64>()};

View File

@@ -99,6 +99,7 @@ private:
void ActivateNpadWithRevision(Kernel::HLERequestContext& ctx);
void StartSixAxisSensor(Kernel::HLERequestContext& ctx);
void StopSixAxisSensor(Kernel::HLERequestContext& ctx);
void EnableSixAxisSensorFusion(Kernel::HLERequestContext& ctx);
void SetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx);
void GetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx);
void ResetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx);
@@ -122,6 +123,8 @@ private:
void SetNpadHandheldActivationMode(Kernel::HLERequestContext& ctx);
void GetNpadHandheldActivationMode(Kernel::HLERequestContext& ctx);
void SwapNpadAssignment(Kernel::HLERequestContext& ctx);
void IsUnintendedHomeButtonInputProtectionEnabled(Kernel::HLERequestContext& ctx);
void EnableUnintendedHomeButtonInputProtection(Kernel::HLERequestContext& ctx);
void BeginPermitVibrationSession(Kernel::HLERequestContext& ctx);
void EndPermitVibrationSession(Kernel::HLERequestContext& ctx);
void SendVibrationValue(Kernel::HLERequestContext& ctx);

View File

@@ -10,6 +10,7 @@
#include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/client_port.h"
#include "core/hle/kernel/client_session.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/scheduler.h"
#include "core/hle/service/time/interface.h"
#include "core/hle/service/time/time.h"
@@ -125,7 +126,7 @@ ResultCode Module::Interface::GetClockSnapshotFromSystemClockContextInternal(
Kernel::Thread* thread, Clock::SystemClockContext user_context,
Clock::SystemClockContext network_context, u8 type, Clock::ClockSnapshot& clock_snapshot) {
auto& time_manager{module->GetTimeManager()};
auto& time_manager{system.GetTimeManager()};
clock_snapshot.is_automatic_correction_enabled =
time_manager.GetStandardUserSystemClockCore().IsAutomaticCorrectionEnabled();
@@ -182,7 +183,7 @@ void Module::Interface::GetStandardUserSystemClock(Kernel::HLERequestContext& ct
LOG_DEBUG(Service_Time, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<ISystemClock>(module->GetTimeManager().GetStandardUserSystemClockCore(),
rb.PushIpcInterface<ISystemClock>(system.GetTimeManager().GetStandardUserSystemClockCore(),
system);
}
@@ -190,7 +191,7 @@ void Module::Interface::GetStandardNetworkSystemClock(Kernel::HLERequestContext&
LOG_DEBUG(Service_Time, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<ISystemClock>(module->GetTimeManager().GetStandardNetworkSystemClockCore(),
rb.PushIpcInterface<ISystemClock>(system.GetTimeManager().GetStandardNetworkSystemClockCore(),
system);
}
@@ -198,29 +199,28 @@ void Module::Interface::GetStandardSteadyClock(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_Time, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<ISteadyClock>(module->GetTimeManager().GetStandardSteadyClockCore(),
system);
rb.PushIpcInterface<ISteadyClock>(system.GetTimeManager().GetStandardSteadyClockCore(), system);
}
void Module::Interface::GetTimeZoneService(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_Time, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<ITimeZoneService>(module->GetTimeManager().GetTimeZoneContentManager());
rb.PushIpcInterface<ITimeZoneService>(system.GetTimeManager().GetTimeZoneContentManager());
}
void Module::Interface::GetStandardLocalSystemClock(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_Time, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<ISystemClock>(module->GetTimeManager().GetStandardLocalSystemClockCore(),
rb.PushIpcInterface<ISystemClock>(system.GetTimeManager().GetStandardLocalSystemClockCore(),
system);
}
void Module::Interface::IsStandardNetworkSystemClockAccuracySufficient(
Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_Time, "called");
auto& clock_core{module->GetTimeManager().GetStandardNetworkSystemClockCore()};
auto& clock_core{system.GetTimeManager().GetStandardNetworkSystemClockCore()};
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
rb.Push<u32>(clock_core.IsStandardNetworkSystemClockAccuracySufficient(system));
@@ -229,7 +229,7 @@ void Module::Interface::IsStandardNetworkSystemClockAccuracySufficient(
void Module::Interface::CalculateMonotonicSystemClockBaseTimePoint(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_Time, "called");
auto& steady_clock_core{module->GetTimeManager().GetStandardSteadyClockCore()};
auto& steady_clock_core{system.GetTimeManager().GetStandardSteadyClockCore()};
if (!steady_clock_core.IsInitialized()) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ERROR_UNINITIALIZED_CLOCK);
@@ -262,8 +262,8 @@ void Module::Interface::GetClockSnapshot(Kernel::HLERequestContext& ctx) {
Clock::SystemClockContext user_context{};
if (const ResultCode result{
module->GetTimeManager().GetStandardUserSystemClockCore().GetClockContext(
system, user_context)};
system.GetTimeManager().GetStandardUserSystemClockCore().GetClockContext(system,
user_context)};
result.IsError()) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(result);
@@ -271,7 +271,7 @@ void Module::Interface::GetClockSnapshot(Kernel::HLERequestContext& ctx) {
}
Clock::SystemClockContext network_context{};
if (const ResultCode result{
module->GetTimeManager().GetStandardNetworkSystemClockCore().GetClockContext(
system.GetTimeManager().GetStandardNetworkSystemClockCore().GetClockContext(
system, network_context)};
result.IsError()) {
IPC::ResponseBuilder rb{ctx, 2};
@@ -372,7 +372,7 @@ void Module::Interface::GetSharedMemoryNativeHandle(Kernel::HLERequestContext& c
LOG_DEBUG(Service_Time, "called");
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(RESULT_SUCCESS);
rb.PushCopyObjects(module->GetTimeManager().GetSharedMemory().GetSharedMemoryHolder());
rb.PushCopyObjects(SharedFrom(&system.Kernel().GetTimeSharedMem()));
}
Module::Interface::Interface(std::shared_ptr<Module> module, Core::System& system, const char* name)
@@ -381,7 +381,7 @@ Module::Interface::Interface(std::shared_ptr<Module> module, Core::System& syste
Module::Interface::~Interface() = default;
void InstallInterfaces(Core::System& system) {
auto module{std::make_shared<Module>(system)};
auto module{std::make_shared<Module>()};
std::make_shared<Time>(module, system, "time:a")->InstallAsService(system.ServiceManager());
std::make_shared<Time>(module, system, "time:s")->InstallAsService(system.ServiceManager());
std::make_shared<Time>(module, system, "time:u")->InstallAsService(system.ServiceManager());

View File

@@ -16,7 +16,7 @@ namespace Service::Time {
class Module final {
public:
Module(Core::System& system) : time_manager{system} {}
Module() = default;
class Interface : public ServiceFramework<Interface> {
public:
@@ -46,13 +46,6 @@ public:
std::shared_ptr<Module> module;
Core::System& system;
};
TimeManager& GetTimeManager() {
return time_manager;
}
private:
TimeManager time_manager;
};
/// Registers all Time services with the specified service manager.

View File

@@ -22,7 +22,277 @@ static std::chrono::seconds GetSecondsSinceEpoch() {
Settings::values.custom_rtc_differential;
}
static s64 GetExternalTimeZoneOffset() {
static s64 GetExternalRtcValue() {
return GetSecondsSinceEpoch().count() + TimeManager::GetExternalTimeZoneOffset();
}
struct TimeManager::Impl final {
explicit Impl(Core::System& system)
: shared_memory{system}, standard_local_system_clock_core{standard_steady_clock_core},
standard_network_system_clock_core{standard_steady_clock_core},
standard_user_system_clock_core{standard_local_system_clock_core,
standard_network_system_clock_core, system},
ephemeral_network_system_clock_core{tick_based_steady_clock_core},
local_system_clock_context_writer{
std::make_shared<Clock::LocalSystemClockContextWriter>(shared_memory)},
network_system_clock_context_writer{
std::make_shared<Clock::NetworkSystemClockContextWriter>(shared_memory)},
ephemeral_network_system_clock_context_writer{
std::make_shared<Clock::EphemeralNetworkSystemClockContextWriter>()},
time_zone_content_manager{system} {
const auto system_time{Clock::TimeSpanType::FromSeconds(GetExternalRtcValue())};
SetupStandardSteadyClock(system, Common::UUID::Generate(), system_time, {}, {});
SetupStandardLocalSystemClock(system, {}, system_time.ToSeconds());
SetupStandardNetworkSystemClock({}, standard_network_clock_accuracy);
SetupStandardUserSystemClock(system, {}, Clock::SteadyClockTimePoint::GetRandom());
SetupEphemeralNetworkSystemClock();
}
~Impl() = default;
Clock::StandardSteadyClockCore& GetStandardSteadyClockCore() {
return standard_steady_clock_core;
}
const Clock::StandardSteadyClockCore& GetStandardSteadyClockCore() const {
return standard_steady_clock_core;
}
Clock::StandardLocalSystemClockCore& GetStandardLocalSystemClockCore() {
return standard_local_system_clock_core;
}
const Clock::StandardLocalSystemClockCore& GetStandardLocalSystemClockCore() const {
return standard_local_system_clock_core;
}
Clock::StandardNetworkSystemClockCore& GetStandardNetworkSystemClockCore() {
return standard_network_system_clock_core;
}
const Clock::StandardNetworkSystemClockCore& GetStandardNetworkSystemClockCore() const {
return standard_network_system_clock_core;
}
Clock::StandardUserSystemClockCore& GetStandardUserSystemClockCore() {
return standard_user_system_clock_core;
}
const Clock::StandardUserSystemClockCore& GetStandardUserSystemClockCore() const {
return standard_user_system_clock_core;
}
TimeZone::TimeZoneContentManager& GetTimeZoneContentManager() {
return time_zone_content_manager;
}
const TimeZone::TimeZoneContentManager& GetTimeZoneContentManager() const {
return time_zone_content_manager;
}
SharedMemory& GetSharedMemory() {
return shared_memory;
}
const SharedMemory& GetSharedMemory() const {
return shared_memory;
}
void SetupTimeZoneManager(std::string location_name,
Clock::SteadyClockTimePoint time_zone_updated_time_point,
std::size_t total_location_name_count, u128 time_zone_rule_version,
FileSys::VirtualFile& vfs_file) {
if (time_zone_content_manager.GetTimeZoneManager().SetDeviceLocationNameWithTimeZoneRule(
location_name, vfs_file) != RESULT_SUCCESS) {
UNREACHABLE();
return;
}
time_zone_content_manager.GetTimeZoneManager().SetUpdatedTime(time_zone_updated_time_point);
time_zone_content_manager.GetTimeZoneManager().SetTotalLocationNameCount(
total_location_name_count);
time_zone_content_manager.GetTimeZoneManager().SetTimeZoneRuleVersion(
time_zone_rule_version);
time_zone_content_manager.GetTimeZoneManager().MarkAsInitialized();
}
static s64 GetExternalTimeZoneOffset() {
// With "auto" timezone setting, we use the external system's timezone offset
if (Settings::GetTimeZoneString() == "auto") {
return Common::TimeZone::GetCurrentOffsetSeconds().count();
}
return 0;
}
void SetupStandardSteadyClock(Core::System& system, Common::UUID clock_source_id,
Clock::TimeSpanType setup_value,
Clock::TimeSpanType internal_offset, bool is_rtc_reset_detected) {
standard_steady_clock_core.SetClockSourceId(clock_source_id);
standard_steady_clock_core.SetSetupValue(setup_value);
standard_steady_clock_core.SetInternalOffset(internal_offset);
standard_steady_clock_core.MarkAsInitialized();
const auto current_time_point{standard_steady_clock_core.GetCurrentRawTimePoint(system)};
shared_memory.SetupStandardSteadyClock(system, clock_source_id, current_time_point);
}
void SetupStandardLocalSystemClock(Core::System& system,
Clock::SystemClockContext clock_context, s64 posix_time) {
standard_local_system_clock_core.SetUpdateCallbackInstance(
local_system_clock_context_writer);
const auto current_time_point{
standard_local_system_clock_core.GetSteadyClockCore().GetCurrentTimePoint(system)};
if (current_time_point.clock_source_id == clock_context.steady_time_point.clock_source_id) {
standard_local_system_clock_core.SetSystemClockContext(clock_context);
} else {
if (standard_local_system_clock_core.SetCurrentTime(system, posix_time) !=
RESULT_SUCCESS) {
UNREACHABLE();
return;
}
}
standard_local_system_clock_core.MarkAsInitialized();
}
void SetupStandardNetworkSystemClock(Clock::SystemClockContext clock_context,
Clock::TimeSpanType sufficient_accuracy) {
standard_network_system_clock_core.SetUpdateCallbackInstance(
network_system_clock_context_writer);
if (standard_network_system_clock_core.SetSystemClockContext(clock_context) !=
RESULT_SUCCESS) {
UNREACHABLE();
return;
}
standard_network_system_clock_core.SetStandardNetworkClockSufficientAccuracy(
sufficient_accuracy);
standard_network_system_clock_core.MarkAsInitialized();
}
void SetupStandardUserSystemClock(Core::System& system, bool is_automatic_correction_enabled,
Clock::SteadyClockTimePoint steady_clock_time_point) {
if (standard_user_system_clock_core.SetAutomaticCorrectionEnabled(
system, is_automatic_correction_enabled) != RESULT_SUCCESS) {
UNREACHABLE();
return;
}
standard_user_system_clock_core.SetAutomaticCorrectionUpdatedTime(steady_clock_time_point);
standard_user_system_clock_core.MarkAsInitialized();
shared_memory.SetAutomaticCorrectionEnabled(is_automatic_correction_enabled);
}
void SetupEphemeralNetworkSystemClock() {
ephemeral_network_system_clock_core.SetUpdateCallbackInstance(
ephemeral_network_system_clock_context_writer);
ephemeral_network_system_clock_core.MarkAsInitialized();
}
void UpdateLocalSystemClockTime(Core::System& system, s64 posix_time) {
const auto timespan{Service::Time::Clock::TimeSpanType::FromSeconds(posix_time)};
if (GetStandardLocalSystemClockCore()
.SetCurrentTime(system, timespan.ToSeconds())
.IsError()) {
UNREACHABLE();
return;
}
}
SharedMemory shared_memory;
Clock::StandardSteadyClockCore standard_steady_clock_core;
Clock::TickBasedSteadyClockCore tick_based_steady_clock_core;
Clock::StandardLocalSystemClockCore standard_local_system_clock_core;
Clock::StandardNetworkSystemClockCore standard_network_system_clock_core;
Clock::StandardUserSystemClockCore standard_user_system_clock_core;
Clock::EphemeralNetworkSystemClockCore ephemeral_network_system_clock_core;
std::shared_ptr<Clock::LocalSystemClockContextWriter> local_system_clock_context_writer;
std::shared_ptr<Clock::NetworkSystemClockContextWriter> network_system_clock_context_writer;
std::shared_ptr<Clock::EphemeralNetworkSystemClockContextWriter>
ephemeral_network_system_clock_context_writer;
TimeZone::TimeZoneContentManager time_zone_content_manager;
};
TimeManager::TimeManager(Core::System& system) : system{system} {}
TimeManager::~TimeManager() = default;
void TimeManager::Initialize() {
impl = std::make_unique<Impl>(system);
// Time zones can only be initialized after impl is valid
impl->time_zone_content_manager.Initialize(*this);
}
Clock::StandardSteadyClockCore& TimeManager::GetStandardSteadyClockCore() {
return impl->standard_steady_clock_core;
}
const Clock::StandardSteadyClockCore& TimeManager::GetStandardSteadyClockCore() const {
return impl->standard_steady_clock_core;
}
Clock::StandardLocalSystemClockCore& TimeManager::GetStandardLocalSystemClockCore() {
return impl->standard_local_system_clock_core;
}
const Clock::StandardLocalSystemClockCore& TimeManager::GetStandardLocalSystemClockCore() const {
return impl->standard_local_system_clock_core;
}
Clock::StandardNetworkSystemClockCore& TimeManager::GetStandardNetworkSystemClockCore() {
return impl->standard_network_system_clock_core;
}
const Clock::StandardNetworkSystemClockCore& TimeManager::GetStandardNetworkSystemClockCore()
const {
return impl->standard_network_system_clock_core;
}
Clock::StandardUserSystemClockCore& TimeManager::GetStandardUserSystemClockCore() {
return impl->standard_user_system_clock_core;
}
const Clock::StandardUserSystemClockCore& TimeManager::GetStandardUserSystemClockCore() const {
return impl->standard_user_system_clock_core;
}
TimeZone::TimeZoneContentManager& TimeManager::GetTimeZoneContentManager() {
return impl->time_zone_content_manager;
}
const TimeZone::TimeZoneContentManager& TimeManager::GetTimeZoneContentManager() const {
return impl->time_zone_content_manager;
}
SharedMemory& TimeManager::GetSharedMemory() {
return impl->shared_memory;
}
const SharedMemory& TimeManager::GetSharedMemory() const {
return impl->shared_memory;
}
void TimeManager::UpdateLocalSystemClockTime(s64 posix_time) {
impl->UpdateLocalSystemClockTime(system, posix_time);
}
void TimeManager::SetupTimeZoneManager(std::string location_name,
Clock::SteadyClockTimePoint time_zone_updated_time_point,
std::size_t total_location_name_count,
u128 time_zone_rule_version,
FileSys::VirtualFile& vfs_file) {
impl->SetupTimeZoneManager(location_name, time_zone_updated_time_point,
total_location_name_count, time_zone_rule_version, vfs_file);
}
/*static*/ s64 TimeManager::GetExternalTimeZoneOffset() {
// With "auto" timezone setting, we use the external system's timezone offset
if (Settings::GetTimeZoneString() == "auto") {
return Common::TimeZone::GetCurrentOffsetSeconds().count();
@@ -30,117 +300,4 @@ static s64 GetExternalTimeZoneOffset() {
return 0;
}
static s64 GetExternalRtcValue() {
return GetSecondsSinceEpoch().count() + GetExternalTimeZoneOffset();
}
TimeManager::TimeManager(Core::System& system)
: shared_memory{system}, standard_local_system_clock_core{standard_steady_clock_core},
standard_network_system_clock_core{standard_steady_clock_core},
standard_user_system_clock_core{standard_local_system_clock_core,
standard_network_system_clock_core, system},
ephemeral_network_system_clock_core{tick_based_steady_clock_core},
local_system_clock_context_writer{
std::make_shared<Clock::LocalSystemClockContextWriter>(shared_memory)},
network_system_clock_context_writer{
std::make_shared<Clock::NetworkSystemClockContextWriter>(shared_memory)},
ephemeral_network_system_clock_context_writer{
std::make_shared<Clock::EphemeralNetworkSystemClockContextWriter>()},
time_zone_content_manager{*this, system} {
const auto system_time{Clock::TimeSpanType::FromSeconds(GetExternalRtcValue())};
SetupStandardSteadyClock(system, Common::UUID::Generate(), system_time, {}, {});
SetupStandardLocalSystemClock(system, {}, system_time.ToSeconds());
SetupStandardNetworkSystemClock({}, standard_network_clock_accuracy);
SetupStandardUserSystemClock(system, {}, Clock::SteadyClockTimePoint::GetRandom());
SetupEphemeralNetworkSystemClock();
}
TimeManager::~TimeManager() = default;
void TimeManager::SetupTimeZoneManager(std::string location_name,
Clock::SteadyClockTimePoint time_zone_updated_time_point,
std::size_t total_location_name_count,
u128 time_zone_rule_version,
FileSys::VirtualFile& vfs_file) {
if (time_zone_content_manager.GetTimeZoneManager().SetDeviceLocationNameWithTimeZoneRule(
location_name, vfs_file) != RESULT_SUCCESS) {
UNREACHABLE();
return;
}
time_zone_content_manager.GetTimeZoneManager().SetUpdatedTime(time_zone_updated_time_point);
time_zone_content_manager.GetTimeZoneManager().SetTotalLocationNameCount(
total_location_name_count);
time_zone_content_manager.GetTimeZoneManager().SetTimeZoneRuleVersion(time_zone_rule_version);
time_zone_content_manager.GetTimeZoneManager().MarkAsInitialized();
}
void TimeManager::SetupStandardSteadyClock(Core::System& system, Common::UUID clock_source_id,
Clock::TimeSpanType setup_value,
Clock::TimeSpanType internal_offset,
bool is_rtc_reset_detected) {
standard_steady_clock_core.SetClockSourceId(clock_source_id);
standard_steady_clock_core.SetSetupValue(setup_value);
standard_steady_clock_core.SetInternalOffset(internal_offset);
standard_steady_clock_core.MarkAsInitialized();
const auto current_time_point{standard_steady_clock_core.GetCurrentRawTimePoint(system)};
shared_memory.SetupStandardSteadyClock(system, clock_source_id, current_time_point);
}
void TimeManager::SetupStandardLocalSystemClock(Core::System& system,
Clock::SystemClockContext clock_context,
s64 posix_time) {
standard_local_system_clock_core.SetUpdateCallbackInstance(local_system_clock_context_writer);
const auto current_time_point{
standard_local_system_clock_core.GetSteadyClockCore().GetCurrentTimePoint(system)};
if (current_time_point.clock_source_id == clock_context.steady_time_point.clock_source_id) {
standard_local_system_clock_core.SetSystemClockContext(clock_context);
} else {
if (standard_local_system_clock_core.SetCurrentTime(system, posix_time) != RESULT_SUCCESS) {
UNREACHABLE();
return;
}
}
standard_local_system_clock_core.MarkAsInitialized();
}
void TimeManager::SetupStandardNetworkSystemClock(Clock::SystemClockContext clock_context,
Clock::TimeSpanType sufficient_accuracy) {
standard_network_system_clock_core.SetUpdateCallbackInstance(
network_system_clock_context_writer);
if (standard_network_system_clock_core.SetSystemClockContext(clock_context) != RESULT_SUCCESS) {
UNREACHABLE();
return;
}
standard_network_system_clock_core.SetStandardNetworkClockSufficientAccuracy(
sufficient_accuracy);
standard_network_system_clock_core.MarkAsInitialized();
}
void TimeManager::SetupStandardUserSystemClock(
Core::System& system, bool is_automatic_correction_enabled,
Clock::SteadyClockTimePoint steady_clock_time_point) {
if (standard_user_system_clock_core.SetAutomaticCorrectionEnabled(
system, is_automatic_correction_enabled) != RESULT_SUCCESS) {
UNREACHABLE();
return;
}
standard_user_system_clock_core.SetAutomaticCorrectionUpdatedTime(steady_clock_time_point);
standard_user_system_clock_core.MarkAsInitialized();
shared_memory.SetAutomaticCorrectionEnabled(is_automatic_correction_enabled);
}
void TimeManager::SetupEphemeralNetworkSystemClock() {
ephemeral_network_system_clock_core.SetUpdateCallbackInstance(
ephemeral_network_system_clock_context_writer);
ephemeral_network_system_clock_core.MarkAsInitialized();
}
} // namespace Service::Time

View File

@@ -5,6 +5,7 @@
#pragma once
#include "common/common_types.h"
#include "common/time_zone.h"
#include "core/file_sys/vfs_types.h"
#include "core/hle/service/time/clock_types.h"
#include "core/hle/service/time/ephemeral_network_system_clock_core.h"
@@ -32,86 +33,46 @@ public:
explicit TimeManager(Core::System& system);
~TimeManager();
Clock::StandardSteadyClockCore& GetStandardSteadyClockCore() {
return standard_steady_clock_core;
}
void Initialize();
const Clock::StandardSteadyClockCore& GetStandardSteadyClockCore() const {
return standard_steady_clock_core;
}
Clock::StandardSteadyClockCore& GetStandardSteadyClockCore();
Clock::StandardLocalSystemClockCore& GetStandardLocalSystemClockCore() {
return standard_local_system_clock_core;
}
const Clock::StandardSteadyClockCore& GetStandardSteadyClockCore() const;
const Clock::StandardLocalSystemClockCore& GetStandardLocalSystemClockCore() const {
return standard_local_system_clock_core;
}
Clock::StandardLocalSystemClockCore& GetStandardLocalSystemClockCore();
Clock::StandardNetworkSystemClockCore& GetStandardNetworkSystemClockCore() {
return standard_network_system_clock_core;
}
const Clock::StandardLocalSystemClockCore& GetStandardLocalSystemClockCore() const;
const Clock::StandardNetworkSystemClockCore& GetStandardNetworkSystemClockCore() const {
return standard_network_system_clock_core;
}
Clock::StandardNetworkSystemClockCore& GetStandardNetworkSystemClockCore();
Clock::StandardUserSystemClockCore& GetStandardUserSystemClockCore() {
return standard_user_system_clock_core;
}
const Clock::StandardNetworkSystemClockCore& GetStandardNetworkSystemClockCore() const;
const Clock::StandardUserSystemClockCore& GetStandardUserSystemClockCore() const {
return standard_user_system_clock_core;
}
Clock::StandardUserSystemClockCore& GetStandardUserSystemClockCore();
TimeZone::TimeZoneContentManager& GetTimeZoneContentManager() {
return time_zone_content_manager;
}
const Clock::StandardUserSystemClockCore& GetStandardUserSystemClockCore() const;
const TimeZone::TimeZoneContentManager& GetTimeZoneContentManager() const {
return time_zone_content_manager;
}
TimeZone::TimeZoneContentManager& GetTimeZoneContentManager();
SharedMemory& GetSharedMemory() {
return shared_memory;
}
const TimeZone::TimeZoneContentManager& GetTimeZoneContentManager() const;
const SharedMemory& GetSharedMemory() const {
return shared_memory;
}
void UpdateLocalSystemClockTime(s64 posix_time);
SharedMemory& GetSharedMemory();
const SharedMemory& GetSharedMemory() const;
void SetupTimeZoneManager(std::string location_name,
Clock::SteadyClockTimePoint time_zone_updated_time_point,
std::size_t total_location_name_count, u128 time_zone_rule_version,
FileSys::VirtualFile& vfs_file);
static s64 GetExternalTimeZoneOffset();
private:
void SetupStandardSteadyClock(Core::System& system, Common::UUID clock_source_id,
Clock::TimeSpanType setup_value,
Clock::TimeSpanType internal_offset, bool is_rtc_reset_detected);
void SetupStandardLocalSystemClock(Core::System& system,
Clock::SystemClockContext clock_context, s64 posix_time);
void SetupStandardNetworkSystemClock(Clock::SystemClockContext clock_context,
Clock::TimeSpanType sufficient_accuracy);
void SetupStandardUserSystemClock(Core::System& system, bool is_automatic_correction_enabled,
Clock::SteadyClockTimePoint steady_clock_time_point);
void SetupEphemeralNetworkSystemClock();
Core::System& system;
SharedMemory shared_memory;
Clock::StandardSteadyClockCore standard_steady_clock_core;
Clock::TickBasedSteadyClockCore tick_based_steady_clock_core;
Clock::StandardLocalSystemClockCore standard_local_system_clock_core;
Clock::StandardNetworkSystemClockCore standard_network_system_clock_core;
Clock::StandardUserSystemClockCore standard_user_system_clock_core;
Clock::EphemeralNetworkSystemClockCore ephemeral_network_system_clock_core;
std::shared_ptr<Clock::LocalSystemClockContextWriter> local_system_clock_context_writer;
std::shared_ptr<Clock::NetworkSystemClockContextWriter> network_system_clock_context_writer;
std::shared_ptr<Clock::EphemeralNetworkSystemClockContextWriter>
ephemeral_network_system_clock_context_writer;
TimeZone::TimeZoneContentManager time_zone_content_manager;
struct Impl;
std::unique_ptr<Impl> impl;
};
} // namespace Service::Time

View File

@@ -68,9 +68,10 @@ static std::vector<std::string> BuildLocationNameCache(Core::System& system) {
return location_name_cache;
}
TimeZoneContentManager::TimeZoneContentManager(TimeManager& time_manager, Core::System& system)
: system{system}, location_name_cache{BuildLocationNameCache(system)} {
TimeZoneContentManager::TimeZoneContentManager(Core::System& system)
: system{system}, location_name_cache{BuildLocationNameCache(system)} {}
void TimeZoneContentManager::Initialize(TimeManager& time_manager) {
std::string location_name;
const auto timezone_setting = Settings::GetTimeZoneString();
if (timezone_setting == "auto" || timezone_setting == "default") {

View File

@@ -21,7 +21,9 @@ namespace Service::Time::TimeZone {
class TimeZoneContentManager final {
public:
TimeZoneContentManager(TimeManager& time_manager, Core::System& system);
TimeZoneContentManager(Core::System& system);
void Initialize(TimeManager& time_manager);
TimeZoneManager& GetTimeZoneManager() {
return time_zone_manager;

View File

@@ -7,6 +7,8 @@ add_library(input_common STATIC
main.h
motion_emu.cpp
motion_emu.h
motion_from_button.cpp
motion_from_button.h
motion_input.cpp
motion_input.h
settings.cpp

View File

@@ -11,6 +11,7 @@
#include "input_common/keyboard.h"
#include "input_common/main.h"
#include "input_common/motion_emu.h"
#include "input_common/motion_from_button.h"
#include "input_common/touch_from_button.h"
#include "input_common/udp/client.h"
#include "input_common/udp/udp.h"
@@ -32,6 +33,8 @@ struct InputSubsystem::Impl {
Input::RegisterFactory<Input::ButtonDevice>("keyboard", keyboard);
Input::RegisterFactory<Input::AnalogDevice>("analog_from_button",
std::make_shared<AnalogFromButton>());
Input::RegisterFactory<Input::MotionDevice>("keyboard",
std::make_shared<MotionFromButton>());
motion_emu = std::make_shared<MotionEmu>();
Input::RegisterFactory<Input::MotionDevice>("motion_emu", motion_emu);
Input::RegisterFactory<Input::TouchDevice>("touch_from_button",
@@ -50,6 +53,7 @@ struct InputSubsystem::Impl {
void Shutdown() {
Input::UnregisterFactory<Input::ButtonDevice>("keyboard");
Input::UnregisterFactory<Input::MotionDevice>("keyboard");
keyboard.reset();
Input::UnregisterFactory<Input::AnalogDevice>("analog_from_button");
Input::UnregisterFactory<Input::MotionDevice>("motion_emu");

View File

@@ -0,0 +1,34 @@
// Copyright 2020 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include "input_common/motion_from_button.h"
#include "input_common/motion_input.h"
namespace InputCommon {
class MotionKey final : public Input::MotionDevice {
public:
using Button = std::unique_ptr<Input::ButtonDevice>;
MotionKey(Button key_) : key(std::move(key_)) {}
Input::MotionStatus GetStatus() const override {
if (key->GetStatus()) {
return motion.GetRandomMotion(2, 6);
}
return motion.GetRandomMotion(0, 0);
}
private:
Button key;
InputCommon::MotionInput motion{0.0f, 0.0f, 0.0f};
};
std::unique_ptr<Input::MotionDevice> MotionFromButton::Create(const Common::ParamPackage& params) {
auto key = Input::CreateDevice<Input::ButtonDevice>(params.Serialize());
return std::make_unique<MotionKey>(std::move(key));
}
} // namespace InputCommon

View File

@@ -0,0 +1,25 @@
// Copyright 2020 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include "core/frontend/input.h"
namespace InputCommon {
/**
* An motion device factory that takes a keyboard button and uses it as a random
* motion device.
*/
class MotionFromButton final : public Input::Factory<Input::MotionDevice> {
public:
/**
* Creates an motion device from button devices
* @param params contains parameters for creating the device:
* - "key": a serialized ParamPackage for creating a button device
*/
std::unique_ptr<Input::MotionDevice> Create(const Common::ParamPackage& params) override;
};
} // namespace InputCommon

View File

@@ -2,6 +2,7 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included
#include <random>
#include "common/math_util.h"
#include "input_common/motion_input.h"
@@ -16,8 +17,16 @@ void MotionInput::SetAcceleration(const Common::Vec3f& acceleration) {
void MotionInput::SetGyroscope(const Common::Vec3f& gyroscope) {
gyro = gyroscope - gyro_drift;
// Auto adjust drift to minimize drift
if (!IsMoving(0.1f)) {
gyro_drift = (gyro_drift * 0.9999f) + (gyroscope * 0.0001f);
}
if (gyro.Length2() < gyro_threshold) {
gyro = {};
} else {
only_accelerometer = false;
}
}
@@ -68,7 +77,7 @@ void MotionInput::UpdateOrientation(u64 elapsed_time) {
f32 q4 = quat.xyz[2];
const f32 sample_period = elapsed_time / 1000000.0f;
// ignore invalid elapsed time
// Ignore invalid elapsed time
if (sample_period > 0.1f) {
return;
}
@@ -80,6 +89,13 @@ void MotionInput::UpdateOrientation(u64 elapsed_time) {
rad_gyro.y = -swap;
rad_gyro.z = -rad_gyro.z;
// Clear gyro values if there is no gyro present
if (only_accelerometer) {
rad_gyro.x = 0;
rad_gyro.y = 0;
rad_gyro.z = 0;
}
// Ignore drift correction if acceleration is not reliable
if (accel.Length() >= 0.75f && accel.Length() <= 1.25f) {
const f32 ax = -normal_accel.x;
@@ -92,8 +108,11 @@ void MotionInput::UpdateOrientation(u64 elapsed_time) {
const f32 vz = q1 * q1 - q2 * q2 - q3 * q3 + q4 * q4;
// Error is cross product between estimated direction and measured direction of gravity
const Common::Vec3f new_real_error = {az * vx - ax * vz, ay * vz - az * vy,
ax * vy - ay * vx};
const Common::Vec3f new_real_error = {
az * vx - ax * vz,
ay * vz - az * vy,
ax * vy - ay * vx,
};
derivative_error = new_real_error - real_error;
real_error = new_real_error;
@@ -106,9 +125,22 @@ void MotionInput::UpdateOrientation(u64 elapsed_time) {
}
// Apply feedback terms
rad_gyro += kp * real_error;
rad_gyro += ki * integral_error;
rad_gyro += kd * derivative_error;
if (!only_accelerometer) {
rad_gyro += kp * real_error;
rad_gyro += ki * integral_error;
rad_gyro += kd * derivative_error;
} else {
// Give more weight to acelerometer values to compensate for the lack of gyro
rad_gyro += 35.0f * kp * real_error;
rad_gyro += 10.0f * ki * integral_error;
rad_gyro += 10.0f * kd * derivative_error;
// Emulate gyro values for games that need them
gyro.x = -rad_gyro.y;
gyro.y = rad_gyro.x;
gyro.z = -rad_gyro.z;
UpdateRotation(elapsed_time);
}
}
const f32 gx = rad_gyro.y;
@@ -159,18 +191,49 @@ Common::Vec3f MotionInput::GetRotations() const {
return rotations;
}
Input::MotionStatus MotionInput::GetMotion() const {
const Common::Vec3f gyroscope = GetGyroscope();
const Common::Vec3f accelerometer = GetAcceleration();
const Common::Vec3f rotation = GetRotations();
const std::array<Common::Vec3f, 3> orientation = GetOrientation();
return {accelerometer, gyroscope, rotation, orientation};
}
Input::MotionStatus MotionInput::GetRandomMotion(int accel_magnitude, int gyro_magnitude) const {
std::random_device device;
std::mt19937 gen(device());
std::uniform_int_distribution<s16> distribution(-1000, 1000);
const Common::Vec3f gyroscope = {
distribution(gen) * 0.001f,
distribution(gen) * 0.001f,
distribution(gen) * 0.001f,
};
const Common::Vec3f accelerometer = {
distribution(gen) * 0.001f,
distribution(gen) * 0.001f,
distribution(gen) * 0.001f,
};
const Common::Vec3f rotation = {};
const std::array<Common::Vec3f, 3> orientation = {
Common::Vec3f{1.0f, 0, 0},
Common::Vec3f{0, 1.0f, 0},
Common::Vec3f{0, 0, 1.0f},
};
return {accelerometer * accel_magnitude, gyroscope * gyro_magnitude, rotation, orientation};
}
void MotionInput::ResetOrientation() {
if (!reset_enabled) {
if (!reset_enabled || only_accelerometer) {
return;
}
if (!IsMoving(0.5f) && accel.z <= -0.9f) {
++reset_counter;
if (reset_counter > 900) {
// TODO: calculate quaternion from gravity vector
quat.w = 0;
quat.xyz[0] = 0;
quat.xyz[1] = 0;
quat.xyz[2] = -1;
SetOrientationFromAccelerometer();
integral_error = {};
reset_counter = 0;
}
@@ -178,4 +241,65 @@ void MotionInput::ResetOrientation() {
reset_counter = 0;
}
}
void MotionInput::SetOrientationFromAccelerometer() {
int iterations = 0;
const f32 sample_period = 0.015f;
const auto normal_accel = accel.Normalized();
const f32 ax = -normal_accel.x;
const f32 ay = normal_accel.y;
const f32 az = -normal_accel.z;
while (!IsCalibrated(0.01f) && ++iterations < 100) {
// Short name local variable for readability
f32 q1 = quat.w;
f32 q2 = quat.xyz[0];
f32 q3 = quat.xyz[1];
f32 q4 = quat.xyz[2];
Common::Vec3f rad_gyro = {};
const f32 ax = -normal_accel.x;
const f32 ay = normal_accel.y;
const f32 az = -normal_accel.z;
// Estimated direction of gravity
const f32 vx = 2.0f * (q2 * q4 - q1 * q3);
const f32 vy = 2.0f * (q1 * q2 + q3 * q4);
const f32 vz = q1 * q1 - q2 * q2 - q3 * q3 + q4 * q4;
// Error is cross product between estimated direction and measured direction of gravity
const Common::Vec3f new_real_error = {
az * vx - ax * vz,
ay * vz - az * vy,
ax * vy - ay * vx,
};
derivative_error = new_real_error - real_error;
real_error = new_real_error;
rad_gyro += 10.0f * kp * real_error;
rad_gyro += 5.0f * ki * integral_error;
rad_gyro += 10.0f * kd * derivative_error;
const f32 gx = rad_gyro.y;
const f32 gy = rad_gyro.x;
const f32 gz = rad_gyro.z;
// Integrate rate of change of quaternion
const f32 pa = q2;
const f32 pb = q3;
const f32 pc = q4;
q1 = q1 + (-q2 * gx - q3 * gy - q4 * gz) * (0.5f * sample_period);
q2 = pa + (q1 * gx + pb * gz - pc * gy) * (0.5f * sample_period);
q3 = pb + (q1 * gy - pa * gz + pc * gx) * (0.5f * sample_period);
q4 = pc + (q1 * gz + pa * gy - pb * gx) * (0.5f * sample_period);
quat.w = q1;
quat.xyz[0] = q2;
quat.xyz[1] = q3;
quat.xyz[2] = q4;
quat = quat.Normalized();
}
}
} // namespace InputCommon

View File

@@ -7,6 +7,7 @@
#include "common/common_types.h"
#include "common/quaternion.h"
#include "common/vector_math.h"
#include "core/frontend/input.h"
namespace InputCommon {
@@ -37,12 +38,15 @@ public:
Common::Vec3f GetGyroscope() const;
Common::Vec3f GetRotations() const;
Common::Quaternion<f32> GetQuaternion() const;
Input::MotionStatus GetMotion() const;
Input::MotionStatus GetRandomMotion(int accel_magnitude, int gyro_magnitude) const;
bool IsMoving(f32 sensitivity) const;
bool IsCalibrated(f32 sensitivity) const;
private:
void ResetOrientation();
void SetOrientationFromAccelerometer();
// PID constants
const f32 kp;
@@ -63,6 +67,7 @@ private:
f32 gyro_threshold = 0.0f;
u32 reset_counter = 0;
bool reset_enabled = true;
bool only_accelerometer = true;
};
} // namespace InputCommon

View File

@@ -22,6 +22,7 @@
#include "common/param_package.h"
#include "common/threadsafe_queue.h"
#include "core/frontend/input.h"
#include "input_common/motion_input.h"
#include "input_common/sdl/sdl_impl.h"
#include "input_common/settings.h"
@@ -123,6 +124,10 @@ public:
return std::make_tuple(x, y);
}
const InputCommon::MotionInput& GetMotion() const {
return motion;
}
void SetHat(int hat, Uint8 direction) {
std::lock_guard lock{mutex};
state.hats.insert_or_assign(hat, direction);
@@ -173,6 +178,9 @@ private:
std::unique_ptr<SDL_Joystick, decltype(&SDL_JoystickClose)> sdl_joystick;
std::unique_ptr<SDL_GameController, decltype(&SDL_GameControllerClose)> sdl_controller;
mutable std::mutex mutex;
// motion is initalized without PID values as motion input is not aviable for SDL2
InputCommon::MotionInput motion{0.0f, 0.0f, 0.0f};
};
std::shared_ptr<SDLJoystick> SDLState::GetSDLJoystickByGUID(const std::string& guid, int port) {
@@ -423,6 +431,68 @@ private:
const float range;
};
class SDLDirectionMotion final : public Input::MotionDevice {
public:
explicit SDLDirectionMotion(std::shared_ptr<SDLJoystick> joystick_, int hat_, Uint8 direction_)
: joystick(std::move(joystick_)), hat(hat_), direction(direction_) {}
Input::MotionStatus GetStatus() const override {
if (joystick->GetHatDirection(hat, direction)) {
return joystick->GetMotion().GetRandomMotion(2, 6);
}
return joystick->GetMotion().GetRandomMotion(0, 0);
}
private:
std::shared_ptr<SDLJoystick> joystick;
int hat;
Uint8 direction;
};
class SDLAxisMotion final : public Input::MotionDevice {
public:
explicit SDLAxisMotion(std::shared_ptr<SDLJoystick> joystick_, int axis_, float threshold_,
bool trigger_if_greater_)
: joystick(std::move(joystick_)), axis(axis_), threshold(threshold_),
trigger_if_greater(trigger_if_greater_) {}
Input::MotionStatus GetStatus() const override {
const float axis_value = joystick->GetAxis(axis, 1.0f);
bool trigger = axis_value < threshold;
if (trigger_if_greater) {
trigger = axis_value > threshold;
}
if (trigger) {
return joystick->GetMotion().GetRandomMotion(2, 6);
}
return joystick->GetMotion().GetRandomMotion(0, 0);
}
private:
std::shared_ptr<SDLJoystick> joystick;
int axis;
float threshold;
bool trigger_if_greater;
};
class SDLButtonMotion final : public Input::MotionDevice {
public:
explicit SDLButtonMotion(std::shared_ptr<SDLJoystick> joystick_, int button_)
: joystick(std::move(joystick_)), button(button_) {}
Input::MotionStatus GetStatus() const override {
if (joystick->GetButton(button)) {
return joystick->GetMotion().GetRandomMotion(2, 6);
}
return joystick->GetMotion().GetRandomMotion(0, 0);
}
private:
std::shared_ptr<SDLJoystick> joystick;
int button;
};
/// A button device factory that creates button devices from SDL joystick
class SDLButtonFactory final : public Input::Factory<Input::ButtonDevice> {
public:
@@ -529,12 +599,78 @@ private:
SDLState& state;
};
/// A motion device factory that creates motion devices from SDL joystick
class SDLMotionFactory final : public Input::Factory<Input::MotionDevice> {
public:
explicit SDLMotionFactory(SDLState& state_) : state(state_) {}
/**
* Creates motion device from joystick axes
* @param params contains parameters for creating the device:
* - "guid": the guid of the joystick to bind
* - "port": the nth joystick of the same type
*/
std::unique_ptr<Input::MotionDevice> Create(const Common::ParamPackage& params) override {
const std::string guid = params.Get("guid", "0");
const int port = params.Get("port", 0);
auto joystick = state.GetSDLJoystickByGUID(guid, port);
if (params.Has("hat")) {
const int hat = params.Get("hat", 0);
const std::string direction_name = params.Get("direction", "");
Uint8 direction;
if (direction_name == "up") {
direction = SDL_HAT_UP;
} else if (direction_name == "down") {
direction = SDL_HAT_DOWN;
} else if (direction_name == "left") {
direction = SDL_HAT_LEFT;
} else if (direction_name == "right") {
direction = SDL_HAT_RIGHT;
} else {
direction = 0;
}
// This is necessary so accessing GetHat with hat won't crash
joystick->SetHat(hat, SDL_HAT_CENTERED);
return std::make_unique<SDLDirectionMotion>(joystick, hat, direction);
}
if (params.Has("axis")) {
const int axis = params.Get("axis", 0);
const float threshold = params.Get("threshold", 0.5f);
const std::string direction_name = params.Get("direction", "");
bool trigger_if_greater;
if (direction_name == "+") {
trigger_if_greater = true;
} else if (direction_name == "-") {
trigger_if_greater = false;
} else {
trigger_if_greater = true;
LOG_ERROR(Input, "Unknown direction {}", direction_name);
}
// This is necessary so accessing GetAxis with axis won't crash
joystick->SetAxis(axis, 0);
return std::make_unique<SDLAxisMotion>(joystick, axis, threshold, trigger_if_greater);
}
const int button = params.Get("button", 0);
// This is necessary so accessing GetButton with button won't crash
joystick->SetButton(button, false);
return std::make_unique<SDLButtonMotion>(joystick, button);
}
private:
SDLState& state;
};
SDLState::SDLState() {
using namespace Input;
analog_factory = std::make_shared<SDLAnalogFactory>(*this);
button_factory = std::make_shared<SDLButtonFactory>(*this);
motion_factory = std::make_shared<SDLMotionFactory>(*this);
RegisterFactory<AnalogDevice>("sdl", analog_factory);
RegisterFactory<ButtonDevice>("sdl", button_factory);
RegisterFactory<MotionDevice>("sdl", motion_factory);
// If the frontend is going to manage the event loop, then we dont start one here
start_thread = !SDL_WasInit(SDL_INIT_JOYSTICK);
@@ -570,6 +706,7 @@ SDLState::~SDLState() {
using namespace Input;
UnregisterFactory<ButtonDevice>("sdl");
UnregisterFactory<AnalogDevice>("sdl");
UnregisterFactory<MotionDevice>("sdl");
CloseJoysticks();
SDL_DelEventWatch(&SDLEventWatcher, this);
@@ -681,6 +818,27 @@ Common::ParamPackage SDLEventToButtonParamPackage(SDLState& state, const SDL_Eve
return {};
}
Common::ParamPackage SDLEventToMotionParamPackage(SDLState& state, const SDL_Event& event) {
switch (event.type) {
case SDL_JOYAXISMOTION: {
const auto joystick = state.GetSDLJoystickBySDLID(event.jaxis.which);
return BuildAnalogParamPackageForButton(joystick->GetPort(), joystick->GetGUID(),
event.jaxis.axis, event.jaxis.value);
}
case SDL_JOYBUTTONUP: {
const auto joystick = state.GetSDLJoystickBySDLID(event.jbutton.which);
return BuildButtonParamPackageForButton(joystick->GetPort(), joystick->GetGUID(),
event.jbutton.button);
}
case SDL_JOYHATMOTION: {
const auto joystick = state.GetSDLJoystickBySDLID(event.jhat.which);
return BuildHatParamPackageForButton(joystick->GetPort(), joystick->GetGUID(),
event.jhat.hat, event.jhat.value);
}
}
return {};
}
Common::ParamPackage BuildParamPackageForBinding(int port, const std::string& guid,
const SDL_GameControllerButtonBind& binding) {
switch (binding.bindType) {
@@ -846,6 +1004,35 @@ public:
}
};
class SDLMotionPoller final : public SDLPoller {
public:
explicit SDLMotionPoller(SDLState& state_) : SDLPoller(state_) {}
Common::ParamPackage GetNextInput() override {
SDL_Event event;
while (state.event_queue.Pop(event)) {
const auto package = FromEvent(event);
if (package) {
return *package;
}
}
return {};
}
[[nodiscard]] std::optional<Common::ParamPackage> FromEvent(const SDL_Event& event) const {
switch (event.type) {
case SDL_JOYAXISMOTION:
if (std::abs(event.jaxis.value / 32767.0) < 0.5) {
break;
}
[[fallthrough]];
case SDL_JOYBUTTONUP:
case SDL_JOYHATMOTION:
return {SDLEventToMotionParamPackage(state, event)};
}
return std::nullopt;
}
};
/**
* Attempts to match the press to a controller joy axis (left/right stick) and if a match
* isn't found, checks if the event matches anything from SDLButtonPoller and uses that
@@ -937,6 +1124,9 @@ SDLState::Pollers SDLState::GetPollers(InputCommon::Polling::DeviceType type) {
case InputCommon::Polling::DeviceType::Button:
pollers.emplace_back(std::make_unique<Polling::SDLButtonPoller>(*this));
break;
case InputCommon::Polling::DeviceType::Motion:
pollers.emplace_back(std::make_unique<Polling::SDLMotionPoller>(*this));
break;
}
return pollers;

View File

@@ -21,6 +21,7 @@ namespace InputCommon::SDL {
class SDLAnalogFactory;
class SDLButtonFactory;
class SDLMotionFactory;
class SDLJoystick;
class SDLState : public State {
@@ -71,6 +72,7 @@ private:
std::shared_ptr<SDLButtonFactory> button_factory;
std::shared_ptr<SDLAnalogFactory> analog_factory;
std::shared_ptr<SDLMotionFactory> motion_factory;
bool start_thread = false;
std::atomic<bool> initialized = false;

View File

@@ -219,14 +219,10 @@ void Client::OnPadData(Response::PadData data) {
clients[client].motion.SetGyroscope(raw_gyroscope / 312.0f);
clients[client].motion.UpdateRotation(time_difference);
clients[client].motion.UpdateOrientation(time_difference);
Common::Vec3f gyroscope = clients[client].motion.GetGyroscope();
Common::Vec3f accelerometer = clients[client].motion.GetAcceleration();
Common::Vec3f rotation = clients[client].motion.GetRotations();
std::array<Common::Vec3f, 3> orientation = clients[client].motion.GetOrientation();
{
std::lock_guard guard(clients[client].status.update_mutex);
clients[client].status.motion_status = {accelerometer, gyroscope, rotation, orientation};
clients[client].status.motion_status = clients[client].motion.GetMotion();
// TODO: add a setting for "click" touch. Click touch refers to a device that differentiates
// between a simple "tap" and a hard press that causes the touch screen to click.
@@ -250,6 +246,8 @@ void Client::OnPadData(Response::PadData data) {
clients[client].status.touch_status = {x, y, is_active};
if (configuring) {
const Common::Vec3f gyroscope = clients[client].motion.GetGyroscope();
const Common::Vec3f accelerometer = clients[client].motion.GetAcceleration();
UpdateYuzuSettings(client, accelerometer, gyroscope, is_active);
}
}
@@ -274,18 +272,22 @@ void Client::Reset() {
void Client::UpdateYuzuSettings(std::size_t client, const Common::Vec3<float>& acc,
const Common::Vec3<float>& gyro, bool touch) {
if (gyro.Length() > 0.2f) {
LOG_DEBUG(Input, "UDP Controller {}: gyro=({}, {}, {}), accel=({}, {}, {}), touch={}",
client, gyro[0], gyro[1], gyro[2], acc[0], acc[1], acc[2], touch);
}
UDPPadStatus pad;
if (touch) {
pad.touch = PadTouch::Click;
pad_queue[client].Push(pad);
}
for (size_t i = 0; i < 3; ++i) {
if (gyro[i] > 6.0f || gyro[i] < -6.0f) {
if (gyro[i] > 5.0f || gyro[i] < -5.0f) {
pad.motion = static_cast<PadMotion>(i);
pad.motion_value = gyro[i];
pad_queue[client].Push(pad);
}
if (acc[i] > 2.0f || acc[i] < -2.0f) {
if (acc[i] > 1.75f || acc[i] < -1.75f) {
pad.motion = static_cast<PadMotion>(i + 3);
pad.motion_value = acc[i];
pad_queue[client].Push(pad);

View File

@@ -273,5 +273,12 @@ endif()
if (MSVC)
target_compile_options(video_core PRIVATE /we4267)
else()
target_compile_options(video_core PRIVATE -Werror=conversion -Wno-error=sign-conversion -Werror=switch)
target_compile_options(video_core PRIVATE
-Werror=conversion
-Wno-error=sign-conversion
-Werror=switch
-Werror=unused-variable
-Werror=unused-but-set-variable
-Werror=class-memaccess
)
endif()

View File

@@ -114,8 +114,6 @@ void MaxwellDMA::CopyBlockLinearToPitch() {
const u32 block_depth = src_params.block_size.depth;
const size_t src_size =
CalculateSize(true, bytes_per_pixel, width, height, depth, block_height, block_depth);
const size_t src_layer_size =
CalculateSize(true, bytes_per_pixel, width, height, 1, block_height, block_depth);
if (read_buffer.size() < src_size) {
read_buffer.resize(src_size);

View File

@@ -41,30 +41,30 @@ struct Header {
BitField<26, 1, u32> does_load_or_store;
BitField<27, 1, u32> does_fp64;
BitField<28, 4, u32> stream_out_mask;
} common0{};
} common0;
union {
BitField<0, 24, u32> shader_local_memory_low_size;
BitField<24, 8, u32> per_patch_attribute_count;
} common1{};
} common1;
union {
BitField<0, 24, u32> shader_local_memory_high_size;
BitField<24, 8, u32> threads_per_input_primitive;
} common2{};
} common2;
union {
BitField<0, 24, u32> shader_local_memory_crs_size;
BitField<24, 4, OutputTopology> output_topology;
BitField<28, 4, u32> reserved;
} common3{};
} common3;
union {
BitField<0, 12, u32> max_output_vertices;
BitField<12, 8, u32> store_req_start; // NOTE: not used by geometry shaders.
BitField<20, 4, u32> reserved;
BitField<24, 8, u32> store_req_end; // NOTE: not used by geometry shaders.
} common4{};
} common4;
union {
struct {
@@ -145,7 +145,7 @@ struct Header {
}
} ps;
std::array<u32, 0xF> raw{};
std::array<u32, 0xF> raw;
};
u64 GetLocalMemorySize() const {
@@ -153,7 +153,6 @@ struct Header {
(common2.shader_local_memory_high_size << 24));
}
};
static_assert(sizeof(Header) == 0x50, "Incorrect structure size");
} // namespace Tegra::Shader

View File

@@ -193,7 +193,6 @@ bool IsASTCSupported() {
Device::Device()
: max_uniform_buffers{BuildMaxUniformBuffers()}, base_bindings{BuildBaseBindings()} {
const std::string_view vendor = reinterpret_cast<const char*>(glGetString(GL_VENDOR));
const std::string_view renderer = reinterpret_cast<const char*>(glGetString(GL_RENDERER));
const std::string_view version = reinterpret_cast<const char*>(glGetString(GL_VERSION));
const std::vector extensions = GetExtensions();

View File

@@ -6,6 +6,7 @@
#include <exception>
#include <memory>
#include <optional>
#include <string_view>
#include <utility>
#include <vector>
@@ -17,21 +18,42 @@ namespace Vulkan::vk {
namespace {
void SortPhysicalDevices(std::vector<VkPhysicalDevice>& devices, const InstanceDispatch& dld) {
std::stable_sort(devices.begin(), devices.end(), [&](auto lhs, auto rhs) {
// This will call Vulkan more than needed, but these calls are cheap.
const auto lhs_properties = vk::PhysicalDevice(lhs, dld).GetProperties();
const auto rhs_properties = vk::PhysicalDevice(rhs, dld).GetProperties();
template <typename Func>
void SortPhysicalDevices(std::vector<VkPhysicalDevice>& devices, const InstanceDispatch& dld,
Func&& func) {
// Calling GetProperties calls Vulkan more than needed. But they are supposed to be cheap
// functions.
std::stable_sort(devices.begin(), devices.end(),
[&dld, &func](VkPhysicalDevice lhs, VkPhysicalDevice rhs) {
return func(vk::PhysicalDevice(lhs, dld).GetProperties(),
vk::PhysicalDevice(rhs, dld).GetProperties());
});
}
// Prefer discrete GPUs, Nvidia over AMD, AMD over Intel, Intel over the rest.
const bool preferred =
(lhs_properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU &&
rhs_properties.deviceType != VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU) ||
(lhs_properties.vendorID == 0x10DE && rhs_properties.vendorID != 0x10DE) ||
(lhs_properties.vendorID == 0x1002 && rhs_properties.vendorID != 0x1002) ||
(lhs_properties.vendorID == 0x8086 && rhs_properties.vendorID != 0x8086);
return !preferred;
void SortPhysicalDevicesPerVendor(std::vector<VkPhysicalDevice>& devices,
const InstanceDispatch& dld,
std::initializer_list<u32> vendor_ids) {
for (auto it = vendor_ids.end(); it != vendor_ids.begin();) {
--it;
SortPhysicalDevices(devices, dld, [id = *it](const auto& lhs, const auto& rhs) {
return lhs.vendorID == id && rhs.vendorID != id;
});
}
}
void SortPhysicalDevices(std::vector<VkPhysicalDevice>& devices, const InstanceDispatch& dld) {
// Sort by name, this will set a base and make GPUs with higher numbers appear first
// (e.g. GTX 1650 will intentionally be listed before a GTX 1080).
SortPhysicalDevices(devices, dld, [](const auto& lhs, const auto& rhs) {
return std::string_view{lhs.deviceName} > std::string_view{rhs.deviceName};
});
// Prefer discrete over non-discrete
SortPhysicalDevices(devices, dld, [](const auto& lhs, const auto& rhs) {
return lhs.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU &&
rhs.deviceType != VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU;
});
// Prefer Nvidia over AMD, AMD over Intel, Intel over the rest.
SortPhysicalDevicesPerVendor(devices, dld, {0x10DE, 0x1002, 0x8086});
}
template <typename T>

View File

@@ -292,33 +292,36 @@ u32 ShaderIR::DecodeTexture(NodeBlock& bb, u32 pc) {
break;
}
const u64 base_index = is_array ? 1 : 0;
const u64 num_components = [texture_type] {
switch (texture_type) {
case TextureType::Texture1D:
return 1;
case TextureType::Texture2D:
return 2;
case TextureType::TextureCube:
return 3;
default:
UNIMPLEMENTED_MSG("Unhandled texture type {}", static_cast<int>(texture_type));
return 2;
}
}();
// TODO: What's the array component used for?
std::vector<Node> coords;
// TODO: Add coordinates for different samplers once other texture types are implemented.
switch (texture_type) {
case TextureType::Texture1D:
coords.push_back(GetRegister(instr.gpr8));
break;
case TextureType::Texture2D:
coords.push_back(GetRegister(instr.gpr8.Value() + 0));
coords.push_back(GetRegister(instr.gpr8.Value() + 1));
break;
default:
UNIMPLEMENTED_MSG("Unhandled texture type {}", static_cast<int>(texture_type));
// Fallback to interpreting as a 2D texture for now
coords.push_back(GetRegister(instr.gpr8.Value() + 0));
coords.push_back(GetRegister(instr.gpr8.Value() + 1));
coords.reserve(num_components);
for (u64 component = 0; component < num_components; ++component) {
coords.push_back(GetRegister(instr.gpr8.Value() + base_index + component));
}
u32 indexer = 0;
for (u32 element = 0; element < 2; ++element) {
if (!instr.tmml.IsComponentEnabled(element)) {
continue;
}
auto params = coords;
MetaTexture meta{*sampler, {}, {}, {}, {}, {}, {}, {}, {}, element, index_var};
const Node value = Operation(OperationCode::TextureQueryLod, meta, std::move(params));
SetTemporary(bb, indexer++, value);
Node value = Operation(OperationCode::TextureQueryLod, meta, coords);
SetTemporary(bb, indexer++, std::move(value));
}
for (u32 i = 0; i < indexer; ++i) {
SetRegister(bb, instr.gpr0.Value() + i, GetTemporary(i));

View File

@@ -12,6 +12,7 @@
#include "common/assert.h"
#include "common/file_util.h"
#include "core/core.h"
#include "core/hle/service/time/time.h"
#include "core/settings.h"
#include "ui_configure_system.h"
#include "yuzu/configuration/configuration_shared.h"
@@ -104,6 +105,22 @@ void ConfigureSystem::SetConfiguration() {
void ConfigureSystem::ReadSystemSettings() {}
void ConfigureSystem::ApplyConfiguration() {
// Allow setting custom RTC even if system is powered on, to allow in-game time to be fast
// forwared
if (Settings::values.custom_rtc.UsingGlobal()) {
if (ui->custom_rtc_checkbox->isChecked()) {
Settings::values.custom_rtc.SetValue(
std::chrono::seconds(ui->custom_rtc_edit->dateTime().toSecsSinceEpoch()));
if (Core::System::GetInstance().IsPoweredOn()) {
const s64 posix_time{Settings::values.custom_rtc.GetValue()->count() +
Service::Time::TimeManager::GetExternalTimeZoneOffset()};
Core::System::GetInstance().GetTimeManager().UpdateLocalSystemClockTime(posix_time);
}
} else {
Settings::values.custom_rtc.SetValue(std::nullopt);
}
}
if (!enabled) {
return;
}
@@ -131,15 +148,6 @@ void ConfigureSystem::ApplyConfiguration() {
Settings::values.rng_seed.SetValue(std::nullopt);
}
}
if (Settings::values.custom_rtc.UsingGlobal()) {
if (ui->custom_rtc_checkbox->isChecked()) {
Settings::values.custom_rtc.SetValue(
std::chrono::seconds(ui->custom_rtc_edit->dateTime().toSecsSinceEpoch()));
} else {
Settings::values.custom_rtc.SetValue(std::nullopt);
}
}
} else {
ConfigurationShared::ApplyPerGameSetting(&Settings::values.language_index,
ui->combo_language);