diff options
Diffstat (limited to 'src')
70 files changed, 512 insertions, 520 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 3575a3cb3..0ac3d254e 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt | |||
| @@ -58,13 +58,11 @@ if (MSVC) | |||
| 58 | 58 | ||
| 59 | # Warnings | 59 | # Warnings |
| 60 | /W3 | 60 | /W3 |
| 61 | /we4018 # 'expression': signed/unsigned mismatch | 61 | /WX |
| 62 | |||
| 62 | /we4062 # Enumerator 'identifier' in a switch of enum 'enumeration' is not handled | 63 | /we4062 # Enumerator 'identifier' in a switch of enum 'enumeration' is not handled |
| 63 | /we4101 # 'identifier': unreferenced local variable | ||
| 64 | /we4189 # 'identifier': local variable is initialized but not referenced | 64 | /we4189 # 'identifier': local variable is initialized but not referenced |
| 65 | /we4265 # 'class': class has virtual functions, but destructor is not virtual | 65 | /we4265 # 'class': class has virtual functions, but destructor is not virtual |
| 66 | /we4267 # 'var': conversion from 'size_t' to 'type', possible loss of data | ||
| 67 | /we4305 # 'context': truncation from 'type1' to 'type2' | ||
| 68 | /we4388 # 'expression': signed/unsigned mismatch | 66 | /we4388 # 'expression': signed/unsigned mismatch |
| 69 | /we4389 # 'operator': signed/unsigned mismatch | 67 | /we4389 # 'operator': signed/unsigned mismatch |
| 70 | /we4456 # Declaration of 'identifier' hides previous local declaration | 68 | /we4456 # Declaration of 'identifier' hides previous local declaration |
| @@ -75,10 +73,13 @@ if (MSVC) | |||
| 75 | /we4547 # 'operator': operator before comma has no effect; expected operator with side-effect | 73 | /we4547 # 'operator': operator before comma has no effect; expected operator with side-effect |
| 76 | /we4549 # 'operator1': operator before comma has no effect; did you intend 'operator2'? | 74 | /we4549 # 'operator1': operator before comma has no effect; did you intend 'operator2'? |
| 77 | /we4555 # Expression has no effect; expected expression with side-effect | 75 | /we4555 # Expression has no effect; expected expression with side-effect |
| 78 | /we4715 # 'function': not all control paths return a value | 76 | /we4826 # Conversion from 'type1' to 'type2' is sign-extended. This may cause unexpected runtime behavior. |
| 79 | /we4834 # Discarding return value of function with 'nodiscard' attribute | ||
| 80 | /we5038 # data member 'member1' will be initialized after data member 'member2' | 77 | /we5038 # data member 'member1' will be initialized after data member 'member2' |
| 78 | /we5233 # explicit lambda capture 'identifier' is not used | ||
| 81 | /we5245 # 'function': unreferenced function with internal linkage has been removed | 79 | /we5245 # 'function': unreferenced function with internal linkage has been removed |
| 80 | |||
| 81 | /wd4100 # 'identifier': unreferenced formal parameter | ||
| 82 | /wd4324 # 'struct_name': structure was padded due to __declspec(align()) | ||
| 82 | ) | 83 | ) |
| 83 | 84 | ||
| 84 | if (USE_CCACHE) | 85 | if (USE_CCACHE) |
| @@ -99,24 +100,18 @@ if (MSVC) | |||
| 99 | set(CMAKE_EXE_LINKER_FLAGS_RELEASE "/DEBUG /MANIFEST:NO /INCREMENTAL:NO /OPT:REF,ICF" CACHE STRING "" FORCE) | 100 | set(CMAKE_EXE_LINKER_FLAGS_RELEASE "/DEBUG /MANIFEST:NO /INCREMENTAL:NO /OPT:REF,ICF" CACHE STRING "" FORCE) |
| 100 | else() | 101 | else() |
| 101 | add_compile_options( | 102 | add_compile_options( |
| 102 | -Wall | 103 | -Werror=all |
| 103 | -Werror=array-bounds | 104 | -Werror=extra |
| 104 | -Werror=implicit-fallthrough | ||
| 105 | -Werror=missing-declarations | 105 | -Werror=missing-declarations |
| 106 | -Werror=missing-field-initializers | ||
| 107 | -Werror=reorder | ||
| 108 | -Werror=shadow | 106 | -Werror=shadow |
| 109 | -Werror=sign-compare | 107 | -Werror=unused |
| 110 | -Werror=switch | 108 | |
| 111 | -Werror=uninitialized | ||
| 112 | -Werror=unused-function | ||
| 113 | -Werror=unused-result | ||
| 114 | -Werror=unused-variable | ||
| 115 | -Wextra | ||
| 116 | -Wmissing-declarations | ||
| 117 | -Wno-attributes | 109 | -Wno-attributes |
| 118 | -Wno-invalid-offsetof | 110 | -Wno-invalid-offsetof |
| 119 | -Wno-unused-parameter | 111 | -Wno-unused-parameter |
| 112 | |||
| 113 | $<$<CXX_COMPILER_ID:Clang>:-Wno-braced-scalar-init> | ||
| 114 | $<$<CXX_COMPILER_ID:Clang>:-Wno-unused-private-field> | ||
| 120 | ) | 115 | ) |
| 121 | 116 | ||
| 122 | if (ARCHITECTURE_x86_64) | 117 | if (ARCHITECTURE_x86_64) |
diff --git a/src/audio_core/CMakeLists.txt b/src/audio_core/CMakeLists.txt index 144f1bab2..0a1f3bf18 100644 --- a/src/audio_core/CMakeLists.txt +++ b/src/audio_core/CMakeLists.txt | |||
| @@ -206,20 +206,11 @@ if (MSVC) | |||
| 206 | /we4244 # 'conversion': conversion from 'type1' to 'type2', possible loss of data | 206 | /we4244 # 'conversion': conversion from 'type1' to 'type2', possible loss of data |
| 207 | /we4245 # 'conversion': conversion from 'type1' to 'type2', signed/unsigned mismatch | 207 | /we4245 # 'conversion': conversion from 'type1' to 'type2', signed/unsigned mismatch |
| 208 | /we4254 # 'operator': conversion from 'type1:field_bits' to 'type2:field_bits', possible loss of data | 208 | /we4254 # 'operator': conversion from 'type1:field_bits' to 'type2:field_bits', possible loss of data |
| 209 | /we4456 # Declaration of 'identifier' hides previous local declaration | 209 | /we4800 # Implicit conversion from 'type' to bool. Possible information loss |
| 210 | /we4457 # Declaration of 'identifier' hides function parameter | ||
| 211 | /we4458 # Declaration of 'identifier' hides class member | ||
| 212 | /we4459 # Declaration of 'identifier' hides global declaration | ||
| 213 | ) | 210 | ) |
| 214 | else() | 211 | else() |
| 215 | target_compile_options(audio_core PRIVATE | 212 | target_compile_options(audio_core PRIVATE |
| 216 | -Werror=conversion | 213 | -Werror=conversion |
| 217 | -Werror=ignored-qualifiers | ||
| 218 | -Werror=shadow | ||
| 219 | -Werror=unused-variable | ||
| 220 | |||
| 221 | $<$<CXX_COMPILER_ID:GNU>:-Werror=unused-but-set-parameter> | ||
| 222 | $<$<CXX_COMPILER_ID:GNU>:-Werror=unused-but-set-variable> | ||
| 223 | 214 | ||
| 224 | -Wno-sign-conversion | 215 | -Wno-sign-conversion |
| 225 | ) | 216 | ) |
diff --git a/src/audio_core/renderer/behavior/info_updater.cpp b/src/audio_core/renderer/behavior/info_updater.cpp index c0a307b89..574cf0982 100644 --- a/src/audio_core/renderer/behavior/info_updater.cpp +++ b/src/audio_core/renderer/behavior/info_updater.cpp | |||
| @@ -91,7 +91,7 @@ Result InfoUpdater::UpdateVoices(VoiceContext& voice_context, | |||
| 91 | voice_info.Initialize(); | 91 | voice_info.Initialize(); |
| 92 | 92 | ||
| 93 | for (u32 channel = 0; channel < in_param.channel_count; channel++) { | 93 | for (u32 channel = 0; channel < in_param.channel_count; channel++) { |
| 94 | std::memset(voice_states[channel], 0, sizeof(VoiceState)); | 94 | *voice_states[channel] = {}; |
| 95 | } | 95 | } |
| 96 | } | 96 | } |
| 97 | 97 | ||
diff --git a/src/audio_core/renderer/command/effect/biquad_filter.cpp b/src/audio_core/renderer/command/effect/biquad_filter.cpp index 1baae74fd..edb30ce72 100644 --- a/src/audio_core/renderer/command/effect/biquad_filter.cpp +++ b/src/audio_core/renderer/command/effect/biquad_filter.cpp | |||
| @@ -94,7 +94,7 @@ void BiquadFilterCommand::Dump([[maybe_unused]] const ADSP::CommandListProcessor | |||
| 94 | void BiquadFilterCommand::Process(const ADSP::CommandListProcessor& processor) { | 94 | void BiquadFilterCommand::Process(const ADSP::CommandListProcessor& processor) { |
| 95 | auto state_{reinterpret_cast<VoiceState::BiquadFilterState*>(state)}; | 95 | auto state_{reinterpret_cast<VoiceState::BiquadFilterState*>(state)}; |
| 96 | if (needs_init) { | 96 | if (needs_init) { |
| 97 | std::memset(state_, 0, sizeof(VoiceState::BiquadFilterState)); | 97 | *state_ = {}; |
| 98 | } | 98 | } |
| 99 | 99 | ||
| 100 | auto input_buffer{ | 100 | auto input_buffer{ |
diff --git a/src/audio_core/renderer/command/effect/multi_tap_biquad_filter.cpp b/src/audio_core/renderer/command/effect/multi_tap_biquad_filter.cpp index b3c3ba4ba..48a7cba8a 100644 --- a/src/audio_core/renderer/command/effect/multi_tap_biquad_filter.cpp +++ b/src/audio_core/renderer/command/effect/multi_tap_biquad_filter.cpp | |||
| @@ -30,7 +30,7 @@ void MultiTapBiquadFilterCommand::Process(const ADSP::CommandListProcessor& proc | |||
| 30 | for (u32 i = 0; i < filter_tap_count; i++) { | 30 | for (u32 i = 0; i < filter_tap_count; i++) { |
| 31 | auto state{reinterpret_cast<VoiceState::BiquadFilterState*>(states[i])}; | 31 | auto state{reinterpret_cast<VoiceState::BiquadFilterState*>(states[i])}; |
| 32 | if (needs_init[i]) { | 32 | if (needs_init[i]) { |
| 33 | std::memset(state, 0, sizeof(VoiceState::BiquadFilterState)); | 33 | *state = {}; |
| 34 | } | 34 | } |
| 35 | 35 | ||
| 36 | ApplyBiquadFilterFloat(output_buffer, input_buffer, biquads[i].b, biquads[i].a, *state, | 36 | ApplyBiquadFilterFloat(output_buffer, input_buffer, biquads[i].b, biquads[i].a, *state, |
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index 46cf75fde..c0555f840 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt | |||
| @@ -156,12 +156,13 @@ if (MSVC) | |||
| 156 | ) | 156 | ) |
| 157 | target_compile_options(common PRIVATE | 157 | target_compile_options(common PRIVATE |
| 158 | /W4 | 158 | /W4 |
| 159 | /WX | 159 | |
| 160 | /we4242 # 'identifier': conversion from 'type1' to 'type2', possible loss of data | ||
| 161 | /we4254 # 'operator': conversion from 'type1:field_bits' to 'type2:field_bits', possible loss of data | ||
| 162 | /we4800 # Implicit conversion from 'type' to bool. Possible information loss | ||
| 160 | ) | 163 | ) |
| 161 | else() | 164 | else() |
| 162 | target_compile_options(common PRIVATE | 165 | target_compile_options(common PRIVATE |
| 163 | -Werror | ||
| 164 | |||
| 165 | $<$<CXX_COMPILER_ID:Clang>:-fsized-deallocation> | 166 | $<$<CXX_COMPILER_ID:Clang>:-fsized-deallocation> |
| 166 | ) | 167 | ) |
| 167 | endif() | 168 | endif() |
diff --git a/src/common/bit_field.h b/src/common/bit_field.h index 7e1df62b1..e4e58ea45 100644 --- a/src/common/bit_field.h +++ b/src/common/bit_field.h | |||
| @@ -141,10 +141,6 @@ public: | |||
| 141 | constexpr BitField(BitField&&) noexcept = default; | 141 | constexpr BitField(BitField&&) noexcept = default; |
| 142 | constexpr BitField& operator=(BitField&&) noexcept = default; | 142 | constexpr BitField& operator=(BitField&&) noexcept = default; |
| 143 | 143 | ||
| 144 | [[nodiscard]] constexpr operator T() const { | ||
| 145 | return Value(); | ||
| 146 | } | ||
| 147 | |||
| 148 | constexpr void Assign(const T& value) { | 144 | constexpr void Assign(const T& value) { |
| 149 | #ifdef _MSC_VER | 145 | #ifdef _MSC_VER |
| 150 | storage = static_cast<StorageType>((storage & ~mask) | FormatValue(value)); | 146 | storage = static_cast<StorageType>((storage & ~mask) | FormatValue(value)); |
| @@ -162,6 +158,17 @@ public: | |||
| 162 | return ExtractValue(storage); | 158 | return ExtractValue(storage); |
| 163 | } | 159 | } |
| 164 | 160 | ||
| 161 | template <typename ConvertedToType> | ||
| 162 | [[nodiscard]] constexpr ConvertedToType As() const { | ||
| 163 | static_assert(!std::is_same_v<T, ConvertedToType>, | ||
| 164 | "Unnecessary cast. Use Value() instead."); | ||
| 165 | return static_cast<ConvertedToType>(Value()); | ||
| 166 | } | ||
| 167 | |||
| 168 | [[nodiscard]] constexpr operator T() const { | ||
| 169 | return Value(); | ||
| 170 | } | ||
| 171 | |||
| 165 | [[nodiscard]] constexpr explicit operator bool() const { | 172 | [[nodiscard]] constexpr explicit operator bool() const { |
| 166 | return Value() != 0; | 173 | return Value() != 0; |
| 167 | } | 174 | } |
diff --git a/src/common/bounded_threadsafe_queue.h b/src/common/bounded_threadsafe_queue.h index 7e465549b..21217801e 100644 --- a/src/common/bounded_threadsafe_queue.h +++ b/src/common/bounded_threadsafe_queue.h | |||
| @@ -21,11 +21,6 @@ constexpr size_t hardware_interference_size = std::hardware_destructive_interfer | |||
| 21 | constexpr size_t hardware_interference_size = 64; | 21 | constexpr size_t hardware_interference_size = 64; |
| 22 | #endif | 22 | #endif |
| 23 | 23 | ||
| 24 | #ifdef _MSC_VER | ||
| 25 | #pragma warning(push) | ||
| 26 | #pragma warning(disable : 4324) | ||
| 27 | #endif | ||
| 28 | |||
| 29 | template <typename T, size_t capacity = 0x400> | 24 | template <typename T, size_t capacity = 0x400> |
| 30 | class MPSCQueue { | 25 | class MPSCQueue { |
| 31 | public: | 26 | public: |
| @@ -160,8 +155,4 @@ private: | |||
| 160 | static_assert(std::is_nothrow_destructible_v<T>, "T must be nothrow destructible"); | 155 | static_assert(std::is_nothrow_destructible_v<T>, "T must be nothrow destructible"); |
| 161 | }; | 156 | }; |
| 162 | 157 | ||
| 163 | #ifdef _MSC_VER | ||
| 164 | #pragma warning(pop) | ||
| 165 | #endif | ||
| 166 | |||
| 167 | } // namespace Common | 158 | } // namespace Common |
diff --git a/src/common/concepts.h b/src/common/concepts.h index e8ce30dfe..a9acff3e7 100644 --- a/src/common/concepts.h +++ b/src/common/concepts.h | |||
| @@ -3,24 +3,14 @@ | |||
| 3 | 3 | ||
| 4 | #pragma once | 4 | #pragma once |
| 5 | 5 | ||
| 6 | #include <iterator> | ||
| 6 | #include <type_traits> | 7 | #include <type_traits> |
| 7 | 8 | ||
| 8 | namespace Common { | 9 | namespace Common { |
| 9 | 10 | ||
| 10 | // Check if type is like an STL container | 11 | // Check if type satisfies the ContiguousContainer named requirement. |
| 11 | template <typename T> | 12 | template <typename T> |
| 12 | concept IsSTLContainer = requires(T t) { | 13 | concept IsContiguousContainer = std::contiguous_iterator<typename T::iterator>; |
| 13 | typename T::value_type; | ||
| 14 | typename T::iterator; | ||
| 15 | typename T::const_iterator; | ||
| 16 | // TODO(ogniK): Replace below is std::same_as<void> when MSVC supports it. | ||
| 17 | t.begin(); | ||
| 18 | t.end(); | ||
| 19 | t.cbegin(); | ||
| 20 | t.cend(); | ||
| 21 | t.data(); | ||
| 22 | t.size(); | ||
| 23 | }; | ||
| 24 | 14 | ||
| 25 | // TODO: Replace with std::derived_from when the <concepts> header | 15 | // TODO: Replace with std::derived_from when the <concepts> header |
| 26 | // is available on all supported platforms. | 16 | // is available on all supported platforms. |
diff --git a/src/common/fs/file.h b/src/common/fs/file.h index 69b53384c..167c4d826 100644 --- a/src/common/fs/file.h +++ b/src/common/fs/file.h | |||
| @@ -209,8 +209,8 @@ public: | |||
| 209 | 209 | ||
| 210 | /** | 210 | /** |
| 211 | * Helper function which deduces the value type of a contiguous STL container used in ReadSpan. | 211 | * Helper function which deduces the value type of a contiguous STL container used in ReadSpan. |
| 212 | * If T is not a contiguous STL container as defined by the concept IsSTLContainer, this calls | 212 | * If T is not a contiguous container as defined by the concept IsContiguousContainer, this |
| 213 | * ReadObject and T must be a trivially copyable object. | 213 | * calls ReadObject and T must be a trivially copyable object. |
| 214 | * | 214 | * |
| 215 | * See ReadSpan for more details if T is a contiguous container. | 215 | * See ReadSpan for more details if T is a contiguous container. |
| 216 | * See ReadObject for more details if T is a trivially copyable object. | 216 | * See ReadObject for more details if T is a trivially copyable object. |
| @@ -223,7 +223,7 @@ public: | |||
| 223 | */ | 223 | */ |
| 224 | template <typename T> | 224 | template <typename T> |
| 225 | [[nodiscard]] size_t Read(T& data) const { | 225 | [[nodiscard]] size_t Read(T& data) const { |
| 226 | if constexpr (IsSTLContainer<T>) { | 226 | if constexpr (IsContiguousContainer<T>) { |
| 227 | using ContiguousType = typename T::value_type; | 227 | using ContiguousType = typename T::value_type; |
| 228 | static_assert(std::is_trivially_copyable_v<ContiguousType>, | 228 | static_assert(std::is_trivially_copyable_v<ContiguousType>, |
| 229 | "Data type must be trivially copyable."); | 229 | "Data type must be trivially copyable."); |
| @@ -235,8 +235,8 @@ public: | |||
| 235 | 235 | ||
| 236 | /** | 236 | /** |
| 237 | * Helper function which deduces the value type of a contiguous STL container used in WriteSpan. | 237 | * Helper function which deduces the value type of a contiguous STL container used in WriteSpan. |
| 238 | * If T is not a contiguous STL container as defined by the concept IsSTLContainer, this calls | 238 | * If T is not a contiguous STL container as defined by the concept IsContiguousContainer, this |
| 239 | * WriteObject and T must be a trivially copyable object. | 239 | * calls WriteObject and T must be a trivially copyable object. |
| 240 | * | 240 | * |
| 241 | * See WriteSpan for more details if T is a contiguous container. | 241 | * See WriteSpan for more details if T is a contiguous container. |
| 242 | * See WriteObject for more details if T is a trivially copyable object. | 242 | * See WriteObject for more details if T is a trivially copyable object. |
| @@ -249,7 +249,7 @@ public: | |||
| 249 | */ | 249 | */ |
| 250 | template <typename T> | 250 | template <typename T> |
| 251 | [[nodiscard]] size_t Write(const T& data) const { | 251 | [[nodiscard]] size_t Write(const T& data) const { |
| 252 | if constexpr (IsSTLContainer<T>) { | 252 | if constexpr (IsContiguousContainer<T>) { |
| 253 | using ContiguousType = typename T::value_type; | 253 | using ContiguousType = typename T::value_type; |
| 254 | static_assert(std::is_trivially_copyable_v<ContiguousType>, | 254 | static_assert(std::is_trivially_copyable_v<ContiguousType>, |
| 255 | "Data type must be trivially copyable."); | 255 | "Data type must be trivially copyable."); |
diff --git a/src/common/input.h b/src/common/input.h index b533f3844..cb30b7254 100644 --- a/src/common/input.h +++ b/src/common/input.h | |||
| @@ -100,7 +100,6 @@ enum class CameraError { | |||
| 100 | enum class VibrationAmplificationType { | 100 | enum class VibrationAmplificationType { |
| 101 | Linear, | 101 | Linear, |
| 102 | Exponential, | 102 | Exponential, |
| 103 | Test, | ||
| 104 | }; | 103 | }; |
| 105 | 104 | ||
| 106 | // Analog properties for calibration | 105 | // Analog properties for calibration |
| @@ -325,6 +324,10 @@ public: | |||
| 325 | return VibrationError::NotSupported; | 324 | return VibrationError::NotSupported; |
| 326 | } | 325 | } |
| 327 | 326 | ||
| 327 | virtual bool IsVibrationEnabled() { | ||
| 328 | return false; | ||
| 329 | } | ||
| 330 | |||
| 328 | virtual PollingError SetPollingMode([[maybe_unused]] PollingMode polling_mode) { | 331 | virtual PollingError SetPollingMode([[maybe_unused]] PollingMode polling_mode) { |
| 329 | return PollingError::NotSupported; | 332 | return PollingError::NotSupported; |
| 330 | } | 333 | } |
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 055bea641..113e663b5 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt | |||
| @@ -774,19 +774,15 @@ if (MSVC) | |||
| 774 | /we4244 # 'conversion': conversion from 'type1' to 'type2', possible loss of data | 774 | /we4244 # 'conversion': conversion from 'type1' to 'type2', possible loss of data |
| 775 | /we4245 # 'conversion': conversion from 'type1' to 'type2', signed/unsigned mismatch | 775 | /we4245 # 'conversion': conversion from 'type1' to 'type2', signed/unsigned mismatch |
| 776 | /we4254 # 'operator': conversion from 'type1:field_bits' to 'type2:field_bits', possible loss of data | 776 | /we4254 # 'operator': conversion from 'type1:field_bits' to 'type2:field_bits', possible loss of data |
| 777 | /we4800 # Implicit conversion from 'type' to bool. Possible information loss | ||
| 777 | ) | 778 | ) |
| 778 | else() | 779 | else() |
| 779 | target_compile_options(core PRIVATE | 780 | target_compile_options(core PRIVATE |
| 780 | -Werror=conversion | 781 | -Werror=conversion |
| 781 | -Werror=ignored-qualifiers | ||
| 782 | 782 | ||
| 783 | $<$<CXX_COMPILER_ID:GNU>:-Werror=class-memaccess> | 783 | -Wno-sign-conversion |
| 784 | $<$<CXX_COMPILER_ID:GNU>:-Werror=unused-but-set-parameter> | ||
| 785 | $<$<CXX_COMPILER_ID:GNU>:-Werror=unused-but-set-variable> | ||
| 786 | 784 | ||
| 787 | $<$<CXX_COMPILER_ID:Clang>:-fsized-deallocation> | 785 | $<$<CXX_COMPILER_ID:Clang>:-fsized-deallocation> |
| 788 | |||
| 789 | -Wno-sign-conversion | ||
| 790 | ) | 786 | ) |
| 791 | endif() | 787 | endif() |
| 792 | 788 | ||
diff --git a/src/core/core.cpp b/src/core/core.cpp index 7fb8bc019..40a610435 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp | |||
| @@ -384,6 +384,7 @@ struct System::Impl { | |||
| 384 | kernel.ShutdownCores(); | 384 | kernel.ShutdownCores(); |
| 385 | cpu_manager.Shutdown(); | 385 | cpu_manager.Shutdown(); |
| 386 | debugger.reset(); | 386 | debugger.reset(); |
| 387 | services->KillNVNFlinger(); | ||
| 387 | kernel.CloseServices(); | 388 | kernel.CloseServices(); |
| 388 | services.reset(); | 389 | services.reset(); |
| 389 | service_manager.reset(); | 390 | service_manager.reset(); |
diff --git a/src/core/file_sys/card_image.cpp b/src/core/file_sys/card_image.cpp index f23d9373b..5d02865f4 100644 --- a/src/core/file_sys/card_image.cpp +++ b/src/core/file_sys/card_image.cpp | |||
| @@ -232,8 +232,8 @@ const std::vector<std::shared_ptr<NCA>>& XCI::GetNCAs() const { | |||
| 232 | 232 | ||
| 233 | std::shared_ptr<NCA> XCI::GetNCAByType(NCAContentType type) const { | 233 | std::shared_ptr<NCA> XCI::GetNCAByType(NCAContentType type) const { |
| 234 | const auto program_id = secure_partition->GetProgramTitleID(); | 234 | const auto program_id = secure_partition->GetProgramTitleID(); |
| 235 | const auto iter = std::find_if( | 235 | const auto iter = |
| 236 | ncas.begin(), ncas.end(), [this, type, program_id](const std::shared_ptr<NCA>& nca) { | 236 | std::find_if(ncas.begin(), ncas.end(), [type, program_id](const std::shared_ptr<NCA>& nca) { |
| 237 | return nca->GetType() == type && nca->GetTitleId() == program_id; | 237 | return nca->GetType() == type && nca->GetTitleId() == program_id; |
| 238 | }); | 238 | }); |
| 239 | return iter == ncas.end() ? nullptr : *iter; | 239 | return iter == ncas.end() ? nullptr : *iter; |
diff --git a/src/core/file_sys/program_metadata.cpp b/src/core/file_sys/program_metadata.cpp index 08d489eab..f00479bd3 100644 --- a/src/core/file_sys/program_metadata.cpp +++ b/src/core/file_sys/program_metadata.cpp | |||
| @@ -127,7 +127,7 @@ void ProgramMetadata::LoadManual(bool is_64_bit, ProgramAddressSpaceType address | |||
| 127 | } | 127 | } |
| 128 | 128 | ||
| 129 | bool ProgramMetadata::Is64BitProgram() const { | 129 | bool ProgramMetadata::Is64BitProgram() const { |
| 130 | return npdm_header.has_64_bit_instructions; | 130 | return npdm_header.has_64_bit_instructions.As<bool>(); |
| 131 | } | 131 | } |
| 132 | 132 | ||
| 133 | ProgramAddressSpaceType ProgramMetadata::GetAddressSpaceType() const { | 133 | ProgramAddressSpaceType ProgramMetadata::GetAddressSpaceType() const { |
diff --git a/src/core/hid/emulated_controller.cpp b/src/core/hid/emulated_controller.cpp index 025f1c78e..ec1364452 100644 --- a/src/core/hid/emulated_controller.cpp +++ b/src/core/hid/emulated_controller.cpp | |||
| @@ -970,14 +970,7 @@ bool EmulatedController::SetVibration(std::size_t device_index, VibrationValue v | |||
| 970 | Common::Input::VibrationError::None; | 970 | Common::Input::VibrationError::None; |
| 971 | } | 971 | } |
| 972 | 972 | ||
| 973 | bool EmulatedController::TestVibration(std::size_t device_index) { | 973 | bool EmulatedController::IsVibrationEnabled(std::size_t device_index) { |
| 974 | if (device_index >= output_devices.size()) { | ||
| 975 | return false; | ||
| 976 | } | ||
| 977 | if (!output_devices[device_index]) { | ||
| 978 | return false; | ||
| 979 | } | ||
| 980 | |||
| 981 | const auto player_index = NpadIdTypeToIndex(npad_id_type); | 974 | const auto player_index = NpadIdTypeToIndex(npad_id_type); |
| 982 | const auto& player = Settings::values.players.GetValue()[player_index]; | 975 | const auto& player = Settings::values.players.GetValue()[player_index]; |
| 983 | 976 | ||
| @@ -985,31 +978,15 @@ bool EmulatedController::TestVibration(std::size_t device_index) { | |||
| 985 | return false; | 978 | return false; |
| 986 | } | 979 | } |
| 987 | 980 | ||
| 988 | const Common::Input::VibrationStatus test_vibration = { | 981 | if (device_index >= output_devices.size()) { |
| 989 | .low_amplitude = 0.001f, | 982 | return false; |
| 990 | .low_frequency = DEFAULT_VIBRATION_VALUE.low_frequency, | 983 | } |
| 991 | .high_amplitude = 0.001f, | ||
| 992 | .high_frequency = DEFAULT_VIBRATION_VALUE.high_frequency, | ||
| 993 | .type = Common::Input::VibrationAmplificationType::Test, | ||
| 994 | }; | ||
| 995 | |||
| 996 | const Common::Input::VibrationStatus zero_vibration = { | ||
| 997 | .low_amplitude = DEFAULT_VIBRATION_VALUE.low_amplitude, | ||
| 998 | .low_frequency = DEFAULT_VIBRATION_VALUE.low_frequency, | ||
| 999 | .high_amplitude = DEFAULT_VIBRATION_VALUE.high_amplitude, | ||
| 1000 | .high_frequency = DEFAULT_VIBRATION_VALUE.high_frequency, | ||
| 1001 | .type = Common::Input::VibrationAmplificationType::Test, | ||
| 1002 | }; | ||
| 1003 | |||
| 1004 | // Send a slight vibration to test for rumble support | ||
| 1005 | output_devices[device_index]->SetVibration(test_vibration); | ||
| 1006 | 984 | ||
| 1007 | // Wait for about 15ms to ensure the controller is ready for the stop command | 985 | if (!output_devices[device_index]) { |
| 1008 | std::this_thread::sleep_for(std::chrono::milliseconds(15)); | 986 | return false; |
| 987 | } | ||
| 1009 | 988 | ||
| 1010 | // Stop any vibration and return the result | 989 | return output_devices[device_index]->IsVibrationEnabled(); |
| 1011 | return output_devices[device_index]->SetVibration(zero_vibration) == | ||
| 1012 | Common::Input::VibrationError::None; | ||
| 1013 | } | 990 | } |
| 1014 | 991 | ||
| 1015 | bool EmulatedController::SetPollingMode(Common::Input::PollingMode polling_mode) { | 992 | bool EmulatedController::SetPollingMode(Common::Input::PollingMode polling_mode) { |
| @@ -1048,6 +1025,7 @@ bool EmulatedController::HasNfc() const { | |||
| 1048 | case NpadStyleIndex::JoyconRight: | 1025 | case NpadStyleIndex::JoyconRight: |
| 1049 | case NpadStyleIndex::JoyconDual: | 1026 | case NpadStyleIndex::JoyconDual: |
| 1050 | case NpadStyleIndex::ProController: | 1027 | case NpadStyleIndex::ProController: |
| 1028 | case NpadStyleIndex::Handheld: | ||
| 1051 | break; | 1029 | break; |
| 1052 | default: | 1030 | default: |
| 1053 | return false; | 1031 | return false; |
| @@ -1158,27 +1136,27 @@ bool EmulatedController::IsControllerSupported(bool use_temporary_value) const { | |||
| 1158 | const auto type = is_configuring && use_temporary_value ? tmp_npad_type : npad_type; | 1136 | const auto type = is_configuring && use_temporary_value ? tmp_npad_type : npad_type; |
| 1159 | switch (type) { | 1137 | switch (type) { |
| 1160 | case NpadStyleIndex::ProController: | 1138 | case NpadStyleIndex::ProController: |
| 1161 | return supported_style_tag.fullkey; | 1139 | return supported_style_tag.fullkey.As<bool>(); |
| 1162 | case NpadStyleIndex::Handheld: | 1140 | case NpadStyleIndex::Handheld: |
| 1163 | return supported_style_tag.handheld; | 1141 | return supported_style_tag.handheld.As<bool>(); |
| 1164 | case NpadStyleIndex::JoyconDual: | 1142 | case NpadStyleIndex::JoyconDual: |
| 1165 | return supported_style_tag.joycon_dual; | 1143 | return supported_style_tag.joycon_dual.As<bool>(); |
| 1166 | case NpadStyleIndex::JoyconLeft: | 1144 | case NpadStyleIndex::JoyconLeft: |
| 1167 | return supported_style_tag.joycon_left; | 1145 | return supported_style_tag.joycon_left.As<bool>(); |
| 1168 | case NpadStyleIndex::JoyconRight: | 1146 | case NpadStyleIndex::JoyconRight: |
| 1169 | return supported_style_tag.joycon_right; | 1147 | return supported_style_tag.joycon_right.As<bool>(); |
| 1170 | case NpadStyleIndex::GameCube: | 1148 | case NpadStyleIndex::GameCube: |
| 1171 | return supported_style_tag.gamecube; | 1149 | return supported_style_tag.gamecube.As<bool>(); |
| 1172 | case NpadStyleIndex::Pokeball: | 1150 | case NpadStyleIndex::Pokeball: |
| 1173 | return supported_style_tag.palma; | 1151 | return supported_style_tag.palma.As<bool>(); |
| 1174 | case NpadStyleIndex::NES: | 1152 | case NpadStyleIndex::NES: |
| 1175 | return supported_style_tag.lark; | 1153 | return supported_style_tag.lark.As<bool>(); |
| 1176 | case NpadStyleIndex::SNES: | 1154 | case NpadStyleIndex::SNES: |
| 1177 | return supported_style_tag.lucia; | 1155 | return supported_style_tag.lucia.As<bool>(); |
| 1178 | case NpadStyleIndex::N64: | 1156 | case NpadStyleIndex::N64: |
| 1179 | return supported_style_tag.lagoon; | 1157 | return supported_style_tag.lagoon.As<bool>(); |
| 1180 | case NpadStyleIndex::SegaGenesis: | 1158 | case NpadStyleIndex::SegaGenesis: |
| 1181 | return supported_style_tag.lager; | 1159 | return supported_style_tag.lager.As<bool>(); |
| 1182 | default: | 1160 | default: |
| 1183 | return false; | 1161 | return false; |
| 1184 | } | 1162 | } |
| @@ -1234,12 +1212,6 @@ bool EmulatedController::IsConnected(bool get_temporary_value) const { | |||
| 1234 | return is_connected; | 1212 | return is_connected; |
| 1235 | } | 1213 | } |
| 1236 | 1214 | ||
| 1237 | bool EmulatedController::IsVibrationEnabled() const { | ||
| 1238 | const auto player_index = NpadIdTypeToIndex(npad_id_type); | ||
| 1239 | const auto& player = Settings::values.players.GetValue()[player_index]; | ||
| 1240 | return player.vibration_enabled; | ||
| 1241 | } | ||
| 1242 | |||
| 1243 | NpadIdType EmulatedController::GetNpadIdType() const { | 1215 | NpadIdType EmulatedController::GetNpadIdType() const { |
| 1244 | std::scoped_lock lock{mutex}; | 1216 | std::scoped_lock lock{mutex}; |
| 1245 | return npad_id_type; | 1217 | return npad_id_type; |
diff --git a/src/core/hid/emulated_controller.h b/src/core/hid/emulated_controller.h index 319226bf8..d004ca56a 100644 --- a/src/core/hid/emulated_controller.h +++ b/src/core/hid/emulated_controller.h | |||
| @@ -206,9 +206,6 @@ public: | |||
| 206 | */ | 206 | */ |
| 207 | bool IsConnected(bool get_temporary_value = false) const; | 207 | bool IsConnected(bool get_temporary_value = false) const; |
| 208 | 208 | ||
| 209 | /// Returns true if vibration is enabled | ||
| 210 | bool IsVibrationEnabled() const; | ||
| 211 | |||
| 212 | /// Removes all callbacks created from input devices | 209 | /// Removes all callbacks created from input devices |
| 213 | void UnloadInput(); | 210 | void UnloadInput(); |
| 214 | 211 | ||
| @@ -339,7 +336,7 @@ public: | |||
| 339 | * Sends a small vibration to the output device | 336 | * Sends a small vibration to the output device |
| 340 | * @return true if SetVibration was successfull | 337 | * @return true if SetVibration was successfull |
| 341 | */ | 338 | */ |
| 342 | bool TestVibration(std::size_t device_index); | 339 | bool IsVibrationEnabled(std::size_t device_index); |
| 343 | 340 | ||
| 344 | /** | 341 | /** |
| 345 | * Sets the desired data to be polled from a controller | 342 | * Sets the desired data to be polled from a controller |
diff --git a/src/core/hle/ipc_helpers.h b/src/core/hle/ipc_helpers.h index aa27be767..18fde8bd6 100644 --- a/src/core/hle/ipc_helpers.h +++ b/src/core/hle/ipc_helpers.h | |||
| @@ -406,7 +406,7 @@ inline s32 RequestParser::Pop() { | |||
| 406 | } | 406 | } |
| 407 | 407 | ||
| 408 | // Ignore the -Wclass-memaccess warning on memcpy for non-trivially default constructible objects. | 408 | // Ignore the -Wclass-memaccess warning on memcpy for non-trivially default constructible objects. |
| 409 | #if defined(__GNUC__) | 409 | #if defined(__GNUC__) && !defined(__clang__) && !defined(__INTEL_COMPILER) |
| 410 | #pragma GCC diagnostic push | 410 | #pragma GCC diagnostic push |
| 411 | #pragma GCC diagnostic ignored "-Wclass-memaccess" | 411 | #pragma GCC diagnostic ignored "-Wclass-memaccess" |
| 412 | #endif | 412 | #endif |
| @@ -417,7 +417,7 @@ void RequestParser::PopRaw(T& value) { | |||
| 417 | std::memcpy(&value, cmdbuf + index, sizeof(T)); | 417 | std::memcpy(&value, cmdbuf + index, sizeof(T)); |
| 418 | index += (sizeof(T) + 3) / 4; // round up to word length | 418 | index += (sizeof(T) + 3) / 4; // round up to word length |
| 419 | } | 419 | } |
| 420 | #if defined(__GNUC__) | 420 | #if defined(__GNUC__) && !defined(__clang__) && !defined(__INTEL_COMPILER) |
| 421 | #pragma GCC diagnostic pop | 421 | #pragma GCC diagnostic pop |
| 422 | #endif | 422 | #endif |
| 423 | 423 | ||
diff --git a/src/core/hle/kernel/hle_ipc.h b/src/core/hle/kernel/hle_ipc.h index a0522bca0..1083638a9 100644 --- a/src/core/hle/kernel/hle_ipc.h +++ b/src/core/hle/kernel/hle_ipc.h | |||
| @@ -304,7 +304,7 @@ public: | |||
| 304 | */ | 304 | */ |
| 305 | template <typename T, typename = std::enable_if_t<!std::is_pointer_v<T>>> | 305 | template <typename T, typename = std::enable_if_t<!std::is_pointer_v<T>>> |
| 306 | std::size_t WriteBuffer(const T& data, std::size_t buffer_index = 0) const { | 306 | std::size_t WriteBuffer(const T& data, std::size_t buffer_index = 0) const { |
| 307 | if constexpr (Common::IsSTLContainer<T>) { | 307 | if constexpr (Common::IsContiguousContainer<T>) { |
| 308 | using ContiguousType = typename T::value_type; | 308 | using ContiguousType = typename T::value_type; |
| 309 | static_assert(std::is_trivially_copyable_v<ContiguousType>, | 309 | static_assert(std::is_trivially_copyable_v<ContiguousType>, |
| 310 | "Container to WriteBuffer must contain trivially copyable objects"); | 310 | "Container to WriteBuffer must contain trivially copyable objects"); |
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index eed2dc9f3..fdc774e30 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp | |||
| @@ -48,8 +48,8 @@ namespace Kernel { | |||
| 48 | 48 | ||
| 49 | struct KernelCore::Impl { | 49 | struct KernelCore::Impl { |
| 50 | explicit Impl(Core::System& system_, KernelCore& kernel_) | 50 | explicit Impl(Core::System& system_, KernelCore& kernel_) |
| 51 | : time_manager{system_}, | 51 | : time_manager{system_}, service_threads_manager{1, "ServiceThreadsManager"}, |
| 52 | service_threads_manager{1, "ServiceThreadsManager"}, system{system_} {} | 52 | service_thread_barrier{2}, system{system_} {} |
| 53 | 53 | ||
| 54 | void SetMulticore(bool is_multi) { | 54 | void SetMulticore(bool is_multi) { |
| 55 | is_multicore = is_multi; | 55 | is_multicore = is_multi; |
| @@ -737,7 +737,12 @@ struct KernelCore::Impl { | |||
| 737 | } | 737 | } |
| 738 | 738 | ||
| 739 | void ClearServiceThreads() { | 739 | void ClearServiceThreads() { |
| 740 | service_threads_manager.QueueWork([this]() { service_threads.clear(); }); | 740 | service_threads_manager.QueueWork([this] { |
| 741 | service_threads.clear(); | ||
| 742 | default_service_thread.reset(); | ||
| 743 | service_thread_barrier.Sync(); | ||
| 744 | }); | ||
| 745 | service_thread_barrier.Sync(); | ||
| 741 | } | 746 | } |
| 742 | 747 | ||
| 743 | std::mutex server_objects_lock; | 748 | std::mutex server_objects_lock; |
| @@ -802,6 +807,7 @@ struct KernelCore::Impl { | |||
| 802 | std::unordered_set<std::shared_ptr<ServiceThread>> service_threads; | 807 | std::unordered_set<std::shared_ptr<ServiceThread>> service_threads; |
| 803 | std::weak_ptr<ServiceThread> default_service_thread; | 808 | std::weak_ptr<ServiceThread> default_service_thread; |
| 804 | Common::ThreadWorker service_threads_manager; | 809 | Common::ThreadWorker service_threads_manager; |
| 810 | Common::Barrier service_thread_barrier; | ||
| 805 | 811 | ||
| 806 | std::array<KThread*, Core::Hardware::NUM_CPU_CORES> shutdown_threads; | 812 | std::array<KThread*, Core::Hardware::NUM_CPU_CORES> shutdown_threads; |
| 807 | std::array<std::unique_ptr<Kernel::KScheduler>, Core::Hardware::NUM_CPU_CORES> schedulers{}; | 813 | std::array<std::unique_ptr<Kernel::KScheduler>, Core::Hardware::NUM_CPU_CORES> schedulers{}; |
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index b07ae3f02..4aca5b27d 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp | |||
| @@ -751,8 +751,8 @@ static void Break(Core::System& system, u32 reason, u64 info1, u64 info2) { | |||
| 751 | } | 751 | } |
| 752 | 752 | ||
| 753 | system.GetReporter().SaveSvcBreakReport( | 753 | system.GetReporter().SaveSvcBreakReport( |
| 754 | static_cast<u32>(break_reason.break_type.Value()), break_reason.signal_debugger, info1, | 754 | static_cast<u32>(break_reason.break_type.Value()), break_reason.signal_debugger.As<bool>(), |
| 755 | info2, has_dumped_buffer ? std::make_optional(debug_buffer) : std::nullopt); | 755 | info1, info2, has_dumped_buffer ? std::make_optional(debug_buffer) : std::nullopt); |
| 756 | 756 | ||
| 757 | if (!break_reason.signal_debugger) { | 757 | if (!break_reason.signal_debugger) { |
| 758 | LOG_CRITICAL( | 758 | LOG_CRITICAL( |
diff --git a/src/core/hle/service/am/applets/applets.h b/src/core/hle/service/am/applets/applets.h index e78a57657..12c6a5b1a 100644 --- a/src/core/hle/service/am/applets/applets.h +++ b/src/core/hle/service/am/applets/applets.h | |||
| @@ -164,7 +164,7 @@ protected: | |||
| 164 | u32_le size; | 164 | u32_le size; |
| 165 | u32_le library_version; | 165 | u32_le library_version; |
| 166 | u32_le theme_color; | 166 | u32_le theme_color; |
| 167 | u8 play_startup_sound; | 167 | bool play_startup_sound; |
| 168 | u64_le system_tick; | 168 | u64_le system_tick; |
| 169 | }; | 169 | }; |
| 170 | static_assert(sizeof(CommonArguments) == 0x20, "CommonArguments has incorrect size."); | 170 | static_assert(sizeof(CommonArguments) == 0x20, "CommonArguments has incorrect size."); |
diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp index ba8a1f786..2f871de31 100644 --- a/src/core/hle/service/hid/controllers/npad.cpp +++ b/src/core/hle/service/hid/controllers/npad.cpp | |||
| @@ -868,7 +868,7 @@ bool Controller_NPad::VibrateControllerAtIndex(Core::HID::NpadIdType npad_id, | |||
| 868 | return false; | 868 | return false; |
| 869 | } | 869 | } |
| 870 | 870 | ||
| 871 | if (!controller.device->IsVibrationEnabled()) { | 871 | if (!controller.device->IsVibrationEnabled(device_index)) { |
| 872 | if (controller.vibration[device_index].latest_vibration_value.low_amplitude != 0.0f || | 872 | if (controller.vibration[device_index].latest_vibration_value.low_amplitude != 0.0f || |
| 873 | controller.vibration[device_index].latest_vibration_value.high_amplitude != 0.0f) { | 873 | controller.vibration[device_index].latest_vibration_value.high_amplitude != 0.0f) { |
| 874 | // Send an empty vibration to stop any vibrations. | 874 | // Send an empty vibration to stop any vibrations. |
| @@ -1001,7 +1001,7 @@ void Controller_NPad::InitializeVibrationDeviceAtIndex(Core::HID::NpadIdType npa | |||
| 1001 | } | 1001 | } |
| 1002 | 1002 | ||
| 1003 | controller.vibration[device_index].device_mounted = | 1003 | controller.vibration[device_index].device_mounted = |
| 1004 | controller.device->TestVibration(device_index); | 1004 | controller.device->IsVibrationEnabled(device_index); |
| 1005 | } | 1005 | } |
| 1006 | 1006 | ||
| 1007 | void Controller_NPad::SetPermitVibrationSession(bool permit_vibration_session) { | 1007 | void Controller_NPad::SetPermitVibrationSession(bool permit_vibration_session) { |
| @@ -1502,25 +1502,25 @@ bool Controller_NPad::IsControllerSupported(Core::HID::NpadStyleIndex controller | |||
| 1502 | Core::HID::NpadStyleTag style = GetSupportedStyleSet(); | 1502 | Core::HID::NpadStyleTag style = GetSupportedStyleSet(); |
| 1503 | switch (controller) { | 1503 | switch (controller) { |
| 1504 | case Core::HID::NpadStyleIndex::ProController: | 1504 | case Core::HID::NpadStyleIndex::ProController: |
| 1505 | return style.fullkey; | 1505 | return style.fullkey.As<bool>(); |
| 1506 | case Core::HID::NpadStyleIndex::JoyconDual: | 1506 | case Core::HID::NpadStyleIndex::JoyconDual: |
| 1507 | return style.joycon_dual; | 1507 | return style.joycon_dual.As<bool>(); |
| 1508 | case Core::HID::NpadStyleIndex::JoyconLeft: | 1508 | case Core::HID::NpadStyleIndex::JoyconLeft: |
| 1509 | return style.joycon_left; | 1509 | return style.joycon_left.As<bool>(); |
| 1510 | case Core::HID::NpadStyleIndex::JoyconRight: | 1510 | case Core::HID::NpadStyleIndex::JoyconRight: |
| 1511 | return style.joycon_right; | 1511 | return style.joycon_right.As<bool>(); |
| 1512 | case Core::HID::NpadStyleIndex::GameCube: | 1512 | case Core::HID::NpadStyleIndex::GameCube: |
| 1513 | return style.gamecube; | 1513 | return style.gamecube.As<bool>(); |
| 1514 | case Core::HID::NpadStyleIndex::Pokeball: | 1514 | case Core::HID::NpadStyleIndex::Pokeball: |
| 1515 | return style.palma; | 1515 | return style.palma.As<bool>(); |
| 1516 | case Core::HID::NpadStyleIndex::NES: | 1516 | case Core::HID::NpadStyleIndex::NES: |
| 1517 | return style.lark; | 1517 | return style.lark.As<bool>(); |
| 1518 | case Core::HID::NpadStyleIndex::SNES: | 1518 | case Core::HID::NpadStyleIndex::SNES: |
| 1519 | return style.lucia; | 1519 | return style.lucia.As<bool>(); |
| 1520 | case Core::HID::NpadStyleIndex::N64: | 1520 | case Core::HID::NpadStyleIndex::N64: |
| 1521 | return style.lagoon; | 1521 | return style.lagoon.As<bool>(); |
| 1522 | case Core::HID::NpadStyleIndex::SegaGenesis: | 1522 | case Core::HID::NpadStyleIndex::SegaGenesis: |
| 1523 | return style.lager; | 1523 | return style.lager.As<bool>(); |
| 1524 | default: | 1524 | default: |
| 1525 | return false; | 1525 | return false; |
| 1526 | } | 1526 | } |
diff --git a/src/core/hle/service/nfp/amiibo_crypto.cpp b/src/core/hle/service/nfp/amiibo_crypto.cpp index c32a6816b..167e29572 100644 --- a/src/core/hle/service/nfp/amiibo_crypto.cpp +++ b/src/core/hle/service/nfp/amiibo_crypto.cpp | |||
| @@ -9,6 +9,7 @@ | |||
| 9 | #include <mbedtls/hmac_drbg.h> | 9 | #include <mbedtls/hmac_drbg.h> |
| 10 | 10 | ||
| 11 | #include "common/fs/file.h" | 11 | #include "common/fs/file.h" |
| 12 | #include "common/fs/fs.h" | ||
| 12 | #include "common/fs/path_util.h" | 13 | #include "common/fs/path_util.h" |
| 13 | #include "common/logging/log.h" | 14 | #include "common/logging/log.h" |
| 14 | #include "core/hle/service/mii/mii_manager.h" | 15 | #include "core/hle/service/mii/mii_manager.h" |
| @@ -279,7 +280,7 @@ bool LoadKeys(InternalKey& locked_secret, InternalKey& unfixed_info) { | |||
| 279 | Common::FS::FileType::BinaryFile}; | 280 | Common::FS::FileType::BinaryFile}; |
| 280 | 281 | ||
| 281 | if (!keys_file.IsOpen()) { | 282 | if (!keys_file.IsOpen()) { |
| 282 | LOG_ERROR(Service_NFP, "No keys detected"); | 283 | LOG_ERROR(Service_NFP, "Failed to open key file"); |
| 283 | return false; | 284 | return false; |
| 284 | } | 285 | } |
| 285 | 286 | ||
| @@ -295,6 +296,11 @@ bool LoadKeys(InternalKey& locked_secret, InternalKey& unfixed_info) { | |||
| 295 | return true; | 296 | return true; |
| 296 | } | 297 | } |
| 297 | 298 | ||
| 299 | bool IsKeyAvailable() { | ||
| 300 | const auto yuzu_keys_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::KeysDir); | ||
| 301 | return Common::FS::Exists(yuzu_keys_dir / "key_retail.bin"); | ||
| 302 | } | ||
| 303 | |||
| 298 | bool DecodeAmiibo(const EncryptedNTAG215File& encrypted_tag_data, NTAG215File& tag_data) { | 304 | bool DecodeAmiibo(const EncryptedNTAG215File& encrypted_tag_data, NTAG215File& tag_data) { |
| 299 | InternalKey locked_secret{}; | 305 | InternalKey locked_secret{}; |
| 300 | InternalKey unfixed_info{}; | 306 | InternalKey unfixed_info{}; |
diff --git a/src/core/hle/service/nfp/amiibo_crypto.h b/src/core/hle/service/nfp/amiibo_crypto.h index 0175ced91..1fa61174e 100644 --- a/src/core/hle/service/nfp/amiibo_crypto.h +++ b/src/core/hle/service/nfp/amiibo_crypto.h | |||
| @@ -91,6 +91,9 @@ void Cipher(const DerivedKeys& keys, const NTAG215File& in_data, NTAG215File& ou | |||
| 91 | /// Loads both amiibo keys from key_retail.bin | 91 | /// Loads both amiibo keys from key_retail.bin |
| 92 | bool LoadKeys(InternalKey& locked_secret, InternalKey& unfixed_info); | 92 | bool LoadKeys(InternalKey& locked_secret, InternalKey& unfixed_info); |
| 93 | 93 | ||
| 94 | /// Returns true if key_retail.bin exist | ||
| 95 | bool IsKeyAvailable(); | ||
| 96 | |||
| 94 | /// Decodes encripted amiibo data returns true if output is valid | 97 | /// Decodes encripted amiibo data returns true if output is valid |
| 95 | bool DecodeAmiibo(const EncryptedNTAG215File& encrypted_tag_data, NTAG215File& tag_data); | 98 | bool DecodeAmiibo(const EncryptedNTAG215File& encrypted_tag_data, NTAG215File& tag_data); |
| 96 | 99 | ||
diff --git a/src/core/hle/service/nfp/nfp_device.cpp b/src/core/hle/service/nfp/nfp_device.cpp index 76f8a267a..b19672560 100644 --- a/src/core/hle/service/nfp/nfp_device.cpp +++ b/src/core/hle/service/nfp/nfp_device.cpp | |||
| @@ -17,6 +17,7 @@ | |||
| 17 | #include "core/hle/ipc_helpers.h" | 17 | #include "core/hle/ipc_helpers.h" |
| 18 | #include "core/hle/kernel/k_event.h" | 18 | #include "core/hle/kernel/k_event.h" |
| 19 | #include "core/hle/service/mii/mii_manager.h" | 19 | #include "core/hle/service/mii/mii_manager.h" |
| 20 | #include "core/hle/service/mii/types.h" | ||
| 20 | #include "core/hle/service/nfp/amiibo_crypto.h" | 21 | #include "core/hle/service/nfp/amiibo_crypto.h" |
| 21 | #include "core/hle/service/nfp/nfp.h" | 22 | #include "core/hle/service/nfp/nfp.h" |
| 22 | #include "core/hle/service/nfp/nfp_device.h" | 23 | #include "core/hle/service/nfp/nfp_device.h" |
| @@ -233,6 +234,14 @@ Result NfpDevice::Mount(MountTarget mount_target_) { | |||
| 233 | return NotAnAmiibo; | 234 | return NotAnAmiibo; |
| 234 | } | 235 | } |
| 235 | 236 | ||
| 237 | // Mark amiibos as read only when keys are missing | ||
| 238 | if (!AmiiboCrypto::IsKeyAvailable()) { | ||
| 239 | LOG_ERROR(Service_NFP, "No keys detected"); | ||
| 240 | device_state = DeviceState::TagMounted; | ||
| 241 | mount_target = MountTarget::Rom; | ||
| 242 | return ResultSuccess; | ||
| 243 | } | ||
| 244 | |||
| 236 | if (!AmiiboCrypto::DecodeAmiibo(encrypted_tag_data, tag_data)) { | 245 | if (!AmiiboCrypto::DecodeAmiibo(encrypted_tag_data, tag_data)) { |
| 237 | LOG_ERROR(Service_NFP, "Can't decode amiibo {}", device_state); | 246 | LOG_ERROR(Service_NFP, "Can't decode amiibo {}", device_state); |
| 238 | return CorruptedData; | 247 | return CorruptedData; |
diff --git a/src/core/hle/service/nfp/nfp_device.h b/src/core/hle/service/nfp/nfp_device.h index a5b72cf19..76d0e9ae4 100644 --- a/src/core/hle/service/nfp/nfp_device.h +++ b/src/core/hle/service/nfp/nfp_device.h | |||
| @@ -8,7 +8,6 @@ | |||
| 8 | 8 | ||
| 9 | #include "common/common_funcs.h" | 9 | #include "common/common_funcs.h" |
| 10 | #include "core/hle/service/kernel_helpers.h" | 10 | #include "core/hle/service/kernel_helpers.h" |
| 11 | #include "core/hle/service/mii/types.h" | ||
| 12 | #include "core/hle/service/nfp/nfp_types.h" | 11 | #include "core/hle/service/nfp/nfp_types.h" |
| 13 | #include "core/hle/service/service.h" | 12 | #include "core/hle/service/service.h" |
| 14 | 13 | ||
diff --git a/src/core/hle/service/nfp/nfp_types.h b/src/core/hle/service/nfp/nfp_types.h index c09f9ddb6..63d5917cb 100644 --- a/src/core/hle/service/nfp/nfp_types.h +++ b/src/core/hle/service/nfp/nfp_types.h | |||
| @@ -17,11 +17,6 @@ enum class ServiceType : u32 { | |||
| 17 | System, | 17 | System, |
| 18 | }; | 18 | }; |
| 19 | 19 | ||
| 20 | enum class State : u32 { | ||
| 21 | NonInitialized, | ||
| 22 | Initialized, | ||
| 23 | }; | ||
| 24 | |||
| 25 | enum class DeviceState : u32 { | 20 | enum class DeviceState : u32 { |
| 26 | Initialized, | 21 | Initialized, |
| 27 | SearchingForTag, | 22 | SearchingForTag, |
diff --git a/src/core/hle/service/nfp/nfp_user.cpp b/src/core/hle/service/nfp/nfp_user.cpp index 4ed53b534..33e2ef518 100644 --- a/src/core/hle/service/nfp/nfp_user.cpp +++ b/src/core/hle/service/nfp/nfp_user.cpp | |||
| @@ -6,12 +6,9 @@ | |||
| 6 | 6 | ||
| 7 | #include "common/logging/log.h" | 7 | #include "common/logging/log.h" |
| 8 | #include "core/core.h" | 8 | #include "core/core.h" |
| 9 | #include "core/hid/emulated_controller.h" | ||
| 10 | #include "core/hid/hid_core.h" | ||
| 11 | #include "core/hid/hid_types.h" | 9 | #include "core/hid/hid_types.h" |
| 12 | #include "core/hle/ipc_helpers.h" | 10 | #include "core/hle/ipc_helpers.h" |
| 13 | #include "core/hle/kernel/k_event.h" | 11 | #include "core/hle/kernel/k_event.h" |
| 14 | #include "core/hle/service/mii/mii_manager.h" | ||
| 15 | #include "core/hle/service/nfp/nfp_device.h" | 12 | #include "core/hle/service/nfp/nfp_device.h" |
| 16 | #include "core/hle/service/nfp/nfp_result.h" | 13 | #include "core/hle/service/nfp/nfp_result.h" |
| 17 | #include "core/hle/service/nfp/nfp_user.h" | 14 | #include "core/hle/service/nfp/nfp_user.h" |
diff --git a/src/core/hle/service/nfp/nfp_user.h b/src/core/hle/service/nfp/nfp_user.h index 68c60ae82..47aff3695 100644 --- a/src/core/hle/service/nfp/nfp_user.h +++ b/src/core/hle/service/nfp/nfp_user.h | |||
| @@ -4,8 +4,7 @@ | |||
| 4 | #pragma once | 4 | #pragma once |
| 5 | 5 | ||
| 6 | #include "core/hle/service/kernel_helpers.h" | 6 | #include "core/hle/service/kernel_helpers.h" |
| 7 | #include "core/hle/service/nfp/nfp.h" | 7 | #include "core/hle/service/service.h" |
| 8 | #include "core/hle/service/nfp/nfp_types.h" | ||
| 9 | 8 | ||
| 10 | namespace Service::NFP { | 9 | namespace Service::NFP { |
| 11 | class NfpDevice; | 10 | class NfpDevice; |
| @@ -15,6 +14,11 @@ public: | |||
| 15 | explicit IUser(Core::System& system_); | 14 | explicit IUser(Core::System& system_); |
| 16 | 15 | ||
| 17 | private: | 16 | private: |
| 17 | enum class State : u32 { | ||
| 18 | NonInitialized, | ||
| 19 | Initialized, | ||
| 20 | }; | ||
| 21 | |||
| 18 | void Initialize(Kernel::HLERequestContext& ctx); | 22 | void Initialize(Kernel::HLERequestContext& ctx); |
| 19 | void Finalize(Kernel::HLERequestContext& ctx); | 23 | void Finalize(Kernel::HLERequestContext& ctx); |
| 20 | void ListDevices(Kernel::HLERequestContext& ctx); | 24 | void ListDevices(Kernel::HLERequestContext& ctx); |
diff --git a/src/core/hle/service/nvdrv/nvdrv.cpp b/src/core/hle/service/nvdrv/nvdrv.cpp index 9d9924395..9f4c7c99a 100644 --- a/src/core/hle/service/nvdrv/nvdrv.cpp +++ b/src/core/hle/service/nvdrv/nvdrv.cpp | |||
| @@ -53,7 +53,7 @@ void InstallInterfaces(SM::ServiceManager& service_manager, NVFlinger::NVFlinger | |||
| 53 | } | 53 | } |
| 54 | 54 | ||
| 55 | Module::Module(Core::System& system) | 55 | Module::Module(Core::System& system) |
| 56 | : service_context{system, "nvdrv"}, events_interface{*this}, container{system.Host1x()} { | 56 | : container{system.Host1x()}, service_context{system, "nvdrv"}, events_interface{*this} { |
| 57 | builders["/dev/nvhost-as-gpu"] = [this, &system](DeviceFD fd) { | 57 | builders["/dev/nvhost-as-gpu"] = [this, &system](DeviceFD fd) { |
| 58 | std::shared_ptr<Devices::nvdevice> device = | 58 | std::shared_ptr<Devices::nvdevice> device = |
| 59 | std::make_shared<Devices::nvhost_as_gpu>(system, *this, container); | 59 | std::make_shared<Devices::nvhost_as_gpu>(system, *this, container); |
diff --git a/src/core/hle/service/nvdrv/nvdrv.h b/src/core/hle/service/nvdrv/nvdrv.h index 146d046a9..f3c81bd88 100644 --- a/src/core/hle/service/nvdrv/nvdrv.h +++ b/src/core/hle/service/nvdrv/nvdrv.h | |||
| @@ -97,6 +97,9 @@ private: | |||
| 97 | friend class EventInterface; | 97 | friend class EventInterface; |
| 98 | friend class Service::NVFlinger::NVFlinger; | 98 | friend class Service::NVFlinger::NVFlinger; |
| 99 | 99 | ||
| 100 | /// Manages syncpoints on the host | ||
| 101 | NvCore::Container container; | ||
| 102 | |||
| 100 | /// Id to use for the next open file descriptor. | 103 | /// Id to use for the next open file descriptor. |
| 101 | DeviceFD next_fd = 1; | 104 | DeviceFD next_fd = 1; |
| 102 | 105 | ||
| @@ -108,9 +111,6 @@ private: | |||
| 108 | 111 | ||
| 109 | EventInterface events_interface; | 112 | EventInterface events_interface; |
| 110 | 113 | ||
| 111 | /// Manages syncpoints on the host | ||
| 112 | NvCore::Container container; | ||
| 113 | |||
| 114 | std::unordered_map<std::string, std::function<FilesContainerType::iterator(DeviceFD)>> builders; | 114 | std::unordered_map<std::string, std::function<FilesContainerType::iterator(DeviceFD)>> builders; |
| 115 | }; | 115 | }; |
| 116 | 116 | ||
diff --git a/src/core/hle/service/nvflinger/nvflinger.cpp b/src/core/hle/service/nvflinger/nvflinger.cpp index aa14d2cbc..dad93b38e 100644 --- a/src/core/hle/service/nvflinger/nvflinger.cpp +++ b/src/core/hle/service/nvflinger/nvflinger.cpp | |||
| @@ -102,15 +102,19 @@ NVFlinger::~NVFlinger() { | |||
| 102 | system.CoreTiming().UnscheduleEvent(single_composition_event, {}); | 102 | system.CoreTiming().UnscheduleEvent(single_composition_event, {}); |
| 103 | } | 103 | } |
| 104 | 104 | ||
| 105 | ShutdownLayers(); | ||
| 106 | |||
| 107 | if (nvdrv) { | ||
| 108 | nvdrv->Close(disp_fd); | ||
| 109 | } | ||
| 110 | } | ||
| 111 | |||
| 112 | void NVFlinger::ShutdownLayers() { | ||
| 105 | for (auto& display : displays) { | 113 | for (auto& display : displays) { |
| 106 | for (size_t layer = 0; layer < display.GetNumLayers(); ++layer) { | 114 | for (size_t layer = 0; layer < display.GetNumLayers(); ++layer) { |
| 107 | display.GetLayer(layer).Core().NotifyShutdown(); | 115 | display.GetLayer(layer).Core().NotifyShutdown(); |
| 108 | } | 116 | } |
| 109 | } | 117 | } |
| 110 | |||
| 111 | if (nvdrv) { | ||
| 112 | nvdrv->Close(disp_fd); | ||
| 113 | } | ||
| 114 | } | 118 | } |
| 115 | 119 | ||
| 116 | void NVFlinger::SetNVDrvInstance(std::shared_ptr<Nvidia::Module> instance) { | 120 | void NVFlinger::SetNVDrvInstance(std::shared_ptr<Nvidia::Module> instance) { |
diff --git a/src/core/hle/service/nvflinger/nvflinger.h b/src/core/hle/service/nvflinger/nvflinger.h index 99509bc5b..b8191c595 100644 --- a/src/core/hle/service/nvflinger/nvflinger.h +++ b/src/core/hle/service/nvflinger/nvflinger.h | |||
| @@ -48,6 +48,8 @@ public: | |||
| 48 | explicit NVFlinger(Core::System& system_, HosBinderDriverServer& hos_binder_driver_server_); | 48 | explicit NVFlinger(Core::System& system_, HosBinderDriverServer& hos_binder_driver_server_); |
| 49 | ~NVFlinger(); | 49 | ~NVFlinger(); |
| 50 | 50 | ||
| 51 | void ShutdownLayers(); | ||
| 52 | |||
| 51 | /// Sets the NVDrv module instance to use to send buffers to the GPU. | 53 | /// Sets the NVDrv module instance to use to send buffers to the GPU. |
| 52 | void SetNVDrvInstance(std::shared_ptr<Nvidia::Module> instance); | 54 | void SetNVDrvInstance(std::shared_ptr<Nvidia::Module> instance); |
| 53 | 55 | ||
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index dadaf897f..5db6588e4 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp | |||
| @@ -303,4 +303,8 @@ Services::Services(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system | |||
| 303 | 303 | ||
| 304 | Services::~Services() = default; | 304 | Services::~Services() = default; |
| 305 | 305 | ||
| 306 | void Services::KillNVNFlinger() { | ||
| 307 | nv_flinger->ShutdownLayers(); | ||
| 308 | } | ||
| 309 | |||
| 306 | } // namespace Service | 310 | } // namespace Service |
diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h index 5bf197c51..ec9deeee4 100644 --- a/src/core/hle/service/service.h +++ b/src/core/hle/service/service.h | |||
| @@ -238,6 +238,8 @@ public: | |||
| 238 | explicit Services(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system); | 238 | explicit Services(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system); |
| 239 | ~Services(); | 239 | ~Services(); |
| 240 | 240 | ||
| 241 | void KillNVNFlinger(); | ||
| 242 | |||
| 241 | private: | 243 | private: |
| 242 | std::unique_ptr<NVFlinger::HosBinderDriverServer> hos_binder_driver_server; | 244 | std::unique_ptr<NVFlinger::HosBinderDriverServer> hos_binder_driver_server; |
| 243 | std::unique_ptr<NVFlinger::NVFlinger> nv_flinger; | 245 | std::unique_ptr<NVFlinger::NVFlinger> nv_flinger; |
diff --git a/src/core/memory.cpp b/src/core/memory.cpp index 9637cb5b1..3ca80c8ff 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp | |||
| @@ -233,18 +233,17 @@ struct Memory::Impl { | |||
| 233 | current_vaddr, src_addr, size); | 233 | current_vaddr, src_addr, size); |
| 234 | std::memset(dest_buffer, 0, copy_amount); | 234 | std::memset(dest_buffer, 0, copy_amount); |
| 235 | }, | 235 | }, |
| 236 | [&dest_buffer](const std::size_t copy_amount, const u8* const src_ptr) { | 236 | [&](const std::size_t copy_amount, const u8* const src_ptr) { |
| 237 | std::memcpy(dest_buffer, src_ptr, copy_amount); | 237 | std::memcpy(dest_buffer, src_ptr, copy_amount); |
| 238 | }, | 238 | }, |
| 239 | [&system = system, &dest_buffer](const VAddr current_vaddr, | 239 | [&](const VAddr current_vaddr, const std::size_t copy_amount, |
| 240 | const std::size_t copy_amount, | 240 | const u8* const host_ptr) { |
| 241 | const u8* const host_ptr) { | ||
| 242 | if constexpr (!UNSAFE) { | 241 | if constexpr (!UNSAFE) { |
| 243 | system.GPU().FlushRegion(current_vaddr, copy_amount); | 242 | system.GPU().FlushRegion(current_vaddr, copy_amount); |
| 244 | } | 243 | } |
| 245 | std::memcpy(dest_buffer, host_ptr, copy_amount); | 244 | std::memcpy(dest_buffer, host_ptr, copy_amount); |
| 246 | }, | 245 | }, |
| 247 | [&dest_buffer](const std::size_t copy_amount) { | 246 | [&](const std::size_t copy_amount) { |
| 248 | dest_buffer = static_cast<u8*>(dest_buffer) + copy_amount; | 247 | dest_buffer = static_cast<u8*>(dest_buffer) + copy_amount; |
| 249 | }); | 248 | }); |
| 250 | } | 249 | } |
| @@ -267,17 +266,16 @@ struct Memory::Impl { | |||
| 267 | "Unmapped WriteBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})", | 266 | "Unmapped WriteBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})", |
| 268 | current_vaddr, dest_addr, size); | 267 | current_vaddr, dest_addr, size); |
| 269 | }, | 268 | }, |
| 270 | [&src_buffer](const std::size_t copy_amount, u8* const dest_ptr) { | 269 | [&](const std::size_t copy_amount, u8* const dest_ptr) { |
| 271 | std::memcpy(dest_ptr, src_buffer, copy_amount); | 270 | std::memcpy(dest_ptr, src_buffer, copy_amount); |
| 272 | }, | 271 | }, |
| 273 | [&system = system, &src_buffer](const VAddr current_vaddr, | 272 | [&](const VAddr current_vaddr, const std::size_t copy_amount, u8* const host_ptr) { |
| 274 | const std::size_t copy_amount, u8* const host_ptr) { | ||
| 275 | if constexpr (!UNSAFE) { | 273 | if constexpr (!UNSAFE) { |
| 276 | system.GPU().InvalidateRegion(current_vaddr, copy_amount); | 274 | system.GPU().InvalidateRegion(current_vaddr, copy_amount); |
| 277 | } | 275 | } |
| 278 | std::memcpy(host_ptr, src_buffer, copy_amount); | 276 | std::memcpy(host_ptr, src_buffer, copy_amount); |
| 279 | }, | 277 | }, |
| 280 | [&src_buffer](const std::size_t copy_amount) { | 278 | [&](const std::size_t copy_amount) { |
| 281 | src_buffer = static_cast<const u8*>(src_buffer) + copy_amount; | 279 | src_buffer = static_cast<const u8*>(src_buffer) + copy_amount; |
| 282 | }); | 280 | }); |
| 283 | } | 281 | } |
| @@ -301,8 +299,7 @@ struct Memory::Impl { | |||
| 301 | [](const std::size_t copy_amount, u8* const dest_ptr) { | 299 | [](const std::size_t copy_amount, u8* const dest_ptr) { |
| 302 | std::memset(dest_ptr, 0, copy_amount); | 300 | std::memset(dest_ptr, 0, copy_amount); |
| 303 | }, | 301 | }, |
| 304 | [&system = system](const VAddr current_vaddr, const std::size_t copy_amount, | 302 | [&](const VAddr current_vaddr, const std::size_t copy_amount, u8* const host_ptr) { |
| 305 | u8* const host_ptr) { | ||
| 306 | system.GPU().InvalidateRegion(current_vaddr, copy_amount); | 303 | system.GPU().InvalidateRegion(current_vaddr, copy_amount); |
| 307 | std::memset(host_ptr, 0, copy_amount); | 304 | std::memset(host_ptr, 0, copy_amount); |
| 308 | }, | 305 | }, |
| @@ -313,22 +310,20 @@ struct Memory::Impl { | |||
| 313 | const std::size_t size) { | 310 | const std::size_t size) { |
| 314 | WalkBlock( | 311 | WalkBlock( |
| 315 | process, dest_addr, size, | 312 | process, dest_addr, size, |
| 316 | [this, &process, &dest_addr, &src_addr, size](const std::size_t copy_amount, | 313 | [&](const std::size_t copy_amount, const VAddr current_vaddr) { |
| 317 | const VAddr current_vaddr) { | ||
| 318 | LOG_ERROR(HW_Memory, | 314 | LOG_ERROR(HW_Memory, |
| 319 | "Unmapped CopyBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})", | 315 | "Unmapped CopyBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})", |
| 320 | current_vaddr, src_addr, size); | 316 | current_vaddr, src_addr, size); |
| 321 | ZeroBlock(process, dest_addr, copy_amount); | 317 | ZeroBlock(process, dest_addr, copy_amount); |
| 322 | }, | 318 | }, |
| 323 | [this, &process, &dest_addr](const std::size_t copy_amount, const u8* const src_ptr) { | 319 | [&](const std::size_t copy_amount, const u8* const src_ptr) { |
| 324 | WriteBlockImpl<false>(process, dest_addr, src_ptr, copy_amount); | 320 | WriteBlockImpl<false>(process, dest_addr, src_ptr, copy_amount); |
| 325 | }, | 321 | }, |
| 326 | [this, &system = system, &process, &dest_addr]( | 322 | [&](const VAddr current_vaddr, const std::size_t copy_amount, u8* const host_ptr) { |
| 327 | const VAddr current_vaddr, const std::size_t copy_amount, u8* const host_ptr) { | ||
| 328 | system.GPU().FlushRegion(current_vaddr, copy_amount); | 323 | system.GPU().FlushRegion(current_vaddr, copy_amount); |
| 329 | WriteBlockImpl<false>(process, dest_addr, host_ptr, copy_amount); | 324 | WriteBlockImpl<false>(process, dest_addr, host_ptr, copy_amount); |
| 330 | }, | 325 | }, |
| 331 | [&dest_addr, &src_addr](const std::size_t copy_amount) { | 326 | [&](const std::size_t copy_amount) { |
| 332 | dest_addr += static_cast<VAddr>(copy_amount); | 327 | dest_addr += static_cast<VAddr>(copy_amount); |
| 333 | src_addr += static_cast<VAddr>(copy_amount); | 328 | src_addr += static_cast<VAddr>(copy_amount); |
| 334 | }); | 329 | }); |
| @@ -575,7 +570,7 @@ struct Memory::Impl { | |||
| 575 | [vaddr]() { | 570 | [vaddr]() { |
| 576 | LOG_ERROR(HW_Memory, "Unmapped Read{} @ 0x{:016X}", sizeof(T) * 8, vaddr); | 571 | LOG_ERROR(HW_Memory, "Unmapped Read{} @ 0x{:016X}", sizeof(T) * 8, vaddr); |
| 577 | }, | 572 | }, |
| 578 | [&system = system, vaddr]() { system.GPU().FlushRegion(vaddr, sizeof(T)); }); | 573 | [&]() { system.GPU().FlushRegion(vaddr, sizeof(T)); }); |
| 579 | if (ptr) { | 574 | if (ptr) { |
| 580 | std::memcpy(&result, ptr, sizeof(T)); | 575 | std::memcpy(&result, ptr, sizeof(T)); |
| 581 | } | 576 | } |
| @@ -599,7 +594,7 @@ struct Memory::Impl { | |||
| 599 | LOG_ERROR(HW_Memory, "Unmapped Write{} @ 0x{:016X} = 0x{:016X}", sizeof(T) * 8, | 594 | LOG_ERROR(HW_Memory, "Unmapped Write{} @ 0x{:016X} = 0x{:016X}", sizeof(T) * 8, |
| 600 | vaddr, static_cast<u64>(data)); | 595 | vaddr, static_cast<u64>(data)); |
| 601 | }, | 596 | }, |
| 602 | [&system = system, vaddr]() { system.GPU().InvalidateRegion(vaddr, sizeof(T)); }); | 597 | [&]() { system.GPU().InvalidateRegion(vaddr, sizeof(T)); }); |
| 603 | if (ptr) { | 598 | if (ptr) { |
| 604 | std::memcpy(ptr, &data, sizeof(T)); | 599 | std::memcpy(ptr, &data, sizeof(T)); |
| 605 | } | 600 | } |
| @@ -613,7 +608,7 @@ struct Memory::Impl { | |||
| 613 | LOG_ERROR(HW_Memory, "Unmapped WriteExclusive{} @ 0x{:016X} = 0x{:016X}", | 608 | LOG_ERROR(HW_Memory, "Unmapped WriteExclusive{} @ 0x{:016X} = 0x{:016X}", |
| 614 | sizeof(T) * 8, vaddr, static_cast<u64>(data)); | 609 | sizeof(T) * 8, vaddr, static_cast<u64>(data)); |
| 615 | }, | 610 | }, |
| 616 | [&system = system, vaddr]() { system.GPU().InvalidateRegion(vaddr, sizeof(T)); }); | 611 | [&]() { system.GPU().InvalidateRegion(vaddr, sizeof(T)); }); |
| 617 | if (ptr) { | 612 | if (ptr) { |
| 618 | const auto volatile_pointer = reinterpret_cast<volatile T*>(ptr); | 613 | const auto volatile_pointer = reinterpret_cast<volatile T*>(ptr); |
| 619 | return Common::AtomicCompareAndSwap(volatile_pointer, data, expected); | 614 | return Common::AtomicCompareAndSwap(volatile_pointer, data, expected); |
| @@ -628,7 +623,7 @@ struct Memory::Impl { | |||
| 628 | LOG_ERROR(HW_Memory, "Unmapped WriteExclusive128 @ 0x{:016X} = 0x{:016X}{:016X}", | 623 | LOG_ERROR(HW_Memory, "Unmapped WriteExclusive128 @ 0x{:016X} = 0x{:016X}{:016X}", |
| 629 | vaddr, static_cast<u64>(data[1]), static_cast<u64>(data[0])); | 624 | vaddr, static_cast<u64>(data[1]), static_cast<u64>(data[0])); |
| 630 | }, | 625 | }, |
| 631 | [&system = system, vaddr]() { system.GPU().InvalidateRegion(vaddr, sizeof(u128)); }); | 626 | [&]() { system.GPU().InvalidateRegion(vaddr, sizeof(u128)); }); |
| 632 | if (ptr) { | 627 | if (ptr) { |
| 633 | const auto volatile_pointer = reinterpret_cast<volatile u64*>(ptr); | 628 | const auto volatile_pointer = reinterpret_cast<volatile u64*>(ptr); |
| 634 | return Common::AtomicCompareAndSwap(volatile_pointer, data, expected); | 629 | return Common::AtomicCompareAndSwap(volatile_pointer, data, expected); |
diff --git a/src/input_common/CMakeLists.txt b/src/input_common/CMakeLists.txt index 2cf9eb97f..cc6f0ffc0 100644 --- a/src/input_common/CMakeLists.txt +++ b/src/input_common/CMakeLists.txt | |||
| @@ -39,21 +39,14 @@ add_library(input_common STATIC | |||
| 39 | if (MSVC) | 39 | if (MSVC) |
| 40 | target_compile_options(input_common PRIVATE | 40 | target_compile_options(input_common PRIVATE |
| 41 | /W4 | 41 | /W4 |
| 42 | /WX | ||
| 43 | 42 | ||
| 44 | /we4242 # 'identifier': conversion from 'type1' to 'type2', possible loss of data | 43 | /we4242 # 'identifier': conversion from 'type1' to 'type2', possible loss of data |
| 45 | /we4244 # 'conversion': conversion from 'type1' to 'type2', possible loss of data | ||
| 46 | /we4245 # 'conversion': conversion from 'type1' to 'type2', signed/unsigned mismatch | ||
| 47 | /we4254 # 'operator': conversion from 'type1:field_bits' to 'type2:field_bits', possible loss of data | 44 | /we4254 # 'operator': conversion from 'type1:field_bits' to 'type2:field_bits', possible loss of data |
| 45 | /we4800 # Implicit conversion from 'type' to bool. Possible information loss | ||
| 48 | ) | 46 | ) |
| 49 | else() | 47 | else() |
| 50 | target_compile_options(input_common PRIVATE | 48 | target_compile_options(input_common PRIVATE |
| 51 | -Werror | ||
| 52 | -Werror=conversion | 49 | -Werror=conversion |
| 53 | -Werror=ignored-qualifiers | ||
| 54 | $<$<CXX_COMPILER_ID:GNU>:-Werror=unused-but-set-parameter> | ||
| 55 | $<$<CXX_COMPILER_ID:GNU>:-Werror=unused-but-set-variable> | ||
| 56 | -Werror=unused-variable | ||
| 57 | ) | 50 | ) |
| 58 | endif() | 51 | endif() |
| 59 | 52 | ||
diff --git a/src/input_common/drivers/gc_adapter.cpp b/src/input_common/drivers/gc_adapter.cpp index f4dd24e7d..826fa2109 100644 --- a/src/input_common/drivers/gc_adapter.cpp +++ b/src/input_common/drivers/gc_adapter.cpp | |||
| @@ -324,7 +324,7 @@ bool GCAdapter::GetGCEndpoint(libusb_device* device) { | |||
| 324 | return true; | 324 | return true; |
| 325 | } | 325 | } |
| 326 | 326 | ||
| 327 | Common::Input::VibrationError GCAdapter::SetRumble( | 327 | Common::Input::VibrationError GCAdapter::SetVibration( |
| 328 | const PadIdentifier& identifier, const Common::Input::VibrationStatus& vibration) { | 328 | const PadIdentifier& identifier, const Common::Input::VibrationStatus& vibration) { |
| 329 | const auto mean_amplitude = (vibration.low_amplitude + vibration.high_amplitude) * 0.5f; | 329 | const auto mean_amplitude = (vibration.low_amplitude + vibration.high_amplitude) * 0.5f; |
| 330 | const auto processed_amplitude = | 330 | const auto processed_amplitude = |
| @@ -338,6 +338,10 @@ Common::Input::VibrationError GCAdapter::SetRumble( | |||
| 338 | return Common::Input::VibrationError::None; | 338 | return Common::Input::VibrationError::None; |
| 339 | } | 339 | } |
| 340 | 340 | ||
| 341 | bool GCAdapter::IsVibrationEnabled([[maybe_unused]] const PadIdentifier& identifier) { | ||
| 342 | return rumble_enabled; | ||
| 343 | } | ||
| 344 | |||
| 341 | void GCAdapter::UpdateVibrations() { | 345 | void GCAdapter::UpdateVibrations() { |
| 342 | // Use 8 states to keep the switching between on/off fast enough for | 346 | // Use 8 states to keep the switching between on/off fast enough for |
| 343 | // a human to feel different vibration strenght | 347 | // a human to feel different vibration strenght |
diff --git a/src/input_common/drivers/gc_adapter.h b/src/input_common/drivers/gc_adapter.h index 8682da847..7f81767f7 100644 --- a/src/input_common/drivers/gc_adapter.h +++ b/src/input_common/drivers/gc_adapter.h | |||
| @@ -25,9 +25,11 @@ public: | |||
| 25 | explicit GCAdapter(std::string input_engine_); | 25 | explicit GCAdapter(std::string input_engine_); |
| 26 | ~GCAdapter() override; | 26 | ~GCAdapter() override; |
| 27 | 27 | ||
| 28 | Common::Input::VibrationError SetRumble( | 28 | Common::Input::VibrationError SetVibration( |
| 29 | const PadIdentifier& identifier, const Common::Input::VibrationStatus& vibration) override; | 29 | const PadIdentifier& identifier, const Common::Input::VibrationStatus& vibration) override; |
| 30 | 30 | ||
| 31 | bool IsVibrationEnabled(const PadIdentifier& identifier) override; | ||
| 32 | |||
| 31 | /// Used for automapping features | 33 | /// Used for automapping features |
| 32 | std::vector<Common::ParamPackage> GetInputDevices() const override; | 34 | std::vector<Common::ParamPackage> GetInputDevices() const override; |
| 33 | ButtonMapping GetButtonMappingForDevice(const Common::ParamPackage& params) override; | 35 | ButtonMapping GetButtonMappingForDevice(const Common::ParamPackage& params) override; |
diff --git a/src/input_common/drivers/sdl_driver.cpp b/src/input_common/drivers/sdl_driver.cpp index b72e4b397..45ce588f0 100644 --- a/src/input_common/drivers/sdl_driver.cpp +++ b/src/input_common/drivers/sdl_driver.cpp | |||
| @@ -40,8 +40,8 @@ public: | |||
| 40 | void EnableMotion() { | 40 | void EnableMotion() { |
| 41 | if (sdl_controller) { | 41 | if (sdl_controller) { |
| 42 | SDL_GameController* controller = sdl_controller.get(); | 42 | SDL_GameController* controller = sdl_controller.get(); |
| 43 | has_accel = SDL_GameControllerHasSensor(controller, SDL_SENSOR_ACCEL); | 43 | has_accel = SDL_GameControllerHasSensor(controller, SDL_SENSOR_ACCEL) == SDL_TRUE; |
| 44 | has_gyro = SDL_GameControllerHasSensor(controller, SDL_SENSOR_GYRO); | 44 | has_gyro = SDL_GameControllerHasSensor(controller, SDL_SENSOR_GYRO) == SDL_TRUE; |
| 45 | if (has_accel) { | 45 | if (has_accel) { |
| 46 | SDL_GameControllerSetSensorEnabled(controller, SDL_SENSOR_ACCEL, SDL_TRUE); | 46 | SDL_GameControllerSetSensorEnabled(controller, SDL_SENSOR_ACCEL, SDL_TRUE); |
| 47 | } | 47 | } |
| @@ -114,6 +114,20 @@ public: | |||
| 114 | } | 114 | } |
| 115 | return false; | 115 | return false; |
| 116 | } | 116 | } |
| 117 | |||
| 118 | void EnableVibration(bool is_enabled) { | ||
| 119 | has_vibration = is_enabled; | ||
| 120 | is_vibration_tested = true; | ||
| 121 | } | ||
| 122 | |||
| 123 | bool HasVibration() const { | ||
| 124 | return has_vibration; | ||
| 125 | } | ||
| 126 | |||
| 127 | bool IsVibrationTested() const { | ||
| 128 | return is_vibration_tested; | ||
| 129 | } | ||
| 130 | |||
| 117 | /** | 131 | /** |
| 118 | * The Pad identifier of the joystick | 132 | * The Pad identifier of the joystick |
| 119 | */ | 133 | */ |
| @@ -236,6 +250,8 @@ private: | |||
| 236 | u64 last_motion_update{}; | 250 | u64 last_motion_update{}; |
| 237 | bool has_gyro{false}; | 251 | bool has_gyro{false}; |
| 238 | bool has_accel{false}; | 252 | bool has_accel{false}; |
| 253 | bool has_vibration{false}; | ||
| 254 | bool is_vibration_tested{false}; | ||
| 239 | BasicMotion motion; | 255 | BasicMotion motion; |
| 240 | }; | 256 | }; |
| 241 | 257 | ||
| @@ -517,7 +533,7 @@ std::vector<Common::ParamPackage> SDLDriver::GetInputDevices() const { | |||
| 517 | return devices; | 533 | return devices; |
| 518 | } | 534 | } |
| 519 | 535 | ||
| 520 | Common::Input::VibrationError SDLDriver::SetRumble( | 536 | Common::Input::VibrationError SDLDriver::SetVibration( |
| 521 | const PadIdentifier& identifier, const Common::Input::VibrationStatus& vibration) { | 537 | const PadIdentifier& identifier, const Common::Input::VibrationStatus& vibration) { |
| 522 | const auto joystick = | 538 | const auto joystick = |
| 523 | GetSDLJoystickByGUID(identifier.guid.RawString(), static_cast<int>(identifier.port)); | 539 | GetSDLJoystickByGUID(identifier.guid.RawString(), static_cast<int>(identifier.port)); |
| @@ -546,13 +562,6 @@ Common::Input::VibrationError SDLDriver::SetRumble( | |||
| 546 | .type = Common::Input::VibrationAmplificationType::Exponential, | 562 | .type = Common::Input::VibrationAmplificationType::Exponential, |
| 547 | }; | 563 | }; |
| 548 | 564 | ||
| 549 | if (vibration.type == Common::Input::VibrationAmplificationType::Test) { | ||
| 550 | if (!joystick->RumblePlay(new_vibration)) { | ||
| 551 | return Common::Input::VibrationError::Unknown; | ||
| 552 | } | ||
| 553 | return Common::Input::VibrationError::None; | ||
| 554 | } | ||
| 555 | |||
| 556 | vibration_queue.Push(VibrationRequest{ | 565 | vibration_queue.Push(VibrationRequest{ |
| 557 | .identifier = identifier, | 566 | .identifier = identifier, |
| 558 | .vibration = new_vibration, | 567 | .vibration = new_vibration, |
| @@ -561,6 +570,45 @@ Common::Input::VibrationError SDLDriver::SetRumble( | |||
| 561 | return Common::Input::VibrationError::None; | 570 | return Common::Input::VibrationError::None; |
| 562 | } | 571 | } |
| 563 | 572 | ||
| 573 | bool SDLDriver::IsVibrationEnabled(const PadIdentifier& identifier) { | ||
| 574 | const auto joystick = | ||
| 575 | GetSDLJoystickByGUID(identifier.guid.RawString(), static_cast<int>(identifier.port)); | ||
| 576 | |||
| 577 | constexpr Common::Input::VibrationStatus test_vibration{ | ||
| 578 | .low_amplitude = 1, | ||
| 579 | .low_frequency = 160.0f, | ||
| 580 | .high_amplitude = 1, | ||
| 581 | .high_frequency = 320.0f, | ||
| 582 | .type = Common::Input::VibrationAmplificationType::Exponential, | ||
| 583 | }; | ||
| 584 | |||
| 585 | constexpr Common::Input::VibrationStatus zero_vibration{ | ||
| 586 | .low_amplitude = 0, | ||
| 587 | .low_frequency = 160.0f, | ||
| 588 | .high_amplitude = 0, | ||
| 589 | .high_frequency = 320.0f, | ||
| 590 | .type = Common::Input::VibrationAmplificationType::Exponential, | ||
| 591 | }; | ||
| 592 | |||
| 593 | if (joystick->IsVibrationTested()) { | ||
| 594 | return joystick->HasVibration(); | ||
| 595 | } | ||
| 596 | |||
| 597 | // First vibration might fail | ||
| 598 | joystick->RumblePlay(test_vibration); | ||
| 599 | |||
| 600 | // Wait for about 15ms to ensure the controller is ready for the stop command | ||
| 601 | std::this_thread::sleep_for(std::chrono::milliseconds(15)); | ||
| 602 | |||
| 603 | if (!joystick->RumblePlay(zero_vibration)) { | ||
| 604 | joystick->EnableVibration(false); | ||
| 605 | return false; | ||
| 606 | } | ||
| 607 | |||
| 608 | joystick->EnableVibration(true); | ||
| 609 | return true; | ||
| 610 | } | ||
| 611 | |||
| 564 | void SDLDriver::SendVibrations() { | 612 | void SDLDriver::SendVibrations() { |
| 565 | while (!vibration_queue.Empty()) { | 613 | while (!vibration_queue.Empty()) { |
| 566 | VibrationRequest request; | 614 | VibrationRequest request; |
diff --git a/src/input_common/drivers/sdl_driver.h b/src/input_common/drivers/sdl_driver.h index fc3a44572..d1b4471cf 100644 --- a/src/input_common/drivers/sdl_driver.h +++ b/src/input_common/drivers/sdl_driver.h | |||
| @@ -61,9 +61,11 @@ public: | |||
| 61 | 61 | ||
| 62 | bool IsStickInverted(const Common::ParamPackage& params) override; | 62 | bool IsStickInverted(const Common::ParamPackage& params) override; |
| 63 | 63 | ||
| 64 | Common::Input::VibrationError SetRumble( | 64 | Common::Input::VibrationError SetVibration( |
| 65 | const PadIdentifier& identifier, const Common::Input::VibrationStatus& vibration) override; | 65 | const PadIdentifier& identifier, const Common::Input::VibrationStatus& vibration) override; |
| 66 | 66 | ||
| 67 | bool IsVibrationEnabled(const PadIdentifier& identifier) override; | ||
| 68 | |||
| 67 | private: | 69 | private: |
| 68 | struct VibrationRequest { | 70 | struct VibrationRequest { |
| 69 | PadIdentifier identifier; | 71 | PadIdentifier identifier; |
diff --git a/src/input_common/input_engine.h b/src/input_common/input_engine.h index cfbdb26bd..d4c264a8e 100644 --- a/src/input_common/input_engine.h +++ b/src/input_common/input_engine.h | |||
| @@ -108,12 +108,17 @@ public: | |||
| 108 | [[maybe_unused]] const Common::Input::LedStatus& led_status) {} | 108 | [[maybe_unused]] const Common::Input::LedStatus& led_status) {} |
| 109 | 109 | ||
| 110 | // Sets rumble to a controller | 110 | // Sets rumble to a controller |
| 111 | virtual Common::Input::VibrationError SetRumble( | 111 | virtual Common::Input::VibrationError SetVibration( |
| 112 | [[maybe_unused]] const PadIdentifier& identifier, | 112 | [[maybe_unused]] const PadIdentifier& identifier, |
| 113 | [[maybe_unused]] const Common::Input::VibrationStatus& vibration) { | 113 | [[maybe_unused]] const Common::Input::VibrationStatus& vibration) { |
| 114 | return Common::Input::VibrationError::NotSupported; | 114 | return Common::Input::VibrationError::NotSupported; |
| 115 | } | 115 | } |
| 116 | 116 | ||
| 117 | // Returns true if device supports vibrations | ||
| 118 | virtual bool IsVibrationEnabled([[maybe_unused]] const PadIdentifier& identifier) { | ||
| 119 | return false; | ||
| 120 | } | ||
| 121 | |||
| 117 | // Sets polling mode to a controller | 122 | // Sets polling mode to a controller |
| 118 | virtual Common::Input::PollingError SetPollingMode( | 123 | virtual Common::Input::PollingError SetPollingMode( |
| 119 | [[maybe_unused]] const PadIdentifier& identifier, | 124 | [[maybe_unused]] const PadIdentifier& identifier, |
diff --git a/src/input_common/input_poller.cpp b/src/input_common/input_poller.cpp index ca33fb4eb..4ac182147 100644 --- a/src/input_common/input_poller.cpp +++ b/src/input_common/input_poller.cpp | |||
| @@ -763,7 +763,11 @@ public: | |||
| 763 | 763 | ||
| 764 | Common::Input::VibrationError SetVibration( | 764 | Common::Input::VibrationError SetVibration( |
| 765 | const Common::Input::VibrationStatus& vibration_status) override { | 765 | const Common::Input::VibrationStatus& vibration_status) override { |
| 766 | return input_engine->SetRumble(identifier, vibration_status); | 766 | return input_engine->SetVibration(identifier, vibration_status); |
| 767 | } | ||
| 768 | |||
| 769 | bool IsVibrationEnabled() override { | ||
| 770 | return input_engine->IsVibrationEnabled(identifier); | ||
| 767 | } | 771 | } |
| 768 | 772 | ||
| 769 | Common::Input::PollingError SetPollingMode(Common::Input::PollingMode polling_mode) override { | 773 | Common::Input::PollingError SetPollingMode(Common::Input::PollingMode polling_mode) override { |
| @@ -797,8 +801,8 @@ std::unique_ptr<Common::Input::InputDevice> InputFactory::CreateButtonDevice( | |||
| 797 | 801 | ||
| 798 | const auto button_id = params.Get("button", 0); | 802 | const auto button_id = params.Get("button", 0); |
| 799 | const auto keyboard_key = params.Get("code", 0); | 803 | const auto keyboard_key = params.Get("code", 0); |
| 800 | const auto toggle = params.Get("toggle", false); | 804 | const auto toggle = params.Get("toggle", false) != 0; |
| 801 | const auto inverted = params.Get("inverted", false); | 805 | const auto inverted = params.Get("inverted", false) != 0; |
| 802 | input_engine->PreSetController(identifier); | 806 | input_engine->PreSetController(identifier); |
| 803 | input_engine->PreSetButton(identifier, button_id); | 807 | input_engine->PreSetButton(identifier, button_id); |
| 804 | input_engine->PreSetButton(identifier, keyboard_key); | 808 | input_engine->PreSetButton(identifier, keyboard_key); |
| @@ -820,8 +824,8 @@ std::unique_ptr<Common::Input::InputDevice> InputFactory::CreateHatButtonDevice( | |||
| 820 | 824 | ||
| 821 | const auto button_id = params.Get("hat", 0); | 825 | const auto button_id = params.Get("hat", 0); |
| 822 | const auto direction = input_engine->GetHatButtonId(params.Get("direction", "")); | 826 | const auto direction = input_engine->GetHatButtonId(params.Get("direction", "")); |
| 823 | const auto toggle = params.Get("toggle", false); | 827 | const auto toggle = params.Get("toggle", false) != 0; |
| 824 | const auto inverted = params.Get("inverted", false); | 828 | const auto inverted = params.Get("inverted", false) != 0; |
| 825 | 829 | ||
| 826 | input_engine->PreSetController(identifier); | 830 | input_engine->PreSetController(identifier); |
| 827 | input_engine->PreSetHatButton(identifier, button_id); | 831 | input_engine->PreSetHatButton(identifier, button_id); |
| @@ -879,7 +883,7 @@ std::unique_ptr<Common::Input::InputDevice> InputFactory::CreateAnalogDevice( | |||
| 879 | .threshold = std::clamp(params.Get("threshold", 0.5f), 0.0f, 1.0f), | 883 | .threshold = std::clamp(params.Get("threshold", 0.5f), 0.0f, 1.0f), |
| 880 | .offset = std::clamp(params.Get("offset", 0.0f), -1.0f, 1.0f), | 884 | .offset = std::clamp(params.Get("offset", 0.0f), -1.0f, 1.0f), |
| 881 | .inverted = params.Get("invert", "+") == "-", | 885 | .inverted = params.Get("invert", "+") == "-", |
| 882 | .toggle = static_cast<bool>(params.Get("toggle", false)), | 886 | .toggle = params.Get("toggle", false) != 0, |
| 883 | }; | 887 | }; |
| 884 | input_engine->PreSetController(identifier); | 888 | input_engine->PreSetController(identifier); |
| 885 | input_engine->PreSetAxis(identifier, axis); | 889 | input_engine->PreSetAxis(identifier, axis); |
| @@ -895,8 +899,8 @@ std::unique_ptr<Common::Input::InputDevice> InputFactory::CreateTriggerDevice( | |||
| 895 | }; | 899 | }; |
| 896 | 900 | ||
| 897 | const auto button = params.Get("button", 0); | 901 | const auto button = params.Get("button", 0); |
| 898 | const auto toggle = params.Get("toggle", false); | 902 | const auto toggle = params.Get("toggle", false) != 0; |
| 899 | const auto inverted = params.Get("inverted", false); | 903 | const auto inverted = params.Get("inverted", false) != 0; |
| 900 | 904 | ||
| 901 | const auto axis = params.Get("axis", 0); | 905 | const auto axis = params.Get("axis", 0); |
| 902 | const Common::Input::AnalogProperties properties = { | 906 | const Common::Input::AnalogProperties properties = { |
| @@ -926,8 +930,8 @@ std::unique_ptr<Common::Input::InputDevice> InputFactory::CreateTouchDevice( | |||
| 926 | }; | 930 | }; |
| 927 | 931 | ||
| 928 | const auto button = params.Get("button", 0); | 932 | const auto button = params.Get("button", 0); |
| 929 | const auto toggle = params.Get("toggle", false); | 933 | const auto toggle = params.Get("toggle", false) != 0; |
| 930 | const auto inverted = params.Get("inverted", false); | 934 | const auto inverted = params.Get("inverted", false) != 0; |
| 931 | 935 | ||
| 932 | const auto axis_x = params.Get("axis_x", 0); | 936 | const auto axis_x = params.Get("axis_x", 0); |
| 933 | const Common::Input::AnalogProperties properties_x = { | 937 | const Common::Input::AnalogProperties properties_x = { |
diff --git a/src/shader_recompiler/CMakeLists.txt b/src/shader_recompiler/CMakeLists.txt index af8e51fe8..bcdd60db9 100644 --- a/src/shader_recompiler/CMakeLists.txt +++ b/src/shader_recompiler/CMakeLists.txt | |||
| @@ -241,24 +241,14 @@ target_link_libraries(shader_recompiler PUBLIC common fmt::fmt sirit) | |||
| 241 | if (MSVC) | 241 | if (MSVC) |
| 242 | target_compile_options(shader_recompiler PRIVATE | 242 | target_compile_options(shader_recompiler PRIVATE |
| 243 | /W4 | 243 | /W4 |
| 244 | /WX | 244 | |
| 245 | /we4018 # 'expression' : signed/unsigned mismatch | 245 | /we4242 # 'identifier': conversion from 'type1' to 'type2', possible loss of data |
| 246 | /we4244 # 'argument' : conversion from 'type1' to 'type2', possible loss of data (floating-point) | ||
| 247 | /we4245 # 'conversion' : conversion from 'type1' to 'type2', signed/unsigned mismatch | ||
| 248 | /we4254 # 'operator': conversion from 'type1:field_bits' to 'type2:field_bits', possible loss of data | 246 | /we4254 # 'operator': conversion from 'type1:field_bits' to 'type2:field_bits', possible loss of data |
| 249 | /we4267 # 'var' : conversion from 'size_t' to 'type', possible loss of data | ||
| 250 | /we4305 # 'context' : truncation from 'type1' to 'type2' | ||
| 251 | /we4800 # Implicit conversion from 'type' to bool. Possible information loss | 247 | /we4800 # Implicit conversion from 'type' to bool. Possible information loss |
| 252 | /we4826 # Conversion from 'type1' to 'type2' is sign-extended. This may cause unexpected runtime behavior. | ||
| 253 | ) | 248 | ) |
| 254 | else() | 249 | else() |
| 255 | target_compile_options(shader_recompiler PRIVATE | 250 | target_compile_options(shader_recompiler PRIVATE |
| 256 | -Werror | ||
| 257 | -Werror=conversion | 251 | -Werror=conversion |
| 258 | -Werror=ignored-qualifiers | ||
| 259 | $<$<CXX_COMPILER_ID:GNU>:-Werror=unused-but-set-parameter> | ||
| 260 | $<$<CXX_COMPILER_ID:GNU>:-Werror=unused-but-set-variable> | ||
| 261 | -Werror=unused-variable | ||
| 262 | 252 | ||
| 263 | # Bracket depth determines maximum size of a fold expression in Clang since 9c9974c3ccb6. | 253 | # Bracket depth determines maximum size of a fold expression in Clang since 9c9974c3ccb6. |
| 264 | # And this in turns limits the size of a std::array. | 254 | # And this in turns limits the size of a std::array. |
diff --git a/src/shader_recompiler/backend/glasm/emit_glasm_not_implemented.cpp b/src/shader_recompiler/backend/glasm/emit_glasm_not_implemented.cpp index 7094d8e42..1f4ffdd62 100644 --- a/src/shader_recompiler/backend/glasm/emit_glasm_not_implemented.cpp +++ b/src/shader_recompiler/backend/glasm/emit_glasm_not_implemented.cpp | |||
| @@ -5,10 +5,6 @@ | |||
| 5 | #include "shader_recompiler/backend/glasm/glasm_emit_context.h" | 5 | #include "shader_recompiler/backend/glasm/glasm_emit_context.h" |
| 6 | #include "shader_recompiler/frontend/ir/value.h" | 6 | #include "shader_recompiler/frontend/ir/value.h" |
| 7 | 7 | ||
| 8 | #ifdef _MSC_VER | ||
| 9 | #pragma warning(disable : 4100) | ||
| 10 | #endif | ||
| 11 | |||
| 12 | namespace Shader::Backend::GLASM { | 8 | namespace Shader::Backend::GLASM { |
| 13 | 9 | ||
| 14 | #define NotImplemented() throw NotImplementedException("GLASM instruction {}", __LINE__) | 10 | #define NotImplemented() throw NotImplementedException("GLASM instruction {}", __LINE__) |
diff --git a/src/shader_recompiler/backend/glsl/emit_glsl_not_implemented.cpp b/src/shader_recompiler/backend/glsl/emit_glsl_not_implemented.cpp index b03a8ba1e..9f1ed95a4 100644 --- a/src/shader_recompiler/backend/glsl/emit_glsl_not_implemented.cpp +++ b/src/shader_recompiler/backend/glsl/emit_glsl_not_implemented.cpp | |||
| @@ -7,10 +7,6 @@ | |||
| 7 | #include "shader_recompiler/backend/glsl/glsl_emit_context.h" | 7 | #include "shader_recompiler/backend/glsl/glsl_emit_context.h" |
| 8 | #include "shader_recompiler/frontend/ir/value.h" | 8 | #include "shader_recompiler/frontend/ir/value.h" |
| 9 | 9 | ||
| 10 | #ifdef _MSC_VER | ||
| 11 | #pragma warning(disable : 4100) | ||
| 12 | #endif | ||
| 13 | |||
| 14 | namespace Shader::Backend::GLSL { | 10 | namespace Shader::Backend::GLSL { |
| 15 | 11 | ||
| 16 | void EmitGetRegister(EmitContext& ctx) { | 12 | void EmitGetRegister(EmitContext& ctx) { |
diff --git a/src/shader_recompiler/frontend/maxwell/translate_program.cpp b/src/shader_recompiler/frontend/maxwell/translate_program.cpp index 77efb4f57..b58741d4d 100644 --- a/src/shader_recompiler/frontend/maxwell/translate_program.cpp +++ b/src/shader_recompiler/frontend/maxwell/translate_program.cpp | |||
| @@ -137,28 +137,35 @@ bool IsLegacyAttribute(IR::Attribute attribute) { | |||
| 137 | } | 137 | } |
| 138 | 138 | ||
| 139 | std::map<IR::Attribute, IR::Attribute> GenerateLegacyToGenericMappings( | 139 | std::map<IR::Attribute, IR::Attribute> GenerateLegacyToGenericMappings( |
| 140 | const VaryingState& state, std::queue<IR::Attribute> ununsed_generics) { | 140 | const VaryingState& state, std::queue<IR::Attribute> unused_generics, |
| 141 | const std::map<IR::Attribute, IR::Attribute>& previous_stage_mapping) { | ||
| 141 | std::map<IR::Attribute, IR::Attribute> mapping; | 142 | std::map<IR::Attribute, IR::Attribute> mapping; |
| 143 | auto update_mapping = [&mapping, &unused_generics, previous_stage_mapping](IR::Attribute attr, | ||
| 144 | size_t count) { | ||
| 145 | if (previous_stage_mapping.find(attr) != previous_stage_mapping.end()) { | ||
| 146 | for (size_t i = 0; i < count; ++i) { | ||
| 147 | mapping.insert({attr + i, previous_stage_mapping.at(attr + i)}); | ||
| 148 | } | ||
| 149 | } else { | ||
| 150 | for (size_t i = 0; i < count; ++i) { | ||
| 151 | mapping.insert({attr + i, unused_generics.front() + i}); | ||
| 152 | } | ||
| 153 | unused_generics.pop(); | ||
| 154 | } | ||
| 155 | }; | ||
| 142 | for (size_t index = 0; index < 4; ++index) { | 156 | for (size_t index = 0; index < 4; ++index) { |
| 143 | auto attr = IR::Attribute::ColorFrontDiffuseR + index * 4; | 157 | auto attr = IR::Attribute::ColorFrontDiffuseR + index * 4; |
| 144 | if (state.AnyComponent(attr)) { | 158 | if (state.AnyComponent(attr)) { |
| 145 | for (size_t i = 0; i < 4; ++i) { | 159 | update_mapping(attr, 4); |
| 146 | mapping.insert({attr + i, ununsed_generics.front() + i}); | ||
| 147 | } | ||
| 148 | ununsed_generics.pop(); | ||
| 149 | } | 160 | } |
| 150 | } | 161 | } |
| 151 | if (state[IR::Attribute::FogCoordinate]) { | 162 | if (state[IR::Attribute::FogCoordinate]) { |
| 152 | mapping.insert({IR::Attribute::FogCoordinate, ununsed_generics.front()}); | 163 | update_mapping(IR::Attribute::FogCoordinate, 1); |
| 153 | ununsed_generics.pop(); | ||
| 154 | } | 164 | } |
| 155 | for (size_t index = 0; index < IR::NUM_FIXEDFNCTEXTURE; ++index) { | 165 | for (size_t index = 0; index < IR::NUM_FIXEDFNCTEXTURE; ++index) { |
| 156 | auto attr = IR::Attribute::FixedFncTexture0S + index * 4; | 166 | auto attr = IR::Attribute::FixedFncTexture0S + index * 4; |
| 157 | if (state.AnyComponent(attr)) { | 167 | if (state.AnyComponent(attr)) { |
| 158 | for (size_t i = 0; i < 4; ++i) { | 168 | update_mapping(attr, 4); |
| 159 | mapping.insert({attr + i, ununsed_generics.front() + i}); | ||
| 160 | } | ||
| 161 | ununsed_generics.pop(); | ||
| 162 | } | 169 | } |
| 163 | } | 170 | } |
| 164 | return mapping; | 171 | return mapping; |
| @@ -265,21 +272,22 @@ IR::Program MergeDualVertexPrograms(IR::Program& vertex_a, IR::Program& vertex_b | |||
| 265 | void ConvertLegacyToGeneric(IR::Program& program, const Shader::RuntimeInfo& runtime_info) { | 272 | void ConvertLegacyToGeneric(IR::Program& program, const Shader::RuntimeInfo& runtime_info) { |
| 266 | auto& stores = program.info.stores; | 273 | auto& stores = program.info.stores; |
| 267 | if (stores.Legacy()) { | 274 | if (stores.Legacy()) { |
| 268 | std::queue<IR::Attribute> ununsed_output_generics{}; | 275 | std::queue<IR::Attribute> unused_output_generics{}; |
| 269 | for (size_t index = 0; index < IR::NUM_GENERICS; ++index) { | 276 | for (size_t index = 0; index < IR::NUM_GENERICS; ++index) { |
| 270 | if (!stores.Generic(index)) { | 277 | if (!stores.Generic(index)) { |
| 271 | ununsed_output_generics.push(IR::Attribute::Generic0X + index * 4); | 278 | unused_output_generics.push(IR::Attribute::Generic0X + index * 4); |
| 272 | } | 279 | } |
| 273 | } | 280 | } |
| 274 | auto mappings = GenerateLegacyToGenericMappings(stores, ununsed_output_generics); | 281 | program.info.legacy_stores_mapping = |
| 282 | GenerateLegacyToGenericMappings(stores, unused_output_generics, {}); | ||
| 275 | for (IR::Block* const block : program.post_order_blocks) { | 283 | for (IR::Block* const block : program.post_order_blocks) { |
| 276 | for (IR::Inst& inst : block->Instructions()) { | 284 | for (IR::Inst& inst : block->Instructions()) { |
| 277 | switch (inst.GetOpcode()) { | 285 | switch (inst.GetOpcode()) { |
| 278 | case IR::Opcode::SetAttribute: { | 286 | case IR::Opcode::SetAttribute: { |
| 279 | const auto attr = inst.Arg(0).Attribute(); | 287 | const auto attr = inst.Arg(0).Attribute(); |
| 280 | if (IsLegacyAttribute(attr)) { | 288 | if (IsLegacyAttribute(attr)) { |
| 281 | stores.Set(mappings[attr], true); | 289 | stores.Set(program.info.legacy_stores_mapping[attr], true); |
| 282 | inst.SetArg(0, Shader::IR::Value(mappings[attr])); | 290 | inst.SetArg(0, Shader::IR::Value(program.info.legacy_stores_mapping[attr])); |
| 283 | } | 291 | } |
| 284 | break; | 292 | break; |
| 285 | } | 293 | } |
| @@ -292,15 +300,16 @@ void ConvertLegacyToGeneric(IR::Program& program, const Shader::RuntimeInfo& run | |||
| 292 | 300 | ||
| 293 | auto& loads = program.info.loads; | 301 | auto& loads = program.info.loads; |
| 294 | if (loads.Legacy()) { | 302 | if (loads.Legacy()) { |
| 295 | std::queue<IR::Attribute> ununsed_input_generics{}; | 303 | std::queue<IR::Attribute> unused_input_generics{}; |
| 296 | for (size_t index = 0; index < IR::NUM_GENERICS; ++index) { | 304 | for (size_t index = 0; index < IR::NUM_GENERICS; ++index) { |
| 297 | const AttributeType input_type{runtime_info.generic_input_types[index]}; | 305 | const AttributeType input_type{runtime_info.generic_input_types[index]}; |
| 298 | if (!runtime_info.previous_stage_stores.Generic(index) || !loads.Generic(index) || | 306 | if (!runtime_info.previous_stage_stores.Generic(index) || !loads.Generic(index) || |
| 299 | input_type == AttributeType::Disabled) { | 307 | input_type == AttributeType::Disabled) { |
| 300 | ununsed_input_generics.push(IR::Attribute::Generic0X + index * 4); | 308 | unused_input_generics.push(IR::Attribute::Generic0X + index * 4); |
| 301 | } | 309 | } |
| 302 | } | 310 | } |
| 303 | auto mappings = GenerateLegacyToGenericMappings(loads, ununsed_input_generics); | 311 | auto mappings = GenerateLegacyToGenericMappings( |
| 312 | loads, unused_input_generics, runtime_info.previous_stage_legacy_stores_mapping); | ||
| 304 | for (IR::Block* const block : program.post_order_blocks) { | 313 | for (IR::Block* const block : program.post_order_blocks) { |
| 305 | for (IR::Inst& inst : block->Instructions()) { | 314 | for (IR::Inst& inst : block->Instructions()) { |
| 306 | switch (inst.GetOpcode()) { | 315 | switch (inst.GetOpcode()) { |
diff --git a/src/shader_recompiler/runtime_info.h b/src/shader_recompiler/runtime_info.h index dcb5ab158..549b81ef7 100644 --- a/src/shader_recompiler/runtime_info.h +++ b/src/shader_recompiler/runtime_info.h | |||
| @@ -4,6 +4,7 @@ | |||
| 4 | #pragma once | 4 | #pragma once |
| 5 | 5 | ||
| 6 | #include <array> | 6 | #include <array> |
| 7 | #include <map> | ||
| 7 | #include <optional> | 8 | #include <optional> |
| 8 | #include <vector> | 9 | #include <vector> |
| 9 | 10 | ||
| @@ -60,6 +61,7 @@ struct TransformFeedbackVarying { | |||
| 60 | struct RuntimeInfo { | 61 | struct RuntimeInfo { |
| 61 | std::array<AttributeType, 32> generic_input_types{}; | 62 | std::array<AttributeType, 32> generic_input_types{}; |
| 62 | VaryingState previous_stage_stores; | 63 | VaryingState previous_stage_stores; |
| 64 | std::map<IR::Attribute, IR::Attribute> previous_stage_legacy_stores_mapping; | ||
| 63 | 65 | ||
| 64 | bool convert_depth_mode{}; | 66 | bool convert_depth_mode{}; |
| 65 | bool force_early_z{}; | 67 | bool force_early_z{}; |
diff --git a/src/shader_recompiler/shader_info.h b/src/shader_recompiler/shader_info.h index cc596da4f..81097bf1a 100644 --- a/src/shader_recompiler/shader_info.h +++ b/src/shader_recompiler/shader_info.h | |||
| @@ -5,6 +5,7 @@ | |||
| 5 | 5 | ||
| 6 | #include <array> | 6 | #include <array> |
| 7 | #include <bitset> | 7 | #include <bitset> |
| 8 | #include <map> | ||
| 8 | 9 | ||
| 9 | #include "common/common_types.h" | 10 | #include "common/common_types.h" |
| 10 | #include "shader_recompiler/frontend/ir/type.h" | 11 | #include "shader_recompiler/frontend/ir/type.h" |
| @@ -127,6 +128,8 @@ struct Info { | |||
| 127 | VaryingState stores; | 128 | VaryingState stores; |
| 128 | VaryingState passthrough; | 129 | VaryingState passthrough; |
| 129 | 130 | ||
| 131 | std::map<IR::Attribute, IR::Attribute> legacy_stores_mapping; | ||
| 132 | |||
| 130 | bool loads_indexed_attributes{}; | 133 | bool loads_indexed_attributes{}; |
| 131 | 134 | ||
| 132 | std::array<bool, 8> stores_frag_color{}; | 135 | std::array<bool, 8> stores_frag_color{}; |
diff --git a/src/tests/video_core/buffer_base.cpp b/src/tests/video_core/buffer_base.cpp index 71121e42a..f7236afab 100644 --- a/src/tests/video_core/buffer_base.cpp +++ b/src/tests/video_core/buffer_base.cpp | |||
| @@ -44,7 +44,7 @@ public: | |||
| 44 | 44 | ||
| 45 | [[nodiscard]] unsigned Count() const noexcept { | 45 | [[nodiscard]] unsigned Count() const noexcept { |
| 46 | unsigned count = 0; | 46 | unsigned count = 0; |
| 47 | for (const auto [index, value] : page_table) { | 47 | for (const auto& [index, value] : page_table) { |
| 48 | count += value; | 48 | count += value; |
| 49 | } | 49 | } |
| 50 | return count; | 50 | return count; |
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt index cb8b46edf..106991969 100644 --- a/src/video_core/CMakeLists.txt +++ b/src/video_core/CMakeLists.txt | |||
| @@ -279,14 +279,8 @@ if (MSVC) | |||
| 279 | else() | 279 | else() |
| 280 | target_compile_options(video_core PRIVATE | 280 | target_compile_options(video_core PRIVATE |
| 281 | -Werror=conversion | 281 | -Werror=conversion |
| 282 | -Wno-error=sign-conversion | ||
| 283 | -Werror=pessimizing-move | ||
| 284 | -Werror=redundant-move | ||
| 285 | -Werror=type-limits | ||
| 286 | 282 | ||
| 287 | $<$<CXX_COMPILER_ID:GNU>:-Werror=class-memaccess> | 283 | -Wno-sign-conversion |
| 288 | $<$<CXX_COMPILER_ID:GNU>:-Werror=unused-but-set-parameter> | ||
| 289 | $<$<CXX_COMPILER_ID:GNU>:-Werror=unused-but-set-variable> | ||
| 290 | ) | 284 | ) |
| 291 | endif() | 285 | endif() |
| 292 | 286 | ||
diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp index b1a22b76c..5208bea75 100644 --- a/src/video_core/engines/maxwell_3d.cpp +++ b/src/video_core/engines/maxwell_3d.cpp | |||
| @@ -117,10 +117,18 @@ void Maxwell3D::InitializeRegisterDefaults() { | |||
| 117 | 117 | ||
| 118 | shadow_state = regs; | 118 | shadow_state = regs; |
| 119 | 119 | ||
| 120 | mme_inline[MAXWELL3D_REG_INDEX(draw.end)] = true; | 120 | draw_command[MAXWELL3D_REG_INDEX(draw.end)] = true; |
| 121 | mme_inline[MAXWELL3D_REG_INDEX(draw.begin)] = true; | 121 | draw_command[MAXWELL3D_REG_INDEX(draw.begin)] = true; |
| 122 | mme_inline[MAXWELL3D_REG_INDEX(vertex_buffer.count)] = true; | 122 | draw_command[MAXWELL3D_REG_INDEX(vertex_buffer.first)] = true; |
| 123 | mme_inline[MAXWELL3D_REG_INDEX(index_buffer.count)] = true; | 123 | draw_command[MAXWELL3D_REG_INDEX(vertex_buffer.count)] = true; |
| 124 | draw_command[MAXWELL3D_REG_INDEX(index_buffer.first)] = true; | ||
| 125 | draw_command[MAXWELL3D_REG_INDEX(index_buffer.count)] = true; | ||
| 126 | draw_command[MAXWELL3D_REG_INDEX(index_buffer32_first)] = true; | ||
| 127 | draw_command[MAXWELL3D_REG_INDEX(index_buffer16_first)] = true; | ||
| 128 | draw_command[MAXWELL3D_REG_INDEX(index_buffer8_first)] = true; | ||
| 129 | draw_command[MAXWELL3D_REG_INDEX(draw_inline_index)] = true; | ||
| 130 | draw_command[MAXWELL3D_REG_INDEX(inline_index_2x16.even)] = true; | ||
| 131 | draw_command[MAXWELL3D_REG_INDEX(inline_index_4x8.index0)] = true; | ||
| 124 | } | 132 | } |
| 125 | 133 | ||
| 126 | void Maxwell3D::ProcessMacro(u32 method, const u32* base_start, u32 amount, bool is_last_call) { | 134 | void Maxwell3D::ProcessMacro(u32 method, const u32* base_start, u32 amount, bool is_last_call) { |
| @@ -208,25 +216,6 @@ void Maxwell3D::ProcessMethodCall(u32 method, u32 argument, u32 nonshadow_argume | |||
| 208 | return ProcessCBBind(3); | 216 | return ProcessCBBind(3); |
| 209 | case MAXWELL3D_REG_INDEX(bind_groups[4].raw_config): | 217 | case MAXWELL3D_REG_INDEX(bind_groups[4].raw_config): |
| 210 | return ProcessCBBind(4); | 218 | return ProcessCBBind(4); |
| 211 | case MAXWELL3D_REG_INDEX(draw.end): | ||
| 212 | return DrawArrays(); | ||
| 213 | case MAXWELL3D_REG_INDEX(index_buffer32_first): | ||
| 214 | regs.index_buffer.count = regs.index_buffer32_first.count; | ||
| 215 | regs.index_buffer.first = regs.index_buffer32_first.first; | ||
| 216 | dirty.flags[VideoCommon::Dirty::IndexBuffer] = true; | ||
| 217 | return DrawArrays(); | ||
| 218 | case MAXWELL3D_REG_INDEX(index_buffer16_first): | ||
| 219 | regs.index_buffer.count = regs.index_buffer16_first.count; | ||
| 220 | regs.index_buffer.first = regs.index_buffer16_first.first; | ||
| 221 | dirty.flags[VideoCommon::Dirty::IndexBuffer] = true; | ||
| 222 | return DrawArrays(); | ||
| 223 | case MAXWELL3D_REG_INDEX(index_buffer8_first): | ||
| 224 | regs.index_buffer.count = regs.index_buffer8_first.count; | ||
| 225 | regs.index_buffer.first = regs.index_buffer8_first.first; | ||
| 226 | dirty.flags[VideoCommon::Dirty::IndexBuffer] = true; | ||
| 227 | // a macro calls this one over and over, should it increase instancing? | ||
| 228 | // Used by Hades and likely other Vulkan games. | ||
| 229 | return DrawArrays(); | ||
| 230 | case MAXWELL3D_REG_INDEX(topology_override): | 219 | case MAXWELL3D_REG_INDEX(topology_override): |
| 231 | use_topology_override = true; | 220 | use_topology_override = true; |
| 232 | return; | 221 | return; |
| @@ -261,14 +250,13 @@ void Maxwell3D::CallMacroMethod(u32 method, const std::vector<u32>& parameters) | |||
| 261 | 250 | ||
| 262 | // Execute the current macro. | 251 | // Execute the current macro. |
| 263 | macro_engine->Execute(macro_positions[entry], parameters); | 252 | macro_engine->Execute(macro_positions[entry], parameters); |
| 264 | if (mme_draw.current_mode != MMEDrawMode::Undefined) { | 253 | |
| 265 | FlushMMEInlineDraw(); | 254 | ProcessDeferredDraw(); |
| 266 | } | ||
| 267 | } | 255 | } |
| 268 | 256 | ||
| 269 | void Maxwell3D::CallMethod(u32 method, u32 method_argument, bool is_last_call) { | 257 | void Maxwell3D::CallMethod(u32 method, u32 method_argument, bool is_last_call) { |
| 270 | // It is an error to write to a register other than the current macro's ARG register before it | 258 | // It is an error to write to a register other than the current macro's ARG register before |
| 271 | // has finished execution. | 259 | // it has finished execution. |
| 272 | if (executing_macro != 0) { | 260 | if (executing_macro != 0) { |
| 273 | ASSERT(method == executing_macro + 1); | 261 | ASSERT(method == executing_macro + 1); |
| 274 | } | 262 | } |
| @@ -283,9 +271,33 @@ void Maxwell3D::CallMethod(u32 method, u32 method_argument, bool is_last_call) { | |||
| 283 | ASSERT_MSG(method < Regs::NUM_REGS, | 271 | ASSERT_MSG(method < Regs::NUM_REGS, |
| 284 | "Invalid Maxwell3D register, increase the size of the Regs structure"); | 272 | "Invalid Maxwell3D register, increase the size of the Regs structure"); |
| 285 | 273 | ||
| 286 | const u32 argument = ProcessShadowRam(method, method_argument); | 274 | if (draw_command[method]) { |
| 287 | ProcessDirtyRegisters(method, argument); | 275 | regs.reg_array[method] = method_argument; |
| 288 | ProcessMethodCall(method, argument, method_argument, is_last_call); | 276 | deferred_draw_method.push_back(method); |
| 277 | auto u32_to_u8 = [&](const u32 argument) { | ||
| 278 | inline_index_draw_indexes.push_back(static_cast<u8>(argument & 0x000000ff)); | ||
| 279 | inline_index_draw_indexes.push_back(static_cast<u8>((argument & 0x0000ff00) >> 8)); | ||
| 280 | inline_index_draw_indexes.push_back(static_cast<u8>((argument & 0x00ff0000) >> 16)); | ||
| 281 | inline_index_draw_indexes.push_back(static_cast<u8>((argument & 0xff000000) >> 24)); | ||
| 282 | }; | ||
| 283 | if (MAXWELL3D_REG_INDEX(draw_inline_index) == method) { | ||
| 284 | u32_to_u8(method_argument); | ||
| 285 | } else if (MAXWELL3D_REG_INDEX(inline_index_2x16.even) == method) { | ||
| 286 | u32_to_u8(regs.inline_index_2x16.even); | ||
| 287 | u32_to_u8(regs.inline_index_2x16.odd); | ||
| 288 | } else if (MAXWELL3D_REG_INDEX(inline_index_4x8.index0) == method) { | ||
| 289 | u32_to_u8(regs.inline_index_4x8.index0); | ||
| 290 | u32_to_u8(regs.inline_index_4x8.index1); | ||
| 291 | u32_to_u8(regs.inline_index_4x8.index2); | ||
| 292 | u32_to_u8(regs.inline_index_4x8.index3); | ||
| 293 | } | ||
| 294 | } else { | ||
| 295 | ProcessDeferredDraw(); | ||
| 296 | |||
| 297 | const u32 argument = ProcessShadowRam(method, method_argument); | ||
| 298 | ProcessDirtyRegisters(method, argument); | ||
| 299 | ProcessMethodCall(method, argument, method_argument, is_last_call); | ||
| 300 | } | ||
| 289 | } | 301 | } |
| 290 | 302 | ||
| 291 | void Maxwell3D::CallMultiMethod(u32 method, const u32* base_start, u32 amount, | 303 | void Maxwell3D::CallMultiMethod(u32 method, const u32* base_start, u32 amount, |
| @@ -326,55 +338,6 @@ void Maxwell3D::CallMultiMethod(u32 method, const u32* base_start, u32 amount, | |||
| 326 | } | 338 | } |
| 327 | } | 339 | } |
| 328 | 340 | ||
| 329 | void Maxwell3D::StepInstance(const MMEDrawMode expected_mode, const u32 count) { | ||
| 330 | if (mme_draw.current_mode == MMEDrawMode::Undefined) { | ||
| 331 | if (mme_draw.gl_begin_consume) { | ||
| 332 | mme_draw.current_mode = expected_mode; | ||
| 333 | mme_draw.current_count = count; | ||
| 334 | mme_draw.instance_count = 1; | ||
| 335 | mme_draw.gl_begin_consume = false; | ||
| 336 | mme_draw.gl_end_count = 0; | ||
| 337 | } | ||
| 338 | return; | ||
| 339 | } else { | ||
| 340 | if (mme_draw.current_mode == expected_mode && count == mme_draw.current_count && | ||
| 341 | mme_draw.instance_mode && mme_draw.gl_begin_consume) { | ||
| 342 | mme_draw.instance_count++; | ||
| 343 | mme_draw.gl_begin_consume = false; | ||
| 344 | return; | ||
| 345 | } else { | ||
| 346 | FlushMMEInlineDraw(); | ||
| 347 | } | ||
| 348 | } | ||
| 349 | // Tail call in case it needs to retry. | ||
| 350 | StepInstance(expected_mode, count); | ||
| 351 | } | ||
| 352 | |||
| 353 | void Maxwell3D::CallMethodFromMME(u32 method, u32 method_argument) { | ||
| 354 | if (mme_inline[method]) { | ||
| 355 | regs.reg_array[method] = method_argument; | ||
| 356 | if (method == MAXWELL3D_REG_INDEX(vertex_buffer.count) || | ||
| 357 | method == MAXWELL3D_REG_INDEX(index_buffer.count)) { | ||
| 358 | const MMEDrawMode expected_mode = method == MAXWELL3D_REG_INDEX(vertex_buffer.count) | ||
| 359 | ? MMEDrawMode::Array | ||
| 360 | : MMEDrawMode::Indexed; | ||
| 361 | StepInstance(expected_mode, method_argument); | ||
| 362 | } else if (method == MAXWELL3D_REG_INDEX(draw.begin)) { | ||
| 363 | mme_draw.instance_mode = | ||
| 364 | (regs.draw.instance_id == Maxwell3D::Regs::Draw::InstanceId::Subsequent) || | ||
| 365 | (regs.draw.instance_id == Maxwell3D::Regs::Draw::InstanceId::Unchanged); | ||
| 366 | mme_draw.gl_begin_consume = true; | ||
| 367 | } else { | ||
| 368 | mme_draw.gl_end_count++; | ||
| 369 | } | ||
| 370 | } else { | ||
| 371 | if (mme_draw.current_mode != MMEDrawMode::Undefined) { | ||
| 372 | FlushMMEInlineDraw(); | ||
| 373 | } | ||
| 374 | CallMethod(method, method_argument, true); | ||
| 375 | } | ||
| 376 | } | ||
| 377 | |||
| 378 | void Maxwell3D::ProcessTopologyOverride() { | 341 | void Maxwell3D::ProcessTopologyOverride() { |
| 379 | using PrimitiveTopology = Maxwell3D::Regs::PrimitiveTopology; | 342 | using PrimitiveTopology = Maxwell3D::Regs::PrimitiveTopology; |
| 380 | using PrimitiveTopologyOverride = Maxwell3D::Regs::PrimitiveTopologyOverride; | 343 | using PrimitiveTopologyOverride = Maxwell3D::Regs::PrimitiveTopologyOverride; |
| @@ -404,41 +367,6 @@ void Maxwell3D::ProcessTopologyOverride() { | |||
| 404 | } | 367 | } |
| 405 | } | 368 | } |
| 406 | 369 | ||
| 407 | void Maxwell3D::FlushMMEInlineDraw() { | ||
| 408 | LOG_TRACE(HW_GPU, "called, topology={}, count={}", regs.draw.topology.Value(), | ||
| 409 | regs.vertex_buffer.count); | ||
| 410 | ASSERT_MSG(!(regs.index_buffer.count && regs.vertex_buffer.count), "Both indexed and direct?"); | ||
| 411 | ASSERT(mme_draw.instance_count == mme_draw.gl_end_count); | ||
| 412 | |||
| 413 | // Both instance configuration registers can not be set at the same time. | ||
| 414 | ASSERT_MSG(regs.draw.instance_id == Maxwell3D::Regs::Draw::InstanceId::First || | ||
| 415 | regs.draw.instance_id != Maxwell3D::Regs::Draw::InstanceId::Unchanged, | ||
| 416 | "Illegal combination of instancing parameters"); | ||
| 417 | |||
| 418 | ProcessTopologyOverride(); | ||
| 419 | |||
| 420 | const bool is_indexed = mme_draw.current_mode == MMEDrawMode::Indexed; | ||
| 421 | if (ShouldExecute()) { | ||
| 422 | rasterizer->Draw(is_indexed, true); | ||
| 423 | } | ||
| 424 | |||
| 425 | // TODO(bunnei): Below, we reset vertex count so that we can use these registers to determine if | ||
| 426 | // the game is trying to draw indexed or direct mode. This needs to be verified on HW still - | ||
| 427 | // it's possible that it is incorrect and that there is some other register used to specify the | ||
| 428 | // drawing mode. | ||
| 429 | if (is_indexed) { | ||
| 430 | regs.index_buffer.count = 0; | ||
| 431 | } else { | ||
| 432 | regs.vertex_buffer.count = 0; | ||
| 433 | } | ||
| 434 | mme_draw.current_mode = MMEDrawMode::Undefined; | ||
| 435 | mme_draw.current_count = 0; | ||
| 436 | mme_draw.instance_count = 0; | ||
| 437 | mme_draw.instance_mode = false; | ||
| 438 | mme_draw.gl_begin_consume = false; | ||
| 439 | mme_draw.gl_end_count = 0; | ||
| 440 | } | ||
| 441 | |||
| 442 | void Maxwell3D::ProcessMacroUpload(u32 data) { | 370 | void Maxwell3D::ProcessMacroUpload(u32 data) { |
| 443 | macro_engine->AddCode(regs.load_mme.instruction_ptr++, data); | 371 | macro_engine->AddCode(regs.load_mme.instruction_ptr++, data); |
| 444 | } | 372 | } |
| @@ -573,42 +501,6 @@ void Maxwell3D::ProcessSyncPoint() { | |||
| 573 | rasterizer->SignalSyncPoint(sync_point); | 501 | rasterizer->SignalSyncPoint(sync_point); |
| 574 | } | 502 | } |
| 575 | 503 | ||
| 576 | void Maxwell3D::DrawArrays() { | ||
| 577 | LOG_TRACE(HW_GPU, "called, topology={}, count={}", regs.draw.topology.Value(), | ||
| 578 | regs.vertex_buffer.count); | ||
| 579 | ASSERT_MSG(!(regs.index_buffer.count && regs.vertex_buffer.count), "Both indexed and direct?"); | ||
| 580 | |||
| 581 | // Both instance configuration registers can not be set at the same time. | ||
| 582 | ASSERT_MSG(regs.draw.instance_id == Maxwell3D::Regs::Draw::InstanceId::First || | ||
| 583 | regs.draw.instance_id != Maxwell3D::Regs::Draw::InstanceId::Unchanged, | ||
| 584 | "Illegal combination of instancing parameters"); | ||
| 585 | |||
| 586 | ProcessTopologyOverride(); | ||
| 587 | |||
| 588 | if (regs.draw.instance_id == Maxwell3D::Regs::Draw::InstanceId::Subsequent) { | ||
| 589 | // Increment the current instance *before* drawing. | ||
| 590 | state.current_instance++; | ||
| 591 | } else if (regs.draw.instance_id != Maxwell3D::Regs::Draw::InstanceId::Unchanged) { | ||
| 592 | // Reset the current instance to 0. | ||
| 593 | state.current_instance = 0; | ||
| 594 | } | ||
| 595 | |||
| 596 | const bool is_indexed{regs.index_buffer.count && !regs.vertex_buffer.count}; | ||
| 597 | if (ShouldExecute()) { | ||
| 598 | rasterizer->Draw(is_indexed, false); | ||
| 599 | } | ||
| 600 | |||
| 601 | // TODO(bunnei): Below, we reset vertex count so that we can use these registers to determine if | ||
| 602 | // the game is trying to draw indexed or direct mode. This needs to be verified on HW still - | ||
| 603 | // it's possible that it is incorrect and that there is some other register used to specify the | ||
| 604 | // drawing mode. | ||
| 605 | if (is_indexed) { | ||
| 606 | regs.index_buffer.count = 0; | ||
| 607 | } else { | ||
| 608 | regs.vertex_buffer.count = 0; | ||
| 609 | } | ||
| 610 | } | ||
| 611 | |||
| 612 | std::optional<u64> Maxwell3D::GetQueryResult() { | 504 | std::optional<u64> Maxwell3D::GetQueryResult() { |
| 613 | switch (regs.report_semaphore.query.report) { | 505 | switch (regs.report_semaphore.query.report) { |
| 614 | case Regs::ReportSemaphore::Report::Payload: | 506 | case Regs::ReportSemaphore::Report::Payload: |
| @@ -691,4 +583,95 @@ void Maxwell3D::ProcessClearBuffers() { | |||
| 691 | rasterizer->Clear(); | 583 | rasterizer->Clear(); |
| 692 | } | 584 | } |
| 693 | 585 | ||
| 586 | void Maxwell3D::ProcessDeferredDraw() { | ||
| 587 | if (deferred_draw_method.empty()) { | ||
| 588 | return; | ||
| 589 | } | ||
| 590 | |||
| 591 | enum class DrawMode { | ||
| 592 | Undefined, | ||
| 593 | General, | ||
| 594 | Instance, | ||
| 595 | }; | ||
| 596 | DrawMode draw_mode{DrawMode::Undefined}; | ||
| 597 | u32 instance_count = 1; | ||
| 598 | |||
| 599 | auto first_method = deferred_draw_method[0]; | ||
| 600 | if (MAXWELL3D_REG_INDEX(draw.begin) == first_method) { | ||
| 601 | // The minimum number of methods for drawing must be greater than or equal to | ||
| 602 | // 3[draw.begin->vertex(index)count->draw.end] to avoid errors in index mode drawing | ||
| 603 | if (deferred_draw_method.size() < 3) { | ||
| 604 | return; | ||
| 605 | } | ||
| 606 | draw_mode = (regs.draw.instance_id == Maxwell3D::Regs::Draw::InstanceId::Subsequent) || | ||
| 607 | (regs.draw.instance_id == Maxwell3D::Regs::Draw::InstanceId::Unchanged) | ||
| 608 | ? DrawMode::Instance | ||
| 609 | : DrawMode::General; | ||
| 610 | } else if (MAXWELL3D_REG_INDEX(index_buffer32_first) == first_method || | ||
| 611 | MAXWELL3D_REG_INDEX(index_buffer16_first) == first_method || | ||
| 612 | MAXWELL3D_REG_INDEX(index_buffer8_first) == first_method) { | ||
| 613 | draw_mode = DrawMode::General; | ||
| 614 | } | ||
| 615 | |||
| 616 | // Drawing will only begin with draw.begin or index_buffer method, other methods directly | ||
| 617 | // clear | ||
| 618 | if (draw_mode == DrawMode::Undefined) { | ||
| 619 | deferred_draw_method.clear(); | ||
| 620 | return; | ||
| 621 | } | ||
| 622 | |||
| 623 | if (draw_mode == DrawMode::Instance) { | ||
| 624 | ASSERT_MSG(deferred_draw_method.size() % 4 == 0, "Instance mode method size error"); | ||
| 625 | instance_count = static_cast<u32>(deferred_draw_method.size()) / 4; | ||
| 626 | } else { | ||
| 627 | if (MAXWELL3D_REG_INDEX(index_buffer32_first) == first_method) { | ||
| 628 | regs.index_buffer.count = regs.index_buffer32_first.count; | ||
| 629 | regs.index_buffer.first = regs.index_buffer32_first.first; | ||
| 630 | dirty.flags[VideoCommon::Dirty::IndexBuffer] = true; | ||
| 631 | } else if (MAXWELL3D_REG_INDEX(index_buffer32_first) == first_method) { | ||
| 632 | regs.index_buffer.count = regs.index_buffer16_first.count; | ||
| 633 | regs.index_buffer.first = regs.index_buffer16_first.first; | ||
| 634 | dirty.flags[VideoCommon::Dirty::IndexBuffer] = true; | ||
| 635 | } else if (MAXWELL3D_REG_INDEX(index_buffer32_first) == first_method) { | ||
| 636 | regs.index_buffer.count = regs.index_buffer8_first.count; | ||
| 637 | regs.index_buffer.first = regs.index_buffer8_first.first; | ||
| 638 | dirty.flags[VideoCommon::Dirty::IndexBuffer] = true; | ||
| 639 | } else { | ||
| 640 | auto second_method = deferred_draw_method[1]; | ||
| 641 | if (MAXWELL3D_REG_INDEX(draw_inline_index) == second_method || | ||
| 642 | MAXWELL3D_REG_INDEX(inline_index_2x16.even) == second_method || | ||
| 643 | MAXWELL3D_REG_INDEX(inline_index_4x8.index0) == second_method) { | ||
| 644 | regs.index_buffer.count = static_cast<u32>(inline_index_draw_indexes.size() / 4); | ||
| 645 | regs.index_buffer.format = Regs::IndexFormat::UnsignedInt; | ||
| 646 | } | ||
| 647 | } | ||
| 648 | } | ||
| 649 | |||
| 650 | LOG_TRACE(HW_GPU, "called, topology={}, count={}", regs.draw.topology.Value(), | ||
| 651 | regs.vertex_buffer.count); | ||
| 652 | |||
| 653 | ASSERT_MSG(!(regs.index_buffer.count && regs.vertex_buffer.count), "Both indexed and direct?"); | ||
| 654 | |||
| 655 | // Both instance configuration registers can not be set at the same time. | ||
| 656 | ASSERT_MSG(regs.draw.instance_id == Maxwell3D::Regs::Draw::InstanceId::First || | ||
| 657 | regs.draw.instance_id != Maxwell3D::Regs::Draw::InstanceId::Unchanged, | ||
| 658 | "Illegal combination of instancing parameters"); | ||
| 659 | |||
| 660 | ProcessTopologyOverride(); | ||
| 661 | |||
| 662 | const bool is_indexed = regs.index_buffer.count && !regs.vertex_buffer.count; | ||
| 663 | if (ShouldExecute()) { | ||
| 664 | rasterizer->Draw(is_indexed, instance_count); | ||
| 665 | } | ||
| 666 | |||
| 667 | if (is_indexed) { | ||
| 668 | regs.index_buffer.count = 0; | ||
| 669 | } else { | ||
| 670 | regs.vertex_buffer.count = 0; | ||
| 671 | } | ||
| 672 | |||
| 673 | deferred_draw_method.clear(); | ||
| 674 | inline_index_draw_indexes.clear(); | ||
| 675 | } | ||
| 676 | |||
| 694 | } // namespace Tegra::Engines | 677 | } // namespace Tegra::Engines |
diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h index 75e3b868d..bd23ebc12 100644 --- a/src/video_core/engines/maxwell_3d.h +++ b/src/video_core/engines/maxwell_3d.h | |||
| @@ -1739,14 +1739,11 @@ public: | |||
| 1739 | Footprint_1x1_Virtual = 2, | 1739 | Footprint_1x1_Virtual = 2, |
| 1740 | }; | 1740 | }; |
| 1741 | 1741 | ||
| 1742 | struct InlineIndex4x8Align { | 1742 | struct InlineIndex4x8 { |
| 1743 | union { | 1743 | union { |
| 1744 | BitField<0, 30, u32> count; | 1744 | BitField<0, 30, u32> count; |
| 1745 | BitField<30, 2, u32> start; | 1745 | BitField<30, 2, u32> start; |
| 1746 | }; | 1746 | }; |
| 1747 | }; | ||
| 1748 | |||
| 1749 | struct InlineIndex4x8Index { | ||
| 1750 | union { | 1747 | union { |
| 1751 | BitField<0, 8, u32> index0; | 1748 | BitField<0, 8, u32> index0; |
| 1752 | BitField<8, 8, u32> index1; | 1749 | BitField<8, 8, u32> index1; |
| @@ -2836,8 +2833,7 @@ public: | |||
| 2836 | u32 depth_write_enabled; ///< 0x12E8 | 2833 | u32 depth_write_enabled; ///< 0x12E8 |
| 2837 | u32 alpha_test_enabled; ///< 0x12EC | 2834 | u32 alpha_test_enabled; ///< 0x12EC |
| 2838 | INSERT_PADDING_BYTES_NOINIT(0x10); | 2835 | INSERT_PADDING_BYTES_NOINIT(0x10); |
| 2839 | InlineIndex4x8Align inline_index_4x8_align; ///< 0x1300 | 2836 | InlineIndex4x8 inline_index_4x8; ///< 0x1300 |
| 2840 | InlineIndex4x8Index inline_index_4x8_index; ///< 0x1304 | ||
| 2841 | D3DCullMode d3d_cull_mode; ///< 0x1308 | 2837 | D3DCullMode d3d_cull_mode; ///< 0x1308 |
| 2842 | ComparisonOp depth_test_func; ///< 0x130C | 2838 | ComparisonOp depth_test_func; ///< 0x130C |
| 2843 | f32 alpha_test_ref; ///< 0x1310 | 2839 | f32 alpha_test_ref; ///< 0x1310 |
| @@ -3048,8 +3044,6 @@ public: | |||
| 3048 | }; | 3044 | }; |
| 3049 | 3045 | ||
| 3050 | std::array<ShaderStageInfo, Regs::MaxShaderStage> shader_stages; | 3046 | std::array<ShaderStageInfo, Regs::MaxShaderStage> shader_stages; |
| 3051 | |||
| 3052 | u32 current_instance = 0; ///< Current instance to be used to simulate instanced rendering. | ||
| 3053 | }; | 3047 | }; |
| 3054 | 3048 | ||
| 3055 | State state{}; | 3049 | State state{}; |
| @@ -3064,11 +3058,6 @@ public: | |||
| 3064 | void CallMultiMethod(u32 method, const u32* base_start, u32 amount, | 3058 | void CallMultiMethod(u32 method, const u32* base_start, u32 amount, |
| 3065 | u32 methods_pending) override; | 3059 | u32 methods_pending) override; |
| 3066 | 3060 | ||
| 3067 | /// Write the value to the register identified by method. | ||
| 3068 | void CallMethodFromMME(u32 method, u32 method_argument); | ||
| 3069 | |||
| 3070 | void FlushMMEInlineDraw(); | ||
| 3071 | |||
| 3072 | bool ShouldExecute() const { | 3061 | bool ShouldExecute() const { |
| 3073 | return execute_on; | 3062 | return execute_on; |
| 3074 | } | 3063 | } |
| @@ -3081,21 +3070,6 @@ public: | |||
| 3081 | return *rasterizer; | 3070 | return *rasterizer; |
| 3082 | } | 3071 | } |
| 3083 | 3072 | ||
| 3084 | enum class MMEDrawMode : u32 { | ||
| 3085 | Undefined, | ||
| 3086 | Array, | ||
| 3087 | Indexed, | ||
| 3088 | }; | ||
| 3089 | |||
| 3090 | struct MMEDrawState { | ||
| 3091 | MMEDrawMode current_mode{MMEDrawMode::Undefined}; | ||
| 3092 | u32 current_count{}; | ||
| 3093 | u32 instance_count{}; | ||
| 3094 | bool instance_mode{}; | ||
| 3095 | bool gl_begin_consume{}; | ||
| 3096 | u32 gl_end_count{}; | ||
| 3097 | } mme_draw; | ||
| 3098 | |||
| 3099 | struct DirtyState { | 3073 | struct DirtyState { |
| 3100 | using Flags = std::bitset<std::numeric_limits<u8>::max()>; | 3074 | using Flags = std::bitset<std::numeric_limits<u8>::max()>; |
| 3101 | using Table = std::array<u8, Regs::NUM_REGS>; | 3075 | using Table = std::array<u8, Regs::NUM_REGS>; |
| @@ -3105,6 +3079,8 @@ public: | |||
| 3105 | Tables tables{}; | 3079 | Tables tables{}; |
| 3106 | } dirty; | 3080 | } dirty; |
| 3107 | 3081 | ||
| 3082 | std::vector<u8> inline_index_draw_indexes; | ||
| 3083 | |||
| 3108 | private: | 3084 | private: |
| 3109 | void InitializeRegisterDefaults(); | 3085 | void InitializeRegisterDefaults(); |
| 3110 | 3086 | ||
| @@ -3164,14 +3140,10 @@ private: | |||
| 3164 | /// Handles a write to the CB_BIND register. | 3140 | /// Handles a write to the CB_BIND register. |
| 3165 | void ProcessCBBind(size_t stage_index); | 3141 | void ProcessCBBind(size_t stage_index); |
| 3166 | 3142 | ||
| 3167 | /// Handles a write to the VERTEX_END_GL register, triggering a draw. | ||
| 3168 | void DrawArrays(); | ||
| 3169 | |||
| 3170 | /// Handles use of topology overrides (e.g., to avoid using a topology assigned from a macro) | 3143 | /// Handles use of topology overrides (e.g., to avoid using a topology assigned from a macro) |
| 3171 | void ProcessTopologyOverride(); | 3144 | void ProcessTopologyOverride(); |
| 3172 | 3145 | ||
| 3173 | // Handles a instance drawcall from MME | 3146 | void ProcessDeferredDraw(); |
| 3174 | void StepInstance(MMEDrawMode expected_mode, u32 count); | ||
| 3175 | 3147 | ||
| 3176 | /// Returns a query's value or an empty object if the value will be deferred through a cache. | 3148 | /// Returns a query's value or an empty object if the value will be deferred through a cache. |
| 3177 | std::optional<u64> GetQueryResult(); | 3149 | std::optional<u64> GetQueryResult(); |
| @@ -3184,8 +3156,6 @@ private: | |||
| 3184 | /// Start offsets of each macro in macro_memory | 3156 | /// Start offsets of each macro in macro_memory |
| 3185 | std::array<u32, 0x80> macro_positions{}; | 3157 | std::array<u32, 0x80> macro_positions{}; |
| 3186 | 3158 | ||
| 3187 | std::array<bool, Regs::NUM_REGS> mme_inline{}; | ||
| 3188 | |||
| 3189 | /// Macro method that is currently being executed / being fed parameters. | 3159 | /// Macro method that is currently being executed / being fed parameters. |
| 3190 | u32 executing_macro = 0; | 3160 | u32 executing_macro = 0; |
| 3191 | /// Parameters that have been submitted to the macro call so far. | 3161 | /// Parameters that have been submitted to the macro call so far. |
| @@ -3198,6 +3168,9 @@ private: | |||
| 3198 | 3168 | ||
| 3199 | bool execute_on{true}; | 3169 | bool execute_on{true}; |
| 3200 | bool use_topology_override{false}; | 3170 | bool use_topology_override{false}; |
| 3171 | |||
| 3172 | std::array<bool, Regs::NUM_REGS> draw_command{}; | ||
| 3173 | std::vector<u32> deferred_draw_method; | ||
| 3201 | }; | 3174 | }; |
| 3202 | 3175 | ||
| 3203 | #define ASSERT_REG_POSITION(field_name, position) \ | 3176 | #define ASSERT_REG_POSITION(field_name, position) \ |
| @@ -3402,8 +3375,7 @@ ASSERT_REG_POSITION(alpha_to_coverage_dither, 0x12E0); | |||
| 3402 | ASSERT_REG_POSITION(blend_per_target_enabled, 0x12E4); | 3375 | ASSERT_REG_POSITION(blend_per_target_enabled, 0x12E4); |
| 3403 | ASSERT_REG_POSITION(depth_write_enabled, 0x12E8); | 3376 | ASSERT_REG_POSITION(depth_write_enabled, 0x12E8); |
| 3404 | ASSERT_REG_POSITION(alpha_test_enabled, 0x12EC); | 3377 | ASSERT_REG_POSITION(alpha_test_enabled, 0x12EC); |
| 3405 | ASSERT_REG_POSITION(inline_index_4x8_align, 0x1300); | 3378 | ASSERT_REG_POSITION(inline_index_4x8, 0x1300); |
| 3406 | ASSERT_REG_POSITION(inline_index_4x8_index, 0x1304); | ||
| 3407 | ASSERT_REG_POSITION(d3d_cull_mode, 0x1308); | 3379 | ASSERT_REG_POSITION(d3d_cull_mode, 0x1308); |
| 3408 | ASSERT_REG_POSITION(depth_test_func, 0x130C); | 3380 | ASSERT_REG_POSITION(depth_test_func, 0x130C); |
| 3409 | ASSERT_REG_POSITION(alpha_test_ref, 0x1310); | 3381 | ASSERT_REG_POSITION(alpha_test_ref, 0x1310); |
diff --git a/src/video_core/macro/macro_hle.cpp b/src/video_core/macro/macro_hle.cpp index 8a8adbb42..f896591bf 100644 --- a/src/video_core/macro/macro_hle.cpp +++ b/src/video_core/macro/macro_hle.cpp | |||
| @@ -22,35 +22,29 @@ void HLE_771BB18C62444DA0(Engines::Maxwell3D& maxwell3d, const std::vector<u32>& | |||
| 22 | maxwell3d.regs.draw.topology.Assign( | 22 | maxwell3d.regs.draw.topology.Assign( |
| 23 | static_cast<Tegra::Engines::Maxwell3D::Regs::PrimitiveTopology>(parameters[0] & 0x3ffffff)); | 23 | static_cast<Tegra::Engines::Maxwell3D::Regs::PrimitiveTopology>(parameters[0] & 0x3ffffff)); |
| 24 | maxwell3d.regs.global_base_instance_index = parameters[5]; | 24 | maxwell3d.regs.global_base_instance_index = parameters[5]; |
| 25 | maxwell3d.mme_draw.instance_count = instance_count; | ||
| 26 | maxwell3d.regs.global_base_vertex_index = parameters[3]; | 25 | maxwell3d.regs.global_base_vertex_index = parameters[3]; |
| 27 | maxwell3d.regs.index_buffer.count = parameters[1]; | 26 | maxwell3d.regs.index_buffer.count = parameters[1]; |
| 28 | maxwell3d.regs.index_buffer.first = parameters[4]; | 27 | maxwell3d.regs.index_buffer.first = parameters[4]; |
| 29 | 28 | ||
| 30 | if (maxwell3d.ShouldExecute()) { | 29 | if (maxwell3d.ShouldExecute()) { |
| 31 | maxwell3d.Rasterizer().Draw(true, true); | 30 | maxwell3d.Rasterizer().Draw(true, instance_count); |
| 32 | } | 31 | } |
| 33 | maxwell3d.regs.index_buffer.count = 0; | 32 | maxwell3d.regs.index_buffer.count = 0; |
| 34 | maxwell3d.mme_draw.instance_count = 0; | ||
| 35 | maxwell3d.mme_draw.current_mode = Engines::Maxwell3D::MMEDrawMode::Undefined; | ||
| 36 | } | 33 | } |
| 37 | 34 | ||
| 38 | void HLE_0D61FC9FAAC9FCAD(Engines::Maxwell3D& maxwell3d, const std::vector<u32>& parameters) { | 35 | void HLE_0D61FC9FAAC9FCAD(Engines::Maxwell3D& maxwell3d, const std::vector<u32>& parameters) { |
| 39 | const u32 count = (maxwell3d.GetRegisterValue(0xD1B) & parameters[2]); | 36 | const u32 instance_count = (maxwell3d.GetRegisterValue(0xD1B) & parameters[2]); |
| 40 | 37 | ||
| 41 | maxwell3d.regs.vertex_buffer.first = parameters[3]; | 38 | maxwell3d.regs.vertex_buffer.first = parameters[3]; |
| 42 | maxwell3d.regs.vertex_buffer.count = parameters[1]; | 39 | maxwell3d.regs.vertex_buffer.count = parameters[1]; |
| 43 | maxwell3d.regs.global_base_instance_index = parameters[4]; | 40 | maxwell3d.regs.global_base_instance_index = parameters[4]; |
| 44 | maxwell3d.regs.draw.topology.Assign( | 41 | maxwell3d.regs.draw.topology.Assign( |
| 45 | static_cast<Tegra::Engines::Maxwell3D::Regs::PrimitiveTopology>(parameters[0])); | 42 | static_cast<Tegra::Engines::Maxwell3D::Regs::PrimitiveTopology>(parameters[0])); |
| 46 | maxwell3d.mme_draw.instance_count = count; | ||
| 47 | 43 | ||
| 48 | if (maxwell3d.ShouldExecute()) { | 44 | if (maxwell3d.ShouldExecute()) { |
| 49 | maxwell3d.Rasterizer().Draw(false, true); | 45 | maxwell3d.Rasterizer().Draw(false, instance_count); |
| 50 | } | 46 | } |
| 51 | maxwell3d.regs.vertex_buffer.count = 0; | 47 | maxwell3d.regs.vertex_buffer.count = 0; |
| 52 | maxwell3d.mme_draw.instance_count = 0; | ||
| 53 | maxwell3d.mme_draw.current_mode = Engines::Maxwell3D::MMEDrawMode::Undefined; | ||
| 54 | } | 48 | } |
| 55 | 49 | ||
| 56 | void HLE_0217920100488FF7(Engines::Maxwell3D& maxwell3d, const std::vector<u32>& parameters) { | 50 | void HLE_0217920100488FF7(Engines::Maxwell3D& maxwell3d, const std::vector<u32>& parameters) { |
| @@ -63,24 +57,21 @@ void HLE_0217920100488FF7(Engines::Maxwell3D& maxwell3d, const std::vector<u32>& | |||
| 63 | maxwell3d.dirty.flags[VideoCommon::Dirty::IndexBuffer] = true; | 57 | maxwell3d.dirty.flags[VideoCommon::Dirty::IndexBuffer] = true; |
| 64 | maxwell3d.regs.global_base_vertex_index = element_base; | 58 | maxwell3d.regs.global_base_vertex_index = element_base; |
| 65 | maxwell3d.regs.global_base_instance_index = base_instance; | 59 | maxwell3d.regs.global_base_instance_index = base_instance; |
| 66 | maxwell3d.mme_draw.instance_count = instance_count; | 60 | maxwell3d.CallMethod(0x8e3, 0x640, true); |
| 67 | maxwell3d.CallMethodFromMME(0x8e3, 0x640); | 61 | maxwell3d.CallMethod(0x8e4, element_base, true); |
| 68 | maxwell3d.CallMethodFromMME(0x8e4, element_base); | 62 | maxwell3d.CallMethod(0x8e5, base_instance, true); |
| 69 | maxwell3d.CallMethodFromMME(0x8e5, base_instance); | ||
| 70 | maxwell3d.regs.draw.topology.Assign( | 63 | maxwell3d.regs.draw.topology.Assign( |
| 71 | static_cast<Tegra::Engines::Maxwell3D::Regs::PrimitiveTopology>(parameters[0])); | 64 | static_cast<Tegra::Engines::Maxwell3D::Regs::PrimitiveTopology>(parameters[0])); |
| 72 | if (maxwell3d.ShouldExecute()) { | 65 | if (maxwell3d.ShouldExecute()) { |
| 73 | maxwell3d.Rasterizer().Draw(true, true); | 66 | maxwell3d.Rasterizer().Draw(true, instance_count); |
| 74 | } | 67 | } |
| 75 | maxwell3d.regs.vertex_id_base = 0x0; | 68 | maxwell3d.regs.vertex_id_base = 0x0; |
| 76 | maxwell3d.regs.index_buffer.count = 0; | 69 | maxwell3d.regs.index_buffer.count = 0; |
| 77 | maxwell3d.regs.global_base_vertex_index = 0x0; | 70 | maxwell3d.regs.global_base_vertex_index = 0x0; |
| 78 | maxwell3d.regs.global_base_instance_index = 0x0; | 71 | maxwell3d.regs.global_base_instance_index = 0x0; |
| 79 | maxwell3d.mme_draw.instance_count = 0; | 72 | maxwell3d.CallMethod(0x8e3, 0x640, true); |
| 80 | maxwell3d.CallMethodFromMME(0x8e3, 0x640); | 73 | maxwell3d.CallMethod(0x8e4, 0x0, true); |
| 81 | maxwell3d.CallMethodFromMME(0x8e4, 0x0); | 74 | maxwell3d.CallMethod(0x8e5, 0x0, true); |
| 82 | maxwell3d.CallMethodFromMME(0x8e5, 0x0); | ||
| 83 | maxwell3d.mme_draw.current_mode = Engines::Maxwell3D::MMEDrawMode::Undefined; | ||
| 84 | } | 75 | } |
| 85 | 76 | ||
| 86 | // Multidraw Indirect | 77 | // Multidraw Indirect |
| @@ -91,11 +82,9 @@ void HLE_3F5E74B9C9A50164(Engines::Maxwell3D& maxwell3d, const std::vector<u32>& | |||
| 91 | maxwell3d.regs.index_buffer.count = 0; | 82 | maxwell3d.regs.index_buffer.count = 0; |
| 92 | maxwell3d.regs.global_base_vertex_index = 0x0; | 83 | maxwell3d.regs.global_base_vertex_index = 0x0; |
| 93 | maxwell3d.regs.global_base_instance_index = 0x0; | 84 | maxwell3d.regs.global_base_instance_index = 0x0; |
| 94 | maxwell3d.mme_draw.instance_count = 0; | 85 | maxwell3d.CallMethod(0x8e3, 0x640, true); |
| 95 | maxwell3d.CallMethodFromMME(0x8e3, 0x640); | 86 | maxwell3d.CallMethod(0x8e4, 0x0, true); |
| 96 | maxwell3d.CallMethodFromMME(0x8e4, 0x0); | 87 | maxwell3d.CallMethod(0x8e5, 0x0, true); |
| 97 | maxwell3d.CallMethodFromMME(0x8e5, 0x0); | ||
| 98 | maxwell3d.mme_draw.current_mode = Engines::Maxwell3D::MMEDrawMode::Undefined; | ||
| 99 | maxwell3d.dirty.flags[VideoCommon::Dirty::IndexBuffer] = true; | 88 | maxwell3d.dirty.flags[VideoCommon::Dirty::IndexBuffer] = true; |
| 100 | }); | 89 | }); |
| 101 | const u32 start_indirect = parameters[0]; | 90 | const u32 start_indirect = parameters[0]; |
| @@ -127,15 +116,13 @@ void HLE_3F5E74B9C9A50164(Engines::Maxwell3D& maxwell3d, const std::vector<u32>& | |||
| 127 | maxwell3d.regs.index_buffer.count = num_vertices; | 116 | maxwell3d.regs.index_buffer.count = num_vertices; |
| 128 | maxwell3d.regs.global_base_vertex_index = base_vertex; | 117 | maxwell3d.regs.global_base_vertex_index = base_vertex; |
| 129 | maxwell3d.regs.global_base_instance_index = base_instance; | 118 | maxwell3d.regs.global_base_instance_index = base_instance; |
| 130 | maxwell3d.mme_draw.instance_count = instance_count; | 119 | maxwell3d.CallMethod(0x8e3, 0x640, true); |
| 131 | maxwell3d.CallMethodFromMME(0x8e3, 0x640); | 120 | maxwell3d.CallMethod(0x8e4, base_vertex, true); |
| 132 | maxwell3d.CallMethodFromMME(0x8e4, base_vertex); | 121 | maxwell3d.CallMethod(0x8e5, base_instance, true); |
| 133 | maxwell3d.CallMethodFromMME(0x8e5, base_instance); | ||
| 134 | maxwell3d.dirty.flags[VideoCommon::Dirty::IndexBuffer] = true; | 122 | maxwell3d.dirty.flags[VideoCommon::Dirty::IndexBuffer] = true; |
| 135 | if (maxwell3d.ShouldExecute()) { | 123 | if (maxwell3d.ShouldExecute()) { |
| 136 | maxwell3d.Rasterizer().Draw(true, true); | 124 | maxwell3d.Rasterizer().Draw(true, instance_count); |
| 137 | } | 125 | } |
| 138 | maxwell3d.mme_draw.current_mode = Engines::Maxwell3D::MMEDrawMode::Undefined; | ||
| 139 | } | 126 | } |
| 140 | } | 127 | } |
| 141 | 128 | ||
diff --git a/src/video_core/macro/macro_interpreter.cpp b/src/video_core/macro/macro_interpreter.cpp index f670b1bca..c0d32c112 100644 --- a/src/video_core/macro/macro_interpreter.cpp +++ b/src/video_core/macro/macro_interpreter.cpp | |||
| @@ -335,7 +335,7 @@ void MacroInterpreterImpl::SetMethodAddress(u32 address) { | |||
| 335 | } | 335 | } |
| 336 | 336 | ||
| 337 | void MacroInterpreterImpl::Send(u32 value) { | 337 | void MacroInterpreterImpl::Send(u32 value) { |
| 338 | maxwell3d.CallMethodFromMME(method_address.address, value); | 338 | maxwell3d.CallMethod(method_address.address, value, true); |
| 339 | // Increment the method address by the method increment. | 339 | // Increment the method address by the method increment. |
| 340 | method_address.address.Assign(method_address.address.Value() + | 340 | method_address.address.Assign(method_address.address.Value() + |
| 341 | method_address.increment.Value()); | 341 | method_address.increment.Value()); |
diff --git a/src/video_core/macro/macro_jit_x64.cpp b/src/video_core/macro/macro_jit_x64.cpp index a302a9603..25c1ce798 100644 --- a/src/video_core/macro/macro_jit_x64.cpp +++ b/src/video_core/macro/macro_jit_x64.cpp | |||
| @@ -346,7 +346,7 @@ void MacroJITx64Impl::Compile_Read(Macro::Opcode opcode) { | |||
| 346 | } | 346 | } |
| 347 | 347 | ||
| 348 | void Send(Engines::Maxwell3D* maxwell3d, Macro::MethodAddress method_address, u32 value) { | 348 | void Send(Engines::Maxwell3D* maxwell3d, Macro::MethodAddress method_address, u32 value) { |
| 349 | maxwell3d->CallMethodFromMME(method_address.address, value); | 349 | maxwell3d->CallMethod(method_address.address, value, true); |
| 350 | } | 350 | } |
| 351 | 351 | ||
| 352 | void MacroJITx64Impl::Compile_Send(Xbyak::Reg32 value) { | 352 | void MacroJITx64Impl::Compile_Send(Xbyak::Reg32 value) { |
diff --git a/src/video_core/memory_manager.cpp b/src/video_core/memory_manager.cpp index d07b21bd6..384350dbd 100644 --- a/src/video_core/memory_manager.cpp +++ b/src/video_core/memory_manager.cpp | |||
| @@ -133,7 +133,7 @@ inline void MemoryManager::SetBigPageContinous(size_t big_page_index, bool value | |||
| 133 | template <MemoryManager::EntryType entry_type> | 133 | template <MemoryManager::EntryType entry_type> |
| 134 | GPUVAddr MemoryManager::PageTableOp(GPUVAddr gpu_addr, [[maybe_unused]] VAddr cpu_addr, size_t size, | 134 | GPUVAddr MemoryManager::PageTableOp(GPUVAddr gpu_addr, [[maybe_unused]] VAddr cpu_addr, size_t size, |
| 135 | PTEKind kind) { | 135 | PTEKind kind) { |
| 136 | u64 remaining_size{size}; | 136 | [[maybe_unused]] u64 remaining_size{size}; |
| 137 | if constexpr (entry_type == EntryType::Mapped) { | 137 | if constexpr (entry_type == EntryType::Mapped) { |
| 138 | page_table.ReserveRange(gpu_addr, size); | 138 | page_table.ReserveRange(gpu_addr, size); |
| 139 | } | 139 | } |
| @@ -159,7 +159,7 @@ GPUVAddr MemoryManager::PageTableOp(GPUVAddr gpu_addr, [[maybe_unused]] VAddr cp | |||
| 159 | template <MemoryManager::EntryType entry_type> | 159 | template <MemoryManager::EntryType entry_type> |
| 160 | GPUVAddr MemoryManager::BigPageTableOp(GPUVAddr gpu_addr, [[maybe_unused]] VAddr cpu_addr, | 160 | GPUVAddr MemoryManager::BigPageTableOp(GPUVAddr gpu_addr, [[maybe_unused]] VAddr cpu_addr, |
| 161 | size_t size, PTEKind kind) { | 161 | size_t size, PTEKind kind) { |
| 162 | u64 remaining_size{size}; | 162 | [[maybe_unused]] u64 remaining_size{size}; |
| 163 | for (u64 offset{}; offset < size; offset += big_page_size) { | 163 | for (u64 offset{}; offset < size; offset += big_page_size) { |
| 164 | const GPUVAddr current_gpu_addr = gpu_addr + offset; | 164 | const GPUVAddr current_gpu_addr = gpu_addr + offset; |
| 165 | [[maybe_unused]] const auto current_entry_type = GetEntry<true>(current_gpu_addr); | 165 | [[maybe_unused]] const auto current_entry_type = GetEntry<true>(current_gpu_addr); |
diff --git a/src/video_core/rasterizer_interface.h b/src/video_core/rasterizer_interface.h index d2d40884c..1cbfef090 100644 --- a/src/video_core/rasterizer_interface.h +++ b/src/video_core/rasterizer_interface.h | |||
| @@ -40,7 +40,7 @@ public: | |||
| 40 | virtual ~RasterizerInterface() = default; | 40 | virtual ~RasterizerInterface() = default; |
| 41 | 41 | ||
| 42 | /// Dispatches a draw invocation | 42 | /// Dispatches a draw invocation |
| 43 | virtual void Draw(bool is_indexed, bool is_instanced) = 0; | 43 | virtual void Draw(bool is_indexed, u32 instance_count) = 0; |
| 44 | 44 | ||
| 45 | /// Clear the current framebuffer | 45 | /// Clear the current framebuffer |
| 46 | virtual void Clear() = 0; | 46 | virtual void Clear() = 0; |
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index e5c09a969..1590b21de 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp | |||
| @@ -205,7 +205,7 @@ void RasterizerOpenGL::Clear() { | |||
| 205 | ++num_queued_commands; | 205 | ++num_queued_commands; |
| 206 | } | 206 | } |
| 207 | 207 | ||
| 208 | void RasterizerOpenGL::Draw(bool is_indexed, bool is_instanced) { | 208 | void RasterizerOpenGL::Draw(bool is_indexed, u32 instance_count) { |
| 209 | MICROPROFILE_SCOPE(OpenGL_Drawing); | 209 | MICROPROFILE_SCOPE(OpenGL_Drawing); |
| 210 | 210 | ||
| 211 | SCOPE_EXIT({ gpu.TickWork(); }); | 211 | SCOPE_EXIT({ gpu.TickWork(); }); |
| @@ -222,14 +222,15 @@ void RasterizerOpenGL::Draw(bool is_indexed, bool is_instanced) { | |||
| 222 | pipeline->SetEngine(maxwell3d, gpu_memory); | 222 | pipeline->SetEngine(maxwell3d, gpu_memory); |
| 223 | pipeline->Configure(is_indexed); | 223 | pipeline->Configure(is_indexed); |
| 224 | 224 | ||
| 225 | BindInlineIndexBuffer(); | ||
| 226 | |||
| 225 | SyncState(); | 227 | SyncState(); |
| 226 | 228 | ||
| 227 | const GLenum primitive_mode = MaxwellToGL::PrimitiveTopology(maxwell3d->regs.draw.topology); | 229 | const GLenum primitive_mode = MaxwellToGL::PrimitiveTopology(maxwell3d->regs.draw.topology); |
| 228 | BeginTransformFeedback(pipeline, primitive_mode); | 230 | BeginTransformFeedback(pipeline, primitive_mode); |
| 229 | 231 | ||
| 230 | const GLuint base_instance = static_cast<GLuint>(maxwell3d->regs.global_base_instance_index); | 232 | const GLuint base_instance = static_cast<GLuint>(maxwell3d->regs.global_base_instance_index); |
| 231 | const GLsizei num_instances = | 233 | const GLsizei num_instances = static_cast<GLsizei>(instance_count); |
| 232 | static_cast<GLsizei>(is_instanced ? maxwell3d->mme_draw.instance_count : 1); | ||
| 233 | if (is_indexed) { | 234 | if (is_indexed) { |
| 234 | const GLint base_vertex = static_cast<GLint>(maxwell3d->regs.global_base_vertex_index); | 235 | const GLint base_vertex = static_cast<GLint>(maxwell3d->regs.global_base_vertex_index); |
| 235 | const GLsizei num_vertices = static_cast<GLsizei>(maxwell3d->regs.index_buffer.count); | 236 | const GLsizei num_vertices = static_cast<GLsizei>(maxwell3d->regs.index_buffer.count); |
| @@ -1129,6 +1130,16 @@ void RasterizerOpenGL::ReleaseChannel(s32 channel_id) { | |||
| 1129 | query_cache.EraseChannel(channel_id); | 1130 | query_cache.EraseChannel(channel_id); |
| 1130 | } | 1131 | } |
| 1131 | 1132 | ||
| 1133 | void RasterizerOpenGL::BindInlineIndexBuffer() { | ||
| 1134 | if (maxwell3d->inline_index_draw_indexes.empty()) { | ||
| 1135 | return; | ||
| 1136 | } | ||
| 1137 | const auto data_count = static_cast<u32>(maxwell3d->inline_index_draw_indexes.size()); | ||
| 1138 | auto buffer = Buffer(buffer_cache_runtime, *this, 0, data_count); | ||
| 1139 | buffer.ImmediateUpload(0, maxwell3d->inline_index_draw_indexes); | ||
| 1140 | buffer_cache_runtime.BindIndexBuffer(buffer, 0, data_count); | ||
| 1141 | } | ||
| 1142 | |||
| 1132 | AccelerateDMA::AccelerateDMA(BufferCache& buffer_cache_) : buffer_cache{buffer_cache_} {} | 1143 | AccelerateDMA::AccelerateDMA(BufferCache& buffer_cache_) : buffer_cache{buffer_cache_} {} |
| 1133 | 1144 | ||
| 1134 | bool AccelerateDMA::BufferCopy(GPUVAddr src_address, GPUVAddr dest_address, u64 amount) { | 1145 | bool AccelerateDMA::BufferCopy(GPUVAddr src_address, GPUVAddr dest_address, u64 amount) { |
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h index 45131b785..793e0d608 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.h +++ b/src/video_core/renderer_opengl/gl_rasterizer.h | |||
| @@ -68,7 +68,7 @@ public: | |||
| 68 | StateTracker& state_tracker_); | 68 | StateTracker& state_tracker_); |
| 69 | ~RasterizerOpenGL() override; | 69 | ~RasterizerOpenGL() override; |
| 70 | 70 | ||
| 71 | void Draw(bool is_indexed, bool is_instanced) override; | 71 | void Draw(bool is_indexed, u32 instance_count) override; |
| 72 | void Clear() override; | 72 | void Clear() override; |
| 73 | void DispatchCompute() override; | 73 | void DispatchCompute() override; |
| 74 | void ResetCounter(VideoCore::QueryType type) override; | 74 | void ResetCounter(VideoCore::QueryType type) override; |
| @@ -199,6 +199,8 @@ private: | |||
| 199 | /// End a transform feedback | 199 | /// End a transform feedback |
| 200 | void EndTransformFeedback(); | 200 | void EndTransformFeedback(); |
| 201 | 201 | ||
| 202 | void BindInlineIndexBuffer(); | ||
| 203 | |||
| 202 | Tegra::GPU& gpu; | 204 | Tegra::GPU& gpu; |
| 203 | 205 | ||
| 204 | const Device& device; | 206 | const Device& device; |
diff --git a/src/video_core/renderer_opengl/gl_shader_cache.cpp b/src/video_core/renderer_opengl/gl_shader_cache.cpp index 609f0a772..e94cfdb1a 100644 --- a/src/video_core/renderer_opengl/gl_shader_cache.cpp +++ b/src/video_core/renderer_opengl/gl_shader_cache.cpp | |||
| @@ -63,6 +63,7 @@ Shader::RuntimeInfo MakeRuntimeInfo(const GraphicsPipelineKey& key, | |||
| 63 | Shader::RuntimeInfo info; | 63 | Shader::RuntimeInfo info; |
| 64 | if (previous_program) { | 64 | if (previous_program) { |
| 65 | info.previous_stage_stores = previous_program->info.stores; | 65 | info.previous_stage_stores = previous_program->info.stores; |
| 66 | info.previous_stage_legacy_stores_mapping = previous_program->info.legacy_stores_mapping; | ||
| 66 | } else { | 67 | } else { |
| 67 | // Mark all stores as available for vertex shaders | 68 | // Mark all stores as available for vertex shaders |
| 68 | info.previous_stage_stores.mask.set(); | 69 | info.previous_stage_stores.mask.set(); |
diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp index 20f1d6584..13d5a1f67 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp | |||
| @@ -134,6 +134,7 @@ Shader::RuntimeInfo MakeRuntimeInfo(std::span<const Shader::IR::Program> program | |||
| 134 | Shader::RuntimeInfo info; | 134 | Shader::RuntimeInfo info; |
| 135 | if (previous_program) { | 135 | if (previous_program) { |
| 136 | info.previous_stage_stores = previous_program->info.stores; | 136 | info.previous_stage_stores = previous_program->info.stores; |
| 137 | info.previous_stage_legacy_stores_mapping = previous_program->info.legacy_stores_mapping; | ||
| 137 | if (previous_program->is_geometry_passthrough) { | 138 | if (previous_program->is_geometry_passthrough) { |
| 138 | info.previous_stage_stores.mask |= previous_program->info.passthrough.mask; | 139 | info.previous_stage_stores.mask |= previous_program->info.passthrough.mask; |
| 139 | } | 140 | } |
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index 47dfb45a1..9f05a7a18 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp | |||
| @@ -127,11 +127,10 @@ VkRect2D GetScissorState(const Maxwell& regs, size_t index, u32 up_scale = 1, u3 | |||
| 127 | return scissor; | 127 | return scissor; |
| 128 | } | 128 | } |
| 129 | 129 | ||
| 130 | DrawParams MakeDrawParams(const Maxwell& regs, u32 num_instances, bool is_instanced, | 130 | DrawParams MakeDrawParams(const Maxwell& regs, u32 num_instances, bool is_indexed) { |
| 131 | bool is_indexed) { | ||
| 132 | DrawParams params{ | 131 | DrawParams params{ |
| 133 | .base_instance = regs.global_base_instance_index, | 132 | .base_instance = regs.global_base_instance_index, |
| 134 | .num_instances = is_instanced ? num_instances : 1, | 133 | .num_instances = num_instances, |
| 135 | .base_vertex = is_indexed ? regs.global_base_vertex_index : regs.vertex_buffer.first, | 134 | .base_vertex = is_indexed ? regs.global_base_vertex_index : regs.vertex_buffer.first, |
| 136 | .num_vertices = is_indexed ? regs.index_buffer.count : regs.vertex_buffer.count, | 135 | .num_vertices = is_indexed ? regs.index_buffer.count : regs.vertex_buffer.count, |
| 137 | .first_index = is_indexed ? regs.index_buffer.first : 0, | 136 | .first_index = is_indexed ? regs.index_buffer.first : 0, |
| @@ -177,7 +176,7 @@ RasterizerVulkan::RasterizerVulkan(Core::Frontend::EmuWindow& emu_window_, Tegra | |||
| 177 | 176 | ||
| 178 | RasterizerVulkan::~RasterizerVulkan() = default; | 177 | RasterizerVulkan::~RasterizerVulkan() = default; |
| 179 | 178 | ||
| 180 | void RasterizerVulkan::Draw(bool is_indexed, bool is_instanced) { | 179 | void RasterizerVulkan::Draw(bool is_indexed, u32 instance_count) { |
| 181 | MICROPROFILE_SCOPE(Vulkan_Drawing); | 180 | MICROPROFILE_SCOPE(Vulkan_Drawing); |
| 182 | 181 | ||
| 183 | SCOPE_EXIT({ gpu.TickWork(); }); | 182 | SCOPE_EXIT({ gpu.TickWork(); }); |
| @@ -194,13 +193,15 @@ void RasterizerVulkan::Draw(bool is_indexed, bool is_instanced) { | |||
| 194 | pipeline->SetEngine(maxwell3d, gpu_memory); | 193 | pipeline->SetEngine(maxwell3d, gpu_memory); |
| 195 | pipeline->Configure(is_indexed); | 194 | pipeline->Configure(is_indexed); |
| 196 | 195 | ||
| 196 | BindInlineIndexBuffer(); | ||
| 197 | |||
| 197 | BeginTransformFeedback(); | 198 | BeginTransformFeedback(); |
| 198 | 199 | ||
| 199 | UpdateDynamicStates(); | 200 | UpdateDynamicStates(); |
| 200 | 201 | ||
| 201 | const auto& regs{maxwell3d->regs}; | 202 | const auto& regs{maxwell3d->regs}; |
| 202 | const u32 num_instances{maxwell3d->mme_draw.instance_count}; | 203 | const u32 num_instances{instance_count}; |
| 203 | const DrawParams draw_params{MakeDrawParams(regs, num_instances, is_instanced, is_indexed)}; | 204 | const DrawParams draw_params{MakeDrawParams(regs, num_instances, is_indexed)}; |
| 204 | scheduler.Record([draw_params](vk::CommandBuffer cmdbuf) { | 205 | scheduler.Record([draw_params](vk::CommandBuffer cmdbuf) { |
| 205 | if (draw_params.is_indexed) { | 206 | if (draw_params.is_indexed) { |
| 206 | cmdbuf.DrawIndexed(draw_params.num_vertices, draw_params.num_instances, | 207 | cmdbuf.DrawIndexed(draw_params.num_vertices, draw_params.num_instances, |
| @@ -1009,4 +1010,17 @@ void RasterizerVulkan::ReleaseChannel(s32 channel_id) { | |||
| 1009 | query_cache.EraseChannel(channel_id); | 1010 | query_cache.EraseChannel(channel_id); |
| 1010 | } | 1011 | } |
| 1011 | 1012 | ||
| 1013 | void RasterizerVulkan::BindInlineIndexBuffer() { | ||
| 1014 | if (maxwell3d->inline_index_draw_indexes.empty()) { | ||
| 1015 | return; | ||
| 1016 | } | ||
| 1017 | const auto data_count = static_cast<u32>(maxwell3d->inline_index_draw_indexes.size()); | ||
| 1018 | auto buffer = buffer_cache_runtime.UploadStagingBuffer(data_count); | ||
| 1019 | std::memcpy(buffer.mapped_span.data(), maxwell3d->inline_index_draw_indexes.data(), data_count); | ||
| 1020 | buffer_cache_runtime.BindIndexBuffer( | ||
| 1021 | maxwell3d->regs.draw.topology, maxwell3d->regs.index_buffer.format, | ||
| 1022 | maxwell3d->regs.index_buffer.first, maxwell3d->regs.index_buffer.count, buffer.buffer, | ||
| 1023 | static_cast<u32>(buffer.offset), data_count); | ||
| 1024 | } | ||
| 1025 | |||
| 1012 | } // namespace Vulkan | 1026 | } // namespace Vulkan |
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.h b/src/video_core/renderer_vulkan/vk_rasterizer.h index 4cde3c983..e2fdc7611 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.h +++ b/src/video_core/renderer_vulkan/vk_rasterizer.h | |||
| @@ -64,7 +64,7 @@ public: | |||
| 64 | StateTracker& state_tracker_, Scheduler& scheduler_); | 64 | StateTracker& state_tracker_, Scheduler& scheduler_); |
| 65 | ~RasterizerVulkan() override; | 65 | ~RasterizerVulkan() override; |
| 66 | 66 | ||
| 67 | void Draw(bool is_indexed, bool is_instanced) override; | 67 | void Draw(bool is_indexed, u32 instance_count) override; |
| 68 | void Clear() override; | 68 | void Clear() override; |
| 69 | void DispatchCompute() override; | 69 | void DispatchCompute() override; |
| 70 | void ResetCounter(VideoCore::QueryType type) override; | 70 | void ResetCounter(VideoCore::QueryType type) override; |
| @@ -141,6 +141,8 @@ private: | |||
| 141 | 141 | ||
| 142 | void UpdateVertexInput(Tegra::Engines::Maxwell3D::Regs& regs); | 142 | void UpdateVertexInput(Tegra::Engines::Maxwell3D::Regs& regs); |
| 143 | 143 | ||
| 144 | void BindInlineIndexBuffer(); | ||
| 145 | |||
| 144 | Tegra::GPU& gpu; | 146 | Tegra::GPU& gpu; |
| 145 | 147 | ||
| 146 | ScreenInfo& screen_info; | 148 | ScreenInfo& screen_info; |
diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h index 0e0fd410f..8ef75fe73 100644 --- a/src/video_core/texture_cache/texture_cache.h +++ b/src/video_core/texture_cache/texture_cache.h | |||
| @@ -442,7 +442,7 @@ void TextureCache<P>::WriteMemory(VAddr cpu_addr, size_t size) { | |||
| 442 | template <class P> | 442 | template <class P> |
| 443 | void TextureCache<P>::DownloadMemory(VAddr cpu_addr, size_t size) { | 443 | void TextureCache<P>::DownloadMemory(VAddr cpu_addr, size_t size) { |
| 444 | std::vector<ImageId> images; | 444 | std::vector<ImageId> images; |
| 445 | ForEachImageInRegion(cpu_addr, size, [this, &images](ImageId image_id, ImageBase& image) { | 445 | ForEachImageInRegion(cpu_addr, size, [&images](ImageId image_id, ImageBase& image) { |
| 446 | if (!image.IsSafeDownload()) { | 446 | if (!image.IsSafeDownload()) { |
| 447 | return; | 447 | return; |
| 448 | } | 448 | } |
| @@ -1502,9 +1502,9 @@ void TextureCache<P>::UnregisterImage(ImageId image_id) { | |||
| 1502 | image.flags &= ~ImageFlagBits::BadOverlap; | 1502 | image.flags &= ~ImageFlagBits::BadOverlap; |
| 1503 | lru_cache.Free(image.lru_index); | 1503 | lru_cache.Free(image.lru_index); |
| 1504 | const auto& clear_page_table = | 1504 | const auto& clear_page_table = |
| 1505 | [this, image_id](u64 page, | 1505 | [image_id](u64 page, |
| 1506 | std::unordered_map<u64, std::vector<ImageId>, Common::IdentityHash<u64>>& | 1506 | std::unordered_map<u64, std::vector<ImageId>, Common::IdentityHash<u64>>& |
| 1507 | selected_page_table) { | 1507 | selected_page_table) { |
| 1508 | const auto page_it = selected_page_table.find(page); | 1508 | const auto page_it = selected_page_table.find(page); |
| 1509 | if (page_it == selected_page_table.end()) { | 1509 | if (page_it == selected_page_table.end()) { |
| 1510 | ASSERT_MSG(false, "Unregistering unregistered page=0x{:x}", page << YUZU_PAGEBITS); | 1510 | ASSERT_MSG(false, "Unregistering unregistered page=0x{:x}", page << YUZU_PAGEBITS); |
diff --git a/src/video_core/textures/astc.cpp b/src/video_core/textures/astc.cpp index 15b9d4182..69a32819a 100644 --- a/src/video_core/textures/astc.cpp +++ b/src/video_core/textures/astc.cpp | |||
| @@ -1661,8 +1661,8 @@ void Decompress(std::span<const uint8_t> data, uint32_t width, uint32_t height, | |||
| 1661 | for (u32 z = 0; z < depth; ++z) { | 1661 | for (u32 z = 0; z < depth; ++z) { |
| 1662 | const u32 depth_offset = z * height * width * 4; | 1662 | const u32 depth_offset = z * height * width * 4; |
| 1663 | for (u32 y_index = 0; y_index < rows; ++y_index) { | 1663 | for (u32 y_index = 0; y_index < rows; ++y_index) { |
| 1664 | auto decompress_stride = [data, width, height, depth, block_width, block_height, output, | 1664 | auto decompress_stride = [data, width, height, block_width, block_height, output, rows, |
| 1665 | rows, cols, z, depth_offset, y_index] { | 1665 | cols, z, depth_offset, y_index] { |
| 1666 | const u32 y = y_index * block_height; | 1666 | const u32 y = y_index * block_height; |
| 1667 | for (u32 x_index = 0; x_index < cols; ++x_index) { | 1667 | for (u32 x_index = 0; x_index < cols; ++x_index) { |
| 1668 | const u32 block_index = (z * rows * cols) + (y_index * cols) + x_index; | 1668 | const u32 block_index = (z * rows * cols) + (y_index * cols) + x_index; |
diff --git a/src/video_core/textures/decoders.cpp b/src/video_core/textures/decoders.cpp index 52d067a2d..fd1a4b987 100644 --- a/src/video_core/textures/decoders.cpp +++ b/src/video_core/textures/decoders.cpp | |||
| @@ -21,7 +21,7 @@ constexpr u32 pdep(u32 value) { | |||
| 21 | u32 m = mask; | 21 | u32 m = mask; |
| 22 | for (u32 bit = 1; m; bit += bit) { | 22 | for (u32 bit = 1; m; bit += bit) { |
| 23 | if (value & bit) | 23 | if (value & bit) |
| 24 | result |= m & -m; | 24 | result |= m & (~m + 1); |
| 25 | m &= m - 1; | 25 | m &= m - 1; |
| 26 | } | 26 | } |
| 27 | return result; | 27 | return result; |
diff --git a/src/yuzu/multiplayer/state.cpp b/src/yuzu/multiplayer/state.cpp index ae2738ad4..285bb150d 100644 --- a/src/yuzu/multiplayer/state.cpp +++ b/src/yuzu/multiplayer/state.cpp | |||
| @@ -268,7 +268,7 @@ bool MultiplayerState::OnCloseRoom() { | |||
| 268 | return true; | 268 | return true; |
| 269 | } | 269 | } |
| 270 | // Save ban list | 270 | // Save ban list |
| 271 | UISettings::values.multiplayer_ban_list = std::move(room->GetBanList()); | 271 | UISettings::values.multiplayer_ban_list = room->GetBanList(); |
| 272 | 272 | ||
| 273 | room->Destroy(); | 273 | room->Destroy(); |
| 274 | announce_multiplayer_session->Stop(); | 274 | announce_multiplayer_session->Stop(); |
diff --git a/src/yuzu/startup_checks.cpp b/src/yuzu/startup_checks.cpp index fc2693f9d..6a91212e2 100644 --- a/src/yuzu/startup_checks.cpp +++ b/src/yuzu/startup_checks.cpp | |||
| @@ -49,7 +49,7 @@ bool CheckEnvVars(bool* is_child) { | |||
| 49 | *is_child = true; | 49 | *is_child = true; |
| 50 | return false; | 50 | return false; |
| 51 | } else if (!SetEnvironmentVariableA(IS_CHILD_ENV_VAR, ENV_VAR_ENABLED_TEXT)) { | 51 | } else if (!SetEnvironmentVariableA(IS_CHILD_ENV_VAR, ENV_VAR_ENABLED_TEXT)) { |
| 52 | std::fprintf(stderr, "SetEnvironmentVariableA failed to set %s with error %d\n", | 52 | std::fprintf(stderr, "SetEnvironmentVariableA failed to set %s with error %lu\n", |
| 53 | IS_CHILD_ENV_VAR, GetLastError()); | 53 | IS_CHILD_ENV_VAR, GetLastError()); |
| 54 | return true; | 54 | return true; |
| 55 | } | 55 | } |
| @@ -62,7 +62,7 @@ bool StartupChecks(const char* arg0, bool* has_broken_vulkan, bool perform_vulka | |||
| 62 | // Set the startup variable for child processes | 62 | // Set the startup variable for child processes |
| 63 | const bool env_var_set = SetEnvironmentVariableA(STARTUP_CHECK_ENV_VAR, ENV_VAR_ENABLED_TEXT); | 63 | const bool env_var_set = SetEnvironmentVariableA(STARTUP_CHECK_ENV_VAR, ENV_VAR_ENABLED_TEXT); |
| 64 | if (!env_var_set) { | 64 | if (!env_var_set) { |
| 65 | std::fprintf(stderr, "SetEnvironmentVariableA failed to set %s with error %d\n", | 65 | std::fprintf(stderr, "SetEnvironmentVariableA failed to set %s with error %lu\n", |
| 66 | STARTUP_CHECK_ENV_VAR, GetLastError()); | 66 | STARTUP_CHECK_ENV_VAR, GetLastError()); |
| 67 | return false; | 67 | return false; |
| 68 | } | 68 | } |
| @@ -81,22 +81,22 @@ bool StartupChecks(const char* arg0, bool* has_broken_vulkan, bool perform_vulka | |||
| 81 | DWORD exit_code = STILL_ACTIVE; | 81 | DWORD exit_code = STILL_ACTIVE; |
| 82 | const int err = GetExitCodeProcess(process_info.hProcess, &exit_code); | 82 | const int err = GetExitCodeProcess(process_info.hProcess, &exit_code); |
| 83 | if (err == 0) { | 83 | if (err == 0) { |
| 84 | std::fprintf(stderr, "GetExitCodeProcess failed with error %d\n", GetLastError()); | 84 | std::fprintf(stderr, "GetExitCodeProcess failed with error %lu\n", GetLastError()); |
| 85 | } | 85 | } |
| 86 | 86 | ||
| 87 | // Vulkan is broken if the child crashed (return value is not zero) | 87 | // Vulkan is broken if the child crashed (return value is not zero) |
| 88 | *has_broken_vulkan = (exit_code != 0); | 88 | *has_broken_vulkan = (exit_code != 0); |
| 89 | 89 | ||
| 90 | if (CloseHandle(process_info.hProcess) == 0) { | 90 | if (CloseHandle(process_info.hProcess) == 0) { |
| 91 | std::fprintf(stderr, "CloseHandle failed with error %d\n", GetLastError()); | 91 | std::fprintf(stderr, "CloseHandle failed with error %lu\n", GetLastError()); |
| 92 | } | 92 | } |
| 93 | if (CloseHandle(process_info.hThread) == 0) { | 93 | if (CloseHandle(process_info.hThread) == 0) { |
| 94 | std::fprintf(stderr, "CloseHandle failed with error %d\n", GetLastError()); | 94 | std::fprintf(stderr, "CloseHandle failed with error %lu\n", GetLastError()); |
| 95 | } | 95 | } |
| 96 | } | 96 | } |
| 97 | 97 | ||
| 98 | if (!SetEnvironmentVariableA(STARTUP_CHECK_ENV_VAR, nullptr)) { | 98 | if (!SetEnvironmentVariableA(STARTUP_CHECK_ENV_VAR, nullptr)) { |
| 99 | std::fprintf(stderr, "SetEnvironmentVariableA failed to clear %s with error %d\n", | 99 | std::fprintf(stderr, "SetEnvironmentVariableA failed to clear %s with error %lu\n", |
| 100 | STARTUP_CHECK_ENV_VAR, GetLastError()); | 100 | STARTUP_CHECK_ENV_VAR, GetLastError()); |
| 101 | } | 101 | } |
| 102 | 102 | ||
| @@ -135,7 +135,8 @@ bool SpawnChild(const char* arg0, PROCESS_INFORMATION* pi, int flags) { | |||
| 135 | startup_info.cb = sizeof(startup_info); | 135 | startup_info.cb = sizeof(startup_info); |
| 136 | 136 | ||
| 137 | char p_name[255]; | 137 | char p_name[255]; |
| 138 | std::strncpy(p_name, arg0, 255); | 138 | std::strncpy(p_name, arg0, 254); |
| 139 | p_name[254] = '\0'; | ||
| 139 | 140 | ||
| 140 | const bool process_created = CreateProcessA(nullptr, // lpApplicationName | 141 | const bool process_created = CreateProcessA(nullptr, // lpApplicationName |
| 141 | p_name, // lpCommandLine | 142 | p_name, // lpCommandLine |
| @@ -149,7 +150,7 @@ bool SpawnChild(const char* arg0, PROCESS_INFORMATION* pi, int flags) { | |||
| 149 | pi // lpProcessInformation | 150 | pi // lpProcessInformation |
| 150 | ); | 151 | ); |
| 151 | if (!process_created) { | 152 | if (!process_created) { |
| 152 | std::fprintf(stderr, "CreateProcessA failed with error %d\n", GetLastError()); | 153 | std::fprintf(stderr, "CreateProcessA failed with error %lu\n", GetLastError()); |
| 153 | return false; | 154 | return false; |
| 154 | } | 155 | } |
| 155 | 156 | ||