From 1d481a395ae18546f9bfd224f196a0271a526691 Mon Sep 17 00:00:00 2001 From: Jordan Woyak Date: Tue, 25 Feb 2025 03:59:37 -0600 Subject: [PATCH 1/3] VariantUtil: Introduce WithVariantAlternative to dynamically construct and visit a variant alternative. --- Source/Core/Common/VariantUtil.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/Source/Core/Common/VariantUtil.h b/Source/Core/Common/VariantUtil.h index 69f886c167..54ac6ba2cf 100644 --- a/Source/Core/Common/VariantUtil.h +++ b/Source/Core/Common/VariantUtil.h @@ -34,3 +34,18 @@ struct overloaded : Ts... template overloaded(Ts...) -> overloaded; + +// Visits a functor with a variant_alternative of the given index. +// e.g. WithVariantAlternative>(1, func) calls func() +// An out-of-bounds index causes no visitation. +template +void WithVariantAlternative(std::size_t index, Func&& func) +{ + if constexpr (I < std::variant_size_v) + { + if (index == 0) + func.template operator()>(); + else + WithVariantAlternative(index - 1, std::forward(func)); + } +} From 0d0734e083de2350407e4d9f7f5d7a9385f27984 Mon Sep 17 00:00:00 2001 From: Jordan Woyak Date: Tue, 25 Feb 2025 01:26:04 -0600 Subject: [PATCH 2/3] WiimoteEmu: Clean up variant handling in DesiredExtensionState. --- .../HW/WiimoteEmu/DesiredWiimoteState.cpp | 97 +++---------------- .../Core/HW/WiimoteEmu/Extension/Classic.h | 2 + .../Extension/DesiredExtensionState.h | 46 +++------ .../HW/WiimoteEmu/Extension/DrawsomeTablet.h | 3 +- .../Core/HW/WiimoteEmu/Extension/Guitar.h | 2 + .../Core/HW/WiimoteEmu/Extension/Nunchuk.h | 2 + .../Core/HW/WiimoteEmu/Extension/TaTaCon.h | 2 + .../Core/HW/WiimoteEmu/Extension/Turntable.h | 2 + .../HW/WiimoteEmu/Extension/UDrawTablet.h | 3 +- 9 files changed, 37 insertions(+), 122 deletions(-) diff --git a/Source/Core/Core/HW/WiimoteEmu/DesiredWiimoteState.cpp b/Source/Core/Core/HW/WiimoteEmu/DesiredWiimoteState.cpp index b59d04606f..b9e68b2594 100644 --- a/Source/Core/Core/HW/WiimoteEmu/DesiredWiimoteState.cpp +++ b/Source/Core/Core/HW/WiimoteEmu/DesiredWiimoteState.cpp @@ -10,16 +10,8 @@ #include "Common/BitUtils.h" #include "Common/CommonTypes.h" +#include "Common/VariantUtil.h" -#include "Core/HW/WiimoteEmu/Extension/Classic.h" -#include "Core/HW/WiimoteEmu/Extension/DrawsomeTablet.h" -#include "Core/HW/WiimoteEmu/Extension/Drums.h" -#include "Core/HW/WiimoteEmu/Extension/Guitar.h" -#include "Core/HW/WiimoteEmu/Extension/Nunchuk.h" -#include "Core/HW/WiimoteEmu/Extension/Shinkansen.h" -#include "Core/HW/WiimoteEmu/Extension/TaTaCon.h" -#include "Core/HW/WiimoteEmu/Extension/Turntable.h" -#include "Core/HW/WiimoteEmu/Extension/UDrawTablet.h" #include "Core/HW/WiimoteEmu/MotionPlus.h" namespace WiimoteEmu @@ -114,13 +106,9 @@ SerializedWiimoteState SerializeDesiredState(const DesiredWiimoteState& state) std::visit( [&s](const auto& arg) { using T = std::decay_t; - if constexpr (!std::is_same_v) - { - static_assert(sizeof(arg) <= 6); - static_assert(std::is_trivially_copyable_v); - std::memcpy(&s.data[s.length], &arg, sizeof(arg)); - s.length += sizeof(arg); - } + static_assert(sizeof(arg) <= 6); + Common::BitCastPtr(&s.data[s.length]) = arg; + s.length += sizeof(arg); }, state.extension.data); } @@ -128,19 +116,6 @@ SerializedWiimoteState SerializeDesiredState(const DesiredWiimoteState& state) return s; } -template -static bool DeserializeExtensionState(DesiredWiimoteState* state, - const SerializedWiimoteState& serialized, size_t offset) -{ - if (serialized.length < offset + sizeof(T)) - return false; - auto& e = state->extension.data.emplace(); - static_assert(std::is_trivially_copyable_v); - std::memcpy(static_cast(&e), static_cast(&serialized.data[offset]), - sizeof(T)); - return true; -} - bool DeserializeDesiredState(DesiredWiimoteState* state, const SerializedWiimoteState& serialized) { // clear state @@ -181,39 +156,10 @@ bool DeserializeDesiredState(DesiredWiimoteState* state, const SerializedWiimote s += 12; if (has_motion_plus) s += 6; - switch (extension) + if (extension) { - case ExtensionNumber::NONE: - break; - case ExtensionNumber::NUNCHUK: - s += sizeof(Nunchuk::DataFormat); - break; - case ExtensionNumber::CLASSIC: - s += sizeof(Classic::DataFormat); - break; - case ExtensionNumber::GUITAR: - s += sizeof(Guitar::DataFormat); - break; - case ExtensionNumber::DRUMS: - s += sizeof(Drums::DesiredState); - break; - case ExtensionNumber::TURNTABLE: - s += sizeof(Turntable::DataFormat); - break; - case ExtensionNumber::UDRAW_TABLET: - s += sizeof(UDrawTablet::DataFormat); - break; - case ExtensionNumber::DRAWSOME_TABLET: - s += sizeof(DrawsomeTablet::DataFormat); - break; - case ExtensionNumber::TATACON: - s += sizeof(TaTaCon::DataFormat); - break; - case ExtensionNumber::SHINKANSEN: - s += sizeof(Shinkansen::DesiredState); - break; - default: - break; + WithVariantAlternative( + extension, [&]() { s += sizeof(T); }); } return s; }(); @@ -283,32 +229,13 @@ bool DeserializeDesiredState(DesiredWiimoteState* state, const SerializedWiimote pos += 6; } - switch (extension) + if (extension) { - case ExtensionNumber::NONE: - return true; - case ExtensionNumber::NUNCHUK: - return DeserializeExtensionState(state, serialized, pos); - case ExtensionNumber::CLASSIC: - return DeserializeExtensionState(state, serialized, pos); - case ExtensionNumber::GUITAR: - return DeserializeExtensionState(state, serialized, pos); - case ExtensionNumber::DRUMS: - return DeserializeExtensionState(state, serialized, pos); - case ExtensionNumber::TURNTABLE: - return DeserializeExtensionState(state, serialized, pos); - case ExtensionNumber::UDRAW_TABLET: - return DeserializeExtensionState(state, serialized, pos); - case ExtensionNumber::DRAWSOME_TABLET: - return DeserializeExtensionState(state, serialized, pos); - case ExtensionNumber::TATACON: - return DeserializeExtensionState(state, serialized, pos); - case ExtensionNumber::SHINKANSEN: - return DeserializeExtensionState(state, serialized, pos); - default: - break; + WithVariantAlternative(extension, [&]() { + state->extension.data.emplace(Common::BitCastPtr(&d[pos])); + }); } - return false; + return true; } } // namespace WiimoteEmu diff --git a/Source/Core/Core/HW/WiimoteEmu/Extension/Classic.h b/Source/Core/Core/HW/WiimoteEmu/Extension/Classic.h index 02781ac8ee..5788fa3e62 100644 --- a/Source/Core/Core/HW/WiimoteEmu/Extension/Classic.h +++ b/Source/Core/Core/HW/WiimoteEmu/Extension/Classic.h @@ -129,6 +129,8 @@ public: }; static_assert(sizeof(DataFormat) == 6, "Wrong size"); + using DesiredState = DataFormat; + static constexpr int CAL_STICK_BITS = 8; static constexpr int CAL_TRIGGER_BITS = 8; diff --git a/Source/Core/Core/HW/WiimoteEmu/Extension/DesiredExtensionState.h b/Source/Core/Core/HW/WiimoteEmu/Extension/DesiredExtensionState.h index 4929c91cd1..a61da143bc 100644 --- a/Source/Core/Core/HW/WiimoteEmu/Extension/DesiredExtensionState.h +++ b/Source/Core/Core/HW/WiimoteEmu/Extension/DesiredExtensionState.h @@ -3,7 +3,6 @@ #pragma once -#include #include #include "Common/BitUtils.h" @@ -18,46 +17,23 @@ #include "Core/HW/WiimoteEmu/Extension/TaTaCon.h" #include "Core/HW/WiimoteEmu/Extension/Turntable.h" #include "Core/HW/WiimoteEmu/Extension/UDrawTablet.h" -#include "Core/HW/WiimoteEmu/ExtensionPort.h" namespace WiimoteEmu { struct DesiredExtensionState { - using ExtensionData = - std::variant; - ExtensionData data = std::monostate(); +private: + template + struct ExtDataImpl + { + using type = std::variant; + }; - static_assert(std::is_same_v>); - static_assert( - std::is_same_v>); - static_assert( - std::is_same_v>); - static_assert(std::is_same_v>); - static_assert(std::is_same_v>); - static_assert( - std::is_same_v>); - static_assert( - std::is_same_v>); - static_assert( - std::is_same_v>); - static_assert( - std::is_same_v>); - static_assert( - std::is_same_v>); - static_assert(std::variant_size_v == ExtensionNumber::MAX); +public: + using ExtensionData = ExtDataImpl::type; + + ExtensionData data = std::monostate{}; }; template diff --git a/Source/Core/Core/HW/WiimoteEmu/Extension/DrawsomeTablet.h b/Source/Core/Core/HW/WiimoteEmu/Extension/DrawsomeTablet.h index fe4a213d09..184d0df250 100644 --- a/Source/Core/Core/HW/WiimoteEmu/Extension/DrawsomeTablet.h +++ b/Source/Core/Core/HW/WiimoteEmu/Extension/DrawsomeTablet.h @@ -50,9 +50,10 @@ public: BitField<3, 5, u8> status; }; }; - static_assert(6 == sizeof(DataFormat), "Wrong size."); + using DesiredState = DataFormat; + private: ControllerEmu::AnalogStick* m_stylus; ControllerEmu::Triggers* m_touch; diff --git a/Source/Core/Core/HW/WiimoteEmu/Extension/Guitar.h b/Source/Core/Core/HW/WiimoteEmu/Extension/Guitar.h index 883d0bc2ed..1e36ef6ee4 100644 --- a/Source/Core/Core/HW/WiimoteEmu/Extension/Guitar.h +++ b/Source/Core/Core/HW/WiimoteEmu/Extension/Guitar.h @@ -48,6 +48,8 @@ public: }; static_assert(sizeof(DataFormat) == 6, "Wrong size"); + using DesiredState = DataFormat; + Guitar(); void BuildDesiredExtensionState(DesiredExtensionState* target_state) override; diff --git a/Source/Core/Core/HW/WiimoteEmu/Extension/Nunchuk.h b/Source/Core/Core/HW/WiimoteEmu/Extension/Nunchuk.h index 438b93c034..3251d83f92 100644 --- a/Source/Core/Core/HW/WiimoteEmu/Extension/Nunchuk.h +++ b/Source/Core/Core/HW/WiimoteEmu/Extension/Nunchuk.h @@ -116,6 +116,8 @@ public: }; static_assert(sizeof(DataFormat) == 6, "Wrong size"); + using DesiredState = DataFormat; + struct CalibrationData { using StickType = DataFormat::StickType; diff --git a/Source/Core/Core/HW/WiimoteEmu/Extension/TaTaCon.h b/Source/Core/Core/HW/WiimoteEmu/Extension/TaTaCon.h index 7ce54770bc..2342feacaf 100644 --- a/Source/Core/Core/HW/WiimoteEmu/Extension/TaTaCon.h +++ b/Source/Core/Core/HW/WiimoteEmu/Extension/TaTaCon.h @@ -29,6 +29,8 @@ public: }; static_assert(sizeof(DataFormat) == 6, "Wrong size"); + using DesiredState = DataFormat; + TaTaCon(); void BuildDesiredExtensionState(DesiredExtensionState* target_state) override; diff --git a/Source/Core/Core/HW/WiimoteEmu/Extension/Turntable.h b/Source/Core/Core/HW/WiimoteEmu/Extension/Turntable.h index 36cda37629..b3ddb0be90 100644 --- a/Source/Core/Core/HW/WiimoteEmu/Extension/Turntable.h +++ b/Source/Core/Core/HW/WiimoteEmu/Extension/Turntable.h @@ -54,6 +54,8 @@ public: }; static_assert(sizeof(DataFormat) == 6, "Wrong size"); + using DesiredState = DataFormat; + Turntable(); void BuildDesiredExtensionState(DesiredExtensionState* target_state) override; diff --git a/Source/Core/Core/HW/WiimoteEmu/Extension/UDrawTablet.h b/Source/Core/Core/HW/WiimoteEmu/Extension/UDrawTablet.h index 7052b55ede..8747100a7d 100644 --- a/Source/Core/Core/HW/WiimoteEmu/Extension/UDrawTablet.h +++ b/Source/Core/Core/HW/WiimoteEmu/Extension/UDrawTablet.h @@ -56,9 +56,10 @@ public: // 0x04 is always unset (neutral state is 0xfb) u8 buttons; }; - static_assert(6 == sizeof(DataFormat), "Wrong size."); + using DesiredState = DataFormat; + private: ControllerEmu::Buttons* m_buttons; ControllerEmu::AnalogStick* m_stylus; From 3f92f86de18162799fc69ac5302b99a8cd8d8cf9 Mon Sep 17 00:00:00 2001 From: Jordan Woyak Date: Tue, 25 Feb 2025 04:34:27 -0600 Subject: [PATCH 3/3] WiimoteEmu: Add a static_assert in DesiredExtensionState to keep variant alternative order consistent. --- .../Extension/DesiredExtensionState.h | 27 ++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/Source/Core/Core/HW/WiimoteEmu/Extension/DesiredExtensionState.h b/Source/Core/Core/HW/WiimoteEmu/Extension/DesiredExtensionState.h index a61da143bc..f2d100bc48 100644 --- a/Source/Core/Core/HW/WiimoteEmu/Extension/DesiredExtensionState.h +++ b/Source/Core/Core/HW/WiimoteEmu/Extension/DesiredExtensionState.h @@ -17,21 +17,42 @@ #include "Core/HW/WiimoteEmu/Extension/TaTaCon.h" #include "Core/HW/WiimoteEmu/Extension/Turntable.h" #include "Core/HW/WiimoteEmu/Extension/UDrawTablet.h" +#include "Core/HW/WiimoteEmu/ExtensionPort.h" namespace WiimoteEmu { struct DesiredExtensionState { private: + template + struct ExtNumTypePair + { + static constexpr ExtensionNumber ext_num = N; + using ext_type = T; + }; + template struct ExtDataImpl { - using type = std::variant; + using type = std::variant; + + static_assert((std::is_same_v, + typename Ts::ext_type::DesiredState> && + ...), + "Please use ExtensionNumber enum order for DTM file index consistency."); }; public: - using ExtensionData = ExtDataImpl::type; + using ExtensionData = + ExtDataImpl, + ExtNumTypePair, + ExtNumTypePair, + ExtNumTypePair, + ExtNumTypePair, + ExtNumTypePair, + ExtNumTypePair, + ExtNumTypePair, + ExtNumTypePair>::type; ExtensionData data = std::monostate{}; };