diff options
Diffstat (limited to 'src/common')
37 files changed, 700 insertions, 701 deletions
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index 5d54516eb..2c2bd2ee8 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt | |||
| @@ -102,7 +102,9 @@ add_library(common STATIC | |||
| 102 | atomic_ops.h | 102 | atomic_ops.h |
| 103 | detached_tasks.cpp | 103 | detached_tasks.cpp |
| 104 | detached_tasks.h | 104 | detached_tasks.h |
| 105 | bit_cast.h | ||
| 105 | bit_field.h | 106 | bit_field.h |
| 107 | bit_set.h | ||
| 106 | bit_util.h | 108 | bit_util.h |
| 107 | cityhash.cpp | 109 | cityhash.cpp |
| 108 | cityhash.h | 110 | cityhash.h |
| @@ -111,6 +113,7 @@ add_library(common STATIC | |||
| 111 | common_paths.h | 113 | common_paths.h |
| 112 | common_types.h | 114 | common_types.h |
| 113 | concepts.h | 115 | concepts.h |
| 116 | div_ceil.h | ||
| 114 | dynamic_library.cpp | 117 | dynamic_library.cpp |
| 115 | dynamic_library.h | 118 | dynamic_library.h |
| 116 | fiber.cpp | 119 | fiber.cpp |
| @@ -132,13 +135,10 @@ add_library(common STATIC | |||
| 132 | math_util.h | 135 | math_util.h |
| 133 | memory_detect.cpp | 136 | memory_detect.cpp |
| 134 | memory_detect.h | 137 | memory_detect.h |
| 135 | memory_hook.cpp | ||
| 136 | memory_hook.h | ||
| 137 | microprofile.cpp | 138 | microprofile.cpp |
| 138 | microprofile.h | 139 | microprofile.h |
| 139 | microprofileui.h | 140 | microprofileui.h |
| 140 | misc.cpp | 141 | misc.cpp |
| 141 | multi_level_queue.h | ||
| 142 | page_table.cpp | 142 | page_table.cpp |
| 143 | page_table.h | 143 | page_table.h |
| 144 | param_package.cpp | 144 | param_package.cpp |
| @@ -150,6 +150,8 @@ add_library(common STATIC | |||
| 150 | scope_exit.h | 150 | scope_exit.h |
| 151 | spin_lock.cpp | 151 | spin_lock.cpp |
| 152 | spin_lock.h | 152 | spin_lock.h |
| 153 | stream.cpp | ||
| 154 | stream.h | ||
| 153 | string_util.cpp | 155 | string_util.cpp |
| 154 | string_util.h | 156 | string_util.h |
| 155 | swap.h | 157 | swap.h |
| @@ -158,6 +160,8 @@ add_library(common STATIC | |||
| 158 | thread.cpp | 160 | thread.cpp |
| 159 | thread.h | 161 | thread.h |
| 160 | thread_queue_list.h | 162 | thread_queue_list.h |
| 163 | thread_worker.cpp | ||
| 164 | thread_worker.h | ||
| 161 | threadsafe_queue.h | 165 | threadsafe_queue.h |
| 162 | time_zone.cpp | 166 | time_zone.cpp |
| 163 | time_zone.h | 167 | time_zone.h |
| @@ -188,8 +192,28 @@ if(ARCHITECTURE_x86_64) | |||
| 188 | ) | 192 | ) |
| 189 | endif() | 193 | endif() |
| 190 | 194 | ||
| 195 | if (MSVC) | ||
| 196 | target_compile_definitions(common PRIVATE | ||
| 197 | # The standard library doesn't provide any replacement for codecvt yet | ||
| 198 | # so we can disable this deprecation warning for the time being. | ||
| 199 | _SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING | ||
| 200 | ) | ||
| 201 | target_compile_options(common PRIVATE | ||
| 202 | /W4 | ||
| 203 | /WX | ||
| 204 | ) | ||
| 205 | else() | ||
| 206 | target_compile_options(common PRIVATE | ||
| 207 | -Werror | ||
| 208 | ) | ||
| 209 | endif() | ||
| 210 | |||
| 191 | create_target_directory_groups(common) | 211 | create_target_directory_groups(common) |
| 192 | find_package(Boost 1.71 COMPONENTS context headers REQUIRED) | ||
| 193 | 212 | ||
| 194 | target_link_libraries(common PUBLIC ${Boost_LIBRARIES} fmt::fmt microprofile) | 213 | target_link_libraries(common PUBLIC ${Boost_LIBRARIES} fmt::fmt microprofile) |
| 195 | target_link_libraries(common PRIVATE lz4::lz4 zstd::zstd xbyak) | 214 | target_link_libraries(common PRIVATE lz4::lz4 xbyak) |
| 215 | if (MSVC) | ||
| 216 | target_link_libraries(common PRIVATE zstd::zstd) | ||
| 217 | else() | ||
| 218 | target_link_libraries(common PRIVATE zstd) | ||
| 219 | endif() | ||
diff --git a/src/common/bit_cast.h b/src/common/bit_cast.h new file mode 100644 index 000000000..a32a063d1 --- /dev/null +++ b/src/common/bit_cast.h | |||
| @@ -0,0 +1,22 @@ | |||
| 1 | // Copyright 2020 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <cstring> | ||
| 8 | #include <type_traits> | ||
| 9 | |||
| 10 | namespace Common { | ||
| 11 | |||
| 12 | template <typename To, typename From> | ||
| 13 | [[nodiscard]] std::enable_if_t<sizeof(To) == sizeof(From) && std::is_trivially_copyable_v<From> && | ||
| 14 | std::is_trivially_copyable_v<To>, | ||
| 15 | To> | ||
| 16 | BitCast(const From& src) noexcept { | ||
| 17 | To dst; | ||
| 18 | std::memcpy(&dst, &src, sizeof(To)); | ||
| 19 | return dst; | ||
| 20 | } | ||
| 21 | |||
| 22 | } // namespace Common | ||
diff --git a/src/common/bit_set.h b/src/common/bit_set.h new file mode 100644 index 000000000..9235ad412 --- /dev/null +++ b/src/common/bit_set.h | |||
| @@ -0,0 +1,99 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2018-2020 Atmosphère-NX | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify it | ||
| 5 | * under the terms and conditions of the GNU General Public License, | ||
| 6 | * version 2, as published by the Free Software Foundation. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
| 9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
| 10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
| 11 | * more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | |||
| 17 | #pragma once | ||
| 18 | |||
| 19 | #include <array> | ||
| 20 | #include <bit> | ||
| 21 | |||
| 22 | #include "common/alignment.h" | ||
| 23 | #include "common/bit_util.h" | ||
| 24 | #include "common/common_types.h" | ||
| 25 | |||
| 26 | namespace Common { | ||
| 27 | |||
| 28 | namespace impl { | ||
| 29 | |||
| 30 | template <typename Storage, size_t N> | ||
| 31 | class BitSet { | ||
| 32 | |||
| 33 | public: | ||
| 34 | constexpr BitSet() = default; | ||
| 35 | |||
| 36 | constexpr void SetBit(size_t i) { | ||
| 37 | this->words[i / FlagsPerWord] |= GetBitMask(i % FlagsPerWord); | ||
| 38 | } | ||
| 39 | |||
| 40 | constexpr void ClearBit(size_t i) { | ||
| 41 | this->words[i / FlagsPerWord] &= ~GetBitMask(i % FlagsPerWord); | ||
| 42 | } | ||
| 43 | |||
| 44 | constexpr size_t CountLeadingZero() const { | ||
| 45 | for (size_t i = 0; i < NumWords; i++) { | ||
| 46 | if (this->words[i]) { | ||
| 47 | return FlagsPerWord * i + CountLeadingZeroImpl(this->words[i]); | ||
| 48 | } | ||
| 49 | } | ||
| 50 | return FlagsPerWord * NumWords; | ||
| 51 | } | ||
| 52 | |||
| 53 | constexpr size_t GetNextSet(size_t n) const { | ||
| 54 | for (size_t i = (n + 1) / FlagsPerWord; i < NumWords; i++) { | ||
| 55 | Storage word = this->words[i]; | ||
| 56 | if (!IsAligned(n + 1, FlagsPerWord)) { | ||
| 57 | word &= GetBitMask(n % FlagsPerWord) - 1; | ||
| 58 | } | ||
| 59 | if (word) { | ||
| 60 | return FlagsPerWord * i + CountLeadingZeroImpl(word); | ||
| 61 | } | ||
| 62 | } | ||
| 63 | return FlagsPerWord * NumWords; | ||
| 64 | } | ||
| 65 | |||
| 66 | private: | ||
| 67 | static_assert(std::is_unsigned_v<Storage>); | ||
| 68 | static_assert(sizeof(Storage) <= sizeof(u64)); | ||
| 69 | |||
| 70 | static constexpr size_t FlagsPerWord = BitSize<Storage>(); | ||
| 71 | static constexpr size_t NumWords = AlignUp(N, FlagsPerWord) / FlagsPerWord; | ||
| 72 | |||
| 73 | static constexpr auto CountLeadingZeroImpl(Storage word) { | ||
| 74 | return std::countl_zero(static_cast<unsigned long long>(word)) - | ||
| 75 | (BitSize<unsigned long long>() - FlagsPerWord); | ||
| 76 | } | ||
| 77 | |||
| 78 | static constexpr Storage GetBitMask(size_t bit) { | ||
| 79 | return Storage(1) << (FlagsPerWord - 1 - bit); | ||
| 80 | } | ||
| 81 | |||
| 82 | std::array<Storage, NumWords> words{}; | ||
| 83 | }; | ||
| 84 | |||
| 85 | } // namespace impl | ||
| 86 | |||
| 87 | template <size_t N> | ||
| 88 | using BitSet8 = impl::BitSet<u8, N>; | ||
| 89 | |||
| 90 | template <size_t N> | ||
| 91 | using BitSet16 = impl::BitSet<u16, N>; | ||
| 92 | |||
| 93 | template <size_t N> | ||
| 94 | using BitSet32 = impl::BitSet<u32, N>; | ||
| 95 | |||
| 96 | template <size_t N> | ||
| 97 | using BitSet64 = impl::BitSet<u64, N>; | ||
| 98 | |||
| 99 | } // namespace Common | ||
diff --git a/src/common/concepts.h b/src/common/concepts.h index 5bef3ad67..aa08065a7 100644 --- a/src/common/concepts.h +++ b/src/common/concepts.h | |||
| @@ -31,4 +31,8 @@ concept DerivedFrom = requires { | |||
| 31 | std::is_convertible_v<const volatile Derived*, const volatile Base*>; | 31 | std::is_convertible_v<const volatile Derived*, const volatile Base*>; |
| 32 | }; | 32 | }; |
| 33 | 33 | ||
| 34 | // TODO: Replace with std::convertible_to when libc++ implements it. | ||
| 35 | template <typename From, typename To> | ||
| 36 | concept ConvertibleTo = std::is_convertible_v<From, To>; | ||
| 37 | |||
| 34 | } // namespace Common | 38 | } // namespace Common |
diff --git a/src/common/div_ceil.h b/src/common/div_ceil.h new file mode 100644 index 000000000..95e1489a9 --- /dev/null +++ b/src/common/div_ceil.h | |||
| @@ -0,0 +1,26 @@ | |||
| 1 | // Copyright 2020 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <cstddef> | ||
| 8 | #include <type_traits> | ||
| 9 | |||
| 10 | namespace Common { | ||
| 11 | |||
| 12 | /// Ceiled integer division. | ||
| 13 | template <typename N, typename D> | ||
| 14 | requires std::is_integral_v<N>&& std::is_unsigned_v<D>[[nodiscard]] constexpr N DivCeil(N number, | ||
| 15 | D divisor) { | ||
| 16 | return static_cast<N>((static_cast<D>(number) + divisor - 1) / divisor); | ||
| 17 | } | ||
| 18 | |||
| 19 | /// Ceiled integer division with logarithmic divisor in base 2 | ||
| 20 | template <typename N, typename D> | ||
| 21 | requires std::is_integral_v<N>&& std::is_unsigned_v<D>[[nodiscard]] constexpr N DivCeilLog2( | ||
| 22 | N value, D alignment_log2) { | ||
| 23 | return static_cast<N>((static_cast<D>(value) + (D(1) << alignment_log2) - 1) >> alignment_log2); | ||
| 24 | } | ||
| 25 | |||
| 26 | } // namespace Common | ||
diff --git a/src/common/fiber.cpp b/src/common/fiber.cpp index 1c1d09ccb..3c1eefcb7 100644 --- a/src/common/fiber.cpp +++ b/src/common/fiber.cpp | |||
| @@ -4,129 +4,51 @@ | |||
| 4 | 4 | ||
| 5 | #include "common/assert.h" | 5 | #include "common/assert.h" |
| 6 | #include "common/fiber.h" | 6 | #include "common/fiber.h" |
| 7 | #if defined(_WIN32) || defined(WIN32) | 7 | #include "common/spin_lock.h" |
| 8 | #include <windows.h> | 8 | #include "common/virtual_buffer.h" |
| 9 | #else | 9 | |
| 10 | #include <boost/context/detail/fcontext.hpp> | 10 | #include <boost/context/detail/fcontext.hpp> |
| 11 | #endif | ||
| 12 | 11 | ||
| 13 | namespace Common { | 12 | namespace Common { |
| 14 | 13 | ||
| 15 | constexpr std::size_t default_stack_size = 256 * 1024; // 256kb | 14 | constexpr std::size_t default_stack_size = 256 * 1024; |
| 16 | |||
| 17 | #if defined(_WIN32) || defined(WIN32) | ||
| 18 | 15 | ||
| 19 | struct Fiber::FiberImpl { | 16 | struct Fiber::FiberImpl { |
| 20 | LPVOID handle = nullptr; | 17 | FiberImpl() : stack{default_stack_size}, rewind_stack{default_stack_size} {} |
| 21 | LPVOID rewind_handle = nullptr; | 18 | |
| 19 | VirtualBuffer<u8> stack; | ||
| 20 | VirtualBuffer<u8> rewind_stack; | ||
| 21 | |||
| 22 | SpinLock guard{}; | ||
| 23 | std::function<void(void*)> entry_point; | ||
| 24 | std::function<void(void*)> rewind_point; | ||
| 25 | void* rewind_parameter{}; | ||
| 26 | void* start_parameter{}; | ||
| 27 | std::shared_ptr<Fiber> previous_fiber; | ||
| 28 | bool is_thread_fiber{}; | ||
| 29 | bool released{}; | ||
| 30 | |||
| 31 | u8* stack_limit{}; | ||
| 32 | u8* rewind_stack_limit{}; | ||
| 33 | boost::context::detail::fcontext_t context{}; | ||
| 34 | boost::context::detail::fcontext_t rewind_context{}; | ||
| 22 | }; | 35 | }; |
| 23 | 36 | ||
| 24 | void Fiber::Start() { | 37 | void Fiber::SetStartParameter(void* new_parameter) { |
| 25 | ASSERT(previous_fiber != nullptr); | 38 | impl->start_parameter = new_parameter; |
| 26 | previous_fiber->guard.unlock(); | ||
| 27 | previous_fiber.reset(); | ||
| 28 | entry_point(start_parameter); | ||
| 29 | UNREACHABLE(); | ||
| 30 | } | ||
| 31 | |||
| 32 | void Fiber::OnRewind() { | ||
| 33 | ASSERT(impl->handle != nullptr); | ||
| 34 | DeleteFiber(impl->handle); | ||
| 35 | impl->handle = impl->rewind_handle; | ||
| 36 | impl->rewind_handle = nullptr; | ||
| 37 | rewind_point(rewind_parameter); | ||
| 38 | UNREACHABLE(); | ||
| 39 | } | ||
| 40 | |||
| 41 | void Fiber::FiberStartFunc(void* fiber_parameter) { | ||
| 42 | auto fiber = static_cast<Fiber*>(fiber_parameter); | ||
| 43 | fiber->Start(); | ||
| 44 | } | ||
| 45 | |||
| 46 | void Fiber::RewindStartFunc(void* fiber_parameter) { | ||
| 47 | auto fiber = static_cast<Fiber*>(fiber_parameter); | ||
| 48 | fiber->OnRewind(); | ||
| 49 | } | ||
| 50 | |||
| 51 | Fiber::Fiber(std::function<void(void*)>&& entry_point_func, void* start_parameter) | ||
| 52 | : entry_point{std::move(entry_point_func)}, start_parameter{start_parameter} { | ||
| 53 | impl = std::make_unique<FiberImpl>(); | ||
| 54 | impl->handle = CreateFiber(default_stack_size, &FiberStartFunc, this); | ||
| 55 | } | ||
| 56 | |||
| 57 | Fiber::Fiber() : impl{std::make_unique<FiberImpl>()} {} | ||
| 58 | |||
| 59 | Fiber::~Fiber() { | ||
| 60 | if (released) { | ||
| 61 | return; | ||
| 62 | } | ||
| 63 | // Make sure the Fiber is not being used | ||
| 64 | const bool locked = guard.try_lock(); | ||
| 65 | ASSERT_MSG(locked, "Destroying a fiber that's still running"); | ||
| 66 | if (locked) { | ||
| 67 | guard.unlock(); | ||
| 68 | } | ||
| 69 | DeleteFiber(impl->handle); | ||
| 70 | } | ||
| 71 | |||
| 72 | void Fiber::Exit() { | ||
| 73 | ASSERT_MSG(is_thread_fiber, "Exitting non main thread fiber"); | ||
| 74 | if (!is_thread_fiber) { | ||
| 75 | return; | ||
| 76 | } | ||
| 77 | ConvertFiberToThread(); | ||
| 78 | guard.unlock(); | ||
| 79 | released = true; | ||
| 80 | } | ||
| 81 | |||
| 82 | void Fiber::SetRewindPoint(std::function<void(void*)>&& rewind_func, void* start_parameter) { | ||
| 83 | rewind_point = std::move(rewind_func); | ||
| 84 | rewind_parameter = start_parameter; | ||
| 85 | } | ||
| 86 | |||
| 87 | void Fiber::Rewind() { | ||
| 88 | ASSERT(rewind_point); | ||
| 89 | ASSERT(impl->rewind_handle == nullptr); | ||
| 90 | impl->rewind_handle = CreateFiber(default_stack_size, &RewindStartFunc, this); | ||
| 91 | SwitchToFiber(impl->rewind_handle); | ||
| 92 | } | ||
| 93 | |||
| 94 | void Fiber::YieldTo(std::shared_ptr<Fiber>& from, std::shared_ptr<Fiber>& to) { | ||
| 95 | ASSERT_MSG(from != nullptr, "Yielding fiber is null!"); | ||
| 96 | ASSERT_MSG(to != nullptr, "Next fiber is null!"); | ||
| 97 | to->guard.lock(); | ||
| 98 | to->previous_fiber = from; | ||
| 99 | SwitchToFiber(to->impl->handle); | ||
| 100 | ASSERT(from->previous_fiber != nullptr); | ||
| 101 | from->previous_fiber->guard.unlock(); | ||
| 102 | from->previous_fiber.reset(); | ||
| 103 | } | 39 | } |
| 104 | 40 | ||
| 105 | std::shared_ptr<Fiber> Fiber::ThreadToFiber() { | 41 | void Fiber::SetRewindPoint(std::function<void(void*)>&& rewind_func, void* rewind_param) { |
| 106 | std::shared_ptr<Fiber> fiber = std::shared_ptr<Fiber>{new Fiber()}; | 42 | impl->rewind_point = std::move(rewind_func); |
| 107 | fiber->guard.lock(); | 43 | impl->rewind_parameter = rewind_param; |
| 108 | fiber->impl->handle = ConvertThreadToFiber(nullptr); | ||
| 109 | fiber->is_thread_fiber = true; | ||
| 110 | return fiber; | ||
| 111 | } | 44 | } |
| 112 | 45 | ||
| 113 | #else | ||
| 114 | |||
| 115 | struct Fiber::FiberImpl { | ||
| 116 | alignas(64) std::array<u8, default_stack_size> stack; | ||
| 117 | alignas(64) std::array<u8, default_stack_size> rewind_stack; | ||
| 118 | u8* stack_limit; | ||
| 119 | u8* rewind_stack_limit; | ||
| 120 | boost::context::detail::fcontext_t context; | ||
| 121 | boost::context::detail::fcontext_t rewind_context; | ||
| 122 | }; | ||
| 123 | |||
| 124 | void Fiber::Start(boost::context::detail::transfer_t& transfer) { | 46 | void Fiber::Start(boost::context::detail::transfer_t& transfer) { |
| 125 | ASSERT(previous_fiber != nullptr); | 47 | ASSERT(impl->previous_fiber != nullptr); |
| 126 | previous_fiber->impl->context = transfer.fctx; | 48 | impl->previous_fiber->impl->context = transfer.fctx; |
| 127 | previous_fiber->guard.unlock(); | 49 | impl->previous_fiber->impl->guard.unlock(); |
| 128 | previous_fiber.reset(); | 50 | impl->previous_fiber.reset(); |
| 129 | entry_point(start_parameter); | 51 | impl->entry_point(impl->start_parameter); |
| 130 | UNREACHABLE(); | 52 | UNREACHABLE(); |
| 131 | } | 53 | } |
| 132 | 54 | ||
| @@ -137,23 +59,24 @@ void Fiber::OnRewind([[maybe_unused]] boost::context::detail::transfer_t& transf | |||
| 137 | u8* tmp = impl->stack_limit; | 59 | u8* tmp = impl->stack_limit; |
| 138 | impl->stack_limit = impl->rewind_stack_limit; | 60 | impl->stack_limit = impl->rewind_stack_limit; |
| 139 | impl->rewind_stack_limit = tmp; | 61 | impl->rewind_stack_limit = tmp; |
| 140 | rewind_point(rewind_parameter); | 62 | impl->rewind_point(impl->rewind_parameter); |
| 141 | UNREACHABLE(); | 63 | UNREACHABLE(); |
| 142 | } | 64 | } |
| 143 | 65 | ||
| 144 | void Fiber::FiberStartFunc(boost::context::detail::transfer_t transfer) { | 66 | void Fiber::FiberStartFunc(boost::context::detail::transfer_t transfer) { |
| 145 | auto fiber = static_cast<Fiber*>(transfer.data); | 67 | auto* fiber = static_cast<Fiber*>(transfer.data); |
| 146 | fiber->Start(transfer); | 68 | fiber->Start(transfer); |
| 147 | } | 69 | } |
| 148 | 70 | ||
| 149 | void Fiber::RewindStartFunc(boost::context::detail::transfer_t transfer) { | 71 | void Fiber::RewindStartFunc(boost::context::detail::transfer_t transfer) { |
| 150 | auto fiber = static_cast<Fiber*>(transfer.data); | 72 | auto* fiber = static_cast<Fiber*>(transfer.data); |
| 151 | fiber->OnRewind(transfer); | 73 | fiber->OnRewind(transfer); |
| 152 | } | 74 | } |
| 153 | 75 | ||
| 154 | Fiber::Fiber(std::function<void(void*)>&& entry_point_func, void* start_parameter) | 76 | Fiber::Fiber(std::function<void(void*)>&& entry_point_func, void* start_parameter) |
| 155 | : entry_point{std::move(entry_point_func)}, start_parameter{start_parameter} { | 77 | : impl{std::make_unique<FiberImpl>()} { |
| 156 | impl = std::make_unique<FiberImpl>(); | 78 | impl->entry_point = std::move(entry_point_func); |
| 79 | impl->start_parameter = start_parameter; | ||
| 157 | impl->stack_limit = impl->stack.data(); | 80 | impl->stack_limit = impl->stack.data(); |
| 158 | impl->rewind_stack_limit = impl->rewind_stack.data(); | 81 | impl->rewind_stack_limit = impl->rewind_stack.data(); |
| 159 | u8* stack_base = impl->stack_limit + default_stack_size; | 82 | u8* stack_base = impl->stack_limit + default_stack_size; |
| @@ -161,37 +84,31 @@ Fiber::Fiber(std::function<void(void*)>&& entry_point_func, void* start_paramete | |||
| 161 | boost::context::detail::make_fcontext(stack_base, impl->stack.size(), FiberStartFunc); | 84 | boost::context::detail::make_fcontext(stack_base, impl->stack.size(), FiberStartFunc); |
| 162 | } | 85 | } |
| 163 | 86 | ||
| 164 | void Fiber::SetRewindPoint(std::function<void(void*)>&& rewind_func, void* start_parameter) { | ||
| 165 | rewind_point = std::move(rewind_func); | ||
| 166 | rewind_parameter = start_parameter; | ||
| 167 | } | ||
| 168 | |||
| 169 | Fiber::Fiber() : impl{std::make_unique<FiberImpl>()} {} | 87 | Fiber::Fiber() : impl{std::make_unique<FiberImpl>()} {} |
| 170 | 88 | ||
| 171 | Fiber::~Fiber() { | 89 | Fiber::~Fiber() { |
| 172 | if (released) { | 90 | if (impl->released) { |
| 173 | return; | 91 | return; |
| 174 | } | 92 | } |
| 175 | // Make sure the Fiber is not being used | 93 | // Make sure the Fiber is not being used |
| 176 | const bool locked = guard.try_lock(); | 94 | const bool locked = impl->guard.try_lock(); |
| 177 | ASSERT_MSG(locked, "Destroying a fiber that's still running"); | 95 | ASSERT_MSG(locked, "Destroying a fiber that's still running"); |
| 178 | if (locked) { | 96 | if (locked) { |
| 179 | guard.unlock(); | 97 | impl->guard.unlock(); |
| 180 | } | 98 | } |
| 181 | } | 99 | } |
| 182 | 100 | ||
| 183 | void Fiber::Exit() { | 101 | void Fiber::Exit() { |
| 184 | 102 | ASSERT_MSG(impl->is_thread_fiber, "Exitting non main thread fiber"); | |
| 185 | ASSERT_MSG(is_thread_fiber, "Exitting non main thread fiber"); | 103 | if (!impl->is_thread_fiber) { |
| 186 | if (!is_thread_fiber) { | ||
| 187 | return; | 104 | return; |
| 188 | } | 105 | } |
| 189 | guard.unlock(); | 106 | impl->guard.unlock(); |
| 190 | released = true; | 107 | impl->released = true; |
| 191 | } | 108 | } |
| 192 | 109 | ||
| 193 | void Fiber::Rewind() { | 110 | void Fiber::Rewind() { |
| 194 | ASSERT(rewind_point); | 111 | ASSERT(impl->rewind_point); |
| 195 | ASSERT(impl->rewind_context == nullptr); | 112 | ASSERT(impl->rewind_context == nullptr); |
| 196 | u8* stack_base = impl->rewind_stack_limit + default_stack_size; | 113 | u8* stack_base = impl->rewind_stack_limit + default_stack_size; |
| 197 | impl->rewind_context = | 114 | impl->rewind_context = |
| @@ -199,24 +116,23 @@ void Fiber::Rewind() { | |||
| 199 | boost::context::detail::jump_fcontext(impl->rewind_context, this); | 116 | boost::context::detail::jump_fcontext(impl->rewind_context, this); |
| 200 | } | 117 | } |
| 201 | 118 | ||
| 202 | void Fiber::YieldTo(std::shared_ptr<Fiber>& from, std::shared_ptr<Fiber>& to) { | 119 | void Fiber::YieldTo(std::shared_ptr<Fiber> from, std::shared_ptr<Fiber> to) { |
| 203 | ASSERT_MSG(from != nullptr, "Yielding fiber is null!"); | 120 | ASSERT_MSG(from != nullptr, "Yielding fiber is null!"); |
| 204 | ASSERT_MSG(to != nullptr, "Next fiber is null!"); | 121 | ASSERT_MSG(to != nullptr, "Next fiber is null!"); |
| 205 | to->guard.lock(); | 122 | to->impl->guard.lock(); |
| 206 | to->previous_fiber = from; | 123 | to->impl->previous_fiber = from; |
| 207 | auto transfer = boost::context::detail::jump_fcontext(to->impl->context, to.get()); | 124 | auto transfer = boost::context::detail::jump_fcontext(to->impl->context, to.get()); |
| 208 | ASSERT(from->previous_fiber != nullptr); | 125 | ASSERT(from->impl->previous_fiber != nullptr); |
| 209 | from->previous_fiber->impl->context = transfer.fctx; | 126 | from->impl->previous_fiber->impl->context = transfer.fctx; |
| 210 | from->previous_fiber->guard.unlock(); | 127 | from->impl->previous_fiber->impl->guard.unlock(); |
| 211 | from->previous_fiber.reset(); | 128 | from->impl->previous_fiber.reset(); |
| 212 | } | 129 | } |
| 213 | 130 | ||
| 214 | std::shared_ptr<Fiber> Fiber::ThreadToFiber() { | 131 | std::shared_ptr<Fiber> Fiber::ThreadToFiber() { |
| 215 | std::shared_ptr<Fiber> fiber = std::shared_ptr<Fiber>{new Fiber()}; | 132 | std::shared_ptr<Fiber> fiber = std::shared_ptr<Fiber>{new Fiber()}; |
| 216 | fiber->guard.lock(); | 133 | fiber->impl->guard.lock(); |
| 217 | fiber->is_thread_fiber = true; | 134 | fiber->impl->is_thread_fiber = true; |
| 218 | return fiber; | 135 | return fiber; |
| 219 | } | 136 | } |
| 220 | 137 | ||
| 221 | #endif | ||
| 222 | } // namespace Common | 138 | } // namespace Common |
diff --git a/src/common/fiber.h b/src/common/fiber.h index 89dde5e36..f7f587f8c 100644 --- a/src/common/fiber.h +++ b/src/common/fiber.h | |||
| @@ -7,14 +7,9 @@ | |||
| 7 | #include <functional> | 7 | #include <functional> |
| 8 | #include <memory> | 8 | #include <memory> |
| 9 | 9 | ||
| 10 | #include "common/common_types.h" | ||
| 11 | #include "common/spin_lock.h" | ||
| 12 | |||
| 13 | #if !defined(_WIN32) && !defined(WIN32) | ||
| 14 | namespace boost::context::detail { | 10 | namespace boost::context::detail { |
| 15 | struct transfer_t; | 11 | struct transfer_t; |
| 16 | } | 12 | } |
| 17 | #endif | ||
| 18 | 13 | ||
| 19 | namespace Common { | 14 | namespace Common { |
| 20 | 15 | ||
| @@ -46,10 +41,10 @@ public: | |||
| 46 | 41 | ||
| 47 | /// Yields control from Fiber 'from' to Fiber 'to' | 42 | /// Yields control from Fiber 'from' to Fiber 'to' |
| 48 | /// Fiber 'from' must be the currently running fiber. | 43 | /// Fiber 'from' must be the currently running fiber. |
| 49 | static void YieldTo(std::shared_ptr<Fiber>& from, std::shared_ptr<Fiber>& to); | 44 | static void YieldTo(std::shared_ptr<Fiber> from, std::shared_ptr<Fiber> to); |
| 50 | [[nodiscard]] static std::shared_ptr<Fiber> ThreadToFiber(); | 45 | [[nodiscard]] static std::shared_ptr<Fiber> ThreadToFiber(); |
| 51 | 46 | ||
| 52 | void SetRewindPoint(std::function<void(void*)>&& rewind_func, void* start_parameter); | 47 | void SetRewindPoint(std::function<void(void*)>&& rewind_func, void* rewind_param); |
| 53 | 48 | ||
| 54 | void Rewind(); | 49 | void Rewind(); |
| 55 | 50 | ||
| @@ -57,36 +52,18 @@ public: | |||
| 57 | void Exit(); | 52 | void Exit(); |
| 58 | 53 | ||
| 59 | /// Changes the start parameter of the fiber. Has no effect if the fiber already started | 54 | /// Changes the start parameter of the fiber. Has no effect if the fiber already started |
| 60 | void SetStartParameter(void* new_parameter) { | 55 | void SetStartParameter(void* new_parameter); |
| 61 | start_parameter = new_parameter; | ||
| 62 | } | ||
| 63 | 56 | ||
| 64 | private: | 57 | private: |
| 65 | Fiber(); | 58 | Fiber(); |
| 66 | 59 | ||
| 67 | #if defined(_WIN32) || defined(WIN32) | ||
| 68 | void OnRewind(); | ||
| 69 | void Start(); | ||
| 70 | static void FiberStartFunc(void* fiber_parameter); | ||
| 71 | static void RewindStartFunc(void* fiber_parameter); | ||
| 72 | #else | ||
| 73 | void OnRewind(boost::context::detail::transfer_t& transfer); | 60 | void OnRewind(boost::context::detail::transfer_t& transfer); |
| 74 | void Start(boost::context::detail::transfer_t& transfer); | 61 | void Start(boost::context::detail::transfer_t& transfer); |
| 75 | static void FiberStartFunc(boost::context::detail::transfer_t transfer); | 62 | static void FiberStartFunc(boost::context::detail::transfer_t transfer); |
| 76 | static void RewindStartFunc(boost::context::detail::transfer_t transfer); | 63 | static void RewindStartFunc(boost::context::detail::transfer_t transfer); |
| 77 | #endif | ||
| 78 | 64 | ||
| 79 | struct FiberImpl; | 65 | struct FiberImpl; |
| 80 | |||
| 81 | SpinLock guard{}; | ||
| 82 | std::function<void(void*)> entry_point; | ||
| 83 | std::function<void(void*)> rewind_point; | ||
| 84 | void* rewind_parameter{}; | ||
| 85 | void* start_parameter{}; | ||
| 86 | std::shared_ptr<Fiber> previous_fiber; | ||
| 87 | std::unique_ptr<FiberImpl> impl; | 66 | std::unique_ptr<FiberImpl> impl; |
| 88 | bool is_thread_fiber{}; | ||
| 89 | bool released{}; | ||
| 90 | }; | 67 | }; |
| 91 | 68 | ||
| 92 | } // namespace Common | 69 | } // namespace Common |
diff --git a/src/common/file_util.cpp b/src/common/file_util.cpp index 16c3713e0..18fbfa25b 100644 --- a/src/common/file_util.cpp +++ b/src/common/file_util.cpp | |||
| @@ -472,13 +472,14 @@ u64 ScanDirectoryTree(const std::string& directory, FSTEntry& parent_entry, | |||
| 472 | } | 472 | } |
| 473 | 473 | ||
| 474 | bool DeleteDirRecursively(const std::string& directory, unsigned int recursion) { | 474 | bool DeleteDirRecursively(const std::string& directory, unsigned int recursion) { |
| 475 | const auto callback = [recursion](u64* num_entries_out, const std::string& directory, | 475 | const auto callback = [recursion](u64*, const std::string& directory, |
| 476 | const std::string& virtual_name) -> bool { | 476 | const std::string& virtual_name) { |
| 477 | std::string new_path = directory + DIR_SEP_CHR + virtual_name; | 477 | const std::string new_path = directory + DIR_SEP_CHR + virtual_name; |
| 478 | 478 | ||
| 479 | if (IsDirectory(new_path)) { | 479 | if (IsDirectory(new_path)) { |
| 480 | if (recursion == 0) | 480 | if (recursion == 0) { |
| 481 | return false; | 481 | return false; |
| 482 | } | ||
| 482 | return DeleteDirRecursively(new_path, recursion - 1); | 483 | return DeleteDirRecursively(new_path, recursion - 1); |
| 483 | } | 484 | } |
| 484 | return Delete(new_path); | 485 | return Delete(new_path); |
| @@ -492,7 +493,8 @@ bool DeleteDirRecursively(const std::string& directory, unsigned int recursion) | |||
| 492 | return true; | 493 | return true; |
| 493 | } | 494 | } |
| 494 | 495 | ||
| 495 | void CopyDir(const std::string& source_path, const std::string& dest_path) { | 496 | void CopyDir([[maybe_unused]] const std::string& source_path, |
| 497 | [[maybe_unused]] const std::string& dest_path) { | ||
| 496 | #ifndef _WIN32 | 498 | #ifndef _WIN32 |
| 497 | if (source_path == dest_path) { | 499 | if (source_path == dest_path) { |
| 498 | return; | 500 | return; |
| @@ -553,7 +555,7 @@ std::optional<std::string> GetCurrentDir() { | |||
| 553 | std::string strDir = dir; | 555 | std::string strDir = dir; |
| 554 | #endif | 556 | #endif |
| 555 | free(dir); | 557 | free(dir); |
| 556 | return std::move(strDir); | 558 | return strDir; |
| 557 | } | 559 | } |
| 558 | 560 | ||
| 559 | bool SetCurrentDir(const std::string& directory) { | 561 | bool SetCurrentDir(const std::string& directory) { |
| @@ -772,21 +774,23 @@ std::size_t ReadFileToString(bool text_file, const std::string& filename, std::s | |||
| 772 | 774 | ||
| 773 | void SplitFilename83(const std::string& filename, std::array<char, 9>& short_name, | 775 | void SplitFilename83(const std::string& filename, std::array<char, 9>& short_name, |
| 774 | std::array<char, 4>& extension) { | 776 | std::array<char, 4>& extension) { |
| 775 | const std::string forbidden_characters = ".\"/\\[]:;=, "; | 777 | static constexpr std::string_view forbidden_characters = ".\"/\\[]:;=, "; |
| 776 | 778 | ||
| 777 | // On a FAT32 partition, 8.3 names are stored as a 11 bytes array, filled with spaces. | 779 | // On a FAT32 partition, 8.3 names are stored as a 11 bytes array, filled with spaces. |
| 778 | short_name = {{' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '\0'}}; | 780 | short_name = {{' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '\0'}}; |
| 779 | extension = {{' ', ' ', ' ', '\0'}}; | 781 | extension = {{' ', ' ', ' ', '\0'}}; |
| 780 | 782 | ||
| 781 | std::string::size_type point = filename.rfind('.'); | 783 | auto point = filename.rfind('.'); |
| 782 | if (point == filename.size() - 1) | 784 | if (point == filename.size() - 1) { |
| 783 | point = filename.rfind('.', point); | 785 | point = filename.rfind('.', point); |
| 786 | } | ||
| 784 | 787 | ||
| 785 | // Get short name. | 788 | // Get short name. |
| 786 | int j = 0; | 789 | int j = 0; |
| 787 | for (char letter : filename.substr(0, point)) { | 790 | for (char letter : filename.substr(0, point)) { |
| 788 | if (forbidden_characters.find(letter, 0) != std::string::npos) | 791 | if (forbidden_characters.find(letter, 0) != std::string::npos) { |
| 789 | continue; | 792 | continue; |
| 793 | } | ||
| 790 | if (j == 8) { | 794 | if (j == 8) { |
| 791 | // TODO(Link Mauve): also do that for filenames containing a space. | 795 | // TODO(Link Mauve): also do that for filenames containing a space. |
| 792 | // TODO(Link Mauve): handle multiple files having the same short name. | 796 | // TODO(Link Mauve): handle multiple files having the same short name. |
| @@ -794,14 +798,15 @@ void SplitFilename83(const std::string& filename, std::array<char, 9>& short_nam | |||
| 794 | short_name[7] = '1'; | 798 | short_name[7] = '1'; |
| 795 | break; | 799 | break; |
| 796 | } | 800 | } |
| 797 | short_name[j++] = toupper(letter); | 801 | short_name[j++] = static_cast<char>(std::toupper(letter)); |
| 798 | } | 802 | } |
| 799 | 803 | ||
| 800 | // Get extension. | 804 | // Get extension. |
| 801 | if (point != std::string::npos) { | 805 | if (point != std::string::npos) { |
| 802 | j = 0; | 806 | j = 0; |
| 803 | for (char letter : filename.substr(point + 1, 3)) | 807 | for (char letter : filename.substr(point + 1, 3)) { |
| 804 | extension[j++] = toupper(letter); | 808 | extension[j++] = static_cast<char>(std::toupper(letter)); |
| 809 | } | ||
| 805 | } | 810 | } |
| 806 | } | 811 | } |
| 807 | 812 | ||
diff --git a/src/common/file_util.h b/src/common/file_util.h index 8b587320f..840cde2a6 100644 --- a/src/common/file_util.h +++ b/src/common/file_util.h | |||
| @@ -232,7 +232,7 @@ public: | |||
| 232 | 232 | ||
| 233 | void Swap(IOFile& other) noexcept; | 233 | void Swap(IOFile& other) noexcept; |
| 234 | 234 | ||
| 235 | [[nodiscard]] bool Open(const std::string& filename, const char openmode[], int flags = 0); | 235 | bool Open(const std::string& filename, const char openmode[], int flags = 0); |
| 236 | bool Close(); | 236 | bool Close(); |
| 237 | 237 | ||
| 238 | template <typename T> | 238 | template <typename T> |
diff --git a/src/common/hex_util.h b/src/common/hex_util.h index 120f1a5e6..a8d414fb8 100644 --- a/src/common/hex_util.h +++ b/src/common/hex_util.h | |||
| @@ -16,14 +16,14 @@ namespace Common { | |||
| 16 | 16 | ||
| 17 | [[nodiscard]] constexpr u8 ToHexNibble(char c) { | 17 | [[nodiscard]] constexpr u8 ToHexNibble(char c) { |
| 18 | if (c >= 65 && c <= 70) { | 18 | if (c >= 65 && c <= 70) { |
| 19 | return c - 55; | 19 | return static_cast<u8>(c - 55); |
| 20 | } | 20 | } |
| 21 | 21 | ||
| 22 | if (c >= 97 && c <= 102) { | 22 | if (c >= 97 && c <= 102) { |
| 23 | return c - 87; | 23 | return static_cast<u8>(c - 87); |
| 24 | } | 24 | } |
| 25 | 25 | ||
| 26 | return c - 48; | 26 | return static_cast<u8>(c - 48); |
| 27 | } | 27 | } |
| 28 | 28 | ||
| 29 | [[nodiscard]] std::vector<u8> HexStringToVector(std::string_view str, bool little_endian); | 29 | [[nodiscard]] std::vector<u8> HexStringToVector(std::string_view str, bool little_endian); |
| @@ -33,11 +33,11 @@ template <std::size_t Size, bool le = false> | |||
| 33 | std::array<u8, Size> out{}; | 33 | std::array<u8, Size> out{}; |
| 34 | if constexpr (le) { | 34 | if constexpr (le) { |
| 35 | for (std::size_t i = 2 * Size - 2; i <= 2 * Size; i -= 2) { | 35 | for (std::size_t i = 2 * Size - 2; i <= 2 * Size; i -= 2) { |
| 36 | out[i / 2] = (ToHexNibble(str[i]) << 4) | ToHexNibble(str[i + 1]); | 36 | out[i / 2] = static_cast<u8>((ToHexNibble(str[i]) << 4) | ToHexNibble(str[i + 1])); |
| 37 | } | 37 | } |
| 38 | } else { | 38 | } else { |
| 39 | for (std::size_t i = 0; i < 2 * Size; i += 2) { | 39 | for (std::size_t i = 0; i < 2 * Size; i += 2) { |
| 40 | out[i / 2] = (ToHexNibble(str[i]) << 4) | ToHexNibble(str[i + 1]); | 40 | out[i / 2] = static_cast<u8>((ToHexNibble(str[i]) << 4) | ToHexNibble(str[i + 1])); |
| 41 | } | 41 | } |
| 42 | } | 42 | } |
| 43 | return out; | 43 | return out; |
diff --git a/src/common/logging/backend.cpp b/src/common/logging/backend.cpp index 62cfde397..631f64d05 100644 --- a/src/common/logging/backend.cpp +++ b/src/common/logging/backend.cpp | |||
| @@ -23,6 +23,7 @@ | |||
| 23 | #include "common/logging/text_formatter.h" | 23 | #include "common/logging/text_formatter.h" |
| 24 | #include "common/string_util.h" | 24 | #include "common/string_util.h" |
| 25 | #include "common/threadsafe_queue.h" | 25 | #include "common/threadsafe_queue.h" |
| 26 | #include "core/settings.h" | ||
| 26 | 27 | ||
| 27 | namespace Log { | 28 | namespace Log { |
| 28 | 29 | ||
| @@ -152,10 +153,19 @@ FileBackend::FileBackend(const std::string& filename) | |||
| 152 | void FileBackend::Write(const Entry& entry) { | 153 | void FileBackend::Write(const Entry& entry) { |
| 153 | // prevent logs from going over the maximum size (in case its spamming and the user doesn't | 154 | // prevent logs from going over the maximum size (in case its spamming and the user doesn't |
| 154 | // know) | 155 | // know) |
| 155 | constexpr std::size_t MAX_BYTES_WRITTEN = 50 * 1024L * 1024L; | 156 | constexpr std::size_t MAX_BYTES_WRITTEN = 100 * 1024 * 1024; |
| 156 | if (!file.IsOpen() || bytes_written > MAX_BYTES_WRITTEN) { | 157 | constexpr std::size_t MAX_BYTES_WRITTEN_EXTENDED = 1024 * 1024 * 1024; |
| 158 | |||
| 159 | if (!file.IsOpen()) { | ||
| 160 | return; | ||
| 161 | } | ||
| 162 | |||
| 163 | if (Settings::values.extended_logging && bytes_written > MAX_BYTES_WRITTEN_EXTENDED) { | ||
| 164 | return; | ||
| 165 | } else if (!Settings::values.extended_logging && bytes_written > MAX_BYTES_WRITTEN) { | ||
| 157 | return; | 166 | return; |
| 158 | } | 167 | } |
| 168 | |||
| 159 | bytes_written += file.WriteString(FormatLogMessage(entry).append(1, '\n')); | 169 | bytes_written += file.WriteString(FormatLogMessage(entry).append(1, '\n')); |
| 160 | if (entry.log_level >= Level::Error) { | 170 | if (entry.log_level >= Level::Error) { |
| 161 | file.Flush(); | 171 | file.Flush(); |
| @@ -222,6 +232,7 @@ void DebuggerBackend::Write(const Entry& entry) { | |||
| 222 | SUB(Service, NPNS) \ | 232 | SUB(Service, NPNS) \ |
| 223 | SUB(Service, NS) \ | 233 | SUB(Service, NS) \ |
| 224 | SUB(Service, NVDRV) \ | 234 | SUB(Service, NVDRV) \ |
| 235 | SUB(Service, OLSC) \ | ||
| 225 | SUB(Service, PCIE) \ | 236 | SUB(Service, PCIE) \ |
| 226 | SUB(Service, PCTL) \ | 237 | SUB(Service, PCTL) \ |
| 227 | SUB(Service, PCV) \ | 238 | SUB(Service, PCV) \ |
| @@ -274,7 +285,6 @@ const char* GetLogClassName(Class log_class) { | |||
| 274 | case Class::Count: | 285 | case Class::Count: |
| 275 | break; | 286 | break; |
| 276 | } | 287 | } |
| 277 | UNREACHABLE(); | ||
| 278 | return "Invalid"; | 288 | return "Invalid"; |
| 279 | } | 289 | } |
| 280 | 290 | ||
| @@ -293,7 +303,6 @@ const char* GetLevelName(Level log_level) { | |||
| 293 | break; | 303 | break; |
| 294 | } | 304 | } |
| 295 | #undef LVL | 305 | #undef LVL |
| 296 | UNREACHABLE(); | ||
| 297 | return "Invalid"; | 306 | return "Invalid"; |
| 298 | } | 307 | } |
| 299 | 308 | ||
diff --git a/src/common/logging/log.h b/src/common/logging/log.h index 13a4f1e30..835894918 100644 --- a/src/common/logging/log.h +++ b/src/common/logging/log.h | |||
| @@ -95,6 +95,7 @@ enum class Class : ClassType { | |||
| 95 | Service_NPNS, ///< The NPNS service | 95 | Service_NPNS, ///< The NPNS service |
| 96 | Service_NS, ///< The NS services | 96 | Service_NS, ///< The NS services |
| 97 | Service_NVDRV, ///< The NVDRV (Nvidia driver) service | 97 | Service_NVDRV, ///< The NVDRV (Nvidia driver) service |
| 98 | Service_OLSC, ///< The OLSC service | ||
| 98 | Service_PCIE, ///< The PCIe service | 99 | Service_PCIE, ///< The PCIe service |
| 99 | Service_PCTL, ///< The PCTL (Parental control) service | 100 | Service_PCTL, ///< The PCTL (Parental control) service |
| 100 | Service_PCV, ///< The PCV service | 101 | Service_PCV, ///< The PCV service |
diff --git a/src/common/math_util.h b/src/common/math_util.h index b35ad8507..4c38d8040 100644 --- a/src/common/math_util.h +++ b/src/common/math_util.h | |||
| @@ -20,14 +20,14 @@ struct Rectangle { | |||
| 20 | 20 | ||
| 21 | constexpr Rectangle() = default; | 21 | constexpr Rectangle() = default; |
| 22 | 22 | ||
| 23 | constexpr Rectangle(T left, T top, T right, T bottom) | 23 | constexpr Rectangle(T left_, T top_, T right_, T bottom_) |
| 24 | : left(left), top(top), right(right), bottom(bottom) {} | 24 | : left(left_), top(top_), right(right_), bottom(bottom_) {} |
| 25 | 25 | ||
| 26 | [[nodiscard]] T GetWidth() const { | 26 | [[nodiscard]] T GetWidth() const { |
| 27 | if constexpr (std::is_floating_point_v<T>) { | 27 | if constexpr (std::is_floating_point_v<T>) { |
| 28 | return std::abs(right - left); | 28 | return std::abs(right - left); |
| 29 | } else { | 29 | } else { |
| 30 | return std::abs(static_cast<std::make_signed_t<T>>(right - left)); | 30 | return static_cast<T>(std::abs(static_cast<std::make_signed_t<T>>(right - left))); |
| 31 | } | 31 | } |
| 32 | } | 32 | } |
| 33 | 33 | ||
| @@ -35,7 +35,7 @@ struct Rectangle { | |||
| 35 | if constexpr (std::is_floating_point_v<T>) { | 35 | if constexpr (std::is_floating_point_v<T>) { |
| 36 | return std::abs(bottom - top); | 36 | return std::abs(bottom - top); |
| 37 | } else { | 37 | } else { |
| 38 | return std::abs(static_cast<std::make_signed_t<T>>(bottom - top)); | 38 | return static_cast<T>(std::abs(static_cast<std::make_signed_t<T>>(bottom - top))); |
| 39 | } | 39 | } |
| 40 | } | 40 | } |
| 41 | 41 | ||
diff --git a/src/common/memory_hook.cpp b/src/common/memory_hook.cpp deleted file mode 100644 index 3986986d6..000000000 --- a/src/common/memory_hook.cpp +++ /dev/null | |||
| @@ -1,11 +0,0 @@ | |||
| 1 | // Copyright 2018 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "common/memory_hook.h" | ||
| 6 | |||
| 7 | namespace Common { | ||
| 8 | |||
| 9 | MemoryHook::~MemoryHook() = default; | ||
| 10 | |||
| 11 | } // namespace Common | ||
diff --git a/src/common/memory_hook.h b/src/common/memory_hook.h deleted file mode 100644 index adaa4c2c5..000000000 --- a/src/common/memory_hook.h +++ /dev/null | |||
| @@ -1,47 +0,0 @@ | |||
| 1 | // Copyright 2016 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <memory> | ||
| 8 | #include <optional> | ||
| 9 | |||
| 10 | #include "common/common_types.h" | ||
| 11 | |||
| 12 | namespace Common { | ||
| 13 | |||
| 14 | /** | ||
| 15 | * Memory hooks have two purposes: | ||
| 16 | * 1. To allow reads and writes to a region of memory to be intercepted. This is used to implement | ||
| 17 | * texture forwarding and memory breakpoints for debugging. | ||
| 18 | * 2. To allow for the implementation of MMIO devices. | ||
| 19 | * | ||
| 20 | * A hook may be mapped to multiple regions of memory. | ||
| 21 | * | ||
| 22 | * If a std::nullopt or false is returned from a function, the read/write request is passed through | ||
| 23 | * to the underlying memory region. | ||
| 24 | */ | ||
| 25 | class MemoryHook { | ||
| 26 | public: | ||
| 27 | virtual ~MemoryHook(); | ||
| 28 | |||
| 29 | virtual std::optional<bool> IsValidAddress(VAddr addr) = 0; | ||
| 30 | |||
| 31 | virtual std::optional<u8> Read8(VAddr addr) = 0; | ||
| 32 | virtual std::optional<u16> Read16(VAddr addr) = 0; | ||
| 33 | virtual std::optional<u32> Read32(VAddr addr) = 0; | ||
| 34 | virtual std::optional<u64> Read64(VAddr addr) = 0; | ||
| 35 | |||
| 36 | virtual bool ReadBlock(VAddr src_addr, void* dest_buffer, std::size_t size) = 0; | ||
| 37 | |||
| 38 | virtual bool Write8(VAddr addr, u8 data) = 0; | ||
| 39 | virtual bool Write16(VAddr addr, u16 data) = 0; | ||
| 40 | virtual bool Write32(VAddr addr, u32 data) = 0; | ||
| 41 | virtual bool Write64(VAddr addr, u64 data) = 0; | ||
| 42 | |||
| 43 | virtual bool WriteBlock(VAddr dest_addr, const void* src_buffer, std::size_t size) = 0; | ||
| 44 | }; | ||
| 45 | |||
| 46 | using MemoryHookPointer = std::shared_ptr<MemoryHook>; | ||
| 47 | } // namespace Common | ||
diff --git a/src/common/misc.cpp b/src/common/misc.cpp index 68cb86cd1..1d5393597 100644 --- a/src/common/misc.cpp +++ b/src/common/misc.cpp | |||
| @@ -16,16 +16,23 @@ | |||
| 16 | // Call directly after the command or use the error num. | 16 | // Call directly after the command or use the error num. |
| 17 | // This function might change the error code. | 17 | // This function might change the error code. |
| 18 | std::string GetLastErrorMsg() { | 18 | std::string GetLastErrorMsg() { |
| 19 | static const std::size_t buff_size = 255; | 19 | static constexpr std::size_t buff_size = 255; |
| 20 | char err_str[buff_size]; | 20 | char err_str[buff_size]; |
| 21 | 21 | ||
| 22 | #ifdef _WIN32 | 22 | #ifdef _WIN32 |
| 23 | FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, nullptr, GetLastError(), | 23 | FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, nullptr, GetLastError(), |
| 24 | MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), err_str, buff_size, nullptr); | 24 | MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), err_str, buff_size, nullptr); |
| 25 | return std::string(err_str, buff_size); | ||
| 26 | #elif defined(__GLIBC__) && (_GNU_SOURCE || (_POSIX_C_SOURCE < 200112L && _XOPEN_SOURCE < 600)) | ||
| 27 | // Thread safe (GNU-specific) | ||
| 28 | const char* str = strerror_r(errno, err_str, buff_size); | ||
| 29 | return std::string(str); | ||
| 25 | #else | 30 | #else |
| 26 | // Thread safe (XSI-compliant) | 31 | // Thread safe (XSI-compliant) |
| 27 | strerror_r(errno, err_str, buff_size); | 32 | const int success = strerror_r(errno, err_str, buff_size); |
| 33 | if (success != 0) { | ||
| 34 | return {}; | ||
| 35 | } | ||
| 36 | return std::string(err_str); | ||
| 28 | #endif | 37 | #endif |
| 29 | |||
| 30 | return std::string(err_str, buff_size); | ||
| 31 | } | 38 | } |
diff --git a/src/common/multi_level_queue.h b/src/common/multi_level_queue.h deleted file mode 100644 index 4b305bf40..000000000 --- a/src/common/multi_level_queue.h +++ /dev/null | |||
| @@ -1,345 +0,0 @@ | |||
| 1 | // Copyright 2019 TuxSH | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <array> | ||
| 8 | #include <iterator> | ||
| 9 | #include <list> | ||
| 10 | #include <utility> | ||
| 11 | |||
| 12 | #include "common/bit_util.h" | ||
| 13 | #include "common/common_types.h" | ||
| 14 | |||
| 15 | namespace Common { | ||
| 16 | |||
| 17 | /** | ||
| 18 | * A MultiLevelQueue is a type of priority queue which has the following characteristics: | ||
| 19 | * - iteratable through each of its elements. | ||
| 20 | * - back can be obtained. | ||
| 21 | * - O(1) add, lookup (both front and back) | ||
| 22 | * - discrete priorities and a max of 64 priorities (limited domain) | ||
| 23 | * This type of priority queue is normaly used for managing threads within an scheduler | ||
| 24 | */ | ||
| 25 | template <typename T, std::size_t Depth> | ||
| 26 | class MultiLevelQueue { | ||
| 27 | public: | ||
| 28 | using value_type = T; | ||
| 29 | using reference = value_type&; | ||
| 30 | using const_reference = const value_type&; | ||
| 31 | using pointer = value_type*; | ||
| 32 | using const_pointer = const value_type*; | ||
| 33 | |||
| 34 | using difference_type = typename std::pointer_traits<pointer>::difference_type; | ||
| 35 | using size_type = std::size_t; | ||
| 36 | |||
| 37 | template <bool is_constant> | ||
| 38 | class iterator_impl { | ||
| 39 | public: | ||
| 40 | using iterator_category = std::bidirectional_iterator_tag; | ||
| 41 | using value_type = T; | ||
| 42 | using pointer = std::conditional_t<is_constant, T*, const T*>; | ||
| 43 | using reference = std::conditional_t<is_constant, const T&, T&>; | ||
| 44 | using difference_type = typename std::pointer_traits<pointer>::difference_type; | ||
| 45 | |||
| 46 | friend bool operator==(const iterator_impl& lhs, const iterator_impl& rhs) { | ||
| 47 | if (lhs.IsEnd() && rhs.IsEnd()) | ||
| 48 | return true; | ||
| 49 | return std::tie(lhs.current_priority, lhs.it) == std::tie(rhs.current_priority, rhs.it); | ||
| 50 | } | ||
| 51 | |||
| 52 | friend bool operator!=(const iterator_impl& lhs, const iterator_impl& rhs) { | ||
| 53 | return !operator==(lhs, rhs); | ||
| 54 | } | ||
| 55 | |||
| 56 | reference operator*() const { | ||
| 57 | return *it; | ||
| 58 | } | ||
| 59 | |||
| 60 | pointer operator->() const { | ||
| 61 | return it.operator->(); | ||
| 62 | } | ||
| 63 | |||
| 64 | iterator_impl& operator++() { | ||
| 65 | if (IsEnd()) { | ||
| 66 | return *this; | ||
| 67 | } | ||
| 68 | |||
| 69 | ++it; | ||
| 70 | |||
| 71 | if (it == GetEndItForPrio()) { | ||
| 72 | u64 prios = mlq.used_priorities; | ||
| 73 | prios &= ~((1ULL << (current_priority + 1)) - 1); | ||
| 74 | if (prios == 0) { | ||
| 75 | current_priority = static_cast<u32>(mlq.depth()); | ||
| 76 | } else { | ||
| 77 | current_priority = CountTrailingZeroes64(prios); | ||
| 78 | it = GetBeginItForPrio(); | ||
| 79 | } | ||
| 80 | } | ||
| 81 | return *this; | ||
| 82 | } | ||
| 83 | |||
| 84 | iterator_impl& operator--() { | ||
| 85 | if (IsEnd()) { | ||
| 86 | if (mlq.used_priorities != 0) { | ||
| 87 | current_priority = 63 - CountLeadingZeroes64(mlq.used_priorities); | ||
| 88 | it = GetEndItForPrio(); | ||
| 89 | --it; | ||
| 90 | } | ||
| 91 | } else if (it == GetBeginItForPrio()) { | ||
| 92 | u64 prios = mlq.used_priorities; | ||
| 93 | prios &= (1ULL << current_priority) - 1; | ||
| 94 | if (prios != 0) { | ||
| 95 | current_priority = CountTrailingZeroes64(prios); | ||
| 96 | it = GetEndItForPrio(); | ||
| 97 | --it; | ||
| 98 | } | ||
| 99 | } else { | ||
| 100 | --it; | ||
| 101 | } | ||
| 102 | return *this; | ||
| 103 | } | ||
| 104 | |||
| 105 | iterator_impl operator++(int) { | ||
| 106 | const iterator_impl v{*this}; | ||
| 107 | ++(*this); | ||
| 108 | return v; | ||
| 109 | } | ||
| 110 | |||
| 111 | iterator_impl operator--(int) { | ||
| 112 | const iterator_impl v{*this}; | ||
| 113 | --(*this); | ||
| 114 | return v; | ||
| 115 | } | ||
| 116 | |||
| 117 | // allow implicit const->non-const | ||
| 118 | iterator_impl(const iterator_impl<false>& other) | ||
| 119 | : mlq(other.mlq), it(other.it), current_priority(other.current_priority) {} | ||
| 120 | |||
| 121 | iterator_impl(const iterator_impl<true>& other) | ||
| 122 | : mlq(other.mlq), it(other.it), current_priority(other.current_priority) {} | ||
| 123 | |||
| 124 | iterator_impl& operator=(const iterator_impl<false>& other) { | ||
| 125 | mlq = other.mlq; | ||
| 126 | it = other.it; | ||
| 127 | current_priority = other.current_priority; | ||
| 128 | return *this; | ||
| 129 | } | ||
| 130 | |||
| 131 | friend class iterator_impl<true>; | ||
| 132 | iterator_impl() = default; | ||
| 133 | |||
| 134 | private: | ||
| 135 | friend class MultiLevelQueue; | ||
| 136 | using container_ref = | ||
| 137 | std::conditional_t<is_constant, const MultiLevelQueue&, MultiLevelQueue&>; | ||
| 138 | using list_iterator = std::conditional_t<is_constant, typename std::list<T>::const_iterator, | ||
| 139 | typename std::list<T>::iterator>; | ||
| 140 | |||
| 141 | explicit iterator_impl(container_ref mlq, list_iterator it, u32 current_priority) | ||
| 142 | : mlq(mlq), it(it), current_priority(current_priority) {} | ||
| 143 | explicit iterator_impl(container_ref mlq, u32 current_priority) | ||
| 144 | : mlq(mlq), it(), current_priority(current_priority) {} | ||
| 145 | |||
| 146 | bool IsEnd() const { | ||
| 147 | return current_priority == mlq.depth(); | ||
| 148 | } | ||
| 149 | |||
| 150 | list_iterator GetBeginItForPrio() const { | ||
| 151 | return mlq.levels[current_priority].begin(); | ||
| 152 | } | ||
| 153 | |||
| 154 | list_iterator GetEndItForPrio() const { | ||
| 155 | return mlq.levels[current_priority].end(); | ||
| 156 | } | ||
| 157 | |||
| 158 | container_ref mlq; | ||
| 159 | list_iterator it; | ||
| 160 | u32 current_priority; | ||
| 161 | }; | ||
| 162 | |||
| 163 | using iterator = iterator_impl<false>; | ||
| 164 | using const_iterator = iterator_impl<true>; | ||
| 165 | |||
| 166 | void add(const T& element, u32 priority, bool send_back = true) { | ||
| 167 | if (send_back) | ||
| 168 | levels[priority].push_back(element); | ||
| 169 | else | ||
| 170 | levels[priority].push_front(element); | ||
| 171 | used_priorities |= 1ULL << priority; | ||
| 172 | } | ||
| 173 | |||
| 174 | void remove(const T& element, u32 priority) { | ||
| 175 | auto it = ListIterateTo(levels[priority], element); | ||
| 176 | if (it == levels[priority].end()) | ||
| 177 | return; | ||
| 178 | levels[priority].erase(it); | ||
| 179 | if (levels[priority].empty()) { | ||
| 180 | used_priorities &= ~(1ULL << priority); | ||
| 181 | } | ||
| 182 | } | ||
| 183 | |||
| 184 | void adjust(const T& element, u32 old_priority, u32 new_priority, bool adjust_front = false) { | ||
| 185 | remove(element, old_priority); | ||
| 186 | add(element, new_priority, !adjust_front); | ||
| 187 | } | ||
| 188 | void adjust(const_iterator it, u32 old_priority, u32 new_priority, bool adjust_front = false) { | ||
| 189 | adjust(*it, old_priority, new_priority, adjust_front); | ||
| 190 | } | ||
| 191 | |||
| 192 | void transfer_to_front(const T& element, u32 priority, MultiLevelQueue& other) { | ||
| 193 | ListSplice(other.levels[priority], other.levels[priority].begin(), levels[priority], | ||
| 194 | ListIterateTo(levels[priority], element)); | ||
| 195 | |||
| 196 | other.used_priorities |= 1ULL << priority; | ||
| 197 | |||
| 198 | if (levels[priority].empty()) { | ||
| 199 | used_priorities &= ~(1ULL << priority); | ||
| 200 | } | ||
| 201 | } | ||
| 202 | |||
| 203 | void transfer_to_front(const_iterator it, u32 priority, MultiLevelQueue& other) { | ||
| 204 | transfer_to_front(*it, priority, other); | ||
| 205 | } | ||
| 206 | |||
| 207 | void transfer_to_back(const T& element, u32 priority, MultiLevelQueue& other) { | ||
| 208 | ListSplice(other.levels[priority], other.levels[priority].end(), levels[priority], | ||
| 209 | ListIterateTo(levels[priority], element)); | ||
| 210 | |||
| 211 | other.used_priorities |= 1ULL << priority; | ||
| 212 | |||
| 213 | if (levels[priority].empty()) { | ||
| 214 | used_priorities &= ~(1ULL << priority); | ||
| 215 | } | ||
| 216 | } | ||
| 217 | |||
| 218 | void transfer_to_back(const_iterator it, u32 priority, MultiLevelQueue& other) { | ||
| 219 | transfer_to_back(*it, priority, other); | ||
| 220 | } | ||
| 221 | |||
| 222 | void yield(u32 priority, std::size_t n = 1) { | ||
| 223 | ListShiftForward(levels[priority], n); | ||
| 224 | } | ||
| 225 | |||
| 226 | [[nodiscard]] std::size_t depth() const { | ||
| 227 | return Depth; | ||
| 228 | } | ||
| 229 | |||
| 230 | [[nodiscard]] std::size_t size(u32 priority) const { | ||
| 231 | return levels[priority].size(); | ||
| 232 | } | ||
| 233 | |||
| 234 | [[nodiscard]] std::size_t size() const { | ||
| 235 | u64 priorities = used_priorities; | ||
| 236 | std::size_t size = 0; | ||
| 237 | while (priorities != 0) { | ||
| 238 | const u64 current_priority = CountTrailingZeroes64(priorities); | ||
| 239 | size += levels[current_priority].size(); | ||
| 240 | priorities &= ~(1ULL << current_priority); | ||
| 241 | } | ||
| 242 | return size; | ||
| 243 | } | ||
| 244 | |||
| 245 | [[nodiscard]] bool empty() const { | ||
| 246 | return used_priorities == 0; | ||
| 247 | } | ||
| 248 | |||
| 249 | [[nodiscard]] bool empty(u32 priority) const { | ||
| 250 | return (used_priorities & (1ULL << priority)) == 0; | ||
| 251 | } | ||
| 252 | |||
| 253 | [[nodiscard]] u32 highest_priority_set(u32 max_priority = 0) const { | ||
| 254 | const u64 priorities = | ||
| 255 | max_priority == 0 ? used_priorities : (used_priorities & ~((1ULL << max_priority) - 1)); | ||
| 256 | return priorities == 0 ? Depth : static_cast<u32>(CountTrailingZeroes64(priorities)); | ||
| 257 | } | ||
| 258 | |||
| 259 | [[nodiscard]] u32 lowest_priority_set(u32 min_priority = Depth - 1) const { | ||
| 260 | const u64 priorities = min_priority >= Depth - 1 | ||
| 261 | ? used_priorities | ||
| 262 | : (used_priorities & ((1ULL << (min_priority + 1)) - 1)); | ||
| 263 | return priorities == 0 ? Depth : 63 - CountLeadingZeroes64(priorities); | ||
| 264 | } | ||
| 265 | |||
| 266 | [[nodiscard]] const_iterator cbegin(u32 max_prio = 0) const { | ||
| 267 | const u32 priority = highest_priority_set(max_prio); | ||
| 268 | return priority == Depth ? cend() | ||
| 269 | : const_iterator{*this, levels[priority].cbegin(), priority}; | ||
| 270 | } | ||
| 271 | [[nodiscard]] const_iterator begin(u32 max_prio = 0) const { | ||
| 272 | return cbegin(max_prio); | ||
| 273 | } | ||
| 274 | [[nodiscard]] iterator begin(u32 max_prio = 0) { | ||
| 275 | const u32 priority = highest_priority_set(max_prio); | ||
| 276 | return priority == Depth ? end() : iterator{*this, levels[priority].begin(), priority}; | ||
| 277 | } | ||
| 278 | |||
| 279 | [[nodiscard]] const_iterator cend(u32 min_prio = Depth - 1) const { | ||
| 280 | return min_prio == Depth - 1 ? const_iterator{*this, Depth} : cbegin(min_prio + 1); | ||
| 281 | } | ||
| 282 | [[nodiscard]] const_iterator end(u32 min_prio = Depth - 1) const { | ||
| 283 | return cend(min_prio); | ||
| 284 | } | ||
| 285 | [[nodiscard]] iterator end(u32 min_prio = Depth - 1) { | ||
| 286 | return min_prio == Depth - 1 ? iterator{*this, Depth} : begin(min_prio + 1); | ||
| 287 | } | ||
| 288 | |||
| 289 | [[nodiscard]] T& front(u32 max_priority = 0) { | ||
| 290 | const u32 priority = highest_priority_set(max_priority); | ||
| 291 | return levels[priority == Depth ? 0 : priority].front(); | ||
| 292 | } | ||
| 293 | [[nodiscard]] const T& front(u32 max_priority = 0) const { | ||
| 294 | const u32 priority = highest_priority_set(max_priority); | ||
| 295 | return levels[priority == Depth ? 0 : priority].front(); | ||
| 296 | } | ||
| 297 | |||
| 298 | [[nodiscard]] T& back(u32 min_priority = Depth - 1) { | ||
| 299 | const u32 priority = lowest_priority_set(min_priority); // intended | ||
| 300 | return levels[priority == Depth ? 63 : priority].back(); | ||
| 301 | } | ||
| 302 | [[nodiscard]] const T& back(u32 min_priority = Depth - 1) const { | ||
| 303 | const u32 priority = lowest_priority_set(min_priority); // intended | ||
| 304 | return levels[priority == Depth ? 63 : priority].back(); | ||
| 305 | } | ||
| 306 | |||
| 307 | void clear() { | ||
| 308 | used_priorities = 0; | ||
| 309 | for (std::size_t i = 0; i < Depth; i++) { | ||
| 310 | levels[i].clear(); | ||
| 311 | } | ||
| 312 | } | ||
| 313 | |||
| 314 | private: | ||
| 315 | using const_list_iterator = typename std::list<T>::const_iterator; | ||
| 316 | |||
| 317 | static void ListShiftForward(std::list<T>& list, const std::size_t shift = 1) { | ||
| 318 | if (shift >= list.size()) { | ||
| 319 | return; | ||
| 320 | } | ||
| 321 | |||
| 322 | const auto begin_range = list.begin(); | ||
| 323 | const auto end_range = std::next(begin_range, shift); | ||
| 324 | list.splice(list.end(), list, begin_range, end_range); | ||
| 325 | } | ||
| 326 | |||
| 327 | static void ListSplice(std::list<T>& in_list, const_list_iterator position, | ||
| 328 | std::list<T>& out_list, const_list_iterator element) { | ||
| 329 | in_list.splice(position, out_list, element); | ||
| 330 | } | ||
| 331 | |||
| 332 | [[nodiscard]] static const_list_iterator ListIterateTo(const std::list<T>& list, | ||
| 333 | const T& element) { | ||
| 334 | auto it = list.cbegin(); | ||
| 335 | while (it != list.cend() && *it != element) { | ||
| 336 | ++it; | ||
| 337 | } | ||
| 338 | return it; | ||
| 339 | } | ||
| 340 | |||
| 341 | std::array<std::list<T>, Depth> levels; | ||
| 342 | u64 used_priorities = 0; | ||
| 343 | }; | ||
| 344 | |||
| 345 | } // namespace Common | ||
diff --git a/src/common/page_table.cpp b/src/common/page_table.cpp index e5d3090d5..8fd8620fd 100644 --- a/src/common/page_table.cpp +++ b/src/common/page_table.cpp | |||
| @@ -8,18 +8,12 @@ namespace Common { | |||
| 8 | 8 | ||
| 9 | PageTable::PageTable() = default; | 9 | PageTable::PageTable() = default; |
| 10 | 10 | ||
| 11 | PageTable::~PageTable() = default; | 11 | PageTable::~PageTable() noexcept = default; |
| 12 | 12 | ||
| 13 | void PageTable::Resize(std::size_t address_space_width_in_bits, std::size_t page_size_in_bits, | 13 | void PageTable::Resize(size_t address_space_width_in_bits, size_t page_size_in_bits) { |
| 14 | bool has_attribute) { | 14 | const size_t num_page_table_entries{1ULL << (address_space_width_in_bits - page_size_in_bits)}; |
| 15 | const std::size_t num_page_table_entries{1ULL | ||
| 16 | << (address_space_width_in_bits - page_size_in_bits)}; | ||
| 17 | pointers.resize(num_page_table_entries); | 15 | pointers.resize(num_page_table_entries); |
| 18 | backing_addr.resize(num_page_table_entries); | 16 | backing_addr.resize(num_page_table_entries); |
| 19 | |||
| 20 | if (has_attribute) { | ||
| 21 | attributes.resize(num_page_table_entries); | ||
| 22 | } | ||
| 23 | } | 17 | } |
| 24 | 18 | ||
| 25 | } // namespace Common | 19 | } // namespace Common |
diff --git a/src/common/page_table.h b/src/common/page_table.h index cf5eed780..61c5552e0 100644 --- a/src/common/page_table.h +++ b/src/common/page_table.h | |||
| @@ -4,12 +4,10 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <vector> | 7 | #include <atomic> |
| 8 | 8 | #include <tuple> | |
| 9 | #include <boost/icl/interval_map.hpp> | ||
| 10 | 9 | ||
| 11 | #include "common/common_types.h" | 10 | #include "common/common_types.h" |
| 12 | #include "common/memory_hook.h" | ||
| 13 | #include "common/virtual_buffer.h" | 11 | #include "common/virtual_buffer.h" |
| 14 | 12 | ||
| 15 | namespace Common { | 13 | namespace Common { |
| @@ -22,27 +20,6 @@ enum class PageType : u8 { | |||
| 22 | /// Page is mapped to regular memory, but also needs to check for rasterizer cache flushing and | 20 | /// Page is mapped to regular memory, but also needs to check for rasterizer cache flushing and |
| 23 | /// invalidation | 21 | /// invalidation |
| 24 | RasterizerCachedMemory, | 22 | RasterizerCachedMemory, |
| 25 | /// Page is mapped to a I/O region. Writing and reading to this page is handled by functions. | ||
| 26 | Special, | ||
| 27 | /// Page is allocated for use. | ||
| 28 | Allocated, | ||
| 29 | }; | ||
| 30 | |||
| 31 | struct SpecialRegion { | ||
| 32 | enum class Type { | ||
| 33 | DebugHook, | ||
| 34 | IODevice, | ||
| 35 | } type; | ||
| 36 | |||
| 37 | MemoryHookPointer handler; | ||
| 38 | |||
| 39 | [[nodiscard]] bool operator<(const SpecialRegion& other) const { | ||
| 40 | return std::tie(type, handler) < std::tie(other.type, other.handler); | ||
| 41 | } | ||
| 42 | |||
| 43 | [[nodiscard]] bool operator==(const SpecialRegion& other) const { | ||
| 44 | return std::tie(type, handler) == std::tie(other.type, other.handler); | ||
| 45 | } | ||
| 46 | }; | 23 | }; |
| 47 | 24 | ||
| 48 | /** | 25 | /** |
| @@ -50,27 +27,84 @@ struct SpecialRegion { | |||
| 50 | * mimics the way a real CPU page table works. | 27 | * mimics the way a real CPU page table works. |
| 51 | */ | 28 | */ |
| 52 | struct PageTable { | 29 | struct PageTable { |
| 30 | /// Number of bits reserved for attribute tagging. | ||
| 31 | /// This can be at most the guaranteed alignment of the pointers in the page table. | ||
| 32 | static constexpr int ATTRIBUTE_BITS = 2; | ||
| 33 | |||
| 34 | /** | ||
| 35 | * Pair of host pointer and page type attribute. | ||
| 36 | * This uses the lower bits of a given pointer to store the attribute tag. | ||
| 37 | * Writing and reading the pointer attribute pair is guaranteed to be atomic for the same method | ||
| 38 | * call. In other words, they are guaranteed to be synchronized at all times. | ||
| 39 | */ | ||
| 40 | class PageInfo { | ||
| 41 | public: | ||
| 42 | /// Returns the page pointer | ||
| 43 | [[nodiscard]] u8* Pointer() const noexcept { | ||
| 44 | return ExtractPointer(raw.load(std::memory_order_relaxed)); | ||
| 45 | } | ||
| 46 | |||
| 47 | /// Returns the page type attribute | ||
| 48 | [[nodiscard]] PageType Type() const noexcept { | ||
| 49 | return ExtractType(raw.load(std::memory_order_relaxed)); | ||
| 50 | } | ||
| 51 | |||
| 52 | /// Returns the page pointer and attribute pair, extracted from the same atomic read | ||
| 53 | [[nodiscard]] std::pair<u8*, PageType> PointerType() const noexcept { | ||
| 54 | const uintptr_t non_atomic_raw = raw.load(std::memory_order_relaxed); | ||
| 55 | return {ExtractPointer(non_atomic_raw), ExtractType(non_atomic_raw)}; | ||
| 56 | } | ||
| 57 | |||
| 58 | /// Returns the raw representation of the page information. | ||
| 59 | /// Use ExtractPointer and ExtractType to unpack the value. | ||
| 60 | [[nodiscard]] uintptr_t Raw() const noexcept { | ||
| 61 | return raw.load(std::memory_order_relaxed); | ||
| 62 | } | ||
| 63 | |||
| 64 | /// Write a page pointer and type pair atomically | ||
| 65 | void Store(u8* pointer, PageType type) noexcept { | ||
| 66 | raw.store(reinterpret_cast<uintptr_t>(pointer) | static_cast<uintptr_t>(type)); | ||
| 67 | } | ||
| 68 | |||
| 69 | /// Unpack a pointer from a page info raw representation | ||
| 70 | [[nodiscard]] static u8* ExtractPointer(uintptr_t raw) noexcept { | ||
| 71 | return reinterpret_cast<u8*>(raw & (~uintptr_t{0} << ATTRIBUTE_BITS)); | ||
| 72 | } | ||
| 73 | |||
| 74 | /// Unpack a page type from a page info raw representation | ||
| 75 | [[nodiscard]] static PageType ExtractType(uintptr_t raw) noexcept { | ||
| 76 | return static_cast<PageType>(raw & ((uintptr_t{1} << ATTRIBUTE_BITS) - 1)); | ||
| 77 | } | ||
| 78 | |||
| 79 | private: | ||
| 80 | std::atomic<uintptr_t> raw; | ||
| 81 | }; | ||
| 82 | |||
| 53 | PageTable(); | 83 | PageTable(); |
| 54 | ~PageTable(); | 84 | ~PageTable() noexcept; |
| 85 | |||
| 86 | PageTable(const PageTable&) = delete; | ||
| 87 | PageTable& operator=(const PageTable&) = delete; | ||
| 88 | |||
| 89 | PageTable(PageTable&&) noexcept = default; | ||
| 90 | PageTable& operator=(PageTable&&) noexcept = default; | ||
| 55 | 91 | ||
| 56 | /** | 92 | /** |
| 57 | * Resizes the page table to be able to accomodate enough pages within | 93 | * Resizes the page table to be able to accommodate enough pages within |
| 58 | * a given address space. | 94 | * a given address space. |
| 59 | * | 95 | * |
| 60 | * @param address_space_width_in_bits The address size width in bits. | 96 | * @param address_space_width_in_bits The address size width in bits. |
| 97 | * @param page_size_in_bits The page size in bits. | ||
| 61 | */ | 98 | */ |
| 62 | void Resize(std::size_t address_space_width_in_bits, std::size_t page_size_in_bits, | 99 | void Resize(size_t address_space_width_in_bits, size_t page_size_in_bits); |
| 63 | bool has_attribute); | ||
| 64 | 100 | ||
| 65 | /** | 101 | /** |
| 66 | * Vector of memory pointers backing each page. An entry can only be non-null if the | 102 | * Vector of memory pointers backing each page. An entry can only be non-null if the |
| 67 | * corresponding entry in the `attributes` vector is of type `Memory`. | 103 | * corresponding attribute element is of type `Memory`. |
| 68 | */ | 104 | */ |
| 69 | VirtualBuffer<u8*> pointers; | 105 | VirtualBuffer<PageInfo> pointers; |
| 70 | 106 | ||
| 71 | VirtualBuffer<u64> backing_addr; | 107 | VirtualBuffer<u64> backing_addr; |
| 72 | |||
| 73 | VirtualBuffer<PageType> attributes; | ||
| 74 | }; | 108 | }; |
| 75 | 109 | ||
| 76 | } // namespace Common | 110 | } // namespace Common |
diff --git a/src/common/scope_exit.h b/src/common/scope_exit.h index 68ef5f197..fa46cb394 100644 --- a/src/common/scope_exit.h +++ b/src/common/scope_exit.h | |||
| @@ -10,7 +10,7 @@ | |||
| 10 | namespace detail { | 10 | namespace detail { |
| 11 | template <typename Func> | 11 | template <typename Func> |
| 12 | struct ScopeExitHelper { | 12 | struct ScopeExitHelper { |
| 13 | explicit ScopeExitHelper(Func&& func) : func(std::move(func)) {} | 13 | explicit ScopeExitHelper(Func&& func_) : func(std::move(func_)) {} |
| 14 | ~ScopeExitHelper() { | 14 | ~ScopeExitHelper() { |
| 15 | if (active) { | 15 | if (active) { |
| 16 | func(); | 16 | func(); |
diff --git a/src/common/spin_lock.h b/src/common/spin_lock.h index 4f946a258..06ac2f5bb 100644 --- a/src/common/spin_lock.h +++ b/src/common/spin_lock.h | |||
| @@ -15,6 +15,14 @@ namespace Common { | |||
| 15 | */ | 15 | */ |
| 16 | class SpinLock { | 16 | class SpinLock { |
| 17 | public: | 17 | public: |
| 18 | SpinLock() = default; | ||
| 19 | |||
| 20 | SpinLock(const SpinLock&) = delete; | ||
| 21 | SpinLock& operator=(const SpinLock&) = delete; | ||
| 22 | |||
| 23 | SpinLock(SpinLock&&) = delete; | ||
| 24 | SpinLock& operator=(SpinLock&&) = delete; | ||
| 25 | |||
| 18 | void lock(); | 26 | void lock(); |
| 19 | void unlock(); | 27 | void unlock(); |
| 20 | [[nodiscard]] bool try_lock(); | 28 | [[nodiscard]] bool try_lock(); |
diff --git a/src/common/stream.cpp b/src/common/stream.cpp new file mode 100644 index 000000000..bf0496c26 --- /dev/null +++ b/src/common/stream.cpp | |||
| @@ -0,0 +1,47 @@ | |||
| 1 | // Copyright 2020 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <stdexcept> | ||
| 6 | #include "common/common_types.h" | ||
| 7 | #include "common/stream.h" | ||
| 8 | |||
| 9 | namespace Common { | ||
| 10 | |||
| 11 | Stream::Stream() = default; | ||
| 12 | Stream::~Stream() = default; | ||
| 13 | |||
| 14 | void Stream::Seek(s32 offset, SeekOrigin origin) { | ||
| 15 | if (origin == SeekOrigin::SetOrigin) { | ||
| 16 | if (offset < 0) { | ||
| 17 | position = 0; | ||
| 18 | } else if (position >= buffer.size()) { | ||
| 19 | position = buffer.size(); | ||
| 20 | } else { | ||
| 21 | position = offset; | ||
| 22 | } | ||
| 23 | } else if (origin == SeekOrigin::FromCurrentPos) { | ||
| 24 | Seek(static_cast<s32>(position) + offset, SeekOrigin::SetOrigin); | ||
| 25 | } else if (origin == SeekOrigin::FromEnd) { | ||
| 26 | Seek(static_cast<s32>(buffer.size()) - offset, SeekOrigin::SetOrigin); | ||
| 27 | } | ||
| 28 | } | ||
| 29 | |||
| 30 | u8 Stream::ReadByte() { | ||
| 31 | if (position < buffer.size()) { | ||
| 32 | return buffer[position++]; | ||
| 33 | } else { | ||
| 34 | throw std::out_of_range("Attempting to read a byte not within the buffer range"); | ||
| 35 | } | ||
| 36 | } | ||
| 37 | |||
| 38 | void Stream::WriteByte(u8 byte) { | ||
| 39 | if (position == buffer.size()) { | ||
| 40 | buffer.push_back(byte); | ||
| 41 | position++; | ||
| 42 | } else { | ||
| 43 | buffer.insert(buffer.begin() + position, byte); | ||
| 44 | } | ||
| 45 | } | ||
| 46 | |||
| 47 | } // namespace Common | ||
diff --git a/src/common/stream.h b/src/common/stream.h new file mode 100644 index 000000000..0e40692de --- /dev/null +++ b/src/common/stream.h | |||
| @@ -0,0 +1,56 @@ | |||
| 1 | // Copyright 2020 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <vector> | ||
| 8 | #include "common/common_types.h" | ||
| 9 | |||
| 10 | namespace Common { | ||
| 11 | |||
| 12 | enum class SeekOrigin { | ||
| 13 | SetOrigin, | ||
| 14 | FromCurrentPos, | ||
| 15 | FromEnd, | ||
| 16 | }; | ||
| 17 | |||
| 18 | class Stream { | ||
| 19 | public: | ||
| 20 | /// Stream creates a bitstream and provides common functionality on the stream. | ||
| 21 | explicit Stream(); | ||
| 22 | ~Stream(); | ||
| 23 | |||
| 24 | Stream(const Stream&) = delete; | ||
| 25 | Stream& operator=(const Stream&) = delete; | ||
| 26 | |||
| 27 | Stream(Stream&&) = default; | ||
| 28 | Stream& operator=(Stream&&) = default; | ||
| 29 | |||
| 30 | /// Reposition bitstream "cursor" to the specified offset from origin | ||
| 31 | void Seek(s32 offset, SeekOrigin origin); | ||
| 32 | |||
| 33 | /// Reads next byte in the stream buffer and increments position | ||
| 34 | u8 ReadByte(); | ||
| 35 | |||
| 36 | /// Writes byte at current position | ||
| 37 | void WriteByte(u8 byte); | ||
| 38 | |||
| 39 | [[nodiscard]] std::size_t GetPosition() const { | ||
| 40 | return position; | ||
| 41 | } | ||
| 42 | |||
| 43 | [[nodiscard]] std::vector<u8>& GetBuffer() { | ||
| 44 | return buffer; | ||
| 45 | } | ||
| 46 | |||
| 47 | [[nodiscard]] const std::vector<u8>& GetBuffer() const { | ||
| 48 | return buffer; | ||
| 49 | } | ||
| 50 | |||
| 51 | private: | ||
| 52 | std::vector<u8> buffer; | ||
| 53 | std::size_t position{0}; | ||
| 54 | }; | ||
| 55 | |||
| 56 | } // namespace Common | ||
diff --git a/src/common/string_util.cpp b/src/common/string_util.cpp index 84883a1d3..4cba2aaa4 100644 --- a/src/common/string_util.cpp +++ b/src/common/string_util.cpp | |||
| @@ -8,6 +8,7 @@ | |||
| 8 | #include <cstdlib> | 8 | #include <cstdlib> |
| 9 | #include <locale> | 9 | #include <locale> |
| 10 | #include <sstream> | 10 | #include <sstream> |
| 11 | |||
| 11 | #include "common/common_paths.h" | 12 | #include "common/common_paths.h" |
| 12 | #include "common/logging/log.h" | 13 | #include "common/logging/log.h" |
| 13 | #include "common/string_util.h" | 14 | #include "common/string_util.h" |
| @@ -21,14 +22,14 @@ namespace Common { | |||
| 21 | /// Make a string lowercase | 22 | /// Make a string lowercase |
| 22 | std::string ToLower(std::string str) { | 23 | std::string ToLower(std::string str) { |
| 23 | std::transform(str.begin(), str.end(), str.begin(), | 24 | std::transform(str.begin(), str.end(), str.begin(), |
| 24 | [](unsigned char c) { return std::tolower(c); }); | 25 | [](unsigned char c) { return static_cast<char>(std::tolower(c)); }); |
| 25 | return str; | 26 | return str; |
| 26 | } | 27 | } |
| 27 | 28 | ||
| 28 | /// Make a string uppercase | 29 | /// Make a string uppercase |
| 29 | std::string ToUpper(std::string str) { | 30 | std::string ToUpper(std::string str) { |
| 30 | std::transform(str.begin(), str.end(), str.begin(), | 31 | std::transform(str.begin(), str.end(), str.begin(), |
| 31 | [](unsigned char c) { return std::toupper(c); }); | 32 | [](unsigned char c) { return static_cast<char>(std::toupper(c)); }); |
| 32 | return str; | 33 | return str; |
| 33 | } | 34 | } |
| 34 | 35 | ||
diff --git a/src/common/swap.h b/src/common/swap.h index 7665942a2..a80e191dc 100644 --- a/src/common/swap.h +++ b/src/common/swap.h | |||
| @@ -394,7 +394,7 @@ public: | |||
| 394 | template <typename S, typename T2, typename F2> | 394 | template <typename S, typename T2, typename F2> |
| 395 | friend S operator%(const S& p, const swapped_t v); | 395 | friend S operator%(const S& p, const swapped_t v); |
| 396 | 396 | ||
| 397 | // Arithmetics + assignements | 397 | // Arithmetics + assignments |
| 398 | template <typename S, typename T2, typename F2> | 398 | template <typename S, typename T2, typename F2> |
| 399 | friend S operator+=(const S& p, const swapped_t v); | 399 | friend S operator+=(const S& p, const swapped_t v); |
| 400 | 400 | ||
| @@ -451,7 +451,7 @@ S operator%(const S& i, const swap_struct_t<T, F> v) { | |||
| 451 | return i % v.swap(); | 451 | return i % v.swap(); |
| 452 | } | 452 | } |
| 453 | 453 | ||
| 454 | // Arithmetics + assignements | 454 | // Arithmetics + assignments |
| 455 | template <typename S, typename T, typename F> | 455 | template <typename S, typename T, typename F> |
| 456 | S& operator+=(S& i, const swap_struct_t<T, F> v) { | 456 | S& operator+=(S& i, const swap_struct_t<T, F> v) { |
| 457 | i += v.swap(); | 457 | i += v.swap(); |
diff --git a/src/common/telemetry.h b/src/common/telemetry.h index a50c5d1de..49186e848 100644 --- a/src/common/telemetry.h +++ b/src/common/telemetry.h | |||
| @@ -52,8 +52,8 @@ public: | |||
| 52 | template <typename T> | 52 | template <typename T> |
| 53 | class Field : public FieldInterface { | 53 | class Field : public FieldInterface { |
| 54 | public: | 54 | public: |
| 55 | Field(FieldType type, std::string name, T value) | 55 | Field(FieldType type_, std::string name_, T value_) |
| 56 | : name(std::move(name)), type(type), value(std::move(value)) {} | 56 | : name(std::move(name_)), type(type_), value(std::move(value_)) {} |
| 57 | 57 | ||
| 58 | Field(const Field&) = default; | 58 | Field(const Field&) = default; |
| 59 | Field& operator=(const Field&) = default; | 59 | Field& operator=(const Field&) = default; |
diff --git a/src/common/thread_worker.cpp b/src/common/thread_worker.cpp new file mode 100644 index 000000000..8f9bf447a --- /dev/null +++ b/src/common/thread_worker.cpp | |||
| @@ -0,0 +1,58 @@ | |||
| 1 | // Copyright 2020 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "common/thread.h" | ||
| 6 | #include "common/thread_worker.h" | ||
| 7 | |||
| 8 | namespace Common { | ||
| 9 | |||
| 10 | ThreadWorker::ThreadWorker(std::size_t num_workers, const std::string& name) { | ||
| 11 | for (std::size_t i = 0; i < num_workers; ++i) | ||
| 12 | threads.emplace_back([this, thread_name{std::string{name}}] { | ||
| 13 | Common::SetCurrentThreadName(thread_name.c_str()); | ||
| 14 | |||
| 15 | // Wait for first request | ||
| 16 | { | ||
| 17 | std::unique_lock lock{queue_mutex}; | ||
| 18 | condition.wait(lock, [this] { return stop || !requests.empty(); }); | ||
| 19 | } | ||
| 20 | |||
| 21 | while (true) { | ||
| 22 | std::function<void()> task; | ||
| 23 | |||
| 24 | { | ||
| 25 | std::unique_lock lock{queue_mutex}; | ||
| 26 | condition.wait(lock, [this] { return stop || !requests.empty(); }); | ||
| 27 | if (stop || requests.empty()) { | ||
| 28 | return; | ||
| 29 | } | ||
| 30 | task = std::move(requests.front()); | ||
| 31 | requests.pop(); | ||
| 32 | } | ||
| 33 | |||
| 34 | task(); | ||
| 35 | } | ||
| 36 | }); | ||
| 37 | } | ||
| 38 | |||
| 39 | ThreadWorker::~ThreadWorker() { | ||
| 40 | { | ||
| 41 | std::unique_lock lock{queue_mutex}; | ||
| 42 | stop = true; | ||
| 43 | } | ||
| 44 | condition.notify_all(); | ||
| 45 | for (std::thread& thread : threads) { | ||
| 46 | thread.join(); | ||
| 47 | } | ||
| 48 | } | ||
| 49 | |||
| 50 | void ThreadWorker::QueueWork(std::function<void()>&& work) { | ||
| 51 | { | ||
| 52 | std::unique_lock lock{queue_mutex}; | ||
| 53 | requests.emplace(work); | ||
| 54 | } | ||
| 55 | condition.notify_one(); | ||
| 56 | } | ||
| 57 | |||
| 58 | } // namespace Common | ||
diff --git a/src/common/thread_worker.h b/src/common/thread_worker.h new file mode 100644 index 000000000..f1859971f --- /dev/null +++ b/src/common/thread_worker.h | |||
| @@ -0,0 +1,30 @@ | |||
| 1 | // Copyright 2020 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <atomic> | ||
| 8 | #include <functional> | ||
| 9 | #include <mutex> | ||
| 10 | #include <string> | ||
| 11 | #include <vector> | ||
| 12 | #include <queue> | ||
| 13 | |||
| 14 | namespace Common { | ||
| 15 | |||
| 16 | class ThreadWorker final { | ||
| 17 | public: | ||
| 18 | explicit ThreadWorker(std::size_t num_workers, const std::string& name); | ||
| 19 | ~ThreadWorker(); | ||
| 20 | void QueueWork(std::function<void()>&& work); | ||
| 21 | |||
| 22 | private: | ||
| 23 | std::vector<std::thread> threads; | ||
| 24 | std::queue<std::function<void()>> requests; | ||
| 25 | std::mutex queue_mutex; | ||
| 26 | std::condition_variable condition; | ||
| 27 | std::atomic_bool stop{}; | ||
| 28 | }; | ||
| 29 | |||
| 30 | } // namespace Common | ||
diff --git a/src/common/timer.cpp b/src/common/timer.cpp index 2dc15e434..d17dc2a50 100644 --- a/src/common/timer.cpp +++ b/src/common/timer.cpp | |||
| @@ -142,20 +142,18 @@ std::string Timer::GetTimeFormatted() { | |||
| 142 | // ---------------- | 142 | // ---------------- |
| 143 | double Timer::GetDoubleTime() { | 143 | double Timer::GetDoubleTime() { |
| 144 | // Get continuous timestamp | 144 | // Get continuous timestamp |
| 145 | u64 TmpSeconds = static_cast<u64>(Common::Timer::GetTimeSinceJan1970().count()); | 145 | auto tmp_seconds = static_cast<u64>(GetTimeSinceJan1970().count()); |
| 146 | double ms = static_cast<u64>(GetTimeMs().count()) % 1000; | 146 | const auto ms = static_cast<double>(static_cast<u64>(GetTimeMs().count()) % 1000); |
| 147 | 147 | ||
| 148 | // Remove a few years. We only really want enough seconds to make | 148 | // Remove a few years. We only really want enough seconds to make |
| 149 | // sure that we are detecting actual actions, perhaps 60 seconds is | 149 | // sure that we are detecting actual actions, perhaps 60 seconds is |
| 150 | // enough really, but I leave a year of seconds anyway, in case the | 150 | // enough really, but I leave a year of seconds anyway, in case the |
| 151 | // user's clock is incorrect or something like that. | 151 | // user's clock is incorrect or something like that. |
| 152 | TmpSeconds = TmpSeconds - (38 * 365 * 24 * 60 * 60); | 152 | tmp_seconds = tmp_seconds - (38 * 365 * 24 * 60 * 60); |
| 153 | 153 | ||
| 154 | // Make a smaller integer that fits in the double | 154 | // Make a smaller integer that fits in the double |
| 155 | u32 Seconds = static_cast<u32>(TmpSeconds); | 155 | const auto seconds = static_cast<u32>(tmp_seconds); |
| 156 | double TmpTime = Seconds + ms; | 156 | return seconds + ms; |
| 157 | |||
| 158 | return TmpTime; | ||
| 159 | } | 157 | } |
| 160 | 158 | ||
| 161 | } // Namespace Common | 159 | } // Namespace Common |
diff --git a/src/common/vector_math.h b/src/common/vector_math.h index 2a0fcf541..22dba3c2d 100644 --- a/src/common/vector_math.h +++ b/src/common/vector_math.h | |||
| @@ -87,7 +87,13 @@ public: | |||
| 87 | 87 | ||
| 88 | template <typename V> | 88 | template <typename V> |
| 89 | [[nodiscard]] constexpr Vec2<decltype(T{} * V{})> operator*(const V& f) const { | 89 | [[nodiscard]] constexpr Vec2<decltype(T{} * V{})> operator*(const V& f) const { |
| 90 | return {x * f, y * f}; | 90 | using TV = decltype(T{} * V{}); |
| 91 | using C = std::common_type_t<T, V>; | ||
| 92 | |||
| 93 | return { | ||
| 94 | static_cast<TV>(static_cast<C>(x) * static_cast<C>(f)), | ||
| 95 | static_cast<TV>(static_cast<C>(y) * static_cast<C>(f)), | ||
| 96 | }; | ||
| 91 | } | 97 | } |
| 92 | 98 | ||
| 93 | template <typename V> | 99 | template <typename V> |
| @@ -98,7 +104,13 @@ public: | |||
| 98 | 104 | ||
| 99 | template <typename V> | 105 | template <typename V> |
| 100 | [[nodiscard]] constexpr Vec2<decltype(T{} / V{})> operator/(const V& f) const { | 106 | [[nodiscard]] constexpr Vec2<decltype(T{} / V{})> operator/(const V& f) const { |
| 101 | return {x / f, y / f}; | 107 | using TV = decltype(T{} / V{}); |
| 108 | using C = std::common_type_t<T, V>; | ||
| 109 | |||
| 110 | return { | ||
| 111 | static_cast<TV>(static_cast<C>(x) / static_cast<C>(f)), | ||
| 112 | static_cast<TV>(static_cast<C>(y) / static_cast<C>(f)), | ||
| 113 | }; | ||
| 102 | } | 114 | } |
| 103 | 115 | ||
| 104 | template <typename V> | 116 | template <typename V> |
| @@ -168,7 +180,10 @@ public: | |||
| 168 | 180 | ||
| 169 | template <typename T, typename V> | 181 | template <typename T, typename V> |
| 170 | [[nodiscard]] constexpr Vec2<T> operator*(const V& f, const Vec2<T>& vec) { | 182 | [[nodiscard]] constexpr Vec2<T> operator*(const V& f, const Vec2<T>& vec) { |
| 171 | return Vec2<T>(f * vec.x, f * vec.y); | 183 | using C = std::common_type_t<T, V>; |
| 184 | |||
| 185 | return Vec2<T>(static_cast<T>(static_cast<C>(f) * static_cast<C>(vec.x)), | ||
| 186 | static_cast<T>(static_cast<C>(f) * static_cast<C>(vec.y))); | ||
| 172 | } | 187 | } |
| 173 | 188 | ||
| 174 | using Vec2f = Vec2<float>; | 189 | using Vec2f = Vec2<float>; |
| @@ -237,7 +252,14 @@ public: | |||
| 237 | 252 | ||
| 238 | template <typename V> | 253 | template <typename V> |
| 239 | [[nodiscard]] constexpr Vec3<decltype(T{} * V{})> operator*(const V& f) const { | 254 | [[nodiscard]] constexpr Vec3<decltype(T{} * V{})> operator*(const V& f) const { |
| 240 | return {x * f, y * f, z * f}; | 255 | using TV = decltype(T{} * V{}); |
| 256 | using C = std::common_type_t<T, V>; | ||
| 257 | |||
| 258 | return { | ||
| 259 | static_cast<TV>(static_cast<C>(x) * static_cast<C>(f)), | ||
| 260 | static_cast<TV>(static_cast<C>(y) * static_cast<C>(f)), | ||
| 261 | static_cast<TV>(static_cast<C>(z) * static_cast<C>(f)), | ||
| 262 | }; | ||
| 241 | } | 263 | } |
| 242 | 264 | ||
| 243 | template <typename V> | 265 | template <typename V> |
| @@ -247,7 +269,14 @@ public: | |||
| 247 | } | 269 | } |
| 248 | template <typename V> | 270 | template <typename V> |
| 249 | [[nodiscard]] constexpr Vec3<decltype(T{} / V{})> operator/(const V& f) const { | 271 | [[nodiscard]] constexpr Vec3<decltype(T{} / V{})> operator/(const V& f) const { |
| 250 | return {x / f, y / f, z / f}; | 272 | using TV = decltype(T{} / V{}); |
| 273 | using C = std::common_type_t<T, V>; | ||
| 274 | |||
| 275 | return { | ||
| 276 | static_cast<TV>(static_cast<C>(x) / static_cast<C>(f)), | ||
| 277 | static_cast<TV>(static_cast<C>(y) / static_cast<C>(f)), | ||
| 278 | static_cast<TV>(static_cast<C>(z) / static_cast<C>(f)), | ||
| 279 | }; | ||
| 251 | } | 280 | } |
| 252 | 281 | ||
| 253 | template <typename V> | 282 | template <typename V> |
| @@ -367,7 +396,11 @@ public: | |||
| 367 | 396 | ||
| 368 | template <typename T, typename V> | 397 | template <typename T, typename V> |
| 369 | [[nodiscard]] constexpr Vec3<T> operator*(const V& f, const Vec3<T>& vec) { | 398 | [[nodiscard]] constexpr Vec3<T> operator*(const V& f, const Vec3<T>& vec) { |
| 370 | return Vec3<T>(f * vec.x, f * vec.y, f * vec.z); | 399 | using C = std::common_type_t<T, V>; |
| 400 | |||
| 401 | return Vec3<T>(static_cast<T>(static_cast<C>(f) * static_cast<C>(vec.x)), | ||
| 402 | static_cast<T>(static_cast<C>(f) * static_cast<C>(vec.y)), | ||
| 403 | static_cast<T>(static_cast<C>(f) * static_cast<C>(vec.z))); | ||
| 371 | } | 404 | } |
| 372 | 405 | ||
| 373 | template <> | 406 | template <> |
| @@ -446,7 +479,15 @@ public: | |||
| 446 | 479 | ||
| 447 | template <typename V> | 480 | template <typename V> |
| 448 | [[nodiscard]] constexpr Vec4<decltype(T{} * V{})> operator*(const V& f) const { | 481 | [[nodiscard]] constexpr Vec4<decltype(T{} * V{})> operator*(const V& f) const { |
| 449 | return {x * f, y * f, z * f, w * f}; | 482 | using TV = decltype(T{} * V{}); |
| 483 | using C = std::common_type_t<T, V>; | ||
| 484 | |||
| 485 | return { | ||
| 486 | static_cast<TV>(static_cast<C>(x) * static_cast<C>(f)), | ||
| 487 | static_cast<TV>(static_cast<C>(y) * static_cast<C>(f)), | ||
| 488 | static_cast<TV>(static_cast<C>(z) * static_cast<C>(f)), | ||
| 489 | static_cast<TV>(static_cast<C>(w) * static_cast<C>(f)), | ||
| 490 | }; | ||
| 450 | } | 491 | } |
| 451 | 492 | ||
| 452 | template <typename V> | 493 | template <typename V> |
| @@ -457,7 +498,15 @@ public: | |||
| 457 | 498 | ||
| 458 | template <typename V> | 499 | template <typename V> |
| 459 | [[nodiscard]] constexpr Vec4<decltype(T{} / V{})> operator/(const V& f) const { | 500 | [[nodiscard]] constexpr Vec4<decltype(T{} / V{})> operator/(const V& f) const { |
| 460 | return {x / f, y / f, z / f, w / f}; | 501 | using TV = decltype(T{} / V{}); |
| 502 | using C = std::common_type_t<T, V>; | ||
| 503 | |||
| 504 | return { | ||
| 505 | static_cast<TV>(static_cast<C>(x) / static_cast<C>(f)), | ||
| 506 | static_cast<TV>(static_cast<C>(y) / static_cast<C>(f)), | ||
| 507 | static_cast<TV>(static_cast<C>(z) / static_cast<C>(f)), | ||
| 508 | static_cast<TV>(static_cast<C>(w) / static_cast<C>(f)), | ||
| 509 | }; | ||
| 461 | } | 510 | } |
| 462 | 511 | ||
| 463 | template <typename V> | 512 | template <typename V> |
| @@ -582,7 +631,15 @@ public: | |||
| 582 | 631 | ||
| 583 | template <typename T, typename V> | 632 | template <typename T, typename V> |
| 584 | [[nodiscard]] constexpr Vec4<decltype(V{} * T{})> operator*(const V& f, const Vec4<T>& vec) { | 633 | [[nodiscard]] constexpr Vec4<decltype(V{} * T{})> operator*(const V& f, const Vec4<T>& vec) { |
| 585 | return {f * vec.x, f * vec.y, f * vec.z, f * vec.w}; | 634 | using TV = decltype(V{} * T{}); |
| 635 | using C = std::common_type_t<T, V>; | ||
| 636 | |||
| 637 | return { | ||
| 638 | static_cast<TV>(static_cast<C>(f) * static_cast<C>(vec.x)), | ||
| 639 | static_cast<TV>(static_cast<C>(f) * static_cast<C>(vec.y)), | ||
| 640 | static_cast<TV>(static_cast<C>(f) * static_cast<C>(vec.z)), | ||
| 641 | static_cast<TV>(static_cast<C>(f) * static_cast<C>(vec.w)), | ||
| 642 | }; | ||
| 586 | } | 643 | } |
| 587 | 644 | ||
| 588 | using Vec4f = Vec4<float>; | 645 | using Vec4f = Vec4<float>; |
diff --git a/src/common/virtual_buffer.cpp b/src/common/virtual_buffer.cpp index b009cb500..e3ca29258 100644 --- a/src/common/virtual_buffer.cpp +++ b/src/common/virtual_buffer.cpp | |||
| @@ -13,7 +13,7 @@ | |||
| 13 | 13 | ||
| 14 | namespace Common { | 14 | namespace Common { |
| 15 | 15 | ||
| 16 | void* AllocateMemoryPages(std::size_t size) { | 16 | void* AllocateMemoryPages(std::size_t size) noexcept { |
| 17 | #ifdef _WIN32 | 17 | #ifdef _WIN32 |
| 18 | void* base{VirtualAlloc(nullptr, size, MEM_COMMIT, PAGE_READWRITE)}; | 18 | void* base{VirtualAlloc(nullptr, size, MEM_COMMIT, PAGE_READWRITE)}; |
| 19 | #else | 19 | #else |
| @@ -29,7 +29,7 @@ void* AllocateMemoryPages(std::size_t size) { | |||
| 29 | return base; | 29 | return base; |
| 30 | } | 30 | } |
| 31 | 31 | ||
| 32 | void FreeMemoryPages(void* base, [[maybe_unused]] std::size_t size) { | 32 | void FreeMemoryPages(void* base, [[maybe_unused]] std::size_t size) noexcept { |
| 33 | if (!base) { | 33 | if (!base) { |
| 34 | return; | 34 | return; |
| 35 | } | 35 | } |
diff --git a/src/common/virtual_buffer.h b/src/common/virtual_buffer.h index 125cb42f0..fb1a6f81f 100644 --- a/src/common/virtual_buffer.h +++ b/src/common/virtual_buffer.h | |||
| @@ -4,29 +4,55 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include "common/common_funcs.h" | 7 | #include <type_traits> |
| 8 | #include <utility> | ||
| 8 | 9 | ||
| 9 | namespace Common { | 10 | namespace Common { |
| 10 | 11 | ||
| 11 | void* AllocateMemoryPages(std::size_t size); | 12 | void* AllocateMemoryPages(std::size_t size) noexcept; |
| 12 | void FreeMemoryPages(void* base, std::size_t size); | 13 | void FreeMemoryPages(void* base, std::size_t size) noexcept; |
| 13 | 14 | ||
| 14 | template <typename T> | 15 | template <typename T> |
| 15 | class VirtualBuffer final : NonCopyable { | 16 | class VirtualBuffer final { |
| 16 | public: | 17 | public: |
| 18 | // TODO: Uncomment this and change Common::PageTable::PageInfo to be trivially constructible | ||
| 19 | // using std::atomic_ref once libc++ has support for it | ||
| 20 | // static_assert( | ||
| 21 | // std::is_trivially_constructible_v<T>, | ||
| 22 | // "T must be trivially constructible, as non-trivial constructors will not be executed " | ||
| 23 | // "with the current allocator"); | ||
| 24 | |||
| 17 | constexpr VirtualBuffer() = default; | 25 | constexpr VirtualBuffer() = default; |
| 18 | explicit VirtualBuffer(std::size_t count) : alloc_size{count * sizeof(T)} { | 26 | explicit VirtualBuffer(std::size_t count) : alloc_size{count * sizeof(T)} { |
| 19 | base_ptr = reinterpret_cast<T*>(AllocateMemoryPages(alloc_size)); | 27 | base_ptr = reinterpret_cast<T*>(AllocateMemoryPages(alloc_size)); |
| 20 | } | 28 | } |
| 21 | 29 | ||
| 22 | ~VirtualBuffer() { | 30 | ~VirtualBuffer() noexcept { |
| 23 | FreeMemoryPages(base_ptr, alloc_size); | 31 | FreeMemoryPages(base_ptr, alloc_size); |
| 24 | } | 32 | } |
| 25 | 33 | ||
| 34 | VirtualBuffer(const VirtualBuffer&) = delete; | ||
| 35 | VirtualBuffer& operator=(const VirtualBuffer&) = delete; | ||
| 36 | |||
| 37 | VirtualBuffer(VirtualBuffer&& other) noexcept | ||
| 38 | : alloc_size{std::exchange(other.alloc_size, 0)}, base_ptr{std::exchange(other.base_ptr), | ||
| 39 | nullptr} {} | ||
| 40 | |||
| 41 | VirtualBuffer& operator=(VirtualBuffer&& other) noexcept { | ||
| 42 | alloc_size = std::exchange(other.alloc_size, 0); | ||
| 43 | base_ptr = std::exchange(other.base_ptr, nullptr); | ||
| 44 | return *this; | ||
| 45 | } | ||
| 46 | |||
| 26 | void resize(std::size_t count) { | 47 | void resize(std::size_t count) { |
| 48 | const auto new_size = count * sizeof(T); | ||
| 49 | if (new_size == alloc_size) { | ||
| 50 | return; | ||
| 51 | } | ||
| 52 | |||
| 27 | FreeMemoryPages(base_ptr, alloc_size); | 53 | FreeMemoryPages(base_ptr, alloc_size); |
| 28 | 54 | ||
| 29 | alloc_size = count * sizeof(T); | 55 | alloc_size = new_size; |
| 30 | base_ptr = reinterpret_cast<T*>(AllocateMemoryPages(alloc_size)); | 56 | base_ptr = reinterpret_cast<T*>(AllocateMemoryPages(alloc_size)); |
| 31 | } | 57 | } |
| 32 | 58 | ||
diff --git a/src/common/wall_clock.cpp b/src/common/wall_clock.cpp index 3afbdb898..a8c143f85 100644 --- a/src/common/wall_clock.cpp +++ b/src/common/wall_clock.cpp | |||
| @@ -15,10 +15,10 @@ namespace Common { | |||
| 15 | using base_timer = std::chrono::steady_clock; | 15 | using base_timer = std::chrono::steady_clock; |
| 16 | using base_time_point = std::chrono::time_point<base_timer>; | 16 | using base_time_point = std::chrono::time_point<base_timer>; |
| 17 | 17 | ||
| 18 | class StandardWallClock : public WallClock { | 18 | class StandardWallClock final : public WallClock { |
| 19 | public: | 19 | public: |
| 20 | StandardWallClock(u64 emulated_cpu_frequency, u64 emulated_clock_frequency) | 20 | explicit StandardWallClock(u64 emulated_cpu_frequency_, u64 emulated_clock_frequency_) |
| 21 | : WallClock(emulated_cpu_frequency, emulated_clock_frequency, false) { | 21 | : WallClock(emulated_cpu_frequency_, emulated_clock_frequency_, false) { |
| 22 | start_time = base_timer::now(); | 22 | start_time = base_timer::now(); |
| 23 | } | 23 | } |
| 24 | 24 | ||
| @@ -53,7 +53,7 @@ public: | |||
| 53 | return Common::Divide128On32(temporary, 1000000000).first; | 53 | return Common::Divide128On32(temporary, 1000000000).first; |
| 54 | } | 54 | } |
| 55 | 55 | ||
| 56 | void Pause(bool is_paused) override { | 56 | void Pause([[maybe_unused]] bool is_paused) override { |
| 57 | // Do nothing in this clock type. | 57 | // Do nothing in this clock type. |
| 58 | } | 58 | } |
| 59 | 59 | ||
diff --git a/src/common/wall_clock.h b/src/common/wall_clock.h index 5db30083d..cef3e9499 100644 --- a/src/common/wall_clock.h +++ b/src/common/wall_clock.h | |||
| @@ -13,6 +13,8 @@ namespace Common { | |||
| 13 | 13 | ||
| 14 | class WallClock { | 14 | class WallClock { |
| 15 | public: | 15 | public: |
| 16 | virtual ~WallClock() = default; | ||
| 17 | |||
| 16 | /// Returns current wall time in nanoseconds | 18 | /// Returns current wall time in nanoseconds |
| 17 | [[nodiscard]] virtual std::chrono::nanoseconds GetTimeNS() = 0; | 19 | [[nodiscard]] virtual std::chrono::nanoseconds GetTimeNS() = 0; |
| 18 | 20 | ||
| @@ -36,9 +38,9 @@ public: | |||
| 36 | } | 38 | } |
| 37 | 39 | ||
| 38 | protected: | 40 | protected: |
| 39 | WallClock(u64 emulated_cpu_frequency, u64 emulated_clock_frequency, bool is_native) | 41 | explicit WallClock(u64 emulated_cpu_frequency_, u64 emulated_clock_frequency_, bool is_native_) |
| 40 | : emulated_cpu_frequency{emulated_cpu_frequency}, | 42 | : emulated_cpu_frequency{emulated_cpu_frequency_}, |
| 41 | emulated_clock_frequency{emulated_clock_frequency}, is_native{is_native} {} | 43 | emulated_clock_frequency{emulated_clock_frequency_}, is_native{is_native_} {} |
| 42 | 44 | ||
| 43 | u64 emulated_cpu_frequency; | 45 | u64 emulated_cpu_frequency; |
| 44 | u64 emulated_clock_frequency; | 46 | u64 emulated_clock_frequency; |
diff --git a/src/common/x64/native_clock.cpp b/src/common/x64/native_clock.cpp index 424b39b1f..eb8a7782f 100644 --- a/src/common/x64/native_clock.cpp +++ b/src/common/x64/native_clock.cpp | |||
| @@ -43,10 +43,10 @@ u64 EstimateRDTSCFrequency() { | |||
| 43 | } | 43 | } |
| 44 | 44 | ||
| 45 | namespace X64 { | 45 | namespace X64 { |
| 46 | NativeClock::NativeClock(u64 emulated_cpu_frequency, u64 emulated_clock_frequency, | 46 | NativeClock::NativeClock(u64 emulated_cpu_frequency_, u64 emulated_clock_frequency_, |
| 47 | u64 rtsc_frequency) | 47 | u64 rtsc_frequency_) |
| 48 | : WallClock(emulated_cpu_frequency, emulated_clock_frequency, true), rtsc_frequency{ | 48 | : WallClock(emulated_cpu_frequency_, emulated_clock_frequency_, true), rtsc_frequency{ |
| 49 | rtsc_frequency} { | 49 | rtsc_frequency_} { |
| 50 | _mm_mfence(); | 50 | _mm_mfence(); |
| 51 | last_measure = __rdtsc(); | 51 | last_measure = __rdtsc(); |
| 52 | accumulated_ticks = 0U; | 52 | accumulated_ticks = 0U; |
diff --git a/src/common/x64/native_clock.h b/src/common/x64/native_clock.h index 891a3bbfd..6d1e32ac8 100644 --- a/src/common/x64/native_clock.h +++ b/src/common/x64/native_clock.h | |||
| @@ -12,9 +12,10 @@ | |||
| 12 | namespace Common { | 12 | namespace Common { |
| 13 | 13 | ||
| 14 | namespace X64 { | 14 | namespace X64 { |
| 15 | class NativeClock : public WallClock { | 15 | class NativeClock final : public WallClock { |
| 16 | public: | 16 | public: |
| 17 | NativeClock(u64 emulated_cpu_frequency, u64 emulated_clock_frequency, u64 rtsc_frequency); | 17 | explicit NativeClock(u64 emulated_cpu_frequency_, u64 emulated_clock_frequency_, |
| 18 | u64 rtsc_frequency_); | ||
| 18 | 19 | ||
| 19 | std::chrono::nanoseconds GetTimeNS() override; | 20 | std::chrono::nanoseconds GetTimeNS() override; |
| 20 | 21 | ||
| @@ -34,7 +35,7 @@ private: | |||
| 34 | /// value used to reduce the native clocks accuracy as some apss rely on | 35 | /// value used to reduce the native clocks accuracy as some apss rely on |
| 35 | /// undefined behavior where the level of accuracy in the clock shouldn't | 36 | /// undefined behavior where the level of accuracy in the clock shouldn't |
| 36 | /// be higher. | 37 | /// be higher. |
| 37 | static constexpr u64 inaccuracy_mask = ~(0x400 - 1); | 38 | static constexpr u64 inaccuracy_mask = ~(UINT64_C(0x400) - 1); |
| 38 | 39 | ||
| 39 | SpinLock rtsc_serialize{}; | 40 | SpinLock rtsc_serialize{}; |
| 40 | u64 last_measure{}; | 41 | u64 last_measure{}; |
diff --git a/src/common/x64/xbyak_abi.h b/src/common/x64/xbyak_abi.h index 26e4bfda5..c2c9b6134 100644 --- a/src/common/x64/xbyak_abi.h +++ b/src/common/x64/xbyak_abi.h | |||
| @@ -11,25 +11,25 @@ | |||
| 11 | 11 | ||
| 12 | namespace Common::X64 { | 12 | namespace Common::X64 { |
| 13 | 13 | ||
| 14 | constexpr std::size_t RegToIndex(const Xbyak::Reg& reg) { | 14 | constexpr size_t RegToIndex(const Xbyak::Reg& reg) { |
| 15 | using Kind = Xbyak::Reg::Kind; | 15 | using Kind = Xbyak::Reg::Kind; |
| 16 | ASSERT_MSG((reg.getKind() & (Kind::REG | Kind::XMM)) != 0, | 16 | ASSERT_MSG((reg.getKind() & (Kind::REG | Kind::XMM)) != 0, |
| 17 | "RegSet only support GPRs and XMM registers."); | 17 | "RegSet only support GPRs and XMM registers."); |
| 18 | ASSERT_MSG(reg.getIdx() < 16, "RegSet only supports XXM0-15."); | 18 | ASSERT_MSG(reg.getIdx() < 16, "RegSet only supports XXM0-15."); |
| 19 | return reg.getIdx() + (reg.getKind() == Kind::REG ? 0 : 16); | 19 | return static_cast<size_t>(reg.getIdx()) + (reg.getKind() == Kind::REG ? 0 : 16); |
| 20 | } | 20 | } |
| 21 | 21 | ||
| 22 | constexpr Xbyak::Reg64 IndexToReg64(std::size_t reg_index) { | 22 | constexpr Xbyak::Reg64 IndexToReg64(size_t reg_index) { |
| 23 | ASSERT(reg_index < 16); | 23 | ASSERT(reg_index < 16); |
| 24 | return Xbyak::Reg64(static_cast<int>(reg_index)); | 24 | return Xbyak::Reg64(static_cast<int>(reg_index)); |
| 25 | } | 25 | } |
| 26 | 26 | ||
| 27 | constexpr Xbyak::Xmm IndexToXmm(std::size_t reg_index) { | 27 | constexpr Xbyak::Xmm IndexToXmm(size_t reg_index) { |
| 28 | ASSERT(reg_index >= 16 && reg_index < 32); | 28 | ASSERT(reg_index >= 16 && reg_index < 32); |
| 29 | return Xbyak::Xmm(static_cast<int>(reg_index - 16)); | 29 | return Xbyak::Xmm(static_cast<int>(reg_index - 16)); |
| 30 | } | 30 | } |
| 31 | 31 | ||
| 32 | constexpr Xbyak::Reg IndexToReg(std::size_t reg_index) { | 32 | constexpr Xbyak::Reg IndexToReg(size_t reg_index) { |
| 33 | if (reg_index < 16) { | 33 | if (reg_index < 16) { |
| 34 | return IndexToReg64(reg_index); | 34 | return IndexToReg64(reg_index); |
| 35 | } else { | 35 | } else { |
| @@ -182,7 +182,7 @@ inline size_t ABI_PushRegistersAndAdjustStack(Xbyak::CodeGenerator& code, std::b | |||
| 182 | size_t rsp_alignment, size_t needed_frame_size = 0) { | 182 | size_t rsp_alignment, size_t needed_frame_size = 0) { |
| 183 | auto frame_info = ABI_CalculateFrameSize(regs, rsp_alignment, needed_frame_size); | 183 | auto frame_info = ABI_CalculateFrameSize(regs, rsp_alignment, needed_frame_size); |
| 184 | 184 | ||
| 185 | for (std::size_t i = 0; i < regs.size(); ++i) { | 185 | for (size_t i = 0; i < regs.size(); ++i) { |
| 186 | if (regs[i] && ABI_ALL_GPRS[i]) { | 186 | if (regs[i] && ABI_ALL_GPRS[i]) { |
| 187 | code.push(IndexToReg64(i)); | 187 | code.push(IndexToReg64(i)); |
| 188 | } | 188 | } |
| @@ -192,7 +192,7 @@ inline size_t ABI_PushRegistersAndAdjustStack(Xbyak::CodeGenerator& code, std::b | |||
| 192 | code.sub(code.rsp, frame_info.subtraction); | 192 | code.sub(code.rsp, frame_info.subtraction); |
| 193 | } | 193 | } |
| 194 | 194 | ||
| 195 | for (std::size_t i = 0; i < regs.size(); ++i) { | 195 | for (size_t i = 0; i < regs.size(); ++i) { |
| 196 | if (regs[i] && ABI_ALL_XMMS[i]) { | 196 | if (regs[i] && ABI_ALL_XMMS[i]) { |
| 197 | code.movaps(code.xword[code.rsp + frame_info.xmm_offset], IndexToXmm(i)); | 197 | code.movaps(code.xword[code.rsp + frame_info.xmm_offset], IndexToXmm(i)); |
| 198 | frame_info.xmm_offset += 0x10; | 198 | frame_info.xmm_offset += 0x10; |
| @@ -206,7 +206,7 @@ inline void ABI_PopRegistersAndAdjustStack(Xbyak::CodeGenerator& code, std::bits | |||
| 206 | size_t rsp_alignment, size_t needed_frame_size = 0) { | 206 | size_t rsp_alignment, size_t needed_frame_size = 0) { |
| 207 | auto frame_info = ABI_CalculateFrameSize(regs, rsp_alignment, needed_frame_size); | 207 | auto frame_info = ABI_CalculateFrameSize(regs, rsp_alignment, needed_frame_size); |
| 208 | 208 | ||
| 209 | for (std::size_t i = 0; i < regs.size(); ++i) { | 209 | for (size_t i = 0; i < regs.size(); ++i) { |
| 210 | if (regs[i] && ABI_ALL_XMMS[i]) { | 210 | if (regs[i] && ABI_ALL_XMMS[i]) { |
| 211 | code.movaps(IndexToXmm(i), code.xword[code.rsp + frame_info.xmm_offset]); | 211 | code.movaps(IndexToXmm(i), code.xword[code.rsp + frame_info.xmm_offset]); |
| 212 | frame_info.xmm_offset += 0x10; | 212 | frame_info.xmm_offset += 0x10; |
| @@ -218,8 +218,8 @@ inline void ABI_PopRegistersAndAdjustStack(Xbyak::CodeGenerator& code, std::bits | |||
| 218 | } | 218 | } |
| 219 | 219 | ||
| 220 | // GPRs need to be popped in reverse order | 220 | // GPRs need to be popped in reverse order |
| 221 | for (std::size_t j = 0; j < regs.size(); ++j) { | 221 | for (size_t j = 0; j < regs.size(); ++j) { |
| 222 | const std::size_t i = regs.size() - j - 1; | 222 | const size_t i = regs.size() - j - 1; |
| 223 | if (regs[i] && ABI_ALL_GPRS[i]) { | 223 | if (regs[i] && ABI_ALL_GPRS[i]) { |
| 224 | code.pop(IndexToReg64(i)); | 224 | code.pop(IndexToReg64(i)); |
| 225 | } | 225 | } |