diff options
Diffstat (limited to 'src')
80 files changed, 1904 insertions, 3601 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 61adbef28..478246b6f 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt | |||
| @@ -67,8 +67,11 @@ else() | |||
| 67 | -Werror=implicit-fallthrough | 67 | -Werror=implicit-fallthrough |
| 68 | -Werror=missing-declarations | 68 | -Werror=missing-declarations |
| 69 | -Werror=reorder | 69 | -Werror=reorder |
| 70 | -Werror=switch | ||
| 70 | -Werror=uninitialized | 71 | -Werror=uninitialized |
| 72 | -Werror=unused-function | ||
| 71 | -Werror=unused-result | 73 | -Werror=unused-result |
| 74 | -Werror=unused-variable | ||
| 72 | -Wextra | 75 | -Wextra |
| 73 | -Wmissing-declarations | 76 | -Wmissing-declarations |
| 74 | -Wno-attributes | 77 | -Wno-attributes |
| @@ -127,7 +130,6 @@ add_subdirectory(tests) | |||
| 127 | 130 | ||
| 128 | if (ENABLE_SDL2) | 131 | if (ENABLE_SDL2) |
| 129 | add_subdirectory(yuzu_cmd) | 132 | add_subdirectory(yuzu_cmd) |
| 130 | add_subdirectory(yuzu_tester) | ||
| 131 | endif() | 133 | endif() |
| 132 | 134 | ||
| 133 | if (ENABLE_QT) | 135 | if (ENABLE_QT) |
diff --git a/src/audio_core/sink_context.h b/src/audio_core/sink_context.h index 05541becb..66ee4e8a0 100644 --- a/src/audio_core/sink_context.h +++ b/src/audio_core/sink_context.h | |||
| @@ -40,17 +40,17 @@ public: | |||
| 40 | SinkSampleFormat sample_format; | 40 | SinkSampleFormat sample_format; |
| 41 | std::array<u8, AudioCommon::MAX_CHANNEL_COUNT> input; | 41 | std::array<u8, AudioCommon::MAX_CHANNEL_COUNT> input; |
| 42 | bool in_use; | 42 | bool in_use; |
| 43 | INSERT_UNION_PADDING_BYTES(5); | 43 | INSERT_PADDING_BYTES_NOINIT(5); |
| 44 | }; | 44 | }; |
| 45 | static_assert(sizeof(CircularBufferIn) == 0x28, | 45 | static_assert(sizeof(CircularBufferIn) == 0x28, |
| 46 | "SinkInfo::CircularBufferIn is in invalid size"); | 46 | "SinkInfo::CircularBufferIn is in invalid size"); |
| 47 | 47 | ||
| 48 | struct DeviceIn { | 48 | struct DeviceIn { |
| 49 | std::array<u8, 255> device_name; | 49 | std::array<u8, 255> device_name; |
| 50 | INSERT_UNION_PADDING_BYTES(1); | 50 | INSERT_PADDING_BYTES_NOINIT(1); |
| 51 | s32_le input_count; | 51 | s32_le input_count; |
| 52 | std::array<u8, AudioCommon::MAX_CHANNEL_COUNT> input; | 52 | std::array<u8, AudioCommon::MAX_CHANNEL_COUNT> input; |
| 53 | INSERT_UNION_PADDING_BYTES(1); | 53 | INSERT_PADDING_BYTES_NOINIT(1); |
| 54 | bool down_matrix_enabled; | 54 | bool down_matrix_enabled; |
| 55 | DownmixCoefficients down_matrix_coef; | 55 | DownmixCoefficients down_matrix_coef; |
| 56 | }; | 56 | }; |
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index 5d781cd77..f77575a00 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt | |||
| @@ -98,7 +98,6 @@ add_library(common STATIC | |||
| 98 | algorithm.h | 98 | algorithm.h |
| 99 | alignment.h | 99 | alignment.h |
| 100 | assert.h | 100 | assert.h |
| 101 | atomic_ops.cpp | ||
| 102 | atomic_ops.h | 101 | atomic_ops.h |
| 103 | detached_tasks.cpp | 102 | detached_tasks.cpp |
| 104 | detached_tasks.h | 103 | detached_tasks.h |
| @@ -108,7 +107,6 @@ add_library(common STATIC | |||
| 108 | bit_util.h | 107 | bit_util.h |
| 109 | cityhash.cpp | 108 | cityhash.cpp |
| 110 | cityhash.h | 109 | cityhash.h |
| 111 | color.h | ||
| 112 | common_funcs.h | 110 | common_funcs.h |
| 113 | common_paths.h | 111 | common_paths.h |
| 114 | common_types.h | 112 | common_types.h |
| @@ -167,8 +165,6 @@ add_library(common STATIC | |||
| 167 | threadsafe_queue.h | 165 | threadsafe_queue.h |
| 168 | time_zone.cpp | 166 | time_zone.cpp |
| 169 | time_zone.h | 167 | time_zone.h |
| 170 | timer.cpp | ||
| 171 | timer.h | ||
| 172 | tree.h | 168 | tree.h |
| 173 | uint128.cpp | 169 | uint128.cpp |
| 174 | uint128.h | 170 | uint128.h |
diff --git a/src/common/alignment.h b/src/common/alignment.h index 5040043de..fb81f10d8 100644 --- a/src/common/alignment.h +++ b/src/common/alignment.h | |||
| @@ -9,50 +9,45 @@ | |||
| 9 | namespace Common { | 9 | namespace Common { |
| 10 | 10 | ||
| 11 | template <typename T> | 11 | template <typename T> |
| 12 | [[nodiscard]] constexpr T AlignUp(T value, std::size_t size) { | 12 | requires std::is_unsigned_v<T>[[nodiscard]] constexpr T AlignUp(T value, size_t size) { |
| 13 | static_assert(std::is_unsigned_v<T>, "T must be an unsigned value."); | ||
| 14 | auto mod{static_cast<T>(value % size)}; | 13 | auto mod{static_cast<T>(value % size)}; |
| 15 | value -= mod; | 14 | value -= mod; |
| 16 | return static_cast<T>(mod == T{0} ? value : value + size); | 15 | return static_cast<T>(mod == T{0} ? value : value + size); |
| 17 | } | 16 | } |
| 18 | 17 | ||
| 19 | template <typename T> | 18 | template <typename T> |
| 20 | [[nodiscard]] constexpr T AlignDown(T value, std::size_t size) { | 19 | requires std::is_unsigned_v<T>[[nodiscard]] constexpr T AlignUpLog2(T value, size_t align_log2) { |
| 21 | static_assert(std::is_unsigned_v<T>, "T must be an unsigned value."); | 20 | return static_cast<T>((value + ((1ULL << align_log2) - 1)) >> align_log2 << align_log2); |
| 22 | return static_cast<T>(value - value % size); | ||
| 23 | } | 21 | } |
| 24 | 22 | ||
| 25 | template <typename T> | 23 | template <typename T> |
| 26 | [[nodiscard]] constexpr T AlignBits(T value, std::size_t align) { | 24 | requires std::is_unsigned_v<T>[[nodiscard]] constexpr T AlignDown(T value, size_t size) { |
| 27 | static_assert(std::is_unsigned_v<T>, "T must be an unsigned value."); | 25 | return static_cast<T>(value - value % size); |
| 28 | return static_cast<T>((value + ((1ULL << align) - 1)) >> align << align); | ||
| 29 | } | 26 | } |
| 30 | 27 | ||
| 31 | template <typename T> | 28 | template <typename T> |
| 32 | [[nodiscard]] constexpr bool Is4KBAligned(T value) { | 29 | requires std::is_unsigned_v<T>[[nodiscard]] constexpr bool Is4KBAligned(T value) { |
| 33 | static_assert(std::is_unsigned_v<T>, "T must be an unsigned value."); | ||
| 34 | return (value & 0xFFF) == 0; | 30 | return (value & 0xFFF) == 0; |
| 35 | } | 31 | } |
| 36 | 32 | ||
| 37 | template <typename T> | 33 | template <typename T> |
| 38 | [[nodiscard]] constexpr bool IsWordAligned(T value) { | 34 | requires std::is_unsigned_v<T>[[nodiscard]] constexpr bool IsWordAligned(T value) { |
| 39 | static_assert(std::is_unsigned_v<T>, "T must be an unsigned value."); | ||
| 40 | return (value & 0b11) == 0; | 35 | return (value & 0b11) == 0; |
| 41 | } | 36 | } |
| 42 | 37 | ||
| 43 | template <typename T> | 38 | template <typename T> |
| 44 | [[nodiscard]] constexpr bool IsAligned(T value, std::size_t alignment) { | 39 | requires std::is_integral_v<T>[[nodiscard]] constexpr bool IsAligned(T value, size_t alignment) { |
| 45 | using U = typename std::make_unsigned<T>::type; | 40 | using U = typename std::make_unsigned_t<T>; |
| 46 | const U mask = static_cast<U>(alignment - 1); | 41 | const U mask = static_cast<U>(alignment - 1); |
| 47 | return (value & mask) == 0; | 42 | return (value & mask) == 0; |
| 48 | } | 43 | } |
| 49 | 44 | ||
| 50 | template <typename T, std::size_t Align = 16> | 45 | template <typename T, size_t Align = 16> |
| 51 | class AlignmentAllocator { | 46 | class AlignmentAllocator { |
| 52 | public: | 47 | public: |
| 53 | using value_type = T; | 48 | using value_type = T; |
| 54 | using size_type = std::size_t; | 49 | using size_type = size_t; |
| 55 | using difference_type = std::ptrdiff_t; | 50 | using difference_type = ptrdiff_t; |
| 56 | 51 | ||
| 57 | using propagate_on_container_copy_assignment = std::true_type; | 52 | using propagate_on_container_copy_assignment = std::true_type; |
| 58 | using propagate_on_container_move_assignment = std::true_type; | 53 | using propagate_on_container_move_assignment = std::true_type; |
diff --git a/src/common/atomic_ops.cpp b/src/common/atomic_ops.cpp deleted file mode 100644 index 1612d0e67..000000000 --- a/src/common/atomic_ops.cpp +++ /dev/null | |||
| @@ -1,75 +0,0 @@ | |||
| 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 <cstring> | ||
| 6 | |||
| 7 | #include "common/atomic_ops.h" | ||
| 8 | |||
| 9 | #if _MSC_VER | ||
| 10 | #include <intrin.h> | ||
| 11 | #endif | ||
| 12 | |||
| 13 | namespace Common { | ||
| 14 | |||
| 15 | #if _MSC_VER | ||
| 16 | |||
| 17 | bool AtomicCompareAndSwap(volatile u8* pointer, u8 value, u8 expected) { | ||
| 18 | const u8 result = | ||
| 19 | _InterlockedCompareExchange8(reinterpret_cast<volatile char*>(pointer), value, expected); | ||
| 20 | return result == expected; | ||
| 21 | } | ||
| 22 | |||
| 23 | bool AtomicCompareAndSwap(volatile u16* pointer, u16 value, u16 expected) { | ||
| 24 | const u16 result = | ||
| 25 | _InterlockedCompareExchange16(reinterpret_cast<volatile short*>(pointer), value, expected); | ||
| 26 | return result == expected; | ||
| 27 | } | ||
| 28 | |||
| 29 | bool AtomicCompareAndSwap(volatile u32* pointer, u32 value, u32 expected) { | ||
| 30 | const u32 result = | ||
| 31 | _InterlockedCompareExchange(reinterpret_cast<volatile long*>(pointer), value, expected); | ||
| 32 | return result == expected; | ||
| 33 | } | ||
| 34 | |||
| 35 | bool AtomicCompareAndSwap(volatile u64* pointer, u64 value, u64 expected) { | ||
| 36 | const u64 result = _InterlockedCompareExchange64(reinterpret_cast<volatile __int64*>(pointer), | ||
| 37 | value, expected); | ||
| 38 | return result == expected; | ||
| 39 | } | ||
| 40 | |||
| 41 | bool AtomicCompareAndSwap(volatile u64* pointer, u128 value, u128 expected) { | ||
| 42 | return _InterlockedCompareExchange128(reinterpret_cast<volatile __int64*>(pointer), value[1], | ||
| 43 | value[0], | ||
| 44 | reinterpret_cast<__int64*>(expected.data())) != 0; | ||
| 45 | } | ||
| 46 | |||
| 47 | #else | ||
| 48 | |||
| 49 | bool AtomicCompareAndSwap(volatile u8* pointer, u8 value, u8 expected) { | ||
| 50 | return __sync_bool_compare_and_swap(pointer, expected, value); | ||
| 51 | } | ||
| 52 | |||
| 53 | bool AtomicCompareAndSwap(volatile u16* pointer, u16 value, u16 expected) { | ||
| 54 | return __sync_bool_compare_and_swap(pointer, expected, value); | ||
| 55 | } | ||
| 56 | |||
| 57 | bool AtomicCompareAndSwap(volatile u32* pointer, u32 value, u32 expected) { | ||
| 58 | return __sync_bool_compare_and_swap(pointer, expected, value); | ||
| 59 | } | ||
| 60 | |||
| 61 | bool AtomicCompareAndSwap(volatile u64* pointer, u64 value, u64 expected) { | ||
| 62 | return __sync_bool_compare_and_swap(pointer, expected, value); | ||
| 63 | } | ||
| 64 | |||
| 65 | bool AtomicCompareAndSwap(volatile u64* pointer, u128 value, u128 expected) { | ||
| 66 | unsigned __int128 value_a; | ||
| 67 | unsigned __int128 expected_a; | ||
| 68 | std::memcpy(&value_a, value.data(), sizeof(u128)); | ||
| 69 | std::memcpy(&expected_a, expected.data(), sizeof(u128)); | ||
| 70 | return __sync_bool_compare_and_swap((unsigned __int128*)pointer, expected_a, value_a); | ||
| 71 | } | ||
| 72 | |||
| 73 | #endif | ||
| 74 | |||
| 75 | } // namespace Common | ||
diff --git a/src/common/atomic_ops.h b/src/common/atomic_ops.h index b46888589..2b1f515e8 100644 --- a/src/common/atomic_ops.h +++ b/src/common/atomic_ops.h | |||
| @@ -4,14 +4,75 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <cstring> | ||
| 8 | #include <memory> | ||
| 9 | |||
| 7 | #include "common/common_types.h" | 10 | #include "common/common_types.h" |
| 8 | 11 | ||
| 12 | #if _MSC_VER | ||
| 13 | #include <intrin.h> | ||
| 14 | #endif | ||
| 15 | |||
| 9 | namespace Common { | 16 | namespace Common { |
| 10 | 17 | ||
| 11 | [[nodiscard]] bool AtomicCompareAndSwap(volatile u8* pointer, u8 value, u8 expected); | 18 | #if _MSC_VER |
| 12 | [[nodiscard]] bool AtomicCompareAndSwap(volatile u16* pointer, u16 value, u16 expected); | 19 | |
| 13 | [[nodiscard]] bool AtomicCompareAndSwap(volatile u32* pointer, u32 value, u32 expected); | 20 | [[nodiscard]] inline bool AtomicCompareAndSwap(volatile u8* pointer, u8 value, u8 expected) { |
| 14 | [[nodiscard]] bool AtomicCompareAndSwap(volatile u64* pointer, u64 value, u64 expected); | 21 | const u8 result = |
| 15 | [[nodiscard]] bool AtomicCompareAndSwap(volatile u64* pointer, u128 value, u128 expected); | 22 | _InterlockedCompareExchange8(reinterpret_cast<volatile char*>(pointer), value, expected); |
| 23 | return result == expected; | ||
| 24 | } | ||
| 25 | |||
| 26 | [[nodiscard]] inline bool AtomicCompareAndSwap(volatile u16* pointer, u16 value, u16 expected) { | ||
| 27 | const u16 result = | ||
| 28 | _InterlockedCompareExchange16(reinterpret_cast<volatile short*>(pointer), value, expected); | ||
| 29 | return result == expected; | ||
| 30 | } | ||
| 31 | |||
| 32 | [[nodiscard]] inline bool AtomicCompareAndSwap(volatile u32* pointer, u32 value, u32 expected) { | ||
| 33 | const u32 result = | ||
| 34 | _InterlockedCompareExchange(reinterpret_cast<volatile long*>(pointer), value, expected); | ||
| 35 | return result == expected; | ||
| 36 | } | ||
| 37 | |||
| 38 | [[nodiscard]] inline bool AtomicCompareAndSwap(volatile u64* pointer, u64 value, u64 expected) { | ||
| 39 | const u64 result = _InterlockedCompareExchange64(reinterpret_cast<volatile __int64*>(pointer), | ||
| 40 | value, expected); | ||
| 41 | return result == expected; | ||
| 42 | } | ||
| 43 | |||
| 44 | [[nodiscard]] inline bool AtomicCompareAndSwap(volatile u64* pointer, u128 value, u128 expected) { | ||
| 45 | return _InterlockedCompareExchange128(reinterpret_cast<volatile __int64*>(pointer), value[1], | ||
| 46 | value[0], | ||
| 47 | reinterpret_cast<__int64*>(expected.data())) != 0; | ||
| 48 | } | ||
| 49 | |||
| 50 | #else | ||
| 51 | |||
| 52 | [[nodiscard]] inline bool AtomicCompareAndSwap(volatile u8* pointer, u8 value, u8 expected) { | ||
| 53 | return __sync_bool_compare_and_swap(pointer, expected, value); | ||
| 54 | } | ||
| 55 | |||
| 56 | [[nodiscard]] inline bool AtomicCompareAndSwap(volatile u16* pointer, u16 value, u16 expected) { | ||
| 57 | return __sync_bool_compare_and_swap(pointer, expected, value); | ||
| 58 | } | ||
| 59 | |||
| 60 | [[nodiscard]] inline bool AtomicCompareAndSwap(volatile u32* pointer, u32 value, u32 expected) { | ||
| 61 | return __sync_bool_compare_and_swap(pointer, expected, value); | ||
| 62 | } | ||
| 63 | |||
| 64 | [[nodiscard]] inline bool AtomicCompareAndSwap(volatile u64* pointer, u64 value, u64 expected) { | ||
| 65 | return __sync_bool_compare_and_swap(pointer, expected, value); | ||
| 66 | } | ||
| 67 | |||
| 68 | [[nodiscard]] inline bool AtomicCompareAndSwap(volatile u64* pointer, u128 value, u128 expected) { | ||
| 69 | unsigned __int128 value_a; | ||
| 70 | unsigned __int128 expected_a; | ||
| 71 | std::memcpy(&value_a, value.data(), sizeof(u128)); | ||
| 72 | std::memcpy(&expected_a, expected.data(), sizeof(u128)); | ||
| 73 | return __sync_bool_compare_and_swap((unsigned __int128*)pointer, expected_a, value_a); | ||
| 74 | } | ||
| 75 | |||
| 76 | #endif | ||
| 16 | 77 | ||
| 17 | } // namespace Common | 78 | } // namespace Common |
diff --git a/src/common/bit_util.h b/src/common/bit_util.h index 29f59a9a3..685e7fc9b 100644 --- a/src/common/bit_util.h +++ b/src/common/bit_util.h | |||
| @@ -22,82 +22,6 @@ template <typename T> | |||
| 22 | } | 22 | } |
| 23 | 23 | ||
| 24 | #ifdef _MSC_VER | 24 | #ifdef _MSC_VER |
| 25 | [[nodiscard]] inline u32 CountLeadingZeroes32(u32 value) { | ||
| 26 | unsigned long leading_zero = 0; | ||
| 27 | |||
| 28 | if (_BitScanReverse(&leading_zero, value) != 0) { | ||
| 29 | return 31 - leading_zero; | ||
| 30 | } | ||
| 31 | |||
| 32 | return 32; | ||
| 33 | } | ||
| 34 | |||
| 35 | [[nodiscard]] inline u32 CountLeadingZeroes64(u64 value) { | ||
| 36 | unsigned long leading_zero = 0; | ||
| 37 | |||
| 38 | if (_BitScanReverse64(&leading_zero, value) != 0) { | ||
| 39 | return 63 - leading_zero; | ||
| 40 | } | ||
| 41 | |||
| 42 | return 64; | ||
| 43 | } | ||
| 44 | #else | ||
| 45 | [[nodiscard]] inline u32 CountLeadingZeroes32(u32 value) { | ||
| 46 | if (value == 0) { | ||
| 47 | return 32; | ||
| 48 | } | ||
| 49 | |||
| 50 | return static_cast<u32>(__builtin_clz(value)); | ||
| 51 | } | ||
| 52 | |||
| 53 | [[nodiscard]] inline u32 CountLeadingZeroes64(u64 value) { | ||
| 54 | if (value == 0) { | ||
| 55 | return 64; | ||
| 56 | } | ||
| 57 | |||
| 58 | return static_cast<u32>(__builtin_clzll(value)); | ||
| 59 | } | ||
| 60 | #endif | ||
| 61 | |||
| 62 | #ifdef _MSC_VER | ||
| 63 | [[nodiscard]] inline u32 CountTrailingZeroes32(u32 value) { | ||
| 64 | unsigned long trailing_zero = 0; | ||
| 65 | |||
| 66 | if (_BitScanForward(&trailing_zero, value) != 0) { | ||
| 67 | return trailing_zero; | ||
| 68 | } | ||
| 69 | |||
| 70 | return 32; | ||
| 71 | } | ||
| 72 | |||
| 73 | [[nodiscard]] inline u32 CountTrailingZeroes64(u64 value) { | ||
| 74 | unsigned long trailing_zero = 0; | ||
| 75 | |||
| 76 | if (_BitScanForward64(&trailing_zero, value) != 0) { | ||
| 77 | return trailing_zero; | ||
| 78 | } | ||
| 79 | |||
| 80 | return 64; | ||
| 81 | } | ||
| 82 | #else | ||
| 83 | [[nodiscard]] inline u32 CountTrailingZeroes32(u32 value) { | ||
| 84 | if (value == 0) { | ||
| 85 | return 32; | ||
| 86 | } | ||
| 87 | |||
| 88 | return static_cast<u32>(__builtin_ctz(value)); | ||
| 89 | } | ||
| 90 | |||
| 91 | [[nodiscard]] inline u32 CountTrailingZeroes64(u64 value) { | ||
| 92 | if (value == 0) { | ||
| 93 | return 64; | ||
| 94 | } | ||
| 95 | |||
| 96 | return static_cast<u32>(__builtin_ctzll(value)); | ||
| 97 | } | ||
| 98 | #endif | ||
| 99 | |||
| 100 | #ifdef _MSC_VER | ||
| 101 | 25 | ||
| 102 | [[nodiscard]] inline u32 MostSignificantBit32(const u32 value) { | 26 | [[nodiscard]] inline u32 MostSignificantBit32(const u32 value) { |
| 103 | unsigned long result; | 27 | unsigned long result; |
diff --git a/src/common/color.h b/src/common/color.h deleted file mode 100644 index bbcac858e..000000000 --- a/src/common/color.h +++ /dev/null | |||
| @@ -1,271 +0,0 @@ | |||
| 1 | // Copyright 2014 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 <cstring> | ||
| 8 | |||
| 9 | #include "common/common_types.h" | ||
| 10 | #include "common/swap.h" | ||
| 11 | #include "common/vector_math.h" | ||
| 12 | |||
| 13 | namespace Common::Color { | ||
| 14 | |||
| 15 | /// Convert a 1-bit color component to 8 bit | ||
| 16 | [[nodiscard]] constexpr u8 Convert1To8(u8 value) { | ||
| 17 | return value * 255; | ||
| 18 | } | ||
| 19 | |||
| 20 | /// Convert a 4-bit color component to 8 bit | ||
| 21 | [[nodiscard]] constexpr u8 Convert4To8(u8 value) { | ||
| 22 | return (value << 4) | value; | ||
| 23 | } | ||
| 24 | |||
| 25 | /// Convert a 5-bit color component to 8 bit | ||
| 26 | [[nodiscard]] constexpr u8 Convert5To8(u8 value) { | ||
| 27 | return (value << 3) | (value >> 2); | ||
| 28 | } | ||
| 29 | |||
| 30 | /// Convert a 6-bit color component to 8 bit | ||
| 31 | [[nodiscard]] constexpr u8 Convert6To8(u8 value) { | ||
| 32 | return (value << 2) | (value >> 4); | ||
| 33 | } | ||
| 34 | |||
| 35 | /// Convert a 8-bit color component to 1 bit | ||
| 36 | [[nodiscard]] constexpr u8 Convert8To1(u8 value) { | ||
| 37 | return value >> 7; | ||
| 38 | } | ||
| 39 | |||
| 40 | /// Convert a 8-bit color component to 4 bit | ||
| 41 | [[nodiscard]] constexpr u8 Convert8To4(u8 value) { | ||
| 42 | return value >> 4; | ||
| 43 | } | ||
| 44 | |||
| 45 | /// Convert a 8-bit color component to 5 bit | ||
| 46 | [[nodiscard]] constexpr u8 Convert8To5(u8 value) { | ||
| 47 | return value >> 3; | ||
| 48 | } | ||
| 49 | |||
| 50 | /// Convert a 8-bit color component to 6 bit | ||
| 51 | [[nodiscard]] constexpr u8 Convert8To6(u8 value) { | ||
| 52 | return value >> 2; | ||
| 53 | } | ||
| 54 | |||
| 55 | /** | ||
| 56 | * Decode a color stored in RGBA8 format | ||
| 57 | * @param bytes Pointer to encoded source color | ||
| 58 | * @return Result color decoded as Common::Vec4<u8> | ||
| 59 | */ | ||
| 60 | [[nodiscard]] inline Common::Vec4<u8> DecodeRGBA8(const u8* bytes) { | ||
| 61 | return {bytes[3], bytes[2], bytes[1], bytes[0]}; | ||
| 62 | } | ||
| 63 | |||
| 64 | /** | ||
| 65 | * Decode a color stored in RGB8 format | ||
| 66 | * @param bytes Pointer to encoded source color | ||
| 67 | * @return Result color decoded as Common::Vec4<u8> | ||
| 68 | */ | ||
| 69 | [[nodiscard]] inline Common::Vec4<u8> DecodeRGB8(const u8* bytes) { | ||
| 70 | return {bytes[2], bytes[1], bytes[0], 255}; | ||
| 71 | } | ||
| 72 | |||
| 73 | /** | ||
| 74 | * Decode a color stored in RG8 (aka HILO8) format | ||
| 75 | * @param bytes Pointer to encoded source color | ||
| 76 | * @return Result color decoded as Common::Vec4<u8> | ||
| 77 | */ | ||
| 78 | [[nodiscard]] inline Common::Vec4<u8> DecodeRG8(const u8* bytes) { | ||
| 79 | return {bytes[1], bytes[0], 0, 255}; | ||
| 80 | } | ||
| 81 | |||
| 82 | /** | ||
| 83 | * Decode a color stored in RGB565 format | ||
| 84 | * @param bytes Pointer to encoded source color | ||
| 85 | * @return Result color decoded as Common::Vec4<u8> | ||
| 86 | */ | ||
| 87 | [[nodiscard]] inline Common::Vec4<u8> DecodeRGB565(const u8* bytes) { | ||
| 88 | u16_le pixel; | ||
| 89 | std::memcpy(&pixel, bytes, sizeof(pixel)); | ||
| 90 | return {Convert5To8((pixel >> 11) & 0x1F), Convert6To8((pixel >> 5) & 0x3F), | ||
| 91 | Convert5To8(pixel & 0x1F), 255}; | ||
| 92 | } | ||
| 93 | |||
| 94 | /** | ||
| 95 | * Decode a color stored in RGB5A1 format | ||
| 96 | * @param bytes Pointer to encoded source color | ||
| 97 | * @return Result color decoded as Common::Vec4<u8> | ||
| 98 | */ | ||
| 99 | [[nodiscard]] inline Common::Vec4<u8> DecodeRGB5A1(const u8* bytes) { | ||
| 100 | u16_le pixel; | ||
| 101 | std::memcpy(&pixel, bytes, sizeof(pixel)); | ||
| 102 | return {Convert5To8((pixel >> 11) & 0x1F), Convert5To8((pixel >> 6) & 0x1F), | ||
| 103 | Convert5To8((pixel >> 1) & 0x1F), Convert1To8(pixel & 0x1)}; | ||
| 104 | } | ||
| 105 | |||
| 106 | /** | ||
| 107 | * Decode a color stored in RGBA4 format | ||
| 108 | * @param bytes Pointer to encoded source color | ||
| 109 | * @return Result color decoded as Common::Vec4<u8> | ||
| 110 | */ | ||
| 111 | [[nodiscard]] inline Common::Vec4<u8> DecodeRGBA4(const u8* bytes) { | ||
| 112 | u16_le pixel; | ||
| 113 | std::memcpy(&pixel, bytes, sizeof(pixel)); | ||
| 114 | return {Convert4To8((pixel >> 12) & 0xF), Convert4To8((pixel >> 8) & 0xF), | ||
| 115 | Convert4To8((pixel >> 4) & 0xF), Convert4To8(pixel & 0xF)}; | ||
| 116 | } | ||
| 117 | |||
| 118 | /** | ||
| 119 | * Decode a depth value stored in D16 format | ||
| 120 | * @param bytes Pointer to encoded source value | ||
| 121 | * @return Depth value as an u32 | ||
| 122 | */ | ||
| 123 | [[nodiscard]] inline u32 DecodeD16(const u8* bytes) { | ||
| 124 | u16_le data; | ||
| 125 | std::memcpy(&data, bytes, sizeof(data)); | ||
| 126 | return data; | ||
| 127 | } | ||
| 128 | |||
| 129 | /** | ||
| 130 | * Decode a depth value stored in D24 format | ||
| 131 | * @param bytes Pointer to encoded source value | ||
| 132 | * @return Depth value as an u32 | ||
| 133 | */ | ||
| 134 | [[nodiscard]] inline u32 DecodeD24(const u8* bytes) { | ||
| 135 | return (bytes[2] << 16) | (bytes[1] << 8) | bytes[0]; | ||
| 136 | } | ||
| 137 | |||
| 138 | /** | ||
| 139 | * Decode a depth value and a stencil value stored in D24S8 format | ||
| 140 | * @param bytes Pointer to encoded source values | ||
| 141 | * @return Resulting values stored as a Common::Vec2 | ||
| 142 | */ | ||
| 143 | [[nodiscard]] inline Common::Vec2<u32> DecodeD24S8(const u8* bytes) { | ||
| 144 | return {static_cast<u32>((bytes[2] << 16) | (bytes[1] << 8) | bytes[0]), bytes[3]}; | ||
| 145 | } | ||
| 146 | |||
| 147 | /** | ||
| 148 | * Encode a color as RGBA8 format | ||
| 149 | * @param color Source color to encode | ||
| 150 | * @param bytes Destination pointer to store encoded color | ||
| 151 | */ | ||
| 152 | inline void EncodeRGBA8(const Common::Vec4<u8>& color, u8* bytes) { | ||
| 153 | bytes[3] = color.r(); | ||
| 154 | bytes[2] = color.g(); | ||
| 155 | bytes[1] = color.b(); | ||
| 156 | bytes[0] = color.a(); | ||
| 157 | } | ||
| 158 | |||
| 159 | /** | ||
| 160 | * Encode a color as RGB8 format | ||
| 161 | * @param color Source color to encode | ||
| 162 | * @param bytes Destination pointer to store encoded color | ||
| 163 | */ | ||
| 164 | inline void EncodeRGB8(const Common::Vec4<u8>& color, u8* bytes) { | ||
| 165 | bytes[2] = color.r(); | ||
| 166 | bytes[1] = color.g(); | ||
| 167 | bytes[0] = color.b(); | ||
| 168 | } | ||
| 169 | |||
| 170 | /** | ||
| 171 | * Encode a color as RG8 (aka HILO8) format | ||
| 172 | * @param color Source color to encode | ||
| 173 | * @param bytes Destination pointer to store encoded color | ||
| 174 | */ | ||
| 175 | inline void EncodeRG8(const Common::Vec4<u8>& color, u8* bytes) { | ||
| 176 | bytes[1] = color.r(); | ||
| 177 | bytes[0] = color.g(); | ||
| 178 | } | ||
| 179 | /** | ||
| 180 | * Encode a color as RGB565 format | ||
| 181 | * @param color Source color to encode | ||
| 182 | * @param bytes Destination pointer to store encoded color | ||
| 183 | */ | ||
| 184 | inline void EncodeRGB565(const Common::Vec4<u8>& color, u8* bytes) { | ||
| 185 | const u16_le data = | ||
| 186 | (Convert8To5(color.r()) << 11) | (Convert8To6(color.g()) << 5) | Convert8To5(color.b()); | ||
| 187 | |||
| 188 | std::memcpy(bytes, &data, sizeof(data)); | ||
| 189 | } | ||
| 190 | |||
| 191 | /** | ||
| 192 | * Encode a color as RGB5A1 format | ||
| 193 | * @param color Source color to encode | ||
| 194 | * @param bytes Destination pointer to store encoded color | ||
| 195 | */ | ||
| 196 | inline void EncodeRGB5A1(const Common::Vec4<u8>& color, u8* bytes) { | ||
| 197 | const u16_le data = (Convert8To5(color.r()) << 11) | (Convert8To5(color.g()) << 6) | | ||
| 198 | (Convert8To5(color.b()) << 1) | Convert8To1(color.a()); | ||
| 199 | |||
| 200 | std::memcpy(bytes, &data, sizeof(data)); | ||
| 201 | } | ||
| 202 | |||
| 203 | /** | ||
| 204 | * Encode a color as RGBA4 format | ||
| 205 | * @param color Source color to encode | ||
| 206 | * @param bytes Destination pointer to store encoded color | ||
| 207 | */ | ||
| 208 | inline void EncodeRGBA4(const Common::Vec4<u8>& color, u8* bytes) { | ||
| 209 | const u16 data = (Convert8To4(color.r()) << 12) | (Convert8To4(color.g()) << 8) | | ||
| 210 | (Convert8To4(color.b()) << 4) | Convert8To4(color.a()); | ||
| 211 | |||
| 212 | std::memcpy(bytes, &data, sizeof(data)); | ||
| 213 | } | ||
| 214 | |||
| 215 | /** | ||
| 216 | * Encode a 16 bit depth value as D16 format | ||
| 217 | * @param value 16 bit source depth value to encode | ||
| 218 | * @param bytes Pointer where to store the encoded value | ||
| 219 | */ | ||
| 220 | inline void EncodeD16(u32 value, u8* bytes) { | ||
| 221 | const u16_le data = static_cast<u16>(value); | ||
| 222 | std::memcpy(bytes, &data, sizeof(data)); | ||
| 223 | } | ||
| 224 | |||
| 225 | /** | ||
| 226 | * Encode a 24 bit depth value as D24 format | ||
| 227 | * @param value 24 bit source depth value to encode | ||
| 228 | * @param bytes Pointer where to store the encoded value | ||
| 229 | */ | ||
| 230 | inline void EncodeD24(u32 value, u8* bytes) { | ||
| 231 | bytes[0] = value & 0xFF; | ||
| 232 | bytes[1] = (value >> 8) & 0xFF; | ||
| 233 | bytes[2] = (value >> 16) & 0xFF; | ||
| 234 | } | ||
| 235 | |||
| 236 | /** | ||
| 237 | * Encode a 24 bit depth and 8 bit stencil values as D24S8 format | ||
| 238 | * @param depth 24 bit source depth value to encode | ||
| 239 | * @param stencil 8 bit source stencil value to encode | ||
| 240 | * @param bytes Pointer where to store the encoded value | ||
| 241 | */ | ||
| 242 | inline void EncodeD24S8(u32 depth, u8 stencil, u8* bytes) { | ||
| 243 | bytes[0] = depth & 0xFF; | ||
| 244 | bytes[1] = (depth >> 8) & 0xFF; | ||
| 245 | bytes[2] = (depth >> 16) & 0xFF; | ||
| 246 | bytes[3] = stencil; | ||
| 247 | } | ||
| 248 | |||
| 249 | /** | ||
| 250 | * Encode a 24 bit depth value as D24X8 format (32 bits per pixel with 8 bits unused) | ||
| 251 | * @param depth 24 bit source depth value to encode | ||
| 252 | * @param bytes Pointer where to store the encoded value | ||
| 253 | * @note unused bits will not be modified | ||
| 254 | */ | ||
| 255 | inline void EncodeD24X8(u32 depth, u8* bytes) { | ||
| 256 | bytes[0] = depth & 0xFF; | ||
| 257 | bytes[1] = (depth >> 8) & 0xFF; | ||
| 258 | bytes[2] = (depth >> 16) & 0xFF; | ||
| 259 | } | ||
| 260 | |||
| 261 | /** | ||
| 262 | * Encode an 8 bit stencil value as X24S8 format (32 bits per pixel with 24 bits unused) | ||
| 263 | * @param stencil 8 bit source stencil value to encode | ||
| 264 | * @param bytes Pointer where to store the encoded value | ||
| 265 | * @note unused bits will not be modified | ||
| 266 | */ | ||
| 267 | inline void EncodeX24S8(u8 stencil, u8* bytes) { | ||
| 268 | bytes[3] = stencil; | ||
| 269 | } | ||
| 270 | |||
| 271 | } // namespace Common::Color | ||
diff --git a/src/common/common_funcs.h b/src/common/common_funcs.h index c90978f9c..75f3027fb 100644 --- a/src/common/common_funcs.h +++ b/src/common/common_funcs.h | |||
| @@ -24,10 +24,10 @@ | |||
| 24 | #define INSERT_PADDING_WORDS(num_words) \ | 24 | #define INSERT_PADDING_WORDS(num_words) \ |
| 25 | std::array<u32, num_words> CONCAT2(pad, __LINE__) {} | 25 | std::array<u32, num_words> CONCAT2(pad, __LINE__) {} |
| 26 | 26 | ||
| 27 | /// These are similar to the INSERT_PADDING_* macros, but are needed for padding unions. This is | 27 | /// These are similar to the INSERT_PADDING_* macros but do not zero-initialize the contents. |
| 28 | /// because unions can only be initialized by one member. | 28 | /// This keeps the structure trivial to construct. |
| 29 | #define INSERT_UNION_PADDING_BYTES(num_bytes) std::array<u8, num_bytes> CONCAT2(pad, __LINE__) | 29 | #define INSERT_PADDING_BYTES_NOINIT(num_bytes) std::array<u8, num_bytes> CONCAT2(pad, __LINE__) |
| 30 | #define INSERT_UNION_PADDING_WORDS(num_words) std::array<u32, num_words> CONCAT2(pad, __LINE__) | 30 | #define INSERT_PADDING_WORDS_NOINIT(num_words) std::array<u32, num_words> CONCAT2(pad, __LINE__) |
| 31 | 31 | ||
| 32 | #ifndef _MSC_VER | 32 | #ifndef _MSC_VER |
| 33 | 33 | ||
diff --git a/src/common/intrusive_red_black_tree.h b/src/common/intrusive_red_black_tree.h index fb55de94e..c0bbcd457 100644 --- a/src/common/intrusive_red_black_tree.h +++ b/src/common/intrusive_red_black_tree.h | |||
| @@ -16,17 +16,30 @@ class IntrusiveRedBlackTreeImpl; | |||
| 16 | } | 16 | } |
| 17 | 17 | ||
| 18 | struct IntrusiveRedBlackTreeNode { | 18 | struct IntrusiveRedBlackTreeNode { |
| 19 | public: | ||
| 20 | using EntryType = RBEntry<IntrusiveRedBlackTreeNode>; | ||
| 21 | |||
| 22 | constexpr IntrusiveRedBlackTreeNode() = default; | ||
| 23 | |||
| 24 | void SetEntry(const EntryType& new_entry) { | ||
| 25 | entry = new_entry; | ||
| 26 | } | ||
| 27 | |||
| 28 | [[nodiscard]] EntryType& GetEntry() { | ||
| 29 | return entry; | ||
| 30 | } | ||
| 31 | |||
| 32 | [[nodiscard]] const EntryType& GetEntry() const { | ||
| 33 | return entry; | ||
| 34 | } | ||
| 19 | 35 | ||
| 20 | private: | 36 | private: |
| 21 | RB_ENTRY(IntrusiveRedBlackTreeNode) entry{}; | 37 | EntryType entry{}; |
| 22 | 38 | ||
| 23 | friend class impl::IntrusiveRedBlackTreeImpl; | 39 | friend class impl::IntrusiveRedBlackTreeImpl; |
| 24 | 40 | ||
| 25 | template <class, class, class> | 41 | template <class, class, class> |
| 26 | friend class IntrusiveRedBlackTree; | 42 | friend class IntrusiveRedBlackTree; |
| 27 | |||
| 28 | public: | ||
| 29 | constexpr IntrusiveRedBlackTreeNode() = default; | ||
| 30 | }; | 43 | }; |
| 31 | 44 | ||
| 32 | template <class T, class Traits, class Comparator> | 45 | template <class T, class Traits, class Comparator> |
| @@ -35,17 +48,12 @@ class IntrusiveRedBlackTree; | |||
| 35 | namespace impl { | 48 | namespace impl { |
| 36 | 49 | ||
| 37 | class IntrusiveRedBlackTreeImpl { | 50 | class IntrusiveRedBlackTreeImpl { |
| 38 | |||
| 39 | private: | 51 | private: |
| 40 | template <class, class, class> | 52 | template <class, class, class> |
| 41 | friend class ::Common::IntrusiveRedBlackTree; | 53 | friend class ::Common::IntrusiveRedBlackTree; |
| 42 | 54 | ||
| 43 | private: | 55 | using RootType = RBHead<IntrusiveRedBlackTreeNode>; |
| 44 | RB_HEAD(IntrusiveRedBlackTreeRoot, IntrusiveRedBlackTreeNode); | 56 | RootType root; |
| 45 | using RootType = IntrusiveRedBlackTreeRoot; | ||
| 46 | |||
| 47 | private: | ||
| 48 | IntrusiveRedBlackTreeRoot root; | ||
| 49 | 57 | ||
| 50 | public: | 58 | public: |
| 51 | template <bool Const> | 59 | template <bool Const> |
| @@ -121,57 +129,45 @@ public: | |||
| 121 | } | 129 | } |
| 122 | }; | 130 | }; |
| 123 | 131 | ||
| 124 | protected: | ||
| 125 | // Generate static implementations for non-comparison operations for IntrusiveRedBlackTreeRoot. | ||
| 126 | RB_GENERATE_WITHOUT_COMPARE_STATIC(IntrusiveRedBlackTreeRoot, IntrusiveRedBlackTreeNode, entry); | ||
| 127 | |||
| 128 | private: | 132 | private: |
| 129 | // Define accessors using RB_* functions. | 133 | // Define accessors using RB_* functions. |
| 130 | constexpr void InitializeImpl() { | ||
| 131 | RB_INIT(&this->root); | ||
| 132 | } | ||
| 133 | |||
| 134 | bool EmptyImpl() const { | 134 | bool EmptyImpl() const { |
| 135 | return RB_EMPTY(&this->root); | 135 | return root.IsEmpty(); |
| 136 | } | 136 | } |
| 137 | 137 | ||
| 138 | IntrusiveRedBlackTreeNode* GetMinImpl() const { | 138 | IntrusiveRedBlackTreeNode* GetMinImpl() const { |
| 139 | return RB_MIN(IntrusiveRedBlackTreeRoot, | 139 | return RB_MIN(const_cast<RootType*>(&root)); |
| 140 | const_cast<IntrusiveRedBlackTreeRoot*>(&this->root)); | ||
| 141 | } | 140 | } |
| 142 | 141 | ||
| 143 | IntrusiveRedBlackTreeNode* GetMaxImpl() const { | 142 | IntrusiveRedBlackTreeNode* GetMaxImpl() const { |
| 144 | return RB_MAX(IntrusiveRedBlackTreeRoot, | 143 | return RB_MAX(const_cast<RootType*>(&root)); |
| 145 | const_cast<IntrusiveRedBlackTreeRoot*>(&this->root)); | ||
| 146 | } | 144 | } |
| 147 | 145 | ||
| 148 | IntrusiveRedBlackTreeNode* RemoveImpl(IntrusiveRedBlackTreeNode* node) { | 146 | IntrusiveRedBlackTreeNode* RemoveImpl(IntrusiveRedBlackTreeNode* node) { |
| 149 | return RB_REMOVE(IntrusiveRedBlackTreeRoot, &this->root, node); | 147 | return RB_REMOVE(&root, node); |
| 150 | } | 148 | } |
| 151 | 149 | ||
| 152 | public: | 150 | public: |
| 153 | static IntrusiveRedBlackTreeNode* GetNext(IntrusiveRedBlackTreeNode* node) { | 151 | static IntrusiveRedBlackTreeNode* GetNext(IntrusiveRedBlackTreeNode* node) { |
| 154 | return RB_NEXT(IntrusiveRedBlackTreeRoot, nullptr, node); | 152 | return RB_NEXT(node); |
| 155 | } | 153 | } |
| 156 | 154 | ||
| 157 | static IntrusiveRedBlackTreeNode* GetPrev(IntrusiveRedBlackTreeNode* node) { | 155 | static IntrusiveRedBlackTreeNode* GetPrev(IntrusiveRedBlackTreeNode* node) { |
| 158 | return RB_PREV(IntrusiveRedBlackTreeRoot, nullptr, node); | 156 | return RB_PREV(node); |
| 159 | } | 157 | } |
| 160 | 158 | ||
| 161 | static IntrusiveRedBlackTreeNode const* GetNext(const IntrusiveRedBlackTreeNode* node) { | 159 | static const IntrusiveRedBlackTreeNode* GetNext(const IntrusiveRedBlackTreeNode* node) { |
| 162 | return static_cast<const IntrusiveRedBlackTreeNode*>( | 160 | return static_cast<const IntrusiveRedBlackTreeNode*>( |
| 163 | GetNext(const_cast<IntrusiveRedBlackTreeNode*>(node))); | 161 | GetNext(const_cast<IntrusiveRedBlackTreeNode*>(node))); |
| 164 | } | 162 | } |
| 165 | 163 | ||
| 166 | static IntrusiveRedBlackTreeNode const* GetPrev(const IntrusiveRedBlackTreeNode* node) { | 164 | static const IntrusiveRedBlackTreeNode* GetPrev(const IntrusiveRedBlackTreeNode* node) { |
| 167 | return static_cast<const IntrusiveRedBlackTreeNode*>( | 165 | return static_cast<const IntrusiveRedBlackTreeNode*>( |
| 168 | GetPrev(const_cast<IntrusiveRedBlackTreeNode*>(node))); | 166 | GetPrev(const_cast<IntrusiveRedBlackTreeNode*>(node))); |
| 169 | } | 167 | } |
| 170 | 168 | ||
| 171 | public: | 169 | public: |
| 172 | constexpr IntrusiveRedBlackTreeImpl() : root() { | 170 | constexpr IntrusiveRedBlackTreeImpl() {} |
| 173 | this->InitializeImpl(); | ||
| 174 | } | ||
| 175 | 171 | ||
| 176 | // Iterator accessors. | 172 | // Iterator accessors. |
| 177 | iterator begin() { | 173 | iterator begin() { |
| @@ -269,8 +265,6 @@ private: | |||
| 269 | ImplType impl{}; | 265 | ImplType impl{}; |
| 270 | 266 | ||
| 271 | public: | 267 | public: |
| 272 | struct IntrusiveRedBlackTreeRootWithCompare : ImplType::IntrusiveRedBlackTreeRoot {}; | ||
| 273 | |||
| 274 | template <bool Const> | 268 | template <bool Const> |
| 275 | class Iterator; | 269 | class Iterator; |
| 276 | 270 | ||
| @@ -363,11 +357,6 @@ public: | |||
| 363 | }; | 357 | }; |
| 364 | 358 | ||
| 365 | private: | 359 | private: |
| 366 | // Generate static implementations for comparison operations for IntrusiveRedBlackTreeRoot. | ||
| 367 | RB_GENERATE_WITH_COMPARE_STATIC(IntrusiveRedBlackTreeRootWithCompare, IntrusiveRedBlackTreeNode, | ||
| 368 | entry, CompareImpl, LightCompareImpl); | ||
| 369 | |||
| 370 | private: | ||
| 371 | static int CompareImpl(const IntrusiveRedBlackTreeNode* lhs, | 360 | static int CompareImpl(const IntrusiveRedBlackTreeNode* lhs, |
| 372 | const IntrusiveRedBlackTreeNode* rhs) { | 361 | const IntrusiveRedBlackTreeNode* rhs) { |
| 373 | return Comparator::Compare(*Traits::GetParent(lhs), *Traits::GetParent(rhs)); | 362 | return Comparator::Compare(*Traits::GetParent(lhs), *Traits::GetParent(rhs)); |
| @@ -379,41 +368,27 @@ private: | |||
| 379 | 368 | ||
| 380 | // Define accessors using RB_* functions. | 369 | // Define accessors using RB_* functions. |
| 381 | IntrusiveRedBlackTreeNode* InsertImpl(IntrusiveRedBlackTreeNode* node) { | 370 | IntrusiveRedBlackTreeNode* InsertImpl(IntrusiveRedBlackTreeNode* node) { |
| 382 | return RB_INSERT(IntrusiveRedBlackTreeRootWithCompare, | 371 | return RB_INSERT(&impl.root, node, CompareImpl); |
| 383 | static_cast<IntrusiveRedBlackTreeRootWithCompare*>(&this->impl.root), | ||
| 384 | node); | ||
| 385 | } | 372 | } |
| 386 | 373 | ||
| 387 | IntrusiveRedBlackTreeNode* FindImpl(const IntrusiveRedBlackTreeNode* node) const { | 374 | IntrusiveRedBlackTreeNode* FindImpl(const IntrusiveRedBlackTreeNode* node) const { |
| 388 | return RB_FIND( | 375 | return RB_FIND(const_cast<ImplType::RootType*>(&impl.root), |
| 389 | IntrusiveRedBlackTreeRootWithCompare, | 376 | const_cast<IntrusiveRedBlackTreeNode*>(node), CompareImpl); |
| 390 | const_cast<IntrusiveRedBlackTreeRootWithCompare*>( | ||
| 391 | static_cast<const IntrusiveRedBlackTreeRootWithCompare*>(&this->impl.root)), | ||
| 392 | const_cast<IntrusiveRedBlackTreeNode*>(node)); | ||
| 393 | } | 377 | } |
| 394 | 378 | ||
| 395 | IntrusiveRedBlackTreeNode* NFindImpl(const IntrusiveRedBlackTreeNode* node) const { | 379 | IntrusiveRedBlackTreeNode* NFindImpl(const IntrusiveRedBlackTreeNode* node) const { |
| 396 | return RB_NFIND( | 380 | return RB_NFIND(const_cast<ImplType::RootType*>(&impl.root), |
| 397 | IntrusiveRedBlackTreeRootWithCompare, | 381 | const_cast<IntrusiveRedBlackTreeNode*>(node), CompareImpl); |
| 398 | const_cast<IntrusiveRedBlackTreeRootWithCompare*>( | ||
| 399 | static_cast<const IntrusiveRedBlackTreeRootWithCompare*>(&this->impl.root)), | ||
| 400 | const_cast<IntrusiveRedBlackTreeNode*>(node)); | ||
| 401 | } | 382 | } |
| 402 | 383 | ||
| 403 | IntrusiveRedBlackTreeNode* FindLightImpl(const_light_pointer lelm) const { | 384 | IntrusiveRedBlackTreeNode* FindLightImpl(const_light_pointer lelm) const { |
| 404 | return RB_FIND_LIGHT( | 385 | return RB_FIND_LIGHT(const_cast<ImplType::RootType*>(&impl.root), |
| 405 | IntrusiveRedBlackTreeRootWithCompare, | 386 | static_cast<const void*>(lelm), LightCompareImpl); |
| 406 | const_cast<IntrusiveRedBlackTreeRootWithCompare*>( | ||
| 407 | static_cast<const IntrusiveRedBlackTreeRootWithCompare*>(&this->impl.root)), | ||
| 408 | static_cast<const void*>(lelm)); | ||
| 409 | } | 387 | } |
| 410 | 388 | ||
| 411 | IntrusiveRedBlackTreeNode* NFindLightImpl(const_light_pointer lelm) const { | 389 | IntrusiveRedBlackTreeNode* NFindLightImpl(const_light_pointer lelm) const { |
| 412 | return RB_NFIND_LIGHT( | 390 | return RB_NFIND_LIGHT(const_cast<ImplType::RootType*>(&impl.root), |
| 413 | IntrusiveRedBlackTreeRootWithCompare, | 391 | static_cast<const void*>(lelm), LightCompareImpl); |
| 414 | const_cast<IntrusiveRedBlackTreeRootWithCompare*>( | ||
| 415 | static_cast<const IntrusiveRedBlackTreeRootWithCompare*>(&this->impl.root)), | ||
| 416 | static_cast<const void*>(lelm)); | ||
| 417 | } | 392 | } |
| 418 | 393 | ||
| 419 | public: | 394 | public: |
diff --git a/src/common/logging/backend.cpp b/src/common/logging/backend.cpp index 631f64d05..2d4d2e9e7 100644 --- a/src/common/logging/backend.cpp +++ b/src/common/logging/backend.cpp | |||
| @@ -145,10 +145,18 @@ void ColorConsoleBackend::Write(const Entry& entry) { | |||
| 145 | PrintColoredMessage(entry); | 145 | PrintColoredMessage(entry); |
| 146 | } | 146 | } |
| 147 | 147 | ||
| 148 | // _SH_DENYWR allows read only access to the file for other programs. | 148 | FileBackend::FileBackend(const std::string& filename) : bytes_written(0) { |
| 149 | // It is #defined to 0 on other platforms | 149 | if (Common::FS::Exists(filename + ".old.txt")) { |
| 150 | FileBackend::FileBackend(const std::string& filename) | 150 | Common::FS::Delete(filename + ".old.txt"); |
| 151 | : file(filename, "w", _SH_DENYWR), bytes_written(0) {} | 151 | } |
| 152 | if (Common::FS::Exists(filename)) { | ||
| 153 | Common::FS::Rename(filename, filename + ".old.txt"); | ||
| 154 | } | ||
| 155 | |||
| 156 | // _SH_DENYWR allows read only access to the file for other programs. | ||
| 157 | // It is #defined to 0 on other platforms | ||
| 158 | file = Common::FS::IOFile(filename, "w", _SH_DENYWR); | ||
| 159 | } | ||
| 152 | 160 | ||
| 153 | void FileBackend::Write(const Entry& entry) { | 161 | void FileBackend::Write(const Entry& entry) { |
| 154 | // prevent logs from going over the maximum size (in case its spamming and the user doesn't | 162 | // prevent logs from going over the maximum size (in case its spamming and the user doesn't |
diff --git a/src/common/timer.cpp b/src/common/timer.cpp deleted file mode 100644 index d17dc2a50..000000000 --- a/src/common/timer.cpp +++ /dev/null | |||
| @@ -1,159 +0,0 @@ | |||
| 1 | // Copyright 2013 Dolphin Emulator Project / 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <ctime> | ||
| 6 | #include <fmt/format.h> | ||
| 7 | #include "common/common_types.h" | ||
| 8 | #include "common/string_util.h" | ||
| 9 | #include "common/timer.h" | ||
| 10 | |||
| 11 | namespace Common { | ||
| 12 | |||
| 13 | std::chrono::milliseconds Timer::GetTimeMs() { | ||
| 14 | return std::chrono::duration_cast<std::chrono::milliseconds>( | ||
| 15 | std::chrono::system_clock::now().time_since_epoch()); | ||
| 16 | } | ||
| 17 | |||
| 18 | // -------------------------------------------- | ||
| 19 | // Initiate, Start, Stop, and Update the time | ||
| 20 | // -------------------------------------------- | ||
| 21 | |||
| 22 | // Set initial values for the class | ||
| 23 | Timer::Timer() : m_LastTime(0), m_StartTime(0), m_Running(false) { | ||
| 24 | Update(); | ||
| 25 | } | ||
| 26 | |||
| 27 | // Write the starting time | ||
| 28 | void Timer::Start() { | ||
| 29 | m_StartTime = GetTimeMs(); | ||
| 30 | m_Running = true; | ||
| 31 | } | ||
| 32 | |||
| 33 | // Stop the timer | ||
| 34 | void Timer::Stop() { | ||
| 35 | // Write the final time | ||
| 36 | m_LastTime = GetTimeMs(); | ||
| 37 | m_Running = false; | ||
| 38 | } | ||
| 39 | |||
| 40 | // Update the last time variable | ||
| 41 | void Timer::Update() { | ||
| 42 | m_LastTime = GetTimeMs(); | ||
| 43 | // TODO(ector) - QPF | ||
| 44 | } | ||
| 45 | |||
| 46 | // ------------------------------------- | ||
| 47 | // Get time difference and elapsed time | ||
| 48 | // ------------------------------------- | ||
| 49 | |||
| 50 | // Get the number of milliseconds since the last Update() | ||
| 51 | std::chrono::milliseconds Timer::GetTimeDifference() { | ||
| 52 | return GetTimeMs() - m_LastTime; | ||
| 53 | } | ||
| 54 | |||
| 55 | // Add the time difference since the last Update() to the starting time. | ||
| 56 | // This is used to compensate for a paused game. | ||
| 57 | void Timer::AddTimeDifference() { | ||
| 58 | m_StartTime += GetTimeDifference(); | ||
| 59 | } | ||
| 60 | |||
| 61 | // Get the time elapsed since the Start() | ||
| 62 | std::chrono::milliseconds Timer::GetTimeElapsed() { | ||
| 63 | // If we have not started yet, return 1 (because then I don't | ||
| 64 | // have to change the FPS calculation in CoreRerecording.cpp . | ||
| 65 | if (m_StartTime.count() == 0) | ||
| 66 | return std::chrono::milliseconds(1); | ||
| 67 | |||
| 68 | // Return the final timer time if the timer is stopped | ||
| 69 | if (!m_Running) | ||
| 70 | return (m_LastTime - m_StartTime); | ||
| 71 | |||
| 72 | return (GetTimeMs() - m_StartTime); | ||
| 73 | } | ||
| 74 | |||
| 75 | // Get the formatted time elapsed since the Start() | ||
| 76 | std::string Timer::GetTimeElapsedFormatted() const { | ||
| 77 | // If we have not started yet, return zero | ||
| 78 | if (m_StartTime.count() == 0) | ||
| 79 | return "00:00:00:000"; | ||
| 80 | |||
| 81 | // The number of milliseconds since the start. | ||
| 82 | // Use a different value if the timer is stopped. | ||
| 83 | std::chrono::milliseconds Milliseconds; | ||
| 84 | if (m_Running) | ||
| 85 | Milliseconds = GetTimeMs() - m_StartTime; | ||
| 86 | else | ||
| 87 | Milliseconds = m_LastTime - m_StartTime; | ||
| 88 | // Seconds | ||
| 89 | std::chrono::seconds Seconds = std::chrono::duration_cast<std::chrono::seconds>(Milliseconds); | ||
| 90 | // Minutes | ||
| 91 | std::chrono::minutes Minutes = std::chrono::duration_cast<std::chrono::minutes>(Milliseconds); | ||
| 92 | // Hours | ||
| 93 | std::chrono::hours Hours = std::chrono::duration_cast<std::chrono::hours>(Milliseconds); | ||
| 94 | |||
| 95 | std::string TmpStr = fmt::format("{:02}:{:02}:{:02}:{:03}", Hours.count(), Minutes.count() % 60, | ||
| 96 | Seconds.count() % 60, Milliseconds.count() % 1000); | ||
| 97 | return TmpStr; | ||
| 98 | } | ||
| 99 | |||
| 100 | // Get the number of seconds since January 1 1970 | ||
| 101 | std::chrono::seconds Timer::GetTimeSinceJan1970() { | ||
| 102 | return std::chrono::duration_cast<std::chrono::seconds>(GetTimeMs()); | ||
| 103 | } | ||
| 104 | |||
| 105 | std::chrono::seconds Timer::GetLocalTimeSinceJan1970() { | ||
| 106 | time_t sysTime, tzDiff, tzDST; | ||
| 107 | struct tm* gmTime; | ||
| 108 | |||
| 109 | time(&sysTime); | ||
| 110 | |||
| 111 | // Account for DST where needed | ||
| 112 | gmTime = localtime(&sysTime); | ||
| 113 | if (gmTime->tm_isdst == 1) | ||
| 114 | tzDST = 3600; | ||
| 115 | else | ||
| 116 | tzDST = 0; | ||
| 117 | |||
| 118 | // Lazy way to get local time in sec | ||
| 119 | gmTime = gmtime(&sysTime); | ||
| 120 | tzDiff = sysTime - mktime(gmTime); | ||
| 121 | |||
| 122 | return std::chrono::seconds(sysTime + tzDiff + tzDST); | ||
| 123 | } | ||
| 124 | |||
| 125 | // Return the current time formatted as Minutes:Seconds:Milliseconds | ||
| 126 | // in the form 00:00:000. | ||
| 127 | std::string Timer::GetTimeFormatted() { | ||
| 128 | time_t sysTime; | ||
| 129 | struct tm* gmTime; | ||
| 130 | char tmp[13]; | ||
| 131 | |||
| 132 | time(&sysTime); | ||
| 133 | gmTime = localtime(&sysTime); | ||
| 134 | |||
| 135 | strftime(tmp, 6, "%M:%S", gmTime); | ||
| 136 | |||
| 137 | u64 milliseconds = static_cast<u64>(GetTimeMs().count()) % 1000; | ||
| 138 | return fmt::format("{}:{:03}", tmp, milliseconds); | ||
| 139 | } | ||
| 140 | |||
| 141 | // Returns a timestamp with decimals for precise time comparisons | ||
| 142 | // ---------------- | ||
| 143 | double Timer::GetDoubleTime() { | ||
| 144 | // Get continuous timestamp | ||
| 145 | auto tmp_seconds = static_cast<u64>(GetTimeSinceJan1970().count()); | ||
| 146 | const auto ms = static_cast<double>(static_cast<u64>(GetTimeMs().count()) % 1000); | ||
| 147 | |||
| 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 | ||
| 150 | // enough really, but I leave a year of seconds anyway, in case the | ||
| 151 | // user's clock is incorrect or something like that. | ||
| 152 | tmp_seconds = tmp_seconds - (38 * 365 * 24 * 60 * 60); | ||
| 153 | |||
| 154 | // Make a smaller integer that fits in the double | ||
| 155 | const auto seconds = static_cast<u32>(tmp_seconds); | ||
| 156 | return seconds + ms; | ||
| 157 | } | ||
| 158 | |||
| 159 | } // Namespace Common | ||
diff --git a/src/common/timer.h b/src/common/timer.h deleted file mode 100644 index 8894a143d..000000000 --- a/src/common/timer.h +++ /dev/null | |||
| @@ -1,41 +0,0 @@ | |||
| 1 | // Copyright 2013 Dolphin Emulator Project / 2014 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 <chrono> | ||
| 8 | #include <string> | ||
| 9 | #include "common/common_types.h" | ||
| 10 | |||
| 11 | namespace Common { | ||
| 12 | class Timer { | ||
| 13 | public: | ||
| 14 | Timer(); | ||
| 15 | |||
| 16 | void Start(); | ||
| 17 | void Stop(); | ||
| 18 | void Update(); | ||
| 19 | |||
| 20 | // The time difference is always returned in milliseconds, regardless of alternative internal | ||
| 21 | // representation | ||
| 22 | [[nodiscard]] std::chrono::milliseconds GetTimeDifference(); | ||
| 23 | void AddTimeDifference(); | ||
| 24 | |||
| 25 | [[nodiscard]] static std::chrono::seconds GetTimeSinceJan1970(); | ||
| 26 | [[nodiscard]] static std::chrono::seconds GetLocalTimeSinceJan1970(); | ||
| 27 | [[nodiscard]] static double GetDoubleTime(); | ||
| 28 | |||
| 29 | [[nodiscard]] static std::string GetTimeFormatted(); | ||
| 30 | [[nodiscard]] std::string GetTimeElapsedFormatted() const; | ||
| 31 | [[nodiscard]] std::chrono::milliseconds GetTimeElapsed(); | ||
| 32 | |||
| 33 | [[nodiscard]] static std::chrono::milliseconds GetTimeMs(); | ||
| 34 | |||
| 35 | private: | ||
| 36 | std::chrono::milliseconds m_LastTime; | ||
| 37 | std::chrono::milliseconds m_StartTime; | ||
| 38 | bool m_Running; | ||
| 39 | }; | ||
| 40 | |||
| 41 | } // Namespace Common | ||
diff --git a/src/common/tree.h b/src/common/tree.h index a6b636646..3da49e422 100644 --- a/src/common/tree.h +++ b/src/common/tree.h | |||
| @@ -27,33 +27,10 @@ | |||
| 27 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 27 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 28 | */ | 28 | */ |
| 29 | 29 | ||
| 30 | #ifndef _SYS_TREE_H_ | 30 | #pragma once |
| 31 | #define _SYS_TREE_H_ | ||
| 32 | |||
| 33 | /* FreeBSD <sys/cdefs.h> has a lot of defines we don't really want. */ | ||
| 34 | /* tree.h only actually uses __inline and __unused, so we'll just define those. */ | ||
| 35 | |||
| 36 | /* #include <sys/cdefs.h> */ | ||
| 37 | |||
| 38 | #ifndef __inline | ||
| 39 | #define __inline inline | ||
| 40 | #endif | ||
| 41 | 31 | ||
| 42 | /* | 32 | /* |
| 43 | * This file defines data structures for different types of trees: | 33 | * This file defines data structures for red-black trees. |
| 44 | * splay trees and red-black trees. | ||
| 45 | * | ||
| 46 | * A splay tree is a self-organizing data structure. Every operation | ||
| 47 | * on the tree causes a splay to happen. The splay moves the requested | ||
| 48 | * node to the root of the tree and partly rebalances it. | ||
| 49 | * | ||
| 50 | * This has the benefit that request locality causes faster lookups as | ||
| 51 | * the requested nodes move to the top of the tree. On the other hand, | ||
| 52 | * every lookup causes memory writes. | ||
| 53 | * | ||
| 54 | * The Balance Theorem bounds the total access time for m operations | ||
| 55 | * and n inserts on an initially empty tree as O((m + n)lg n). The | ||
| 56 | * amortized cost for a sequence of m accesses to a splay tree is O(lg n); | ||
| 57 | * | 34 | * |
| 58 | * A red-black tree is a binary search tree with the node color as an | 35 | * A red-black tree is a binary search tree with the node color as an |
| 59 | * extra attribute. It fulfills a set of conditions: | 36 | * extra attribute. It fulfills a set of conditions: |
| @@ -66,757 +43,632 @@ | |||
| 66 | * The maximum height of a red-black tree is 2lg (n+1). | 43 | * The maximum height of a red-black tree is 2lg (n+1). |
| 67 | */ | 44 | */ |
| 68 | 45 | ||
| 69 | #define SPLAY_HEAD(name, type) \ | 46 | namespace Common { |
| 70 | struct name { \ | 47 | template <typename T> |
| 71 | struct type* sph_root; /* root of the tree */ \ | 48 | class RBHead { |
| 72 | } | 49 | public: |
| 73 | 50 | [[nodiscard]] T* Root() { | |
| 74 | #define SPLAY_INITIALIZER(root) \ | 51 | return rbh_root; |
| 75 | { NULL } | 52 | } |
| 76 | 53 | ||
| 77 | #define SPLAY_INIT(root) \ | 54 | [[nodiscard]] const T* Root() const { |
| 78 | do { \ | 55 | return rbh_root; |
| 79 | (root)->sph_root = NULL; \ | 56 | } |
| 80 | } while (/*CONSTCOND*/ 0) | 57 | |
| 81 | 58 | void SetRoot(T* root) { | |
| 82 | #define SPLAY_ENTRY(type) \ | 59 | rbh_root = root; |
| 83 | struct { \ | 60 | } |
| 84 | struct type* spe_left; /* left element */ \ | 61 | |
| 85 | struct type* spe_right; /* right element */ \ | 62 | [[nodiscard]] bool IsEmpty() const { |
| 86 | } | 63 | return Root() == nullptr; |
| 87 | 64 | } | |
| 88 | #define SPLAY_LEFT(elm, field) (elm)->field.spe_left | 65 | |
| 89 | #define SPLAY_RIGHT(elm, field) (elm)->field.spe_right | 66 | private: |
| 90 | #define SPLAY_ROOT(head) (head)->sph_root | 67 | T* rbh_root = nullptr; |
| 91 | #define SPLAY_EMPTY(head) (SPLAY_ROOT(head) == NULL) | 68 | }; |
| 92 | 69 | ||
| 93 | /* SPLAY_ROTATE_{LEFT,RIGHT} expect that tmp hold SPLAY_{RIGHT,LEFT} */ | 70 | enum class EntryColor { |
| 94 | #define SPLAY_ROTATE_RIGHT(head, tmp, field) \ | 71 | Black, |
| 95 | do { \ | 72 | Red, |
| 96 | SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(tmp, field); \ | 73 | }; |
| 97 | SPLAY_RIGHT(tmp, field) = (head)->sph_root; \ | 74 | |
| 98 | (head)->sph_root = tmp; \ | 75 | template <typename T> |
| 99 | } while (/*CONSTCOND*/ 0) | 76 | class RBEntry { |
| 100 | 77 | public: | |
| 101 | #define SPLAY_ROTATE_LEFT(head, tmp, field) \ | 78 | [[nodiscard]] T* Left() { |
| 102 | do { \ | 79 | return rbe_left; |
| 103 | SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(tmp, field); \ | 80 | } |
| 104 | SPLAY_LEFT(tmp, field) = (head)->sph_root; \ | 81 | |
| 105 | (head)->sph_root = tmp; \ | 82 | [[nodiscard]] const T* Left() const { |
| 106 | } while (/*CONSTCOND*/ 0) | 83 | return rbe_left; |
| 107 | 84 | } | |
| 108 | #define SPLAY_LINKLEFT(head, tmp, field) \ | 85 | |
| 109 | do { \ | 86 | void SetLeft(T* left) { |
| 110 | SPLAY_LEFT(tmp, field) = (head)->sph_root; \ | 87 | rbe_left = left; |
| 111 | tmp = (head)->sph_root; \ | 88 | } |
| 112 | (head)->sph_root = SPLAY_LEFT((head)->sph_root, field); \ | 89 | |
| 113 | } while (/*CONSTCOND*/ 0) | 90 | [[nodiscard]] T* Right() { |
| 114 | 91 | return rbe_right; | |
| 115 | #define SPLAY_LINKRIGHT(head, tmp, field) \ | 92 | } |
| 116 | do { \ | 93 | |
| 117 | SPLAY_RIGHT(tmp, field) = (head)->sph_root; \ | 94 | [[nodiscard]] const T* Right() const { |
| 118 | tmp = (head)->sph_root; \ | 95 | return rbe_right; |
| 119 | (head)->sph_root = SPLAY_RIGHT((head)->sph_root, field); \ | 96 | } |
| 120 | } while (/*CONSTCOND*/ 0) | 97 | |
| 121 | 98 | void SetRight(T* right) { | |
| 122 | #define SPLAY_ASSEMBLE(head, node, left, right, field) \ | 99 | rbe_right = right; |
| 123 | do { \ | 100 | } |
| 124 | SPLAY_RIGHT(left, field) = SPLAY_LEFT((head)->sph_root, field); \ | 101 | |
| 125 | SPLAY_LEFT(right, field) = SPLAY_RIGHT((head)->sph_root, field); \ | 102 | [[nodiscard]] T* Parent() { |
| 126 | SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(node, field); \ | 103 | return rbe_parent; |
| 127 | SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(node, field); \ | 104 | } |
| 128 | } while (/*CONSTCOND*/ 0) | 105 | |
| 129 | 106 | [[nodiscard]] const T* Parent() const { | |
| 130 | /* Generates prototypes and inline functions */ | 107 | return rbe_parent; |
| 131 | 108 | } | |
| 132 | #define SPLAY_PROTOTYPE(name, type, field, cmp) \ | 109 | |
| 133 | void name##_SPLAY(struct name*, struct type*); \ | 110 | void SetParent(T* parent) { |
| 134 | void name##_SPLAY_MINMAX(struct name*, int); \ | 111 | rbe_parent = parent; |
| 135 | struct type* name##_SPLAY_INSERT(struct name*, struct type*); \ | 112 | } |
| 136 | struct type* name##_SPLAY_REMOVE(struct name*, struct type*); \ | 113 | |
| 137 | \ | 114 | [[nodiscard]] bool IsBlack() const { |
| 138 | /* Finds the node with the same key as elm */ \ | 115 | return rbe_color == EntryColor::Black; |
| 139 | static __inline struct type* name##_SPLAY_FIND(struct name* head, struct type* elm) { \ | 116 | } |
| 140 | if (SPLAY_EMPTY(head)) \ | 117 | |
| 141 | return (NULL); \ | 118 | [[nodiscard]] bool IsRed() const { |
| 142 | name##_SPLAY(head, elm); \ | 119 | return rbe_color == EntryColor::Red; |
| 143 | if ((cmp)(elm, (head)->sph_root) == 0) \ | 120 | } |
| 144 | return (head->sph_root); \ | 121 | |
| 145 | return (NULL); \ | 122 | [[nodiscard]] EntryColor Color() const { |
| 146 | } \ | 123 | return rbe_color; |
| 147 | \ | 124 | } |
| 148 | static __inline struct type* name##_SPLAY_NEXT(struct name* head, struct type* elm) { \ | 125 | |
| 149 | name##_SPLAY(head, elm); \ | 126 | void SetColor(EntryColor color) { |
| 150 | if (SPLAY_RIGHT(elm, field) != NULL) { \ | 127 | rbe_color = color; |
| 151 | elm = SPLAY_RIGHT(elm, field); \ | 128 | } |
| 152 | while (SPLAY_LEFT(elm, field) != NULL) { \ | 129 | |
| 153 | elm = SPLAY_LEFT(elm, field); \ | 130 | private: |
| 154 | } \ | 131 | T* rbe_left = nullptr; |
| 155 | } else \ | 132 | T* rbe_right = nullptr; |
| 156 | elm = NULL; \ | 133 | T* rbe_parent = nullptr; |
| 157 | return (elm); \ | 134 | EntryColor rbe_color{}; |
| 158 | } \ | 135 | }; |
| 159 | \ | 136 | |
| 160 | static __inline struct type* name##_SPLAY_MIN_MAX(struct name* head, int val) { \ | 137 | template <typename Node> |
| 161 | name##_SPLAY_MINMAX(head, val); \ | 138 | [[nodiscard]] RBEntry<Node>& RB_ENTRY(Node* node) { |
| 162 | return (SPLAY_ROOT(head)); \ | 139 | return node->GetEntry(); |
| 163 | } | 140 | } |
| 164 | 141 | ||
| 165 | /* Main splay operation. | 142 | template <typename Node> |
| 166 | * Moves node close to the key of elm to top | 143 | [[nodiscard]] const RBEntry<Node>& RB_ENTRY(const Node* node) { |
| 167 | */ | 144 | return node->GetEntry(); |
| 168 | #define SPLAY_GENERATE(name, type, field, cmp) \ | 145 | } |
| 169 | struct type* name##_SPLAY_INSERT(struct name* head, struct type* elm) { \ | 146 | |
| 170 | if (SPLAY_EMPTY(head)) { \ | 147 | template <typename Node> |
| 171 | SPLAY_LEFT(elm, field) = SPLAY_RIGHT(elm, field) = NULL; \ | 148 | [[nodiscard]] Node* RB_PARENT(Node* node) { |
| 172 | } else { \ | 149 | return RB_ENTRY(node).Parent(); |
| 173 | int __comp; \ | 150 | } |
| 174 | name##_SPLAY(head, elm); \ | 151 | |
| 175 | __comp = (cmp)(elm, (head)->sph_root); \ | 152 | template <typename Node> |
| 176 | if (__comp < 0) { \ | 153 | [[nodiscard]] const Node* RB_PARENT(const Node* node) { |
| 177 | SPLAY_LEFT(elm, field) = SPLAY_LEFT((head)->sph_root, field); \ | 154 | return RB_ENTRY(node).Parent(); |
| 178 | SPLAY_RIGHT(elm, field) = (head)->sph_root; \ | 155 | } |
| 179 | SPLAY_LEFT((head)->sph_root, field) = NULL; \ | 156 | |
| 180 | } else if (__comp > 0) { \ | 157 | template <typename Node> |
| 181 | SPLAY_RIGHT(elm, field) = SPLAY_RIGHT((head)->sph_root, field); \ | 158 | void RB_SET_PARENT(Node* node, Node* parent) { |
| 182 | SPLAY_LEFT(elm, field) = (head)->sph_root; \ | 159 | return RB_ENTRY(node).SetParent(parent); |
| 183 | SPLAY_RIGHT((head)->sph_root, field) = NULL; \ | 160 | } |
| 184 | } else \ | 161 | |
| 185 | return ((head)->sph_root); \ | 162 | template <typename Node> |
| 186 | } \ | 163 | [[nodiscard]] Node* RB_LEFT(Node* node) { |
| 187 | (head)->sph_root = (elm); \ | 164 | return RB_ENTRY(node).Left(); |
| 188 | return (NULL); \ | 165 | } |
| 189 | } \ | 166 | |
| 190 | \ | 167 | template <typename Node> |
| 191 | struct type* name##_SPLAY_REMOVE(struct name* head, struct type* elm) { \ | 168 | [[nodiscard]] const Node* RB_LEFT(const Node* node) { |
| 192 | struct type* __tmp; \ | 169 | return RB_ENTRY(node).Left(); |
| 193 | if (SPLAY_EMPTY(head)) \ | 170 | } |
| 194 | return (NULL); \ | 171 | |
| 195 | name##_SPLAY(head, elm); \ | 172 | template <typename Node> |
| 196 | if ((cmp)(elm, (head)->sph_root) == 0) { \ | 173 | void RB_SET_LEFT(Node* node, Node* left) { |
| 197 | if (SPLAY_LEFT((head)->sph_root, field) == NULL) { \ | 174 | return RB_ENTRY(node).SetLeft(left); |
| 198 | (head)->sph_root = SPLAY_RIGHT((head)->sph_root, field); \ | 175 | } |
| 199 | } else { \ | 176 | |
| 200 | __tmp = SPLAY_RIGHT((head)->sph_root, field); \ | 177 | template <typename Node> |
| 201 | (head)->sph_root = SPLAY_LEFT((head)->sph_root, field); \ | 178 | [[nodiscard]] Node* RB_RIGHT(Node* node) { |
| 202 | name##_SPLAY(head, elm); \ | 179 | return RB_ENTRY(node).Right(); |
| 203 | SPLAY_RIGHT((head)->sph_root, field) = __tmp; \ | 180 | } |
| 204 | } \ | 181 | |
| 205 | return (elm); \ | 182 | template <typename Node> |
| 206 | } \ | 183 | [[nodiscard]] const Node* RB_RIGHT(const Node* node) { |
| 207 | return (NULL); \ | 184 | return RB_ENTRY(node).Right(); |
| 208 | } \ | 185 | } |
| 209 | \ | 186 | |
| 210 | void name##_SPLAY(struct name* head, struct type* elm) { \ | 187 | template <typename Node> |
| 211 | struct type __node, *__left, *__right, *__tmp; \ | 188 | void RB_SET_RIGHT(Node* node, Node* right) { |
| 212 | int __comp; \ | 189 | return RB_ENTRY(node).SetRight(right); |
| 213 | \ | 190 | } |
| 214 | SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL; \ | 191 | |
| 215 | __left = __right = &__node; \ | 192 | template <typename Node> |
| 216 | \ | 193 | [[nodiscard]] bool RB_IS_BLACK(const Node* node) { |
| 217 | while ((__comp = (cmp)(elm, (head)->sph_root)) != 0) { \ | 194 | return RB_ENTRY(node).IsBlack(); |
| 218 | if (__comp < 0) { \ | 195 | } |
| 219 | __tmp = SPLAY_LEFT((head)->sph_root, field); \ | 196 | |
| 220 | if (__tmp == NULL) \ | 197 | template <typename Node> |
| 221 | break; \ | 198 | [[nodiscard]] bool RB_IS_RED(const Node* node) { |
| 222 | if ((cmp)(elm, __tmp) < 0) { \ | 199 | return RB_ENTRY(node).IsRed(); |
| 223 | SPLAY_ROTATE_RIGHT(head, __tmp, field); \ | 200 | } |
| 224 | if (SPLAY_LEFT((head)->sph_root, field) == NULL) \ | 201 | |
| 225 | break; \ | 202 | template <typename Node> |
| 226 | } \ | 203 | [[nodiscard]] EntryColor RB_COLOR(const Node* node) { |
| 227 | SPLAY_LINKLEFT(head, __right, field); \ | 204 | return RB_ENTRY(node).Color(); |
| 228 | } else if (__comp > 0) { \ | 205 | } |
| 229 | __tmp = SPLAY_RIGHT((head)->sph_root, field); \ | 206 | |
| 230 | if (__tmp == NULL) \ | 207 | template <typename Node> |
| 231 | break; \ | 208 | void RB_SET_COLOR(Node* node, EntryColor color) { |
| 232 | if ((cmp)(elm, __tmp) > 0) { \ | 209 | return RB_ENTRY(node).SetColor(color); |
| 233 | SPLAY_ROTATE_LEFT(head, __tmp, field); \ | 210 | } |
| 234 | if (SPLAY_RIGHT((head)->sph_root, field) == NULL) \ | 211 | |
| 235 | break; \ | 212 | template <typename Node> |
| 236 | } \ | 213 | void RB_SET(Node* node, Node* parent) { |
| 237 | SPLAY_LINKRIGHT(head, __left, field); \ | 214 | auto& entry = RB_ENTRY(node); |
| 238 | } \ | 215 | entry.SetParent(parent); |
| 239 | } \ | 216 | entry.SetLeft(nullptr); |
| 240 | SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \ | 217 | entry.SetRight(nullptr); |
| 241 | } \ | 218 | entry.SetColor(EntryColor::Red); |
| 242 | \ | 219 | } |
| 243 | /* Splay with either the minimum or the maximum element \ | 220 | |
| 244 | * Used to find minimum or maximum element in tree. \ | 221 | template <typename Node> |
| 245 | */ \ | 222 | void RB_SET_BLACKRED(Node* black, Node* red) { |
| 246 | void name##_SPLAY_MINMAX(struct name* head, int __comp) { \ | 223 | RB_SET_COLOR(black, EntryColor::Black); |
| 247 | struct type __node, *__left, *__right, *__tmp; \ | 224 | RB_SET_COLOR(red, EntryColor::Red); |
| 248 | \ | 225 | } |
| 249 | SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL; \ | 226 | |
| 250 | __left = __right = &__node; \ | 227 | template <typename Node> |
| 251 | \ | 228 | void RB_ROTATE_LEFT(RBHead<Node>* head, Node* elm, Node*& tmp) { |
| 252 | while (1) { \ | 229 | tmp = RB_RIGHT(elm); |
| 253 | if (__comp < 0) { \ | 230 | RB_SET_RIGHT(elm, RB_LEFT(tmp)); |
| 254 | __tmp = SPLAY_LEFT((head)->sph_root, field); \ | 231 | if (RB_RIGHT(elm) != nullptr) { |
| 255 | if (__tmp == NULL) \ | 232 | RB_SET_PARENT(RB_LEFT(tmp), elm); |
| 256 | break; \ | 233 | } |
| 257 | if (__comp < 0) { \ | 234 | |
| 258 | SPLAY_ROTATE_RIGHT(head, __tmp, field); \ | 235 | RB_SET_PARENT(tmp, RB_PARENT(elm)); |
| 259 | if (SPLAY_LEFT((head)->sph_root, field) == NULL) \ | 236 | if (RB_PARENT(tmp) != nullptr) { |
| 260 | break; \ | 237 | if (elm == RB_LEFT(RB_PARENT(elm))) { |
| 261 | } \ | 238 | RB_SET_LEFT(RB_PARENT(elm), tmp); |
| 262 | SPLAY_LINKLEFT(head, __right, field); \ | 239 | } else { |
| 263 | } else if (__comp > 0) { \ | 240 | RB_SET_RIGHT(RB_PARENT(elm), tmp); |
| 264 | __tmp = SPLAY_RIGHT((head)->sph_root, field); \ | 241 | } |
| 265 | if (__tmp == NULL) \ | 242 | } else { |
| 266 | break; \ | 243 | head->SetRoot(tmp); |
| 267 | if (__comp > 0) { \ | 244 | } |
| 268 | SPLAY_ROTATE_LEFT(head, __tmp, field); \ | 245 | |
| 269 | if (SPLAY_RIGHT((head)->sph_root, field) == NULL) \ | 246 | RB_SET_LEFT(tmp, elm); |
| 270 | break; \ | 247 | RB_SET_PARENT(elm, tmp); |
| 271 | } \ | 248 | } |
| 272 | SPLAY_LINKRIGHT(head, __left, field); \ | 249 | |
| 273 | } \ | 250 | template <typename Node> |
| 274 | } \ | 251 | void RB_ROTATE_RIGHT(RBHead<Node>* head, Node* elm, Node*& tmp) { |
| 275 | SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \ | 252 | tmp = RB_LEFT(elm); |
| 276 | } | 253 | RB_SET_LEFT(elm, RB_RIGHT(tmp)); |
| 277 | 254 | if (RB_LEFT(elm) != nullptr) { | |
| 278 | #define SPLAY_NEGINF -1 | 255 | RB_SET_PARENT(RB_RIGHT(tmp), elm); |
| 279 | #define SPLAY_INF 1 | 256 | } |
| 280 | 257 | ||
| 281 | #define SPLAY_INSERT(name, x, y) name##_SPLAY_INSERT(x, y) | 258 | RB_SET_PARENT(tmp, RB_PARENT(elm)); |
| 282 | #define SPLAY_REMOVE(name, x, y) name##_SPLAY_REMOVE(x, y) | 259 | if (RB_PARENT(tmp) != nullptr) { |
| 283 | #define SPLAY_FIND(name, x, y) name##_SPLAY_FIND(x, y) | 260 | if (elm == RB_LEFT(RB_PARENT(elm))) { |
| 284 | #define SPLAY_NEXT(name, x, y) name##_SPLAY_NEXT(x, y) | 261 | RB_SET_LEFT(RB_PARENT(elm), tmp); |
| 285 | #define SPLAY_MIN(name, x) (SPLAY_EMPTY(x) ? NULL : name##_SPLAY_MIN_MAX(x, SPLAY_NEGINF)) | 262 | } else { |
| 286 | #define SPLAY_MAX(name, x) (SPLAY_EMPTY(x) ? NULL : name##_SPLAY_MIN_MAX(x, SPLAY_INF)) | 263 | RB_SET_RIGHT(RB_PARENT(elm), tmp); |
| 287 | 264 | } | |
| 288 | #define SPLAY_FOREACH(x, name, head) \ | 265 | } else { |
| 289 | for ((x) = SPLAY_MIN(name, head); (x) != NULL; (x) = SPLAY_NEXT(name, head, x)) | 266 | head->SetRoot(tmp); |
| 290 | 267 | } | |
| 291 | /* Macros that define a red-black tree */ | 268 | |
| 292 | #define RB_HEAD(name, type) \ | 269 | RB_SET_RIGHT(tmp, elm); |
| 293 | struct name { \ | 270 | RB_SET_PARENT(elm, tmp); |
| 294 | struct type* rbh_root; /* root of the tree */ \ | 271 | } |
| 295 | } | 272 | |
| 296 | 273 | template <typename Node> | |
| 297 | #define RB_INITIALIZER(root) \ | 274 | void RB_INSERT_COLOR(RBHead<Node>* head, Node* elm) { |
| 298 | { NULL } | 275 | Node* parent = nullptr; |
| 299 | 276 | Node* tmp = nullptr; | |
| 300 | #define RB_INIT(root) \ | 277 | |
| 301 | do { \ | 278 | while ((parent = RB_PARENT(elm)) != nullptr && RB_IS_RED(parent)) { |
| 302 | (root)->rbh_root = NULL; \ | 279 | Node* gparent = RB_PARENT(parent); |
| 303 | } while (/*CONSTCOND*/ 0) | 280 | if (parent == RB_LEFT(gparent)) { |
| 304 | 281 | tmp = RB_RIGHT(gparent); | |
| 305 | #define RB_BLACK 0 | 282 | if (tmp && RB_IS_RED(tmp)) { |
| 306 | #define RB_RED 1 | 283 | RB_SET_COLOR(tmp, EntryColor::Black); |
| 307 | #define RB_ENTRY(type) \ | 284 | RB_SET_BLACKRED(parent, gparent); |
| 308 | struct { \ | 285 | elm = gparent; |
| 309 | struct type* rbe_left; /* left element */ \ | 286 | continue; |
| 310 | struct type* rbe_right; /* right element */ \ | 287 | } |
| 311 | struct type* rbe_parent; /* parent element */ \ | 288 | |
| 312 | int rbe_color; /* node color */ \ | 289 | if (RB_RIGHT(parent) == elm) { |
| 313 | } | 290 | RB_ROTATE_LEFT(head, parent, tmp); |
| 314 | 291 | tmp = parent; | |
| 315 | #define RB_LEFT(elm, field) (elm)->field.rbe_left | 292 | parent = elm; |
| 316 | #define RB_RIGHT(elm, field) (elm)->field.rbe_right | 293 | elm = tmp; |
| 317 | #define RB_PARENT(elm, field) (elm)->field.rbe_parent | 294 | } |
| 318 | #define RB_COLOR(elm, field) (elm)->field.rbe_color | 295 | |
| 319 | #define RB_ROOT(head) (head)->rbh_root | 296 | RB_SET_BLACKRED(parent, gparent); |
| 320 | #define RB_EMPTY(head) (RB_ROOT(head) == NULL) | 297 | RB_ROTATE_RIGHT(head, gparent, tmp); |
| 321 | 298 | } else { | |
| 322 | #define RB_SET(elm, parent, field) \ | 299 | tmp = RB_LEFT(gparent); |
| 323 | do { \ | 300 | if (tmp && RB_IS_RED(tmp)) { |
| 324 | RB_PARENT(elm, field) = parent; \ | 301 | RB_SET_COLOR(tmp, EntryColor::Black); |
| 325 | RB_LEFT(elm, field) = RB_RIGHT(elm, field) = NULL; \ | 302 | RB_SET_BLACKRED(parent, gparent); |
| 326 | RB_COLOR(elm, field) = RB_RED; \ | 303 | elm = gparent; |
| 327 | } while (/*CONSTCOND*/ 0) | 304 | continue; |
| 328 | 305 | } | |
| 329 | #define RB_SET_BLACKRED(black, red, field) \ | 306 | |
| 330 | do { \ | 307 | if (RB_LEFT(parent) == elm) { |
| 331 | RB_COLOR(black, field) = RB_BLACK; \ | 308 | RB_ROTATE_RIGHT(head, parent, tmp); |
| 332 | RB_COLOR(red, field) = RB_RED; \ | 309 | tmp = parent; |
| 333 | } while (/*CONSTCOND*/ 0) | 310 | parent = elm; |
| 334 | 311 | elm = tmp; | |
| 335 | #ifndef RB_AUGMENT | 312 | } |
| 336 | #define RB_AUGMENT(x) \ | 313 | |
| 337 | do { \ | 314 | RB_SET_BLACKRED(parent, gparent); |
| 338 | } while (0) | 315 | RB_ROTATE_LEFT(head, gparent, tmp); |
| 339 | #endif | 316 | } |
| 340 | 317 | } | |
| 341 | #define RB_ROTATE_LEFT(head, elm, tmp, field) \ | 318 | |
| 342 | do { \ | 319 | RB_SET_COLOR(head->Root(), EntryColor::Black); |
| 343 | (tmp) = RB_RIGHT(elm, field); \ | 320 | } |
| 344 | if ((RB_RIGHT(elm, field) = RB_LEFT(tmp, field)) != NULL) { \ | 321 | |
| 345 | RB_PARENT(RB_LEFT(tmp, field), field) = (elm); \ | 322 | template <typename Node> |
| 346 | } \ | 323 | void RB_REMOVE_COLOR(RBHead<Node>* head, Node* parent, Node* elm) { |
| 347 | RB_AUGMENT(elm); \ | 324 | Node* tmp; |
| 348 | if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field)) != NULL) { \ | 325 | while ((elm == nullptr || RB_IS_BLACK(elm)) && elm != head->Root()) { |
| 349 | if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \ | 326 | if (RB_LEFT(parent) == elm) { |
| 350 | RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \ | 327 | tmp = RB_RIGHT(parent); |
| 351 | else \ | 328 | if (RB_IS_RED(tmp)) { |
| 352 | RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \ | 329 | RB_SET_BLACKRED(tmp, parent); |
| 353 | } else \ | 330 | RB_ROTATE_LEFT(head, parent, tmp); |
| 354 | (head)->rbh_root = (tmp); \ | 331 | tmp = RB_RIGHT(parent); |
| 355 | RB_LEFT(tmp, field) = (elm); \ | 332 | } |
| 356 | RB_PARENT(elm, field) = (tmp); \ | 333 | |
| 357 | RB_AUGMENT(tmp); \ | 334 | if ((RB_LEFT(tmp) == nullptr || RB_IS_BLACK(RB_LEFT(tmp))) && |
| 358 | if ((RB_PARENT(tmp, field))) \ | 335 | (RB_RIGHT(tmp) == nullptr || RB_IS_BLACK(RB_RIGHT(tmp)))) { |
| 359 | RB_AUGMENT(RB_PARENT(tmp, field)); \ | 336 | RB_SET_COLOR(tmp, EntryColor::Red); |
| 360 | } while (/*CONSTCOND*/ 0) | 337 | elm = parent; |
| 361 | 338 | parent = RB_PARENT(elm); | |
| 362 | #define RB_ROTATE_RIGHT(head, elm, tmp, field) \ | 339 | } else { |
| 363 | do { \ | 340 | if (RB_RIGHT(tmp) == nullptr || RB_IS_BLACK(RB_RIGHT(tmp))) { |
| 364 | (tmp) = RB_LEFT(elm, field); \ | 341 | Node* oleft; |
| 365 | if ((RB_LEFT(elm, field) = RB_RIGHT(tmp, field)) != NULL) { \ | 342 | if ((oleft = RB_LEFT(tmp)) != nullptr) { |
| 366 | RB_PARENT(RB_RIGHT(tmp, field), field) = (elm); \ | 343 | RB_SET_COLOR(oleft, EntryColor::Black); |
| 367 | } \ | 344 | } |
| 368 | RB_AUGMENT(elm); \ | 345 | |
| 369 | if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field)) != NULL) { \ | 346 | RB_SET_COLOR(tmp, EntryColor::Red); |
| 370 | if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \ | 347 | RB_ROTATE_RIGHT(head, tmp, oleft); |
| 371 | RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \ | 348 | tmp = RB_RIGHT(parent); |
| 372 | else \ | 349 | } |
| 373 | RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \ | 350 | |
| 374 | } else \ | 351 | RB_SET_COLOR(tmp, RB_COLOR(parent)); |
| 375 | (head)->rbh_root = (tmp); \ | 352 | RB_SET_COLOR(parent, EntryColor::Black); |
| 376 | RB_RIGHT(tmp, field) = (elm); \ | 353 | if (RB_RIGHT(tmp)) { |
| 377 | RB_PARENT(elm, field) = (tmp); \ | 354 | RB_SET_COLOR(RB_RIGHT(tmp), EntryColor::Black); |
| 378 | RB_AUGMENT(tmp); \ | 355 | } |
| 379 | if ((RB_PARENT(tmp, field))) \ | 356 | |
| 380 | RB_AUGMENT(RB_PARENT(tmp, field)); \ | 357 | RB_ROTATE_LEFT(head, parent, tmp); |
| 381 | } while (/*CONSTCOND*/ 0) | 358 | elm = head->Root(); |
| 382 | 359 | break; | |
| 383 | /* Generates prototypes and inline functions */ | 360 | } |
| 384 | #define RB_PROTOTYPE(name, type, field, cmp) RB_PROTOTYPE_INTERNAL(name, type, field, cmp, ) | 361 | } else { |
| 385 | #define RB_PROTOTYPE_STATIC(name, type, field, cmp) \ | 362 | tmp = RB_LEFT(parent); |
| 386 | RB_PROTOTYPE_INTERNAL(name, type, field, cmp, static) | 363 | if (RB_IS_RED(tmp)) { |
| 387 | #define RB_PROTOTYPE_INTERNAL(name, type, field, cmp, attr) \ | 364 | RB_SET_BLACKRED(tmp, parent); |
| 388 | RB_PROTOTYPE_INSERT_COLOR(name, type, attr); \ | 365 | RB_ROTATE_RIGHT(head, parent, tmp); |
| 389 | RB_PROTOTYPE_REMOVE_COLOR(name, type, attr); \ | 366 | tmp = RB_LEFT(parent); |
| 390 | RB_PROTOTYPE_INSERT(name, type, attr); \ | 367 | } |
| 391 | RB_PROTOTYPE_REMOVE(name, type, attr); \ | 368 | |
| 392 | RB_PROTOTYPE_FIND(name, type, attr); \ | 369 | if ((RB_LEFT(tmp) == nullptr || RB_IS_BLACK(RB_LEFT(tmp))) && |
| 393 | RB_PROTOTYPE_NFIND(name, type, attr); \ | 370 | (RB_RIGHT(tmp) == nullptr || RB_IS_BLACK(RB_RIGHT(tmp)))) { |
| 394 | RB_PROTOTYPE_FIND_LIGHT(name, type, attr); \ | 371 | RB_SET_COLOR(tmp, EntryColor::Red); |
| 395 | RB_PROTOTYPE_NFIND_LIGHT(name, type, attr); \ | 372 | elm = parent; |
| 396 | RB_PROTOTYPE_NEXT(name, type, attr); \ | 373 | parent = RB_PARENT(elm); |
| 397 | RB_PROTOTYPE_PREV(name, type, attr); \ | 374 | } else { |
| 398 | RB_PROTOTYPE_MINMAX(name, type, attr); | 375 | if (RB_LEFT(tmp) == nullptr || RB_IS_BLACK(RB_LEFT(tmp))) { |
| 399 | #define RB_PROTOTYPE_INSERT_COLOR(name, type, attr) \ | 376 | Node* oright; |
| 400 | attr void name##_RB_INSERT_COLOR(struct name*, struct type*) | 377 | if ((oright = RB_RIGHT(tmp)) != nullptr) { |
| 401 | #define RB_PROTOTYPE_REMOVE_COLOR(name, type, attr) \ | 378 | RB_SET_COLOR(oright, EntryColor::Black); |
| 402 | attr void name##_RB_REMOVE_COLOR(struct name*, struct type*, struct type*) | 379 | } |
| 403 | #define RB_PROTOTYPE_REMOVE(name, type, attr) \ | 380 | |
| 404 | attr struct type* name##_RB_REMOVE(struct name*, struct type*) | 381 | RB_SET_COLOR(tmp, EntryColor::Red); |
| 405 | #define RB_PROTOTYPE_INSERT(name, type, attr) \ | 382 | RB_ROTATE_LEFT(head, tmp, oright); |
| 406 | attr struct type* name##_RB_INSERT(struct name*, struct type*) | 383 | tmp = RB_LEFT(parent); |
| 407 | #define RB_PROTOTYPE_FIND(name, type, attr) \ | 384 | } |
| 408 | attr struct type* name##_RB_FIND(struct name*, struct type*) | 385 | |
| 409 | #define RB_PROTOTYPE_NFIND(name, type, attr) \ | 386 | RB_SET_COLOR(tmp, RB_COLOR(parent)); |
| 410 | attr struct type* name##_RB_NFIND(struct name*, struct type*) | 387 | RB_SET_COLOR(parent, EntryColor::Black); |
| 411 | #define RB_PROTOTYPE_FIND_LIGHT(name, type, attr) \ | 388 | |
| 412 | attr struct type* name##_RB_FIND_LIGHT(struct name*, const void*) | 389 | if (RB_LEFT(tmp)) { |
| 413 | #define RB_PROTOTYPE_NFIND_LIGHT(name, type, attr) \ | 390 | RB_SET_COLOR(RB_LEFT(tmp), EntryColor::Black); |
| 414 | attr struct type* name##_RB_NFIND_LIGHT(struct name*, const void*) | 391 | } |
| 415 | #define RB_PROTOTYPE_NEXT(name, type, attr) attr struct type* name##_RB_NEXT(struct type*) | 392 | |
| 416 | #define RB_PROTOTYPE_PREV(name, type, attr) attr struct type* name##_RB_PREV(struct type*) | 393 | RB_ROTATE_RIGHT(head, parent, tmp); |
| 417 | #define RB_PROTOTYPE_MINMAX(name, type, attr) attr struct type* name##_RB_MINMAX(struct name*, int) | 394 | elm = head->Root(); |
| 418 | 395 | break; | |
| 419 | /* Main rb operation. | 396 | } |
| 420 | * Moves node close to the key of elm to top | 397 | } |
| 421 | */ | 398 | } |
| 422 | #define RB_GENERATE_WITHOUT_COMPARE(name, type, field) \ | 399 | |
| 423 | RB_GENERATE_WITHOUT_COMPARE_INTERNAL(name, type, field, ) | 400 | if (elm) { |
| 424 | #define RB_GENERATE_WITHOUT_COMPARE_STATIC(name, type, field) \ | 401 | RB_SET_COLOR(elm, EntryColor::Black); |
| 425 | RB_GENERATE_WITHOUT_COMPARE_INTERNAL(name, type, field, static) | 402 | } |
| 426 | #define RB_GENERATE_WITHOUT_COMPARE_INTERNAL(name, type, field, attr) \ | 403 | } |
| 427 | RB_GENERATE_REMOVE_COLOR(name, type, field, attr) \ | 404 | |
| 428 | RB_GENERATE_REMOVE(name, type, field, attr) \ | 405 | template <typename Node> |
| 429 | RB_GENERATE_NEXT(name, type, field, attr) \ | 406 | Node* RB_REMOVE(RBHead<Node>* head, Node* elm) { |
| 430 | RB_GENERATE_PREV(name, type, field, attr) \ | 407 | Node* child = nullptr; |
| 431 | RB_GENERATE_MINMAX(name, type, field, attr) | 408 | Node* parent = nullptr; |
| 432 | 409 | Node* old = elm; | |
| 433 | #define RB_GENERATE_WITH_COMPARE(name, type, field, cmp, lcmp) \ | 410 | EntryColor color{}; |
| 434 | RB_GENERATE_WITH_COMPARE_INTERNAL(name, type, field, cmp, lcmp, ) | 411 | |
| 435 | #define RB_GENERATE_WITH_COMPARE_STATIC(name, type, field, cmp, lcmp) \ | 412 | const auto finalize = [&] { |
| 436 | RB_GENERATE_WITH_COMPARE_INTERNAL(name, type, field, cmp, lcmp, static) | 413 | if (color == EntryColor::Black) { |
| 437 | #define RB_GENERATE_WITH_COMPARE_INTERNAL(name, type, field, cmp, lcmp, attr) \ | 414 | RB_REMOVE_COLOR(head, parent, child); |
| 438 | RB_GENERATE_INSERT_COLOR(name, type, field, attr) \ | 415 | } |
| 439 | RB_GENERATE_INSERT(name, type, field, cmp, attr) \ | 416 | |
| 440 | RB_GENERATE_FIND(name, type, field, cmp, attr) \ | 417 | return old; |
| 441 | RB_GENERATE_NFIND(name, type, field, cmp, attr) \ | 418 | }; |
| 442 | RB_GENERATE_FIND_LIGHT(name, type, field, lcmp, attr) \ | 419 | |
| 443 | RB_GENERATE_NFIND_LIGHT(name, type, field, lcmp, attr) | 420 | if (RB_LEFT(elm) == nullptr) { |
| 444 | 421 | child = RB_RIGHT(elm); | |
| 445 | #define RB_GENERATE_ALL(name, type, field, cmp) RB_GENERATE_ALL_INTERNAL(name, type, field, cmp, ) | 422 | } else if (RB_RIGHT(elm) == nullptr) { |
| 446 | #define RB_GENERATE_ALL_STATIC(name, type, field, cmp) \ | 423 | child = RB_LEFT(elm); |
| 447 | RB_GENERATE_ALL_INTERNAL(name, type, field, cmp, static) | 424 | } else { |
| 448 | #define RB_GENERATE_ALL_INTERNAL(name, type, field, cmp, attr) \ | 425 | Node* left; |
| 449 | RB_GENERATE_WITHOUT_COMPARE_INTERNAL(name, type, field, attr) \ | 426 | elm = RB_RIGHT(elm); |
| 450 | RB_GENERATE_WITH_COMPARE_INTERNAL(name, type, field, cmp, attr) | 427 | while ((left = RB_LEFT(elm)) != nullptr) { |
| 451 | 428 | elm = left; | |
| 452 | #define RB_GENERATE_INSERT_COLOR(name, type, field, attr) \ | 429 | } |
| 453 | attr void name##_RB_INSERT_COLOR(struct name* head, struct type* elm) { \ | 430 | |
| 454 | struct type *parent, *gparent, *tmp; \ | 431 | child = RB_RIGHT(elm); |
| 455 | while ((parent = RB_PARENT(elm, field)) != NULL && RB_COLOR(parent, field) == RB_RED) { \ | 432 | parent = RB_PARENT(elm); |
| 456 | gparent = RB_PARENT(parent, field); \ | 433 | color = RB_COLOR(elm); |
| 457 | if (parent == RB_LEFT(gparent, field)) { \ | 434 | |
| 458 | tmp = RB_RIGHT(gparent, field); \ | 435 | if (child) { |
| 459 | if (tmp && RB_COLOR(tmp, field) == RB_RED) { \ | 436 | RB_SET_PARENT(child, parent); |
| 460 | RB_COLOR(tmp, field) = RB_BLACK; \ | 437 | } |
| 461 | RB_SET_BLACKRED(parent, gparent, field); \ | 438 | if (parent) { |
| 462 | elm = gparent; \ | 439 | if (RB_LEFT(parent) == elm) { |
| 463 | continue; \ | 440 | RB_SET_LEFT(parent, child); |
| 464 | } \ | 441 | } else { |
| 465 | if (RB_RIGHT(parent, field) == elm) { \ | 442 | RB_SET_RIGHT(parent, child); |
| 466 | RB_ROTATE_LEFT(head, parent, tmp, field); \ | 443 | } |
| 467 | tmp = parent; \ | 444 | } else { |
| 468 | parent = elm; \ | 445 | head->SetRoot(child); |
| 469 | elm = tmp; \ | 446 | } |
| 470 | } \ | 447 | |
| 471 | RB_SET_BLACKRED(parent, gparent, field); \ | 448 | if (RB_PARENT(elm) == old) { |
| 472 | RB_ROTATE_RIGHT(head, gparent, tmp, field); \ | 449 | parent = elm; |
| 473 | } else { \ | 450 | } |
| 474 | tmp = RB_LEFT(gparent, field); \ | 451 | |
| 475 | if (tmp && RB_COLOR(tmp, field) == RB_RED) { \ | 452 | elm->SetEntry(old->GetEntry()); |
| 476 | RB_COLOR(tmp, field) = RB_BLACK; \ | 453 | |
| 477 | RB_SET_BLACKRED(parent, gparent, field); \ | 454 | if (RB_PARENT(old)) { |
| 478 | elm = gparent; \ | 455 | if (RB_LEFT(RB_PARENT(old)) == old) { |
| 479 | continue; \ | 456 | RB_SET_LEFT(RB_PARENT(old), elm); |
| 480 | } \ | 457 | } else { |
| 481 | if (RB_LEFT(parent, field) == elm) { \ | 458 | RB_SET_RIGHT(RB_PARENT(old), elm); |
| 482 | RB_ROTATE_RIGHT(head, parent, tmp, field); \ | 459 | } |
| 483 | tmp = parent; \ | 460 | } else { |
| 484 | parent = elm; \ | 461 | head->SetRoot(elm); |
| 485 | elm = tmp; \ | 462 | } |
| 486 | } \ | 463 | RB_SET_PARENT(RB_LEFT(old), elm); |
| 487 | RB_SET_BLACKRED(parent, gparent, field); \ | 464 | if (RB_RIGHT(old)) { |
| 488 | RB_ROTATE_LEFT(head, gparent, tmp, field); \ | 465 | RB_SET_PARENT(RB_RIGHT(old), elm); |
| 489 | } \ | 466 | } |
| 490 | } \ | 467 | if (parent) { |
| 491 | RB_COLOR(head->rbh_root, field) = RB_BLACK; \ | 468 | left = parent; |
| 492 | } | 469 | } |
| 493 | 470 | ||
| 494 | #define RB_GENERATE_REMOVE_COLOR(name, type, field, attr) \ | 471 | return finalize(); |
| 495 | attr void name##_RB_REMOVE_COLOR(struct name* head, struct type* parent, struct type* elm) { \ | 472 | } |
| 496 | struct type* tmp; \ | 473 | |
| 497 | while ((elm == NULL || RB_COLOR(elm, field) == RB_BLACK) && elm != RB_ROOT(head)) { \ | 474 | parent = RB_PARENT(elm); |
| 498 | if (RB_LEFT(parent, field) == elm) { \ | 475 | color = RB_COLOR(elm); |
| 499 | tmp = RB_RIGHT(parent, field); \ | 476 | |
| 500 | if (RB_COLOR(tmp, field) == RB_RED) { \ | 477 | if (child) { |
| 501 | RB_SET_BLACKRED(tmp, parent, field); \ | 478 | RB_SET_PARENT(child, parent); |
| 502 | RB_ROTATE_LEFT(head, parent, tmp, field); \ | 479 | } |
| 503 | tmp = RB_RIGHT(parent, field); \ | 480 | if (parent) { |
| 504 | } \ | 481 | if (RB_LEFT(parent) == elm) { |
| 505 | if ((RB_LEFT(tmp, field) == NULL || \ | 482 | RB_SET_LEFT(parent, child); |
| 506 | RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) && \ | 483 | } else { |
| 507 | (RB_RIGHT(tmp, field) == NULL || \ | 484 | RB_SET_RIGHT(parent, child); |
| 508 | RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) { \ | 485 | } |
| 509 | RB_COLOR(tmp, field) = RB_RED; \ | 486 | } else { |
| 510 | elm = parent; \ | 487 | head->SetRoot(child); |
| 511 | parent = RB_PARENT(elm, field); \ | 488 | } |
| 512 | } else { \ | 489 | |
| 513 | if (RB_RIGHT(tmp, field) == NULL || \ | 490 | return finalize(); |
| 514 | RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK) { \ | 491 | } |
| 515 | struct type* oleft; \ | 492 | |
| 516 | if ((oleft = RB_LEFT(tmp, field)) != NULL) \ | 493 | // Inserts a node into the RB tree |
| 517 | RB_COLOR(oleft, field) = RB_BLACK; \ | 494 | template <typename Node, typename CompareFunction> |
| 518 | RB_COLOR(tmp, field) = RB_RED; \ | 495 | Node* RB_INSERT(RBHead<Node>* head, Node* elm, CompareFunction cmp) { |
| 519 | RB_ROTATE_RIGHT(head, tmp, oleft, field); \ | 496 | Node* parent = nullptr; |
| 520 | tmp = RB_RIGHT(parent, field); \ | 497 | Node* tmp = head->Root(); |
| 521 | } \ | 498 | int comp = 0; |
| 522 | RB_COLOR(tmp, field) = RB_COLOR(parent, field); \ | 499 | |
| 523 | RB_COLOR(parent, field) = RB_BLACK; \ | 500 | while (tmp) { |
| 524 | if (RB_RIGHT(tmp, field)) \ | 501 | parent = tmp; |
| 525 | RB_COLOR(RB_RIGHT(tmp, field), field) = RB_BLACK; \ | 502 | comp = cmp(elm, parent); |
| 526 | RB_ROTATE_LEFT(head, parent, tmp, field); \ | 503 | if (comp < 0) { |
| 527 | elm = RB_ROOT(head); \ | 504 | tmp = RB_LEFT(tmp); |
| 528 | break; \ | 505 | } else if (comp > 0) { |
| 529 | } \ | 506 | tmp = RB_RIGHT(tmp); |
| 530 | } else { \ | 507 | } else { |
| 531 | tmp = RB_LEFT(parent, field); \ | 508 | return tmp; |
| 532 | if (RB_COLOR(tmp, field) == RB_RED) { \ | 509 | } |
| 533 | RB_SET_BLACKRED(tmp, parent, field); \ | 510 | } |
| 534 | RB_ROTATE_RIGHT(head, parent, tmp, field); \ | 511 | |
| 535 | tmp = RB_LEFT(parent, field); \ | 512 | RB_SET(elm, parent); |
| 536 | } \ | 513 | |
| 537 | if ((RB_LEFT(tmp, field) == NULL || \ | 514 | if (parent != nullptr) { |
| 538 | RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) && \ | 515 | if (comp < 0) { |
| 539 | (RB_RIGHT(tmp, field) == NULL || \ | 516 | RB_SET_LEFT(parent, elm); |
| 540 | RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) { \ | 517 | } else { |
| 541 | RB_COLOR(tmp, field) = RB_RED; \ | 518 | RB_SET_RIGHT(parent, elm); |
| 542 | elm = parent; \ | 519 | } |
| 543 | parent = RB_PARENT(elm, field); \ | 520 | } else { |
| 544 | } else { \ | 521 | head->SetRoot(elm); |
| 545 | if (RB_LEFT(tmp, field) == NULL || \ | 522 | } |
| 546 | RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) { \ | 523 | |
| 547 | struct type* oright; \ | 524 | RB_INSERT_COLOR(head, elm); |
| 548 | if ((oright = RB_RIGHT(tmp, field)) != NULL) \ | 525 | return nullptr; |
| 549 | RB_COLOR(oright, field) = RB_BLACK; \ | 526 | } |
| 550 | RB_COLOR(tmp, field) = RB_RED; \ | 527 | |
| 551 | RB_ROTATE_LEFT(head, tmp, oright, field); \ | 528 | // Finds the node with the same key as elm |
| 552 | tmp = RB_LEFT(parent, field); \ | 529 | template <typename Node, typename CompareFunction> |
| 553 | } \ | 530 | Node* RB_FIND(RBHead<Node>* head, Node* elm, CompareFunction cmp) { |
| 554 | RB_COLOR(tmp, field) = RB_COLOR(parent, field); \ | 531 | Node* tmp = head->Root(); |
| 555 | RB_COLOR(parent, field) = RB_BLACK; \ | 532 | |
| 556 | if (RB_LEFT(tmp, field)) \ | 533 | while (tmp) { |
| 557 | RB_COLOR(RB_LEFT(tmp, field), field) = RB_BLACK; \ | 534 | const int comp = cmp(elm, tmp); |
| 558 | RB_ROTATE_RIGHT(head, parent, tmp, field); \ | 535 | if (comp < 0) { |
| 559 | elm = RB_ROOT(head); \ | 536 | tmp = RB_LEFT(tmp); |
| 560 | break; \ | 537 | } else if (comp > 0) { |
| 561 | } \ | 538 | tmp = RB_RIGHT(tmp); |
| 562 | } \ | 539 | } else { |
| 563 | } \ | 540 | return tmp; |
| 564 | if (elm) \ | 541 | } |
| 565 | RB_COLOR(elm, field) = RB_BLACK; \ | 542 | } |
| 566 | } | 543 | |
| 567 | 544 | return nullptr; | |
| 568 | #define RB_GENERATE_REMOVE(name, type, field, attr) \ | 545 | } |
| 569 | attr struct type* name##_RB_REMOVE(struct name* head, struct type* elm) { \ | 546 | |
| 570 | struct type *child, *parent, *old = elm; \ | 547 | // Finds the first node greater than or equal to the search key |
| 571 | int color; \ | 548 | template <typename Node, typename CompareFunction> |
| 572 | if (RB_LEFT(elm, field) == NULL) \ | 549 | Node* RB_NFIND(RBHead<Node>* head, Node* elm, CompareFunction cmp) { |
| 573 | child = RB_RIGHT(elm, field); \ | 550 | Node* tmp = head->Root(); |
| 574 | else if (RB_RIGHT(elm, field) == NULL) \ | 551 | Node* res = nullptr; |
| 575 | child = RB_LEFT(elm, field); \ | 552 | |
| 576 | else { \ | 553 | while (tmp) { |
| 577 | struct type* left; \ | 554 | const int comp = cmp(elm, tmp); |
| 578 | elm = RB_RIGHT(elm, field); \ | 555 | if (comp < 0) { |
| 579 | while ((left = RB_LEFT(elm, field)) != NULL) \ | 556 | res = tmp; |
| 580 | elm = left; \ | 557 | tmp = RB_LEFT(tmp); |
| 581 | child = RB_RIGHT(elm, field); \ | 558 | } else if (comp > 0) { |
| 582 | parent = RB_PARENT(elm, field); \ | 559 | tmp = RB_RIGHT(tmp); |
| 583 | color = RB_COLOR(elm, field); \ | 560 | } else { |
| 584 | if (child) \ | 561 | return tmp; |
| 585 | RB_PARENT(child, field) = parent; \ | 562 | } |
| 586 | if (parent) { \ | 563 | } |
| 587 | if (RB_LEFT(parent, field) == elm) \ | 564 | |
| 588 | RB_LEFT(parent, field) = child; \ | 565 | return res; |
| 589 | else \ | 566 | } |
| 590 | RB_RIGHT(parent, field) = child; \ | 567 | |
| 591 | RB_AUGMENT(parent); \ | 568 | // Finds the node with the same key as lelm |
| 592 | } else \ | 569 | template <typename Node, typename CompareFunction> |
| 593 | RB_ROOT(head) = child; \ | 570 | Node* RB_FIND_LIGHT(RBHead<Node>* head, const void* lelm, CompareFunction lcmp) { |
| 594 | if (RB_PARENT(elm, field) == old) \ | 571 | Node* tmp = head->Root(); |
| 595 | parent = elm; \ | 572 | |
| 596 | (elm)->field = (old)->field; \ | 573 | while (tmp) { |
| 597 | if (RB_PARENT(old, field)) { \ | 574 | const int comp = lcmp(lelm, tmp); |
| 598 | if (RB_LEFT(RB_PARENT(old, field), field) == old) \ | 575 | if (comp < 0) { |
| 599 | RB_LEFT(RB_PARENT(old, field), field) = elm; \ | 576 | tmp = RB_LEFT(tmp); |
| 600 | else \ | 577 | } else if (comp > 0) { |
| 601 | RB_RIGHT(RB_PARENT(old, field), field) = elm; \ | 578 | tmp = RB_RIGHT(tmp); |
| 602 | RB_AUGMENT(RB_PARENT(old, field)); \ | 579 | } else { |
| 603 | } else \ | 580 | return tmp; |
| 604 | RB_ROOT(head) = elm; \ | 581 | } |
| 605 | RB_PARENT(RB_LEFT(old, field), field) = elm; \ | 582 | } |
| 606 | if (RB_RIGHT(old, field)) \ | 583 | |
| 607 | RB_PARENT(RB_RIGHT(old, field), field) = elm; \ | 584 | return nullptr; |
| 608 | if (parent) { \ | 585 | } |
| 609 | left = parent; \ | 586 | |
| 610 | do { \ | 587 | // Finds the first node greater than or equal to the search key |
| 611 | RB_AUGMENT(left); \ | 588 | template <typename Node, typename CompareFunction> |
| 612 | } while ((left = RB_PARENT(left, field)) != NULL); \ | 589 | Node* RB_NFIND_LIGHT(RBHead<Node>* head, const void* lelm, CompareFunction lcmp) { |
| 613 | } \ | 590 | Node* tmp = head->Root(); |
| 614 | goto color; \ | 591 | Node* res = nullptr; |
| 615 | } \ | 592 | |
| 616 | parent = RB_PARENT(elm, field); \ | 593 | while (tmp) { |
| 617 | color = RB_COLOR(elm, field); \ | 594 | const int comp = lcmp(lelm, tmp); |
| 618 | if (child) \ | 595 | if (comp < 0) { |
| 619 | RB_PARENT(child, field) = parent; \ | 596 | res = tmp; |
| 620 | if (parent) { \ | 597 | tmp = RB_LEFT(tmp); |
| 621 | if (RB_LEFT(parent, field) == elm) \ | 598 | } else if (comp > 0) { |
| 622 | RB_LEFT(parent, field) = child; \ | 599 | tmp = RB_RIGHT(tmp); |
| 623 | else \ | 600 | } else { |
| 624 | RB_RIGHT(parent, field) = child; \ | 601 | return tmp; |
| 625 | RB_AUGMENT(parent); \ | 602 | } |
| 626 | } else \ | 603 | } |
| 627 | RB_ROOT(head) = child; \ | 604 | |
| 628 | color: \ | 605 | return res; |
| 629 | if (color == RB_BLACK) \ | 606 | } |
| 630 | name##_RB_REMOVE_COLOR(head, parent, child); \ | 607 | |
| 631 | return (old); \ | 608 | template <typename Node> |
| 632 | } | 609 | Node* RB_NEXT(Node* elm) { |
| 633 | 610 | if (RB_RIGHT(elm)) { | |
| 634 | #define RB_GENERATE_INSERT(name, type, field, cmp, attr) \ | 611 | elm = RB_RIGHT(elm); |
| 635 | /* Inserts a node into the RB tree */ \ | 612 | while (RB_LEFT(elm)) { |
| 636 | attr struct type* name##_RB_INSERT(struct name* head, struct type* elm) { \ | 613 | elm = RB_LEFT(elm); |
| 637 | struct type* tmp; \ | 614 | } |
| 638 | struct type* parent = NULL; \ | 615 | } else { |
| 639 | int comp = 0; \ | 616 | if (RB_PARENT(elm) && (elm == RB_LEFT(RB_PARENT(elm)))) { |
| 640 | tmp = RB_ROOT(head); \ | 617 | elm = RB_PARENT(elm); |
| 641 | while (tmp) { \ | 618 | } else { |
| 642 | parent = tmp; \ | 619 | while (RB_PARENT(elm) && (elm == RB_RIGHT(RB_PARENT(elm)))) { |
| 643 | comp = (cmp)(elm, parent); \ | 620 | elm = RB_PARENT(elm); |
| 644 | if (comp < 0) \ | 621 | } |
| 645 | tmp = RB_LEFT(tmp, field); \ | 622 | elm = RB_PARENT(elm); |
| 646 | else if (comp > 0) \ | 623 | } |
| 647 | tmp = RB_RIGHT(tmp, field); \ | 624 | } |
| 648 | else \ | 625 | return elm; |
| 649 | return (tmp); \ | 626 | } |
| 650 | } \ | 627 | |
| 651 | RB_SET(elm, parent, field); \ | 628 | template <typename Node> |
| 652 | if (parent != NULL) { \ | 629 | Node* RB_PREV(Node* elm) { |
| 653 | if (comp < 0) \ | 630 | if (RB_LEFT(elm)) { |
| 654 | RB_LEFT(parent, field) = elm; \ | 631 | elm = RB_LEFT(elm); |
| 655 | else \ | 632 | while (RB_RIGHT(elm)) { |
| 656 | RB_RIGHT(parent, field) = elm; \ | 633 | elm = RB_RIGHT(elm); |
| 657 | RB_AUGMENT(parent); \ | 634 | } |
| 658 | } else \ | 635 | } else { |
| 659 | RB_ROOT(head) = elm; \ | 636 | if (RB_PARENT(elm) && (elm == RB_RIGHT(RB_PARENT(elm)))) { |
| 660 | name##_RB_INSERT_COLOR(head, elm); \ | 637 | elm = RB_PARENT(elm); |
| 661 | return (NULL); \ | 638 | } else { |
| 662 | } | 639 | while (RB_PARENT(elm) && (elm == RB_LEFT(RB_PARENT(elm)))) { |
| 663 | 640 | elm = RB_PARENT(elm); | |
| 664 | #define RB_GENERATE_FIND(name, type, field, cmp, attr) \ | 641 | } |
| 665 | /* Finds the node with the same key as elm */ \ | 642 | elm = RB_PARENT(elm); |
| 666 | attr struct type* name##_RB_FIND(struct name* head, struct type* elm) { \ | 643 | } |
| 667 | struct type* tmp = RB_ROOT(head); \ | 644 | } |
| 668 | int comp; \ | 645 | return elm; |
| 669 | while (tmp) { \ | 646 | } |
| 670 | comp = cmp(elm, tmp); \ | 647 | |
| 671 | if (comp < 0) \ | 648 | template <typename Node> |
| 672 | tmp = RB_LEFT(tmp, field); \ | 649 | Node* RB_MINMAX(RBHead<Node>* head, bool is_min) { |
| 673 | else if (comp > 0) \ | 650 | Node* tmp = head->Root(); |
| 674 | tmp = RB_RIGHT(tmp, field); \ | 651 | Node* parent = nullptr; |
| 675 | else \ | 652 | |
| 676 | return (tmp); \ | 653 | while (tmp) { |
| 677 | } \ | 654 | parent = tmp; |
| 678 | return (NULL); \ | 655 | if (is_min) { |
| 679 | } | 656 | tmp = RB_LEFT(tmp); |
| 680 | 657 | } else { | |
| 681 | #define RB_GENERATE_NFIND(name, type, field, cmp, attr) \ | 658 | tmp = RB_RIGHT(tmp); |
| 682 | /* Finds the first node greater than or equal to the search key */ \ | 659 | } |
| 683 | attr struct type* name##_RB_NFIND(struct name* head, struct type* elm) { \ | 660 | } |
| 684 | struct type* tmp = RB_ROOT(head); \ | 661 | |
| 685 | struct type* res = NULL; \ | 662 | return parent; |
| 686 | int comp; \ | 663 | } |
| 687 | while (tmp) { \ | 664 | |
| 688 | comp = cmp(elm, tmp); \ | 665 | template <typename Node> |
| 689 | if (comp < 0) { \ | 666 | Node* RB_MIN(RBHead<Node>* head) { |
| 690 | res = tmp; \ | 667 | return RB_MINMAX(head, true); |
| 691 | tmp = RB_LEFT(tmp, field); \ | 668 | } |
| 692 | } else if (comp > 0) \ | 669 | |
| 693 | tmp = RB_RIGHT(tmp, field); \ | 670 | template <typename Node> |
| 694 | else \ | 671 | Node* RB_MAX(RBHead<Node>* head) { |
| 695 | return (tmp); \ | 672 | return RB_MINMAX(head, false); |
| 696 | } \ | 673 | } |
| 697 | return (res); \ | 674 | } // namespace Common |
| 698 | } | ||
| 699 | |||
| 700 | #define RB_GENERATE_FIND_LIGHT(name, type, field, lcmp, attr) \ | ||
| 701 | /* Finds the node with the same key as elm */ \ | ||
| 702 | attr struct type* name##_RB_FIND_LIGHT(struct name* head, const void* lelm) { \ | ||
| 703 | struct type* tmp = RB_ROOT(head); \ | ||
| 704 | int comp; \ | ||
| 705 | while (tmp) { \ | ||
| 706 | comp = lcmp(lelm, tmp); \ | ||
| 707 | if (comp < 0) \ | ||
| 708 | tmp = RB_LEFT(tmp, field); \ | ||
| 709 | else if (comp > 0) \ | ||
| 710 | tmp = RB_RIGHT(tmp, field); \ | ||
| 711 | else \ | ||
| 712 | return (tmp); \ | ||
| 713 | } \ | ||
| 714 | return (NULL); \ | ||
| 715 | } | ||
| 716 | |||
| 717 | #define RB_GENERATE_NFIND_LIGHT(name, type, field, lcmp, attr) \ | ||
| 718 | /* Finds the first node greater than or equal to the search key */ \ | ||
| 719 | attr struct type* name##_RB_NFIND_LIGHT(struct name* head, const void* lelm) { \ | ||
| 720 | struct type* tmp = RB_ROOT(head); \ | ||
| 721 | struct type* res = NULL; \ | ||
| 722 | int comp; \ | ||
| 723 | while (tmp) { \ | ||
| 724 | comp = lcmp(lelm, tmp); \ | ||
| 725 | if (comp < 0) { \ | ||
| 726 | res = tmp; \ | ||
| 727 | tmp = RB_LEFT(tmp, field); \ | ||
| 728 | } else if (comp > 0) \ | ||
| 729 | tmp = RB_RIGHT(tmp, field); \ | ||
| 730 | else \ | ||
| 731 | return (tmp); \ | ||
| 732 | } \ | ||
| 733 | return (res); \ | ||
| 734 | } | ||
| 735 | |||
| 736 | #define RB_GENERATE_NEXT(name, type, field, attr) \ | ||
| 737 | /* ARGSUSED */ \ | ||
| 738 | attr struct type* name##_RB_NEXT(struct type* elm) { \ | ||
| 739 | if (RB_RIGHT(elm, field)) { \ | ||
| 740 | elm = RB_RIGHT(elm, field); \ | ||
| 741 | while (RB_LEFT(elm, field)) \ | ||
| 742 | elm = RB_LEFT(elm, field); \ | ||
| 743 | } else { \ | ||
| 744 | if (RB_PARENT(elm, field) && (elm == RB_LEFT(RB_PARENT(elm, field), field))) \ | ||
| 745 | elm = RB_PARENT(elm, field); \ | ||
| 746 | else { \ | ||
| 747 | while (RB_PARENT(elm, field) && (elm == RB_RIGHT(RB_PARENT(elm, field), field))) \ | ||
| 748 | elm = RB_PARENT(elm, field); \ | ||
| 749 | elm = RB_PARENT(elm, field); \ | ||
| 750 | } \ | ||
| 751 | } \ | ||
| 752 | return (elm); \ | ||
| 753 | } | ||
| 754 | |||
| 755 | #define RB_GENERATE_PREV(name, type, field, attr) \ | ||
| 756 | /* ARGSUSED */ \ | ||
| 757 | attr struct type* name##_RB_PREV(struct type* elm) { \ | ||
| 758 | if (RB_LEFT(elm, field)) { \ | ||
| 759 | elm = RB_LEFT(elm, field); \ | ||
| 760 | while (RB_RIGHT(elm, field)) \ | ||
| 761 | elm = RB_RIGHT(elm, field); \ | ||
| 762 | } else { \ | ||
| 763 | if (RB_PARENT(elm, field) && (elm == RB_RIGHT(RB_PARENT(elm, field), field))) \ | ||
| 764 | elm = RB_PARENT(elm, field); \ | ||
| 765 | else { \ | ||
| 766 | while (RB_PARENT(elm, field) && (elm == RB_LEFT(RB_PARENT(elm, field), field))) \ | ||
| 767 | elm = RB_PARENT(elm, field); \ | ||
| 768 | elm = RB_PARENT(elm, field); \ | ||
| 769 | } \ | ||
| 770 | } \ | ||
| 771 | return (elm); \ | ||
| 772 | } | ||
| 773 | |||
| 774 | #define RB_GENERATE_MINMAX(name, type, field, attr) \ | ||
| 775 | attr struct type* name##_RB_MINMAX(struct name* head, int val) { \ | ||
| 776 | struct type* tmp = RB_ROOT(head); \ | ||
| 777 | struct type* parent = NULL; \ | ||
| 778 | while (tmp) { \ | ||
| 779 | parent = tmp; \ | ||
| 780 | if (val < 0) \ | ||
| 781 | tmp = RB_LEFT(tmp, field); \ | ||
| 782 | else \ | ||
| 783 | tmp = RB_RIGHT(tmp, field); \ | ||
| 784 | } \ | ||
| 785 | return (parent); \ | ||
| 786 | } | ||
| 787 | |||
| 788 | #define RB_NEGINF -1 | ||
| 789 | #define RB_INF 1 | ||
| 790 | |||
| 791 | #define RB_INSERT(name, x, y) name##_RB_INSERT(x, y) | ||
| 792 | #define RB_REMOVE(name, x, y) name##_RB_REMOVE(x, y) | ||
| 793 | #define RB_FIND(name, x, y) name##_RB_FIND(x, y) | ||
| 794 | #define RB_NFIND(name, x, y) name##_RB_NFIND(x, y) | ||
| 795 | #define RB_FIND_LIGHT(name, x, y) name##_RB_FIND_LIGHT(x, y) | ||
| 796 | #define RB_NFIND_LIGHT(name, x, y) name##_RB_NFIND_LIGHT(x, y) | ||
| 797 | #define RB_NEXT(name, x, y) name##_RB_NEXT(y) | ||
| 798 | #define RB_PREV(name, x, y) name##_RB_PREV(y) | ||
| 799 | #define RB_MIN(name, x) name##_RB_MINMAX(x, RB_NEGINF) | ||
| 800 | #define RB_MAX(name, x) name##_RB_MINMAX(x, RB_INF) | ||
| 801 | |||
| 802 | #define RB_FOREACH(x, name, head) \ | ||
| 803 | for ((x) = RB_MIN(name, head); (x) != NULL; (x) = name##_RB_NEXT(x)) | ||
| 804 | |||
| 805 | #define RB_FOREACH_FROM(x, name, y) \ | ||
| 806 | for ((x) = (y); ((x) != NULL) && ((y) = name##_RB_NEXT(x), (x) != NULL); (x) = (y)) | ||
| 807 | |||
| 808 | #define RB_FOREACH_SAFE(x, name, head, y) \ | ||
| 809 | for ((x) = RB_MIN(name, head); ((x) != NULL) && ((y) = name##_RB_NEXT(x), (x) != NULL); \ | ||
| 810 | (x) = (y)) | ||
| 811 | |||
| 812 | #define RB_FOREACH_REVERSE(x, name, head) \ | ||
| 813 | for ((x) = RB_MAX(name, head); (x) != NULL; (x) = name##_RB_PREV(x)) | ||
| 814 | |||
| 815 | #define RB_FOREACH_REVERSE_FROM(x, name, y) \ | ||
| 816 | for ((x) = (y); ((x) != NULL) && ((y) = name##_RB_PREV(x), (x) != NULL); (x) = (y)) | ||
| 817 | |||
| 818 | #define RB_FOREACH_REVERSE_SAFE(x, name, head, y) \ | ||
| 819 | for ((x) = RB_MAX(name, head); ((x) != NULL) && ((y) = name##_RB_PREV(x), (x) != NULL); \ | ||
| 820 | (x) = (y)) | ||
| 821 | |||
| 822 | #endif /* _SYS_TREE_H_ */ | ||
diff --git a/src/common/x64/native_clock.cpp b/src/common/x64/native_clock.cpp index eb8a7782f..a65f6b832 100644 --- a/src/common/x64/native_clock.cpp +++ b/src/common/x64/native_clock.cpp | |||
| @@ -2,19 +2,74 @@ | |||
| 2 | // Licensed under GPLv2 or any later version | 2 | // Licensed under GPLv2 or any later version |
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include <array> | ||
| 5 | #include <chrono> | 6 | #include <chrono> |
| 7 | #include <limits> | ||
| 6 | #include <mutex> | 8 | #include <mutex> |
| 7 | #include <thread> | 9 | #include <thread> |
| 8 | 10 | ||
| 9 | #ifdef _MSC_VER | 11 | #ifdef _MSC_VER |
| 10 | #include <intrin.h> | 12 | #include <intrin.h> |
| 13 | |||
| 14 | #pragma intrinsic(__umulh) | ||
| 15 | #pragma intrinsic(_udiv128) | ||
| 11 | #else | 16 | #else |
| 12 | #include <x86intrin.h> | 17 | #include <x86intrin.h> |
| 13 | #endif | 18 | #endif |
| 14 | 19 | ||
| 20 | #include "common/atomic_ops.h" | ||
| 15 | #include "common/uint128.h" | 21 | #include "common/uint128.h" |
| 16 | #include "common/x64/native_clock.h" | 22 | #include "common/x64/native_clock.h" |
| 17 | 23 | ||
| 24 | namespace { | ||
| 25 | |||
| 26 | [[nodiscard]] u64 GetFixedPoint64Factor(u64 numerator, u64 divisor) { | ||
| 27 | #ifdef __SIZEOF_INT128__ | ||
| 28 | const auto base = static_cast<unsigned __int128>(numerator) << 64ULL; | ||
| 29 | return static_cast<u64>(base / divisor); | ||
| 30 | #elif defined(_M_X64) || defined(_M_ARM64) | ||
| 31 | std::array<u64, 2> r = {0, numerator}; | ||
| 32 | u64 remainder; | ||
| 33 | #if _MSC_VER < 1923 | ||
| 34 | return udiv128(r[1], r[0], divisor, &remainder); | ||
| 35 | #else | ||
| 36 | return _udiv128(r[1], r[0], divisor, &remainder); | ||
| 37 | #endif | ||
| 38 | #else | ||
| 39 | // This one is bit more inaccurate. | ||
| 40 | return MultiplyAndDivide64(std::numeric_limits<u64>::max(), numerator, divisor); | ||
| 41 | #endif | ||
| 42 | } | ||
| 43 | |||
| 44 | [[nodiscard]] u64 MultiplyHigh(u64 a, u64 b) { | ||
| 45 | #ifdef __SIZEOF_INT128__ | ||
| 46 | return (static_cast<unsigned __int128>(a) * static_cast<unsigned __int128>(b)) >> 64; | ||
| 47 | #elif defined(_M_X64) || defined(_M_ARM64) | ||
| 48 | return __umulh(a, b); // MSVC | ||
| 49 | #else | ||
| 50 | // Generic fallback | ||
| 51 | const u64 a_lo = u32(a); | ||
| 52 | const u64 a_hi = a >> 32; | ||
| 53 | const u64 b_lo = u32(b); | ||
| 54 | const u64 b_hi = b >> 32; | ||
| 55 | |||
| 56 | const u64 a_x_b_hi = a_hi * b_hi; | ||
| 57 | const u64 a_x_b_mid = a_hi * b_lo; | ||
| 58 | const u64 b_x_a_mid = b_hi * a_lo; | ||
| 59 | const u64 a_x_b_lo = a_lo * b_lo; | ||
| 60 | |||
| 61 | const u64 carry_bit = (static_cast<u64>(static_cast<u32>(a_x_b_mid)) + | ||
| 62 | static_cast<u64>(static_cast<u32>(b_x_a_mid)) + (a_x_b_lo >> 32)) >> | ||
| 63 | 32; | ||
| 64 | |||
| 65 | const u64 multhi = a_x_b_hi + (a_x_b_mid >> 32) + (b_x_a_mid >> 32) + carry_bit; | ||
| 66 | |||
| 67 | return multhi; | ||
| 68 | #endif | ||
| 69 | } | ||
| 70 | |||
| 71 | } // namespace | ||
| 72 | |||
| 18 | namespace Common { | 73 | namespace Common { |
| 19 | 74 | ||
| 20 | u64 EstimateRDTSCFrequency() { | 75 | u64 EstimateRDTSCFrequency() { |
| @@ -48,54 +103,71 @@ NativeClock::NativeClock(u64 emulated_cpu_frequency_, u64 emulated_clock_frequen | |||
| 48 | : WallClock(emulated_cpu_frequency_, emulated_clock_frequency_, true), rtsc_frequency{ | 103 | : WallClock(emulated_cpu_frequency_, emulated_clock_frequency_, true), rtsc_frequency{ |
| 49 | rtsc_frequency_} { | 104 | rtsc_frequency_} { |
| 50 | _mm_mfence(); | 105 | _mm_mfence(); |
| 51 | last_measure = __rdtsc(); | 106 | time_point.inner.last_measure = __rdtsc(); |
| 52 | accumulated_ticks = 0U; | 107 | time_point.inner.accumulated_ticks = 0U; |
| 108 | ns_rtsc_factor = GetFixedPoint64Factor(1000000000, rtsc_frequency); | ||
| 109 | us_rtsc_factor = GetFixedPoint64Factor(1000000, rtsc_frequency); | ||
| 110 | ms_rtsc_factor = GetFixedPoint64Factor(1000, rtsc_frequency); | ||
| 111 | clock_rtsc_factor = GetFixedPoint64Factor(emulated_clock_frequency, rtsc_frequency); | ||
| 112 | cpu_rtsc_factor = GetFixedPoint64Factor(emulated_cpu_frequency, rtsc_frequency); | ||
| 53 | } | 113 | } |
| 54 | 114 | ||
| 55 | u64 NativeClock::GetRTSC() { | 115 | u64 NativeClock::GetRTSC() { |
| 56 | std::scoped_lock scope{rtsc_serialize}; | 116 | TimePoint new_time_point{}; |
| 57 | _mm_mfence(); | 117 | TimePoint current_time_point{}; |
| 58 | const u64 current_measure = __rdtsc(); | 118 | do { |
| 59 | u64 diff = current_measure - last_measure; | 119 | current_time_point.pack = time_point.pack; |
| 60 | diff = diff & ~static_cast<u64>(static_cast<s64>(diff) >> 63); // max(diff, 0) | 120 | _mm_mfence(); |
| 61 | if (current_measure > last_measure) { | 121 | const u64 current_measure = __rdtsc(); |
| 62 | last_measure = current_measure; | 122 | u64 diff = current_measure - current_time_point.inner.last_measure; |
| 63 | } | 123 | diff = diff & ~static_cast<u64>(static_cast<s64>(diff) >> 63); // max(diff, 0) |
| 64 | accumulated_ticks += diff; | 124 | new_time_point.inner.last_measure = current_measure > current_time_point.inner.last_measure |
| 125 | ? current_measure | ||
| 126 | : current_time_point.inner.last_measure; | ||
| 127 | new_time_point.inner.accumulated_ticks = current_time_point.inner.accumulated_ticks + diff; | ||
| 128 | } while (!Common::AtomicCompareAndSwap(time_point.pack.data(), new_time_point.pack, | ||
| 129 | current_time_point.pack)); | ||
| 65 | /// The clock cannot be more precise than the guest timer, remove the lower bits | 130 | /// The clock cannot be more precise than the guest timer, remove the lower bits |
| 66 | return accumulated_ticks & inaccuracy_mask; | 131 | return new_time_point.inner.accumulated_ticks & inaccuracy_mask; |
| 67 | } | 132 | } |
| 68 | 133 | ||
| 69 | void NativeClock::Pause(bool is_paused) { | 134 | void NativeClock::Pause(bool is_paused) { |
| 70 | if (!is_paused) { | 135 | if (!is_paused) { |
| 71 | _mm_mfence(); | 136 | TimePoint current_time_point{}; |
| 72 | last_measure = __rdtsc(); | 137 | TimePoint new_time_point{}; |
| 138 | do { | ||
| 139 | current_time_point.pack = time_point.pack; | ||
| 140 | new_time_point.pack = current_time_point.pack; | ||
| 141 | _mm_mfence(); | ||
| 142 | new_time_point.inner.last_measure = __rdtsc(); | ||
| 143 | } while (!Common::AtomicCompareAndSwap(time_point.pack.data(), new_time_point.pack, | ||
| 144 | current_time_point.pack)); | ||
| 73 | } | 145 | } |
| 74 | } | 146 | } |
| 75 | 147 | ||
| 76 | std::chrono::nanoseconds NativeClock::GetTimeNS() { | 148 | std::chrono::nanoseconds NativeClock::GetTimeNS() { |
| 77 | const u64 rtsc_value = GetRTSC(); | 149 | const u64 rtsc_value = GetRTSC(); |
| 78 | return std::chrono::nanoseconds{MultiplyAndDivide64(rtsc_value, 1000000000, rtsc_frequency)}; | 150 | return std::chrono::nanoseconds{MultiplyHigh(rtsc_value, ns_rtsc_factor)}; |
| 79 | } | 151 | } |
| 80 | 152 | ||
| 81 | std::chrono::microseconds NativeClock::GetTimeUS() { | 153 | std::chrono::microseconds NativeClock::GetTimeUS() { |
| 82 | const u64 rtsc_value = GetRTSC(); | 154 | const u64 rtsc_value = GetRTSC(); |
| 83 | return std::chrono::microseconds{MultiplyAndDivide64(rtsc_value, 1000000, rtsc_frequency)}; | 155 | return std::chrono::microseconds{MultiplyHigh(rtsc_value, us_rtsc_factor)}; |
| 84 | } | 156 | } |
| 85 | 157 | ||
| 86 | std::chrono::milliseconds NativeClock::GetTimeMS() { | 158 | std::chrono::milliseconds NativeClock::GetTimeMS() { |
| 87 | const u64 rtsc_value = GetRTSC(); | 159 | const u64 rtsc_value = GetRTSC(); |
| 88 | return std::chrono::milliseconds{MultiplyAndDivide64(rtsc_value, 1000, rtsc_frequency)}; | 160 | return std::chrono::milliseconds{MultiplyHigh(rtsc_value, ms_rtsc_factor)}; |
| 89 | } | 161 | } |
| 90 | 162 | ||
| 91 | u64 NativeClock::GetClockCycles() { | 163 | u64 NativeClock::GetClockCycles() { |
| 92 | const u64 rtsc_value = GetRTSC(); | 164 | const u64 rtsc_value = GetRTSC(); |
| 93 | return MultiplyAndDivide64(rtsc_value, emulated_clock_frequency, rtsc_frequency); | 165 | return MultiplyHigh(rtsc_value, clock_rtsc_factor); |
| 94 | } | 166 | } |
| 95 | 167 | ||
| 96 | u64 NativeClock::GetCPUCycles() { | 168 | u64 NativeClock::GetCPUCycles() { |
| 97 | const u64 rtsc_value = GetRTSC(); | 169 | const u64 rtsc_value = GetRTSC(); |
| 98 | return MultiplyAndDivide64(rtsc_value, emulated_cpu_frequency, rtsc_frequency); | 170 | return MultiplyHigh(rtsc_value, cpu_rtsc_factor); |
| 99 | } | 171 | } |
| 100 | 172 | ||
| 101 | } // namespace X64 | 173 | } // namespace X64 |
diff --git a/src/common/x64/native_clock.h b/src/common/x64/native_clock.h index 6d1e32ac8..7cbd400d2 100644 --- a/src/common/x64/native_clock.h +++ b/src/common/x64/native_clock.h | |||
| @@ -6,7 +6,6 @@ | |||
| 6 | 6 | ||
| 7 | #include <optional> | 7 | #include <optional> |
| 8 | 8 | ||
| 9 | #include "common/spin_lock.h" | ||
| 10 | #include "common/wall_clock.h" | 9 | #include "common/wall_clock.h" |
| 11 | 10 | ||
| 12 | namespace Common { | 11 | namespace Common { |
| @@ -32,14 +31,28 @@ public: | |||
| 32 | private: | 31 | private: |
| 33 | u64 GetRTSC(); | 32 | u64 GetRTSC(); |
| 34 | 33 | ||
| 34 | union alignas(16) TimePoint { | ||
| 35 | TimePoint() : pack{} {} | ||
| 36 | u128 pack{}; | ||
| 37 | struct Inner { | ||
| 38 | u64 last_measure{}; | ||
| 39 | u64 accumulated_ticks{}; | ||
| 40 | } inner; | ||
| 41 | }; | ||
| 42 | |||
| 35 | /// value used to reduce the native clocks accuracy as some apss rely on | 43 | /// value used to reduce the native clocks accuracy as some apss rely on |
| 36 | /// undefined behavior where the level of accuracy in the clock shouldn't | 44 | /// undefined behavior where the level of accuracy in the clock shouldn't |
| 37 | /// be higher. | 45 | /// be higher. |
| 38 | static constexpr u64 inaccuracy_mask = ~(UINT64_C(0x400) - 1); | 46 | static constexpr u64 inaccuracy_mask = ~(UINT64_C(0x400) - 1); |
| 39 | 47 | ||
| 40 | SpinLock rtsc_serialize{}; | 48 | TimePoint time_point; |
| 41 | u64 last_measure{}; | 49 | // factors |
| 42 | u64 accumulated_ticks{}; | 50 | u64 clock_rtsc_factor{}; |
| 51 | u64 cpu_rtsc_factor{}; | ||
| 52 | u64 ns_rtsc_factor{}; | ||
| 53 | u64 us_rtsc_factor{}; | ||
| 54 | u64 ms_rtsc_factor{}; | ||
| 55 | |||
| 43 | u64 rtsc_frequency; | 56 | u64 rtsc_frequency; |
| 44 | }; | 57 | }; |
| 45 | } // namespace X64 | 58 | } // namespace X64 |
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 1b8ad476e..99310dc50 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt | |||
| @@ -643,9 +643,7 @@ else() | |||
| 643 | -Werror=conversion | 643 | -Werror=conversion |
| 644 | -Werror=ignored-qualifiers | 644 | -Werror=ignored-qualifiers |
| 645 | -Werror=implicit-fallthrough | 645 | -Werror=implicit-fallthrough |
| 646 | -Werror=reorder | ||
| 647 | -Werror=sign-compare | 646 | -Werror=sign-compare |
| 648 | -Werror=unused-variable | ||
| 649 | 647 | ||
| 650 | $<$<CXX_COMPILER_ID:GNU>:-Werror=unused-but-set-parameter> | 648 | $<$<CXX_COMPILER_ID:GNU>:-Werror=unused-but-set-parameter> |
| 651 | $<$<CXX_COMPILER_ID:GNU>:-Werror=unused-but-set-variable> | 649 | $<$<CXX_COMPILER_ID:GNU>:-Werror=unused-but-set-variable> |
diff --git a/src/core/file_sys/content_archive.cpp b/src/core/file_sys/content_archive.cpp index a6c0337fa..d12218fc2 100644 --- a/src/core/file_sys/content_archive.cpp +++ b/src/core/file_sys/content_archive.cpp | |||
| @@ -43,17 +43,17 @@ static_assert(sizeof(IVFCLevel) == 0x18, "IVFCLevel has incorrect size."); | |||
| 43 | struct IVFCHeader { | 43 | struct IVFCHeader { |
| 44 | u32_le magic; | 44 | u32_le magic; |
| 45 | u32_le magic_number; | 45 | u32_le magic_number; |
| 46 | INSERT_UNION_PADDING_BYTES(8); | 46 | INSERT_PADDING_BYTES_NOINIT(8); |
| 47 | std::array<IVFCLevel, 6> levels; | 47 | std::array<IVFCLevel, 6> levels; |
| 48 | INSERT_UNION_PADDING_BYTES(64); | 48 | INSERT_PADDING_BYTES_NOINIT(64); |
| 49 | }; | 49 | }; |
| 50 | static_assert(sizeof(IVFCHeader) == 0xE0, "IVFCHeader has incorrect size."); | 50 | static_assert(sizeof(IVFCHeader) == 0xE0, "IVFCHeader has incorrect size."); |
| 51 | 51 | ||
| 52 | struct NCASectionHeaderBlock { | 52 | struct NCASectionHeaderBlock { |
| 53 | INSERT_UNION_PADDING_BYTES(3); | 53 | INSERT_PADDING_BYTES_NOINIT(3); |
| 54 | NCASectionFilesystemType filesystem_type; | 54 | NCASectionFilesystemType filesystem_type; |
| 55 | NCASectionCryptoType crypto_type; | 55 | NCASectionCryptoType crypto_type; |
| 56 | INSERT_UNION_PADDING_BYTES(3); | 56 | INSERT_PADDING_BYTES_NOINIT(3); |
| 57 | }; | 57 | }; |
| 58 | static_assert(sizeof(NCASectionHeaderBlock) == 0x8, "NCASectionHeaderBlock has incorrect size."); | 58 | static_assert(sizeof(NCASectionHeaderBlock) == 0x8, "NCASectionHeaderBlock has incorrect size."); |
| 59 | 59 | ||
| @@ -61,7 +61,7 @@ struct NCASectionRaw { | |||
| 61 | NCASectionHeaderBlock header; | 61 | NCASectionHeaderBlock header; |
| 62 | std::array<u8, 0x138> block_data; | 62 | std::array<u8, 0x138> block_data; |
| 63 | std::array<u8, 0x8> section_ctr; | 63 | std::array<u8, 0x8> section_ctr; |
| 64 | INSERT_UNION_PADDING_BYTES(0xB8); | 64 | INSERT_PADDING_BYTES_NOINIT(0xB8); |
| 65 | }; | 65 | }; |
| 66 | static_assert(sizeof(NCASectionRaw) == 0x200, "NCASectionRaw has incorrect size."); | 66 | static_assert(sizeof(NCASectionRaw) == 0x200, "NCASectionRaw has incorrect size."); |
| 67 | 67 | ||
| @@ -69,19 +69,19 @@ struct PFS0Superblock { | |||
| 69 | NCASectionHeaderBlock header_block; | 69 | NCASectionHeaderBlock header_block; |
| 70 | std::array<u8, 0x20> hash; | 70 | std::array<u8, 0x20> hash; |
| 71 | u32_le size; | 71 | u32_le size; |
| 72 | INSERT_UNION_PADDING_BYTES(4); | 72 | INSERT_PADDING_BYTES_NOINIT(4); |
| 73 | u64_le hash_table_offset; | 73 | u64_le hash_table_offset; |
| 74 | u64_le hash_table_size; | 74 | u64_le hash_table_size; |
| 75 | u64_le pfs0_header_offset; | 75 | u64_le pfs0_header_offset; |
| 76 | u64_le pfs0_size; | 76 | u64_le pfs0_size; |
| 77 | INSERT_UNION_PADDING_BYTES(0x1B0); | 77 | INSERT_PADDING_BYTES_NOINIT(0x1B0); |
| 78 | }; | 78 | }; |
| 79 | static_assert(sizeof(PFS0Superblock) == 0x200, "PFS0Superblock has incorrect size."); | 79 | static_assert(sizeof(PFS0Superblock) == 0x200, "PFS0Superblock has incorrect size."); |
| 80 | 80 | ||
| 81 | struct RomFSSuperblock { | 81 | struct RomFSSuperblock { |
| 82 | NCASectionHeaderBlock header_block; | 82 | NCASectionHeaderBlock header_block; |
| 83 | IVFCHeader ivfc; | 83 | IVFCHeader ivfc; |
| 84 | INSERT_UNION_PADDING_BYTES(0x118); | 84 | INSERT_PADDING_BYTES_NOINIT(0x118); |
| 85 | }; | 85 | }; |
| 86 | static_assert(sizeof(RomFSSuperblock) == 0x200, "RomFSSuperblock has incorrect size."); | 86 | static_assert(sizeof(RomFSSuperblock) == 0x200, "RomFSSuperblock has incorrect size."); |
| 87 | 87 | ||
| @@ -89,19 +89,19 @@ struct BKTRHeader { | |||
| 89 | u64_le offset; | 89 | u64_le offset; |
| 90 | u64_le size; | 90 | u64_le size; |
| 91 | u32_le magic; | 91 | u32_le magic; |
| 92 | INSERT_UNION_PADDING_BYTES(0x4); | 92 | INSERT_PADDING_BYTES_NOINIT(0x4); |
| 93 | u32_le number_entries; | 93 | u32_le number_entries; |
| 94 | INSERT_UNION_PADDING_BYTES(0x4); | 94 | INSERT_PADDING_BYTES_NOINIT(0x4); |
| 95 | }; | 95 | }; |
| 96 | static_assert(sizeof(BKTRHeader) == 0x20, "BKTRHeader has incorrect size."); | 96 | static_assert(sizeof(BKTRHeader) == 0x20, "BKTRHeader has incorrect size."); |
| 97 | 97 | ||
| 98 | struct BKTRSuperblock { | 98 | struct BKTRSuperblock { |
| 99 | NCASectionHeaderBlock header_block; | 99 | NCASectionHeaderBlock header_block; |
| 100 | IVFCHeader ivfc; | 100 | IVFCHeader ivfc; |
| 101 | INSERT_UNION_PADDING_BYTES(0x18); | 101 | INSERT_PADDING_BYTES_NOINIT(0x18); |
| 102 | BKTRHeader relocation; | 102 | BKTRHeader relocation; |
| 103 | BKTRHeader subsection; | 103 | BKTRHeader subsection; |
| 104 | INSERT_UNION_PADDING_BYTES(0xC0); | 104 | INSERT_PADDING_BYTES_NOINIT(0xC0); |
| 105 | }; | 105 | }; |
| 106 | static_assert(sizeof(BKTRSuperblock) == 0x200, "BKTRSuperblock has incorrect size."); | 106 | static_assert(sizeof(BKTRSuperblock) == 0x200, "BKTRSuperblock has incorrect size."); |
| 107 | 107 | ||
diff --git a/src/core/frontend/input_interpreter.cpp b/src/core/frontend/input_interpreter.cpp index 66ae506cd..ec5fe660e 100644 --- a/src/core/frontend/input_interpreter.cpp +++ b/src/core/frontend/input_interpreter.cpp | |||
| @@ -25,6 +25,10 @@ void InputInterpreter::PollInput() { | |||
| 25 | button_states[current_index] = button_state; | 25 | button_states[current_index] = button_state; |
| 26 | } | 26 | } |
| 27 | 27 | ||
| 28 | bool InputInterpreter::IsButtonPressed(HIDButton button) const { | ||
| 29 | return (button_states[current_index] & (1U << static_cast<u8>(button))) != 0; | ||
| 30 | } | ||
| 31 | |||
| 28 | bool InputInterpreter::IsButtonPressedOnce(HIDButton button) const { | 32 | bool InputInterpreter::IsButtonPressedOnce(HIDButton button) const { |
| 29 | const bool current_press = | 33 | const bool current_press = |
| 30 | (button_states[current_index] & (1U << static_cast<u8>(button))) != 0; | 34 | (button_states[current_index] & (1U << static_cast<u8>(button))) != 0; |
diff --git a/src/core/frontend/input_interpreter.h b/src/core/frontend/input_interpreter.h index fea9aebe6..36a92a6b6 100644 --- a/src/core/frontend/input_interpreter.h +++ b/src/core/frontend/input_interpreter.h | |||
| @@ -67,6 +67,27 @@ public: | |||
| 67 | void PollInput(); | 67 | void PollInput(); |
| 68 | 68 | ||
| 69 | /** | 69 | /** |
| 70 | * Checks whether the button is pressed. | ||
| 71 | * | ||
| 72 | * @param button The button to check. | ||
| 73 | * | ||
| 74 | * @returns True when the button is pressed. | ||
| 75 | */ | ||
| 76 | [[nodiscard]] bool IsButtonPressed(HIDButton button) const; | ||
| 77 | |||
| 78 | /** | ||
| 79 | * Checks whether any of the buttons in the parameter list is pressed. | ||
| 80 | * | ||
| 81 | * @tparam HIDButton The buttons to check. | ||
| 82 | * | ||
| 83 | * @returns True when at least one of the buttons is pressed. | ||
| 84 | */ | ||
| 85 | template <HIDButton... T> | ||
| 86 | [[nodiscard]] bool IsAnyButtonPressed() { | ||
| 87 | return (IsButtonPressed(T) || ...); | ||
| 88 | } | ||
| 89 | |||
| 90 | /** | ||
| 70 | * The specified button is considered to be pressed once | 91 | * The specified button is considered to be pressed once |
| 71 | * if it is currently pressed and not pressed previously. | 92 | * if it is currently pressed and not pressed previously. |
| 72 | * | 93 | * |
diff --git a/src/core/hle/ipc.h b/src/core/hle/ipc.h index 7ce313190..79bcf5762 100644 --- a/src/core/hle/ipc.h +++ b/src/core/hle/ipc.h | |||
| @@ -160,7 +160,7 @@ struct DomainMessageHeader { | |||
| 160 | // Used when responding to an IPC request, Server -> Client. | 160 | // Used when responding to an IPC request, Server -> Client. |
| 161 | struct { | 161 | struct { |
| 162 | u32_le num_objects; | 162 | u32_le num_objects; |
| 163 | INSERT_UNION_PADDING_WORDS(3); | 163 | INSERT_PADDING_WORDS_NOINIT(3); |
| 164 | }; | 164 | }; |
| 165 | 165 | ||
| 166 | // Used when performing an IPC request, Client -> Server. | 166 | // Used when performing an IPC request, Client -> Server. |
| @@ -171,7 +171,7 @@ struct DomainMessageHeader { | |||
| 171 | BitField<16, 16, u32> size; | 171 | BitField<16, 16, u32> size; |
| 172 | }; | 172 | }; |
| 173 | u32_le object_id; | 173 | u32_le object_id; |
| 174 | INSERT_UNION_PADDING_WORDS(2); | 174 | INSERT_PADDING_WORDS_NOINIT(2); |
| 175 | }; | 175 | }; |
| 176 | 176 | ||
| 177 | std::array<u32, 4> raw{}; | 177 | std::array<u32, 4> raw{}; |
diff --git a/src/core/hle/kernel/k_priority_queue.h b/src/core/hle/kernel/k_priority_queue.h index 99fb8fe93..0dc929040 100644 --- a/src/core/hle/kernel/k_priority_queue.h +++ b/src/core/hle/kernel/k_priority_queue.h | |||
| @@ -8,11 +8,11 @@ | |||
| 8 | #pragma once | 8 | #pragma once |
| 9 | 9 | ||
| 10 | #include <array> | 10 | #include <array> |
| 11 | #include <bit> | ||
| 11 | #include <concepts> | 12 | #include <concepts> |
| 12 | 13 | ||
| 13 | #include "common/assert.h" | 14 | #include "common/assert.h" |
| 14 | #include "common/bit_set.h" | 15 | #include "common/bit_set.h" |
| 15 | #include "common/bit_util.h" | ||
| 16 | #include "common/common_types.h" | 16 | #include "common/common_types.h" |
| 17 | #include "common/concepts.h" | 17 | #include "common/concepts.h" |
| 18 | 18 | ||
| @@ -268,7 +268,7 @@ private: | |||
| 268 | } | 268 | } |
| 269 | 269 | ||
| 270 | constexpr s32 GetNextCore(u64& affinity) { | 270 | constexpr s32 GetNextCore(u64& affinity) { |
| 271 | const s32 core = Common::CountTrailingZeroes64(affinity); | 271 | const s32 core = std::countr_zero(affinity); |
| 272 | ClearAffinityBit(affinity, core); | 272 | ClearAffinityBit(affinity, core); |
| 273 | return core; | 273 | return core; |
| 274 | } | 274 | } |
diff --git a/src/core/hle/kernel/k_scheduler.cpp b/src/core/hle/kernel/k_scheduler.cpp index 42f0ea483..12b5619fb 100644 --- a/src/core/hle/kernel/k_scheduler.cpp +++ b/src/core/hle/kernel/k_scheduler.cpp | |||
| @@ -5,6 +5,8 @@ | |||
| 5 | // This file references various implementation details from Atmosphere, an open-source firmware for | 5 | // This file references various implementation details from Atmosphere, an open-source firmware for |
| 6 | // the Nintendo Switch. Copyright 2018-2020 Atmosphere-NX. | 6 | // the Nintendo Switch. Copyright 2018-2020 Atmosphere-NX. |
| 7 | 7 | ||
| 8 | #include <bit> | ||
| 9 | |||
| 8 | #include "common/assert.h" | 10 | #include "common/assert.h" |
| 9 | #include "common/bit_util.h" | 11 | #include "common/bit_util.h" |
| 10 | #include "common/fiber.h" | 12 | #include "common/fiber.h" |
| @@ -31,12 +33,12 @@ static void IncrementScheduledCount(Kernel::Thread* thread) { | |||
| 31 | 33 | ||
| 32 | void KScheduler::RescheduleCores(KernelCore& kernel, u64 cores_pending_reschedule, | 34 | void KScheduler::RescheduleCores(KernelCore& kernel, u64 cores_pending_reschedule, |
| 33 | Core::EmuThreadHandle global_thread) { | 35 | Core::EmuThreadHandle global_thread) { |
| 34 | u32 current_core = global_thread.host_handle; | 36 | const u32 current_core = global_thread.host_handle; |
| 35 | bool must_context_switch = global_thread.guest_handle != InvalidHandle && | 37 | bool must_context_switch = global_thread.guest_handle != InvalidHandle && |
| 36 | (current_core < Core::Hardware::NUM_CPU_CORES); | 38 | (current_core < Core::Hardware::NUM_CPU_CORES); |
| 37 | 39 | ||
| 38 | while (cores_pending_reschedule != 0) { | 40 | while (cores_pending_reschedule != 0) { |
| 39 | u32 core = Common::CountTrailingZeroes64(cores_pending_reschedule); | 41 | const auto core = static_cast<u32>(std::countr_zero(cores_pending_reschedule)); |
| 40 | ASSERT(core < Core::Hardware::NUM_CPU_CORES); | 42 | ASSERT(core < Core::Hardware::NUM_CPU_CORES); |
| 41 | if (!must_context_switch || core != current_core) { | 43 | if (!must_context_switch || core != current_core) { |
| 42 | auto& phys_core = kernel.PhysicalCore(core); | 44 | auto& phys_core = kernel.PhysicalCore(core); |
| @@ -109,7 +111,7 @@ u64 KScheduler::UpdateHighestPriorityThreadsImpl(KernelCore& kernel) { | |||
| 109 | 111 | ||
| 110 | // Idle cores are bad. We're going to try to migrate threads to each idle core in turn. | 112 | // Idle cores are bad. We're going to try to migrate threads to each idle core in turn. |
| 111 | while (idle_cores != 0) { | 113 | while (idle_cores != 0) { |
| 112 | u32 core_id = Common::CountTrailingZeroes64(idle_cores); | 114 | const auto core_id = static_cast<u32>(std::countr_zero(idle_cores)); |
| 113 | if (Thread* suggested = priority_queue.GetSuggestedFront(core_id); suggested != nullptr) { | 115 | if (Thread* suggested = priority_queue.GetSuggestedFront(core_id); suggested != nullptr) { |
| 114 | s32 migration_candidates[Core::Hardware::NUM_CPU_CORES]; | 116 | s32 migration_candidates[Core::Hardware::NUM_CPU_CORES]; |
| 115 | size_t num_candidates = 0; | 117 | size_t num_candidates = 0; |
diff --git a/src/core/hle/kernel/memory/page_heap.h b/src/core/hle/kernel/memory/page_heap.h index 22b0de860..131093284 100644 --- a/src/core/hle/kernel/memory/page_heap.h +++ b/src/core/hle/kernel/memory/page_heap.h | |||
| @@ -8,11 +8,11 @@ | |||
| 8 | #pragma once | 8 | #pragma once |
| 9 | 9 | ||
| 10 | #include <array> | 10 | #include <array> |
| 11 | #include <bit> | ||
| 11 | #include <vector> | 12 | #include <vector> |
| 12 | 13 | ||
| 13 | #include "common/alignment.h" | 14 | #include "common/alignment.h" |
| 14 | #include "common/assert.h" | 15 | #include "common/assert.h" |
| 15 | #include "common/bit_util.h" | ||
| 16 | #include "common/common_funcs.h" | 16 | #include "common/common_funcs.h" |
| 17 | #include "common/common_types.h" | 17 | #include "common/common_types.h" |
| 18 | #include "core/hle/kernel/memory/memory_types.h" | 18 | #include "core/hle/kernel/memory/memory_types.h" |
| @@ -105,7 +105,7 @@ private: | |||
| 105 | ASSERT(depth == 0); | 105 | ASSERT(depth == 0); |
| 106 | return -1; | 106 | return -1; |
| 107 | } | 107 | } |
| 108 | offset = offset * 64 + Common::CountTrailingZeroes64(v); | 108 | offset = offset * 64 + static_cast<u32>(std::countr_zero(v)); |
| 109 | ++depth; | 109 | ++depth; |
| 110 | } while (depth < static_cast<s32>(used_depths)); | 110 | } while (depth < static_cast<s32>(used_depths)); |
| 111 | 111 | ||
diff --git a/src/core/hle/kernel/process_capability.cpp b/src/core/hle/kernel/process_capability.cpp index 0f128c586..0566311b6 100644 --- a/src/core/hle/kernel/process_capability.cpp +++ b/src/core/hle/kernel/process_capability.cpp | |||
| @@ -2,6 +2,8 @@ | |||
| 2 | // Licensed under GPLv2 or any later version | 2 | // Licensed under GPLv2 or any later version |
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include <bit> | ||
| 6 | |||
| 5 | #include "common/bit_util.h" | 7 | #include "common/bit_util.h" |
| 6 | #include "common/logging/log.h" | 8 | #include "common/logging/log.h" |
| 7 | #include "core/hle/kernel/errors.h" | 9 | #include "core/hle/kernel/errors.h" |
| @@ -60,7 +62,7 @@ constexpr CapabilityType GetCapabilityType(u32 value) { | |||
| 60 | 62 | ||
| 61 | u32 GetFlagBitOffset(CapabilityType type) { | 63 | u32 GetFlagBitOffset(CapabilityType type) { |
| 62 | const auto value = static_cast<u32>(type); | 64 | const auto value = static_cast<u32>(type); |
| 63 | return static_cast<u32>(Common::BitSize<u32>() - Common::CountLeadingZeroes32(value)); | 65 | return static_cast<u32>(Common::BitSize<u32>() - static_cast<u32>(std::countl_zero(value))); |
| 64 | } | 66 | } |
| 65 | 67 | ||
| 66 | } // Anonymous namespace | 68 | } // Anonymous namespace |
diff --git a/src/core/hle/service/am/applets/error.cpp b/src/core/hle/service/am/applets/error.cpp index d85505082..0c8b632e8 100644 --- a/src/core/hle/service/am/applets/error.cpp +++ b/src/core/hle/service/am/applets/error.cpp | |||
| @@ -20,9 +20,9 @@ namespace Service::AM::Applets { | |||
| 20 | struct ShowError { | 20 | struct ShowError { |
| 21 | u8 mode; | 21 | u8 mode; |
| 22 | bool jump; | 22 | bool jump; |
| 23 | INSERT_UNION_PADDING_BYTES(4); | 23 | INSERT_PADDING_BYTES_NOINIT(4); |
| 24 | bool use_64bit_error_code; | 24 | bool use_64bit_error_code; |
| 25 | INSERT_UNION_PADDING_BYTES(1); | 25 | INSERT_PADDING_BYTES_NOINIT(1); |
| 26 | u64 error_code_64; | 26 | u64 error_code_64; |
| 27 | u32 error_code_32; | 27 | u32 error_code_32; |
| 28 | }; | 28 | }; |
| @@ -32,7 +32,7 @@ static_assert(sizeof(ShowError) == 0x14, "ShowError has incorrect size."); | |||
| 32 | struct ShowErrorRecord { | 32 | struct ShowErrorRecord { |
| 33 | u8 mode; | 33 | u8 mode; |
| 34 | bool jump; | 34 | bool jump; |
| 35 | INSERT_UNION_PADDING_BYTES(6); | 35 | INSERT_PADDING_BYTES_NOINIT(6); |
| 36 | u64 error_code_64; | 36 | u64 error_code_64; |
| 37 | u64 posix_time; | 37 | u64 posix_time; |
| 38 | }; | 38 | }; |
| @@ -41,7 +41,7 @@ static_assert(sizeof(ShowErrorRecord) == 0x18, "ShowErrorRecord has incorrect si | |||
| 41 | struct SystemErrorArg { | 41 | struct SystemErrorArg { |
| 42 | u8 mode; | 42 | u8 mode; |
| 43 | bool jump; | 43 | bool jump; |
| 44 | INSERT_UNION_PADDING_BYTES(6); | 44 | INSERT_PADDING_BYTES_NOINIT(6); |
| 45 | u64 error_code_64; | 45 | u64 error_code_64; |
| 46 | std::array<char, 8> language_code; | 46 | std::array<char, 8> language_code; |
| 47 | std::array<char, 0x800> main_text; | 47 | std::array<char, 0x800> main_text; |
| @@ -52,7 +52,7 @@ static_assert(sizeof(SystemErrorArg) == 0x1018, "SystemErrorArg has incorrect si | |||
| 52 | struct ApplicationErrorArg { | 52 | struct ApplicationErrorArg { |
| 53 | u8 mode; | 53 | u8 mode; |
| 54 | bool jump; | 54 | bool jump; |
| 55 | INSERT_UNION_PADDING_BYTES(6); | 55 | INSERT_PADDING_BYTES_NOINIT(6); |
| 56 | u32 error_code; | 56 | u32 error_code; |
| 57 | std::array<char, 8> language_code; | 57 | std::array<char, 8> language_code; |
| 58 | std::array<char, 0x800> main_text; | 58 | std::array<char, 0x800> main_text; |
diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt index 5b637f3c5..6a5c18945 100644 --- a/src/tests/CMakeLists.txt +++ b/src/tests/CMakeLists.txt | |||
| @@ -1,6 +1,5 @@ | |||
| 1 | add_executable(tests | 1 | add_executable(tests |
| 2 | common/bit_field.cpp | 2 | common/bit_field.cpp |
| 3 | common/bit_utils.cpp | ||
| 4 | common/fibers.cpp | 3 | common/fibers.cpp |
| 5 | common/param_package.cpp | 4 | common/param_package.cpp |
| 6 | common/ring_buffer.cpp | 5 | common/ring_buffer.cpp |
diff --git a/src/tests/common/bit_utils.cpp b/src/tests/common/bit_utils.cpp deleted file mode 100644 index 479b5995a..000000000 --- a/src/tests/common/bit_utils.cpp +++ /dev/null | |||
| @@ -1,23 +0,0 @@ | |||
| 1 | // Copyright 2017 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <catch2/catch.hpp> | ||
| 6 | #include <math.h> | ||
| 7 | #include "common/bit_util.h" | ||
| 8 | |||
| 9 | namespace Common { | ||
| 10 | |||
| 11 | TEST_CASE("BitUtils::CountTrailingZeroes", "[common]") { | ||
| 12 | REQUIRE(Common::CountTrailingZeroes32(0) == 32); | ||
| 13 | REQUIRE(Common::CountTrailingZeroes64(0) == 64); | ||
| 14 | REQUIRE(Common::CountTrailingZeroes32(9) == 0); | ||
| 15 | REQUIRE(Common::CountTrailingZeroes32(8) == 3); | ||
| 16 | REQUIRE(Common::CountTrailingZeroes32(0x801000) == 12); | ||
| 17 | REQUIRE(Common::CountTrailingZeroes64(9) == 0); | ||
| 18 | REQUIRE(Common::CountTrailingZeroes64(8) == 3); | ||
| 19 | REQUIRE(Common::CountTrailingZeroes64(0x801000) == 12); | ||
| 20 | REQUIRE(Common::CountTrailingZeroes64(0x801000000000UL) == 36); | ||
| 21 | } | ||
| 22 | |||
| 23 | } // namespace Common | ||
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt index c3d0f4c31..e01ea55ab 100644 --- a/src/video_core/CMakeLists.txt +++ b/src/video_core/CMakeLists.txt | |||
| @@ -136,8 +136,6 @@ add_library(video_core STATIC | |||
| 136 | renderer_vulkan/vk_graphics_pipeline.h | 136 | renderer_vulkan/vk_graphics_pipeline.h |
| 137 | renderer_vulkan/vk_master_semaphore.cpp | 137 | renderer_vulkan/vk_master_semaphore.cpp |
| 138 | renderer_vulkan/vk_master_semaphore.h | 138 | renderer_vulkan/vk_master_semaphore.h |
| 139 | renderer_vulkan/vk_memory_manager.cpp | ||
| 140 | renderer_vulkan/vk_memory_manager.h | ||
| 141 | renderer_vulkan/vk_pipeline_cache.cpp | 139 | renderer_vulkan/vk_pipeline_cache.cpp |
| 142 | renderer_vulkan/vk_pipeline_cache.h | 140 | renderer_vulkan/vk_pipeline_cache.h |
| 143 | renderer_vulkan/vk_query_cache.cpp | 141 | renderer_vulkan/vk_query_cache.cpp |
| @@ -260,6 +258,8 @@ add_library(video_core STATIC | |||
| 260 | vulkan_common/vulkan_instance.h | 258 | vulkan_common/vulkan_instance.h |
| 261 | vulkan_common/vulkan_library.cpp | 259 | vulkan_common/vulkan_library.cpp |
| 262 | vulkan_common/vulkan_library.h | 260 | vulkan_common/vulkan_library.h |
| 261 | vulkan_common/vulkan_memory_allocator.cpp | ||
| 262 | vulkan_common/vulkan_memory_allocator.h | ||
| 263 | vulkan_common/vulkan_surface.cpp | 263 | vulkan_common/vulkan_surface.cpp |
| 264 | vulkan_common/vulkan_surface.h | 264 | vulkan_common/vulkan_surface.h |
| 265 | vulkan_common/vulkan_wrapper.cpp | 265 | vulkan_common/vulkan_wrapper.cpp |
| @@ -313,9 +313,7 @@ else() | |||
| 313 | -Werror=pessimizing-move | 313 | -Werror=pessimizing-move |
| 314 | -Werror=redundant-move | 314 | -Werror=redundant-move |
| 315 | -Werror=shadow | 315 | -Werror=shadow |
| 316 | -Werror=switch | ||
| 317 | -Werror=type-limits | 316 | -Werror=type-limits |
| 318 | -Werror=unused-variable | ||
| 319 | 317 | ||
| 320 | $<$<CXX_COMPILER_ID:GNU>:-Werror=class-memaccess> | 318 | $<$<CXX_COMPILER_ID:GNU>:-Werror=class-memaccess> |
| 321 | $<$<CXX_COMPILER_ID:GNU>:-Werror=unused-but-set-parameter> | 319 | $<$<CXX_COMPILER_ID:GNU>:-Werror=unused-but-set-parameter> |
diff --git a/src/video_core/cdma_pusher.cpp b/src/video_core/cdma_pusher.cpp index 94679d5d1..33b3c060b 100644 --- a/src/video_core/cdma_pusher.cpp +++ b/src/video_core/cdma_pusher.cpp | |||
| @@ -18,10 +18,10 @@ | |||
| 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
| 19 | // | 19 | // |
| 20 | 20 | ||
| 21 | #include <bit> | ||
| 21 | #include "command_classes/host1x.h" | 22 | #include "command_classes/host1x.h" |
| 22 | #include "command_classes/nvdec.h" | 23 | #include "command_classes/nvdec.h" |
| 23 | #include "command_classes/vic.h" | 24 | #include "command_classes/vic.h" |
| 24 | #include "common/bit_util.h" | ||
| 25 | #include "video_core/cdma_pusher.h" | 25 | #include "video_core/cdma_pusher.h" |
| 26 | #include "video_core/command_classes/nvdec_common.h" | 26 | #include "video_core/command_classes/nvdec_common.h" |
| 27 | #include "video_core/engines/maxwell_3d.h" | 27 | #include "video_core/engines/maxwell_3d.h" |
| @@ -56,7 +56,7 @@ void CDmaPusher::Step() { | |||
| 56 | 56 | ||
| 57 | for (const u32 value : values) { | 57 | for (const u32 value : values) { |
| 58 | if (mask != 0) { | 58 | if (mask != 0) { |
| 59 | const u32 lbs = Common::CountTrailingZeroes32(mask); | 59 | const auto lbs = static_cast<u32>(std::countr_zero(mask)); |
| 60 | mask &= ~(1U << lbs); | 60 | mask &= ~(1U << lbs); |
| 61 | ExecuteCommand(static_cast<u32>(offset + lbs), value); | 61 | ExecuteCommand(static_cast<u32>(offset + lbs), value); |
| 62 | continue; | 62 | continue; |
diff --git a/src/video_core/cdma_pusher.h b/src/video_core/cdma_pusher.h index 8ca70b6dd..e5f212c1a 100644 --- a/src/video_core/cdma_pusher.h +++ b/src/video_core/cdma_pusher.h | |||
| @@ -126,7 +126,7 @@ private: | |||
| 126 | 126 | ||
| 127 | s32 count{}; | 127 | s32 count{}; |
| 128 | s32 offset{}; | 128 | s32 offset{}; |
| 129 | s32 mask{}; | 129 | u32 mask{}; |
| 130 | bool incrementing{}; | 130 | bool incrementing{}; |
| 131 | 131 | ||
| 132 | // Queue of command lists to be processed | 132 | // Queue of command lists to be processed |
diff --git a/src/video_core/command_classes/codecs/h264.cpp b/src/video_core/command_classes/codecs/h264.cpp index 65bbeac78..fea6aed98 100644 --- a/src/video_core/command_classes/codecs/h264.cpp +++ b/src/video_core/command_classes/codecs/h264.cpp | |||
| @@ -19,7 +19,7 @@ | |||
| 19 | // | 19 | // |
| 20 | 20 | ||
| 21 | #include <array> | 21 | #include <array> |
| 22 | #include "common/bit_util.h" | 22 | #include <bit> |
| 23 | #include "video_core/command_classes/codecs/h264.h" | 23 | #include "video_core/command_classes/codecs/h264.h" |
| 24 | #include "video_core/gpu.h" | 24 | #include "video_core/gpu.h" |
| 25 | #include "video_core/memory_manager.h" | 25 | #include "video_core/memory_manager.h" |
| @@ -266,7 +266,7 @@ void H264BitWriter::WriteExpGolombCodedInt(s32 value) { | |||
| 266 | } | 266 | } |
| 267 | 267 | ||
| 268 | void H264BitWriter::WriteExpGolombCodedUInt(u32 value) { | 268 | void H264BitWriter::WriteExpGolombCodedUInt(u32 value) { |
| 269 | const s32 size = 32 - Common::CountLeadingZeroes32(static_cast<s32>(value + 1)); | 269 | const s32 size = 32 - std::countl_zero(value + 1); |
| 270 | WriteBits(1, size); | 270 | WriteBits(1, size); |
| 271 | 271 | ||
| 272 | value -= (1U << (size - 1)) - 1; | 272 | value -= (1U << (size - 1)) - 1; |
diff --git a/src/video_core/engines/fermi_2d.h b/src/video_core/engines/fermi_2d.h index 81522988e..0de3280a2 100644 --- a/src/video_core/engines/fermi_2d.h +++ b/src/video_core/engines/fermi_2d.h | |||
| @@ -171,30 +171,30 @@ public: | |||
| 171 | static constexpr std::size_t NUM_REGS = 0x258; | 171 | static constexpr std::size_t NUM_REGS = 0x258; |
| 172 | struct { | 172 | struct { |
| 173 | u32 object; | 173 | u32 object; |
| 174 | INSERT_UNION_PADDING_WORDS(0x3F); | 174 | INSERT_PADDING_WORDS_NOINIT(0x3F); |
| 175 | u32 no_operation; | 175 | u32 no_operation; |
| 176 | NotifyType notify; | 176 | NotifyType notify; |
| 177 | INSERT_UNION_PADDING_WORDS(0x2); | 177 | INSERT_PADDING_WORDS_NOINIT(0x2); |
| 178 | u32 wait_for_idle; | 178 | u32 wait_for_idle; |
| 179 | INSERT_UNION_PADDING_WORDS(0xB); | 179 | INSERT_PADDING_WORDS_NOINIT(0xB); |
| 180 | u32 pm_trigger; | 180 | u32 pm_trigger; |
| 181 | INSERT_UNION_PADDING_WORDS(0xF); | 181 | INSERT_PADDING_WORDS_NOINIT(0xF); |
| 182 | u32 context_dma_notify; | 182 | u32 context_dma_notify; |
| 183 | u32 dst_context_dma; | 183 | u32 dst_context_dma; |
| 184 | u32 src_context_dma; | 184 | u32 src_context_dma; |
| 185 | u32 semaphore_context_dma; | 185 | u32 semaphore_context_dma; |
| 186 | INSERT_UNION_PADDING_WORDS(0x1C); | 186 | INSERT_PADDING_WORDS_NOINIT(0x1C); |
| 187 | Surface dst; | 187 | Surface dst; |
| 188 | CpuIndexWrap pixels_from_cpu_index_wrap; | 188 | CpuIndexWrap pixels_from_cpu_index_wrap; |
| 189 | u32 kind2d_check_enable; | 189 | u32 kind2d_check_enable; |
| 190 | Surface src; | 190 | Surface src; |
| 191 | SectorPromotion pixels_from_memory_sector_promotion; | 191 | SectorPromotion pixels_from_memory_sector_promotion; |
| 192 | INSERT_UNION_PADDING_WORDS(0x1); | 192 | INSERT_PADDING_WORDS_NOINIT(0x1); |
| 193 | NumTpcs num_tpcs; | 193 | NumTpcs num_tpcs; |
| 194 | u32 render_enable_addr_upper; | 194 | u32 render_enable_addr_upper; |
| 195 | u32 render_enable_addr_lower; | 195 | u32 render_enable_addr_lower; |
| 196 | RenderEnableMode render_enable_mode; | 196 | RenderEnableMode render_enable_mode; |
| 197 | INSERT_UNION_PADDING_WORDS(0x4); | 197 | INSERT_PADDING_WORDS_NOINIT(0x4); |
| 198 | u32 clip_x0; | 198 | u32 clip_x0; |
| 199 | u32 clip_y0; | 199 | u32 clip_y0; |
| 200 | u32 clip_width; | 200 | u32 clip_width; |
| @@ -212,7 +212,7 @@ public: | |||
| 212 | BitField<8, 6, u32> y; | 212 | BitField<8, 6, u32> y; |
| 213 | } pattern_offset; | 213 | } pattern_offset; |
| 214 | BitField<0, 2, PatternSelect> pattern_select; | 214 | BitField<0, 2, PatternSelect> pattern_select; |
| 215 | INSERT_UNION_PADDING_WORDS(0xC); | 215 | INSERT_PADDING_WORDS_NOINIT(0xC); |
| 216 | struct { | 216 | struct { |
| 217 | BitField<0, 3, MonochromePatternColorFormat> color_format; | 217 | BitField<0, 3, MonochromePatternColorFormat> color_format; |
| 218 | BitField<0, 1, MonochromePatternFormat> format; | 218 | BitField<0, 1, MonochromePatternFormat> format; |
| @@ -227,15 +227,15 @@ public: | |||
| 227 | std::array<u32, 0x20> X1R5G5B5; | 227 | std::array<u32, 0x20> X1R5G5B5; |
| 228 | std::array<u32, 0x10> Y8; | 228 | std::array<u32, 0x10> Y8; |
| 229 | } color_pattern; | 229 | } color_pattern; |
| 230 | INSERT_UNION_PADDING_WORDS(0x10); | 230 | INSERT_PADDING_WORDS_NOINIT(0x10); |
| 231 | struct { | 231 | struct { |
| 232 | u32 prim_mode; | 232 | u32 prim_mode; |
| 233 | u32 prim_color_format; | 233 | u32 prim_color_format; |
| 234 | u32 prim_color; | 234 | u32 prim_color; |
| 235 | u32 line_tie_break_bits; | 235 | u32 line_tie_break_bits; |
| 236 | INSERT_UNION_PADDING_WORDS(0x14); | 236 | INSERT_PADDING_WORDS_NOINIT(0x14); |
| 237 | u32 prim_point_xy; | 237 | u32 prim_point_xy; |
| 238 | INSERT_UNION_PADDING_WORDS(0x7); | 238 | INSERT_PADDING_WORDS_NOINIT(0x7); |
| 239 | std::array<Point, 0x40> prim_point; | 239 | std::array<Point, 0x40> prim_point; |
| 240 | } render_solid; | 240 | } render_solid; |
| 241 | struct { | 241 | struct { |
| @@ -247,7 +247,7 @@ public: | |||
| 247 | u32 color0; | 247 | u32 color0; |
| 248 | u32 color1; | 248 | u32 color1; |
| 249 | u32 mono_opacity; | 249 | u32 mono_opacity; |
| 250 | INSERT_UNION_PADDING_WORDS(0x6); | 250 | INSERT_PADDING_WORDS_NOINIT(0x6); |
| 251 | u32 src_width; | 251 | u32 src_width; |
| 252 | u32 src_height; | 252 | u32 src_height; |
| 253 | u32 dx_du_frac; | 253 | u32 dx_du_frac; |
| @@ -260,9 +260,9 @@ public: | |||
| 260 | u32 dst_y0_int; | 260 | u32 dst_y0_int; |
| 261 | u32 data; | 261 | u32 data; |
| 262 | } pixels_from_cpu; | 262 | } pixels_from_cpu; |
| 263 | INSERT_UNION_PADDING_WORDS(0x3); | 263 | INSERT_PADDING_WORDS_NOINIT(0x3); |
| 264 | u32 big_endian_control; | 264 | u32 big_endian_control; |
| 265 | INSERT_UNION_PADDING_WORDS(0x3); | 265 | INSERT_PADDING_WORDS_NOINIT(0x3); |
| 266 | struct { | 266 | struct { |
| 267 | BitField<0, 3, u32> block_shape; | 267 | BitField<0, 3, u32> block_shape; |
| 268 | BitField<0, 5, u32> corral_size; | 268 | BitField<0, 5, u32> corral_size; |
| @@ -271,7 +271,7 @@ public: | |||
| 271 | BitField<0, 1, Origin> origin; | 271 | BitField<0, 1, Origin> origin; |
| 272 | BitField<4, 1, Filter> filter; | 272 | BitField<4, 1, Filter> filter; |
| 273 | } sample_mode; | 273 | } sample_mode; |
| 274 | INSERT_UNION_PADDING_WORDS(0x8); | 274 | INSERT_PADDING_WORDS_NOINIT(0x8); |
| 275 | s32 dst_x0; | 275 | s32 dst_x0; |
| 276 | s32 dst_y0; | 276 | s32 dst_y0; |
| 277 | s32 dst_width; | 277 | s32 dst_width; |
diff --git a/src/video_core/engines/kepler_compute.h b/src/video_core/engines/kepler_compute.h index 51a041202..9f0a7b76d 100644 --- a/src/video_core/engines/kepler_compute.h +++ b/src/video_core/engines/kepler_compute.h | |||
| @@ -55,7 +55,7 @@ public: | |||
| 55 | 55 | ||
| 56 | union { | 56 | union { |
| 57 | struct { | 57 | struct { |
| 58 | INSERT_UNION_PADDING_WORDS(0x60); | 58 | INSERT_PADDING_WORDS_NOINIT(0x60); |
| 59 | 59 | ||
| 60 | Upload::Registers upload; | 60 | Upload::Registers upload; |
| 61 | 61 | ||
| @@ -67,7 +67,7 @@ public: | |||
| 67 | 67 | ||
| 68 | u32 data_upload; | 68 | u32 data_upload; |
| 69 | 69 | ||
| 70 | INSERT_UNION_PADDING_WORDS(0x3F); | 70 | INSERT_PADDING_WORDS_NOINIT(0x3F); |
| 71 | 71 | ||
| 72 | struct { | 72 | struct { |
| 73 | u32 address; | 73 | u32 address; |
| @@ -76,11 +76,11 @@ public: | |||
| 76 | } | 76 | } |
| 77 | } launch_desc_loc; | 77 | } launch_desc_loc; |
| 78 | 78 | ||
| 79 | INSERT_UNION_PADDING_WORDS(0x1); | 79 | INSERT_PADDING_WORDS_NOINIT(0x1); |
| 80 | 80 | ||
| 81 | u32 launch; | 81 | u32 launch; |
| 82 | 82 | ||
| 83 | INSERT_UNION_PADDING_WORDS(0x4A7); | 83 | INSERT_PADDING_WORDS_NOINIT(0x4A7); |
| 84 | 84 | ||
| 85 | struct { | 85 | struct { |
| 86 | u32 address_high; | 86 | u32 address_high; |
| @@ -92,7 +92,7 @@ public: | |||
| 92 | } | 92 | } |
| 93 | } tsc; | 93 | } tsc; |
| 94 | 94 | ||
| 95 | INSERT_UNION_PADDING_WORDS(0x3); | 95 | INSERT_PADDING_WORDS_NOINIT(0x3); |
| 96 | 96 | ||
| 97 | struct { | 97 | struct { |
| 98 | u32 address_high; | 98 | u32 address_high; |
| @@ -104,7 +104,7 @@ public: | |||
| 104 | } | 104 | } |
| 105 | } tic; | 105 | } tic; |
| 106 | 106 | ||
| 107 | INSERT_UNION_PADDING_WORDS(0x22); | 107 | INSERT_PADDING_WORDS_NOINIT(0x22); |
| 108 | 108 | ||
| 109 | struct { | 109 | struct { |
| 110 | u32 address_high; | 110 | u32 address_high; |
| @@ -115,11 +115,11 @@ public: | |||
| 115 | } | 115 | } |
| 116 | } code_loc; | 116 | } code_loc; |
| 117 | 117 | ||
| 118 | INSERT_UNION_PADDING_WORDS(0x3FE); | 118 | INSERT_PADDING_WORDS_NOINIT(0x3FE); |
| 119 | 119 | ||
| 120 | u32 tex_cb_index; | 120 | u32 tex_cb_index; |
| 121 | 121 | ||
| 122 | INSERT_UNION_PADDING_WORDS(0x374); | 122 | INSERT_PADDING_WORDS_NOINIT(0x374); |
| 123 | }; | 123 | }; |
| 124 | std::array<u32, NUM_REGS> reg_array; | 124 | std::array<u32, NUM_REGS> reg_array; |
| 125 | }; | 125 | }; |
diff --git a/src/video_core/engines/kepler_memory.h b/src/video_core/engines/kepler_memory.h index 62483589e..19808a5c6 100644 --- a/src/video_core/engines/kepler_memory.h +++ b/src/video_core/engines/kepler_memory.h | |||
| @@ -50,7 +50,7 @@ public: | |||
| 50 | 50 | ||
| 51 | union { | 51 | union { |
| 52 | struct { | 52 | struct { |
| 53 | INSERT_UNION_PADDING_WORDS(0x60); | 53 | INSERT_PADDING_WORDS_NOINIT(0x60); |
| 54 | 54 | ||
| 55 | Upload::Registers upload; | 55 | Upload::Registers upload; |
| 56 | 56 | ||
| @@ -62,7 +62,7 @@ public: | |||
| 62 | 62 | ||
| 63 | u32 data; | 63 | u32 data; |
| 64 | 64 | ||
| 65 | INSERT_UNION_PADDING_WORDS(0x11); | 65 | INSERT_PADDING_WORDS_NOINIT(0x11); |
| 66 | }; | 66 | }; |
| 67 | std::array<u32, NUM_REGS> reg_array; | 67 | std::array<u32, NUM_REGS> reg_array; |
| 68 | }; | 68 | }; |
diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h index bf9e07c9b..326b32228 100644 --- a/src/video_core/engines/maxwell_3d.h +++ b/src/video_core/engines/maxwell_3d.h | |||
| @@ -536,7 +536,7 @@ public: | |||
| 536 | Equation equation_a; | 536 | Equation equation_a; |
| 537 | Factor factor_source_a; | 537 | Factor factor_source_a; |
| 538 | Factor factor_dest_a; | 538 | Factor factor_dest_a; |
| 539 | INSERT_UNION_PADDING_WORDS(1); | 539 | INSERT_PADDING_WORDS_NOINIT(1); |
| 540 | }; | 540 | }; |
| 541 | 541 | ||
| 542 | enum class TessellationPrimitive : u32 { | 542 | enum class TessellationPrimitive : u32 { |
| @@ -608,7 +608,7 @@ public: | |||
| 608 | }; | 608 | }; |
| 609 | u32 layer_stride; | 609 | u32 layer_stride; |
| 610 | u32 base_layer; | 610 | u32 base_layer; |
| 611 | INSERT_UNION_PADDING_WORDS(7); | 611 | INSERT_PADDING_WORDS_NOINIT(7); |
| 612 | 612 | ||
| 613 | GPUVAddr Address() const { | 613 | GPUVAddr Address() const { |
| 614 | return static_cast<GPUVAddr>((static_cast<GPUVAddr>(address_high) << 32) | | 614 | return static_cast<GPUVAddr>((static_cast<GPUVAddr>(address_high) << 32) | |
| @@ -640,7 +640,7 @@ public: | |||
| 640 | BitField<8, 3, ViewportSwizzle> z; | 640 | BitField<8, 3, ViewportSwizzle> z; |
| 641 | BitField<12, 3, ViewportSwizzle> w; | 641 | BitField<12, 3, ViewportSwizzle> w; |
| 642 | } swizzle; | 642 | } swizzle; |
| 643 | INSERT_UNION_PADDING_WORDS(1); | 643 | INSERT_PADDING_WORDS_NOINIT(1); |
| 644 | 644 | ||
| 645 | Common::Rectangle<f32> GetRect() const { | 645 | Common::Rectangle<f32> GetRect() const { |
| 646 | return { | 646 | return { |
| @@ -700,7 +700,7 @@ public: | |||
| 700 | u32 address_low; | 700 | u32 address_low; |
| 701 | s32 buffer_size; | 701 | s32 buffer_size; |
| 702 | s32 buffer_offset; | 702 | s32 buffer_offset; |
| 703 | INSERT_UNION_PADDING_WORDS(3); | 703 | INSERT_PADDING_WORDS_NOINIT(3); |
| 704 | 704 | ||
| 705 | GPUVAddr Address() const { | 705 | GPUVAddr Address() const { |
| 706 | return static_cast<GPUVAddr>((static_cast<GPUVAddr>(address_high) << 32) | | 706 | return static_cast<GPUVAddr>((static_cast<GPUVAddr>(address_high) << 32) | |
| @@ -713,7 +713,7 @@ public: | |||
| 713 | u32 stream; | 713 | u32 stream; |
| 714 | u32 varying_count; | 714 | u32 varying_count; |
| 715 | u32 stride; | 715 | u32 stride; |
| 716 | INSERT_UNION_PADDING_WORDS(1); | 716 | INSERT_PADDING_WORDS_NOINIT(1); |
| 717 | }; | 717 | }; |
| 718 | static_assert(sizeof(TransformFeedbackLayout) == 16); | 718 | static_assert(sizeof(TransformFeedbackLayout) == 16); |
| 719 | 719 | ||
| @@ -731,7 +731,7 @@ public: | |||
| 731 | 731 | ||
| 732 | union { | 732 | union { |
| 733 | struct { | 733 | struct { |
| 734 | INSERT_UNION_PADDING_WORDS(0x44); | 734 | INSERT_PADDING_WORDS_NOINIT(0x44); |
| 735 | 735 | ||
| 736 | u32 wait_for_idle; | 736 | u32 wait_for_idle; |
| 737 | 737 | ||
| @@ -744,7 +744,7 @@ public: | |||
| 744 | 744 | ||
| 745 | ShadowRamControl shadow_ram_control; | 745 | ShadowRamControl shadow_ram_control; |
| 746 | 746 | ||
| 747 | INSERT_UNION_PADDING_WORDS(0x16); | 747 | INSERT_PADDING_WORDS_NOINIT(0x16); |
| 748 | 748 | ||
| 749 | Upload::Registers upload; | 749 | Upload::Registers upload; |
| 750 | struct { | 750 | struct { |
| @@ -755,11 +755,11 @@ public: | |||
| 755 | 755 | ||
| 756 | u32 data_upload; | 756 | u32 data_upload; |
| 757 | 757 | ||
| 758 | INSERT_UNION_PADDING_WORDS(0x16); | 758 | INSERT_PADDING_WORDS_NOINIT(0x16); |
| 759 | 759 | ||
| 760 | u32 force_early_fragment_tests; | 760 | u32 force_early_fragment_tests; |
| 761 | 761 | ||
| 762 | INSERT_UNION_PADDING_WORDS(0x2D); | 762 | INSERT_PADDING_WORDS_NOINIT(0x2D); |
| 763 | 763 | ||
| 764 | struct { | 764 | struct { |
| 765 | union { | 765 | union { |
| @@ -769,7 +769,7 @@ public: | |||
| 769 | }; | 769 | }; |
| 770 | } sync_info; | 770 | } sync_info; |
| 771 | 771 | ||
| 772 | INSERT_UNION_PADDING_WORDS(0x15); | 772 | INSERT_PADDING_WORDS_NOINIT(0x15); |
| 773 | 773 | ||
| 774 | union { | 774 | union { |
| 775 | BitField<0, 2, TessellationPrimitive> prim; | 775 | BitField<0, 2, TessellationPrimitive> prim; |
| @@ -781,21 +781,21 @@ public: | |||
| 781 | std::array<f32, 4> tess_level_outer; | 781 | std::array<f32, 4> tess_level_outer; |
| 782 | std::array<f32, 2> tess_level_inner; | 782 | std::array<f32, 2> tess_level_inner; |
| 783 | 783 | ||
| 784 | INSERT_UNION_PADDING_WORDS(0x10); | 784 | INSERT_PADDING_WORDS_NOINIT(0x10); |
| 785 | 785 | ||
| 786 | u32 rasterize_enable; | 786 | u32 rasterize_enable; |
| 787 | 787 | ||
| 788 | std::array<TransformFeedbackBinding, NumTransformFeedbackBuffers> tfb_bindings; | 788 | std::array<TransformFeedbackBinding, NumTransformFeedbackBuffers> tfb_bindings; |
| 789 | 789 | ||
| 790 | INSERT_UNION_PADDING_WORDS(0xC0); | 790 | INSERT_PADDING_WORDS_NOINIT(0xC0); |
| 791 | 791 | ||
| 792 | std::array<TransformFeedbackLayout, NumTransformFeedbackBuffers> tfb_layouts; | 792 | std::array<TransformFeedbackLayout, NumTransformFeedbackBuffers> tfb_layouts; |
| 793 | 793 | ||
| 794 | INSERT_UNION_PADDING_WORDS(0x1); | 794 | INSERT_PADDING_WORDS_NOINIT(0x1); |
| 795 | 795 | ||
| 796 | u32 tfb_enabled; | 796 | u32 tfb_enabled; |
| 797 | 797 | ||
| 798 | INSERT_UNION_PADDING_WORDS(0x2E); | 798 | INSERT_PADDING_WORDS_NOINIT(0x2E); |
| 799 | 799 | ||
| 800 | std::array<RenderTargetConfig, NumRenderTargets> rt; | 800 | std::array<RenderTargetConfig, NumRenderTargets> rt; |
| 801 | 801 | ||
| @@ -803,7 +803,7 @@ public: | |||
| 803 | 803 | ||
| 804 | std::array<ViewPort, NumViewports> viewports; | 804 | std::array<ViewPort, NumViewports> viewports; |
| 805 | 805 | ||
| 806 | INSERT_UNION_PADDING_WORDS(0x1D); | 806 | INSERT_PADDING_WORDS_NOINIT(0x1D); |
| 807 | 807 | ||
| 808 | struct { | 808 | struct { |
| 809 | u32 first; | 809 | u32 first; |
| @@ -815,16 +815,16 @@ public: | |||
| 815 | float clear_color[4]; | 815 | float clear_color[4]; |
| 816 | float clear_depth; | 816 | float clear_depth; |
| 817 | 817 | ||
| 818 | INSERT_UNION_PADDING_WORDS(0x3); | 818 | INSERT_PADDING_WORDS_NOINIT(0x3); |
| 819 | 819 | ||
| 820 | s32 clear_stencil; | 820 | s32 clear_stencil; |
| 821 | 821 | ||
| 822 | INSERT_UNION_PADDING_WORDS(0x2); | 822 | INSERT_PADDING_WORDS_NOINIT(0x2); |
| 823 | 823 | ||
| 824 | PolygonMode polygon_mode_front; | 824 | PolygonMode polygon_mode_front; |
| 825 | PolygonMode polygon_mode_back; | 825 | PolygonMode polygon_mode_back; |
| 826 | 826 | ||
| 827 | INSERT_UNION_PADDING_WORDS(0x3); | 827 | INSERT_PADDING_WORDS_NOINIT(0x3); |
| 828 | 828 | ||
| 829 | u32 polygon_offset_point_enable; | 829 | u32 polygon_offset_point_enable; |
| 830 | u32 polygon_offset_line_enable; | 830 | u32 polygon_offset_line_enable; |
| @@ -832,47 +832,47 @@ public: | |||
| 832 | 832 | ||
| 833 | u32 patch_vertices; | 833 | u32 patch_vertices; |
| 834 | 834 | ||
| 835 | INSERT_UNION_PADDING_WORDS(0x4); | 835 | INSERT_PADDING_WORDS_NOINIT(0x4); |
| 836 | 836 | ||
| 837 | u32 fragment_barrier; | 837 | u32 fragment_barrier; |
| 838 | 838 | ||
| 839 | INSERT_UNION_PADDING_WORDS(0x7); | 839 | INSERT_PADDING_WORDS_NOINIT(0x7); |
| 840 | 840 | ||
| 841 | std::array<ScissorTest, NumViewports> scissor_test; | 841 | std::array<ScissorTest, NumViewports> scissor_test; |
| 842 | 842 | ||
| 843 | INSERT_UNION_PADDING_WORDS(0x15); | 843 | INSERT_PADDING_WORDS_NOINIT(0x15); |
| 844 | 844 | ||
| 845 | s32 stencil_back_func_ref; | 845 | s32 stencil_back_func_ref; |
| 846 | u32 stencil_back_mask; | 846 | u32 stencil_back_mask; |
| 847 | u32 stencil_back_func_mask; | 847 | u32 stencil_back_func_mask; |
| 848 | 848 | ||
| 849 | INSERT_UNION_PADDING_WORDS(0x5); | 849 | INSERT_PADDING_WORDS_NOINIT(0x5); |
| 850 | 850 | ||
| 851 | u32 invalidate_texture_data_cache; | 851 | u32 invalidate_texture_data_cache; |
| 852 | 852 | ||
| 853 | INSERT_UNION_PADDING_WORDS(0x1); | 853 | INSERT_PADDING_WORDS_NOINIT(0x1); |
| 854 | 854 | ||
| 855 | u32 tiled_cache_barrier; | 855 | u32 tiled_cache_barrier; |
| 856 | 856 | ||
| 857 | INSERT_UNION_PADDING_WORDS(0x4); | 857 | INSERT_PADDING_WORDS_NOINIT(0x4); |
| 858 | 858 | ||
| 859 | u32 color_mask_common; | 859 | u32 color_mask_common; |
| 860 | 860 | ||
| 861 | INSERT_UNION_PADDING_WORDS(0x2); | 861 | INSERT_PADDING_WORDS_NOINIT(0x2); |
| 862 | 862 | ||
| 863 | f32 depth_bounds[2]; | 863 | f32 depth_bounds[2]; |
| 864 | 864 | ||
| 865 | INSERT_UNION_PADDING_WORDS(0x2); | 865 | INSERT_PADDING_WORDS_NOINIT(0x2); |
| 866 | 866 | ||
| 867 | u32 rt_separate_frag_data; | 867 | u32 rt_separate_frag_data; |
| 868 | 868 | ||
| 869 | INSERT_UNION_PADDING_WORDS(0x1); | 869 | INSERT_PADDING_WORDS_NOINIT(0x1); |
| 870 | 870 | ||
| 871 | u32 multisample_raster_enable; | 871 | u32 multisample_raster_enable; |
| 872 | u32 multisample_raster_samples; | 872 | u32 multisample_raster_samples; |
| 873 | std::array<u32, 4> multisample_sample_mask; | 873 | std::array<u32, 4> multisample_sample_mask; |
| 874 | 874 | ||
| 875 | INSERT_UNION_PADDING_WORDS(0x5); | 875 | INSERT_PADDING_WORDS_NOINIT(0x5); |
| 876 | 876 | ||
| 877 | struct { | 877 | struct { |
| 878 | u32 address_high; | 878 | u32 address_high; |
| @@ -898,7 +898,7 @@ public: | |||
| 898 | }; | 898 | }; |
| 899 | } render_area; | 899 | } render_area; |
| 900 | 900 | ||
| 901 | INSERT_UNION_PADDING_WORDS(0x3F); | 901 | INSERT_PADDING_WORDS_NOINIT(0x3F); |
| 902 | 902 | ||
| 903 | union { | 903 | union { |
| 904 | BitField<0, 4, u32> stencil; | 904 | BitField<0, 4, u32> stencil; |
| @@ -907,24 +907,24 @@ public: | |||
| 907 | BitField<12, 4, u32> viewport; | 907 | BitField<12, 4, u32> viewport; |
| 908 | } clear_flags; | 908 | } clear_flags; |
| 909 | 909 | ||
| 910 | INSERT_UNION_PADDING_WORDS(0x10); | 910 | INSERT_PADDING_WORDS_NOINIT(0x10); |
| 911 | 911 | ||
| 912 | u32 fill_rectangle; | 912 | u32 fill_rectangle; |
| 913 | 913 | ||
| 914 | INSERT_UNION_PADDING_WORDS(0x8); | 914 | INSERT_PADDING_WORDS_NOINIT(0x8); |
| 915 | 915 | ||
| 916 | std::array<VertexAttribute, NumVertexAttributes> vertex_attrib_format; | 916 | std::array<VertexAttribute, NumVertexAttributes> vertex_attrib_format; |
| 917 | 917 | ||
| 918 | std::array<MsaaSampleLocation, 4> multisample_sample_locations; | 918 | std::array<MsaaSampleLocation, 4> multisample_sample_locations; |
| 919 | 919 | ||
| 920 | INSERT_UNION_PADDING_WORDS(0x2); | 920 | INSERT_PADDING_WORDS_NOINIT(0x2); |
| 921 | 921 | ||
| 922 | union { | 922 | union { |
| 923 | BitField<0, 1, u32> enable; | 923 | BitField<0, 1, u32> enable; |
| 924 | BitField<4, 3, u32> target; | 924 | BitField<4, 3, u32> target; |
| 925 | } multisample_coverage_to_color; | 925 | } multisample_coverage_to_color; |
| 926 | 926 | ||
| 927 | INSERT_UNION_PADDING_WORDS(0x8); | 927 | INSERT_PADDING_WORDS_NOINIT(0x8); |
| 928 | 928 | ||
| 929 | struct { | 929 | struct { |
| 930 | union { | 930 | union { |
| @@ -947,7 +947,7 @@ public: | |||
| 947 | } | 947 | } |
| 948 | } rt_control; | 948 | } rt_control; |
| 949 | 949 | ||
| 950 | INSERT_UNION_PADDING_WORDS(0x2); | 950 | INSERT_PADDING_WORDS_NOINIT(0x2); |
| 951 | 951 | ||
| 952 | u32 zeta_width; | 952 | u32 zeta_width; |
| 953 | u32 zeta_height; | 953 | u32 zeta_height; |
| @@ -958,11 +958,11 @@ public: | |||
| 958 | 958 | ||
| 959 | SamplerIndex sampler_index; | 959 | SamplerIndex sampler_index; |
| 960 | 960 | ||
| 961 | INSERT_UNION_PADDING_WORDS(0x25); | 961 | INSERT_PADDING_WORDS_NOINIT(0x25); |
| 962 | 962 | ||
| 963 | u32 depth_test_enable; | 963 | u32 depth_test_enable; |
| 964 | 964 | ||
| 965 | INSERT_UNION_PADDING_WORDS(0x5); | 965 | INSERT_PADDING_WORDS_NOINIT(0x5); |
| 966 | 966 | ||
| 967 | u32 independent_blend_enable; | 967 | u32 independent_blend_enable; |
| 968 | 968 | ||
| @@ -970,7 +970,7 @@ public: | |||
| 970 | 970 | ||
| 971 | u32 alpha_test_enabled; | 971 | u32 alpha_test_enabled; |
| 972 | 972 | ||
| 973 | INSERT_UNION_PADDING_WORDS(0x6); | 973 | INSERT_PADDING_WORDS_NOINIT(0x6); |
| 974 | 974 | ||
| 975 | u32 d3d_cull_mode; | 975 | u32 d3d_cull_mode; |
| 976 | 976 | ||
| @@ -985,7 +985,7 @@ public: | |||
| 985 | float a; | 985 | float a; |
| 986 | } blend_color; | 986 | } blend_color; |
| 987 | 987 | ||
| 988 | INSERT_UNION_PADDING_WORDS(0x4); | 988 | INSERT_PADDING_WORDS_NOINIT(0x4); |
| 989 | 989 | ||
| 990 | struct { | 990 | struct { |
| 991 | u32 separate_alpha; | 991 | u32 separate_alpha; |
| @@ -994,7 +994,7 @@ public: | |||
| 994 | Blend::Factor factor_dest_rgb; | 994 | Blend::Factor factor_dest_rgb; |
| 995 | Blend::Equation equation_a; | 995 | Blend::Equation equation_a; |
| 996 | Blend::Factor factor_source_a; | 996 | Blend::Factor factor_source_a; |
| 997 | INSERT_UNION_PADDING_WORDS(1); | 997 | INSERT_PADDING_WORDS_NOINIT(1); |
| 998 | Blend::Factor factor_dest_a; | 998 | Blend::Factor factor_dest_a; |
| 999 | 999 | ||
| 1000 | u32 enable_common; | 1000 | u32 enable_common; |
| @@ -1010,7 +1010,7 @@ public: | |||
| 1010 | u32 stencil_front_func_mask; | 1010 | u32 stencil_front_func_mask; |
| 1011 | u32 stencil_front_mask; | 1011 | u32 stencil_front_mask; |
| 1012 | 1012 | ||
| 1013 | INSERT_UNION_PADDING_WORDS(0x2); | 1013 | INSERT_PADDING_WORDS_NOINIT(0x2); |
| 1014 | 1014 | ||
| 1015 | u32 frag_color_clamp; | 1015 | u32 frag_color_clamp; |
| 1016 | 1016 | ||
| @@ -1022,17 +1022,17 @@ public: | |||
| 1022 | float line_width_smooth; | 1022 | float line_width_smooth; |
| 1023 | float line_width_aliased; | 1023 | float line_width_aliased; |
| 1024 | 1024 | ||
| 1025 | INSERT_UNION_PADDING_WORDS(0x1B); | 1025 | INSERT_PADDING_WORDS_NOINIT(0x1B); |
| 1026 | 1026 | ||
| 1027 | u32 invalidate_sampler_cache_no_wfi; | 1027 | u32 invalidate_sampler_cache_no_wfi; |
| 1028 | u32 invalidate_texture_header_cache_no_wfi; | 1028 | u32 invalidate_texture_header_cache_no_wfi; |
| 1029 | 1029 | ||
| 1030 | INSERT_UNION_PADDING_WORDS(0x2); | 1030 | INSERT_PADDING_WORDS_NOINIT(0x2); |
| 1031 | 1031 | ||
| 1032 | u32 vb_element_base; | 1032 | u32 vb_element_base; |
| 1033 | u32 vb_base_instance; | 1033 | u32 vb_base_instance; |
| 1034 | 1034 | ||
| 1035 | INSERT_UNION_PADDING_WORDS(0x35); | 1035 | INSERT_PADDING_WORDS_NOINIT(0x35); |
| 1036 | 1036 | ||
| 1037 | u32 clip_distance_enabled; | 1037 | u32 clip_distance_enabled; |
| 1038 | 1038 | ||
| @@ -1040,11 +1040,11 @@ public: | |||
| 1040 | 1040 | ||
| 1041 | float point_size; | 1041 | float point_size; |
| 1042 | 1042 | ||
| 1043 | INSERT_UNION_PADDING_WORDS(0x1); | 1043 | INSERT_PADDING_WORDS_NOINIT(0x1); |
| 1044 | 1044 | ||
| 1045 | u32 point_sprite_enable; | 1045 | u32 point_sprite_enable; |
| 1046 | 1046 | ||
| 1047 | INSERT_UNION_PADDING_WORDS(0x3); | 1047 | INSERT_PADDING_WORDS_NOINIT(0x3); |
| 1048 | 1048 | ||
| 1049 | CounterReset counter_reset; | 1049 | CounterReset counter_reset; |
| 1050 | 1050 | ||
| @@ -1057,7 +1057,7 @@ public: | |||
| 1057 | BitField<4, 1, u32> alpha_to_one; | 1057 | BitField<4, 1, u32> alpha_to_one; |
| 1058 | } multisample_control; | 1058 | } multisample_control; |
| 1059 | 1059 | ||
| 1060 | INSERT_UNION_PADDING_WORDS(0x4); | 1060 | INSERT_PADDING_WORDS_NOINIT(0x4); |
| 1061 | 1061 | ||
| 1062 | struct { | 1062 | struct { |
| 1063 | u32 address_high; | 1063 | u32 address_high; |
| @@ -1081,7 +1081,7 @@ public: | |||
| 1081 | } | 1081 | } |
| 1082 | } tsc; | 1082 | } tsc; |
| 1083 | 1083 | ||
| 1084 | INSERT_UNION_PADDING_WORDS(0x1); | 1084 | INSERT_PADDING_WORDS_NOINIT(0x1); |
| 1085 | 1085 | ||
| 1086 | float polygon_offset_factor; | 1086 | float polygon_offset_factor; |
| 1087 | 1087 | ||
| @@ -1098,7 +1098,7 @@ public: | |||
| 1098 | } | 1098 | } |
| 1099 | } tic; | 1099 | } tic; |
| 1100 | 1100 | ||
| 1101 | INSERT_UNION_PADDING_WORDS(0x5); | 1101 | INSERT_PADDING_WORDS_NOINIT(0x5); |
| 1102 | 1102 | ||
| 1103 | u32 stencil_two_side_enable; | 1103 | u32 stencil_two_side_enable; |
| 1104 | StencilOp stencil_back_op_fail; | 1104 | StencilOp stencil_back_op_fail; |
| @@ -1106,17 +1106,17 @@ public: | |||
| 1106 | StencilOp stencil_back_op_zpass; | 1106 | StencilOp stencil_back_op_zpass; |
| 1107 | ComparisonOp stencil_back_func_func; | 1107 | ComparisonOp stencil_back_func_func; |
| 1108 | 1108 | ||
| 1109 | INSERT_UNION_PADDING_WORDS(0x4); | 1109 | INSERT_PADDING_WORDS_NOINIT(0x4); |
| 1110 | 1110 | ||
| 1111 | u32 framebuffer_srgb; | 1111 | u32 framebuffer_srgb; |
| 1112 | 1112 | ||
| 1113 | float polygon_offset_units; | 1113 | float polygon_offset_units; |
| 1114 | 1114 | ||
| 1115 | INSERT_UNION_PADDING_WORDS(0x4); | 1115 | INSERT_PADDING_WORDS_NOINIT(0x4); |
| 1116 | 1116 | ||
| 1117 | Tegra::Texture::MsaaMode multisample_mode; | 1117 | Tegra::Texture::MsaaMode multisample_mode; |
| 1118 | 1118 | ||
| 1119 | INSERT_UNION_PADDING_WORDS(0xC); | 1119 | INSERT_PADDING_WORDS_NOINIT(0xC); |
| 1120 | 1120 | ||
| 1121 | union { | 1121 | union { |
| 1122 | BitField<2, 1, u32> coord_origin; | 1122 | BitField<2, 1, u32> coord_origin; |
| @@ -1132,7 +1132,7 @@ public: | |||
| 1132 | (static_cast<GPUVAddr>(code_address_high) << 32) | code_address_low); | 1132 | (static_cast<GPUVAddr>(code_address_high) << 32) | code_address_low); |
| 1133 | } | 1133 | } |
| 1134 | } code_address; | 1134 | } code_address; |
| 1135 | INSERT_UNION_PADDING_WORDS(1); | 1135 | INSERT_PADDING_WORDS_NOINIT(1); |
| 1136 | 1136 | ||
| 1137 | struct { | 1137 | struct { |
| 1138 | u32 vertex_end_gl; | 1138 | u32 vertex_end_gl; |
| @@ -1144,14 +1144,14 @@ public: | |||
| 1144 | }; | 1144 | }; |
| 1145 | } draw; | 1145 | } draw; |
| 1146 | 1146 | ||
| 1147 | INSERT_UNION_PADDING_WORDS(0xA); | 1147 | INSERT_PADDING_WORDS_NOINIT(0xA); |
| 1148 | 1148 | ||
| 1149 | struct { | 1149 | struct { |
| 1150 | u32 enabled; | 1150 | u32 enabled; |
| 1151 | u32 index; | 1151 | u32 index; |
| 1152 | } primitive_restart; | 1152 | } primitive_restart; |
| 1153 | 1153 | ||
| 1154 | INSERT_UNION_PADDING_WORDS(0x5F); | 1154 | INSERT_PADDING_WORDS_NOINIT(0x5F); |
| 1155 | 1155 | ||
| 1156 | struct { | 1156 | struct { |
| 1157 | u32 start_addr_high; | 1157 | u32 start_addr_high; |
| @@ -1192,9 +1192,9 @@ public: | |||
| 1192 | } | 1192 | } |
| 1193 | } index_array; | 1193 | } index_array; |
| 1194 | 1194 | ||
| 1195 | INSERT_UNION_PADDING_WORDS(0x7); | 1195 | INSERT_PADDING_WORDS_NOINIT(0x7); |
| 1196 | 1196 | ||
| 1197 | INSERT_UNION_PADDING_WORDS(0x1F); | 1197 | INSERT_PADDING_WORDS_NOINIT(0x1F); |
| 1198 | 1198 | ||
| 1199 | float polygon_offset_clamp; | 1199 | float polygon_offset_clamp; |
| 1200 | 1200 | ||
| @@ -1208,14 +1208,14 @@ public: | |||
| 1208 | } | 1208 | } |
| 1209 | } instanced_arrays; | 1209 | } instanced_arrays; |
| 1210 | 1210 | ||
| 1211 | INSERT_UNION_PADDING_WORDS(0x4); | 1211 | INSERT_PADDING_WORDS_NOINIT(0x4); |
| 1212 | 1212 | ||
| 1213 | union { | 1213 | union { |
| 1214 | BitField<0, 1, u32> enable; | 1214 | BitField<0, 1, u32> enable; |
| 1215 | BitField<4, 8, u32> unk4; | 1215 | BitField<4, 8, u32> unk4; |
| 1216 | } vp_point_size; | 1216 | } vp_point_size; |
| 1217 | 1217 | ||
| 1218 | INSERT_UNION_PADDING_WORDS(1); | 1218 | INSERT_PADDING_WORDS_NOINIT(1); |
| 1219 | 1219 | ||
| 1220 | u32 cull_test_enabled; | 1220 | u32 cull_test_enabled; |
| 1221 | FrontFace front_face; | 1221 | FrontFace front_face; |
| @@ -1223,11 +1223,11 @@ public: | |||
| 1223 | 1223 | ||
| 1224 | u32 pixel_center_integer; | 1224 | u32 pixel_center_integer; |
| 1225 | 1225 | ||
| 1226 | INSERT_UNION_PADDING_WORDS(0x1); | 1226 | INSERT_PADDING_WORDS_NOINIT(0x1); |
| 1227 | 1227 | ||
| 1228 | u32 viewport_transform_enabled; | 1228 | u32 viewport_transform_enabled; |
| 1229 | 1229 | ||
| 1230 | INSERT_UNION_PADDING_WORDS(0x3); | 1230 | INSERT_PADDING_WORDS_NOINIT(0x3); |
| 1231 | 1231 | ||
| 1232 | union { | 1232 | union { |
| 1233 | BitField<0, 1, u32> depth_range_0_1; | 1233 | BitField<0, 1, u32> depth_range_0_1; |
| @@ -1236,18 +1236,18 @@ public: | |||
| 1236 | BitField<11, 1, u32> depth_clamp_disabled; | 1236 | BitField<11, 1, u32> depth_clamp_disabled; |
| 1237 | } view_volume_clip_control; | 1237 | } view_volume_clip_control; |
| 1238 | 1238 | ||
| 1239 | INSERT_UNION_PADDING_WORDS(0x1F); | 1239 | INSERT_PADDING_WORDS_NOINIT(0x1F); |
| 1240 | 1240 | ||
| 1241 | u32 depth_bounds_enable; | 1241 | u32 depth_bounds_enable; |
| 1242 | 1242 | ||
| 1243 | INSERT_UNION_PADDING_WORDS(1); | 1243 | INSERT_PADDING_WORDS_NOINIT(1); |
| 1244 | 1244 | ||
| 1245 | struct { | 1245 | struct { |
| 1246 | u32 enable; | 1246 | u32 enable; |
| 1247 | LogicOperation operation; | 1247 | LogicOperation operation; |
| 1248 | } logic_op; | 1248 | } logic_op; |
| 1249 | 1249 | ||
| 1250 | INSERT_UNION_PADDING_WORDS(0x1); | 1250 | INSERT_PADDING_WORDS_NOINIT(0x1); |
| 1251 | 1251 | ||
| 1252 | union { | 1252 | union { |
| 1253 | u32 raw; | 1253 | u32 raw; |
| @@ -1260,9 +1260,9 @@ public: | |||
| 1260 | BitField<6, 4, u32> RT; | 1260 | BitField<6, 4, u32> RT; |
| 1261 | BitField<10, 11, u32> layer; | 1261 | BitField<10, 11, u32> layer; |
| 1262 | } clear_buffers; | 1262 | } clear_buffers; |
| 1263 | INSERT_UNION_PADDING_WORDS(0xB); | 1263 | INSERT_PADDING_WORDS_NOINIT(0xB); |
| 1264 | std::array<ColorMask, NumRenderTargets> color_mask; | 1264 | std::array<ColorMask, NumRenderTargets> color_mask; |
| 1265 | INSERT_UNION_PADDING_WORDS(0x38); | 1265 | INSERT_PADDING_WORDS_NOINIT(0x38); |
| 1266 | 1266 | ||
| 1267 | struct { | 1267 | struct { |
| 1268 | u32 query_address_high; | 1268 | u32 query_address_high; |
| @@ -1284,7 +1284,7 @@ public: | |||
| 1284 | } | 1284 | } |
| 1285 | } query; | 1285 | } query; |
| 1286 | 1286 | ||
| 1287 | INSERT_UNION_PADDING_WORDS(0x3C); | 1287 | INSERT_PADDING_WORDS_NOINIT(0x3C); |
| 1288 | 1288 | ||
| 1289 | struct { | 1289 | struct { |
| 1290 | union { | 1290 | union { |
| @@ -1325,10 +1325,10 @@ public: | |||
| 1325 | BitField<4, 4, ShaderProgram> program; | 1325 | BitField<4, 4, ShaderProgram> program; |
| 1326 | }; | 1326 | }; |
| 1327 | u32 offset; | 1327 | u32 offset; |
| 1328 | INSERT_UNION_PADDING_WORDS(14); | 1328 | INSERT_PADDING_WORDS_NOINIT(14); |
| 1329 | } shader_config[MaxShaderProgram]; | 1329 | } shader_config[MaxShaderProgram]; |
| 1330 | 1330 | ||
| 1331 | INSERT_UNION_PADDING_WORDS(0x60); | 1331 | INSERT_PADDING_WORDS_NOINIT(0x60); |
| 1332 | 1332 | ||
| 1333 | u32 firmware[0x20]; | 1333 | u32 firmware[0x20]; |
| 1334 | 1334 | ||
| @@ -1345,7 +1345,7 @@ public: | |||
| 1345 | } | 1345 | } |
| 1346 | } const_buffer; | 1346 | } const_buffer; |
| 1347 | 1347 | ||
| 1348 | INSERT_UNION_PADDING_WORDS(0x10); | 1348 | INSERT_PADDING_WORDS_NOINIT(0x10); |
| 1349 | 1349 | ||
| 1350 | struct { | 1350 | struct { |
| 1351 | union { | 1351 | union { |
| @@ -1353,18 +1353,18 @@ public: | |||
| 1353 | BitField<0, 1, u32> valid; | 1353 | BitField<0, 1, u32> valid; |
| 1354 | BitField<4, 5, u32> index; | 1354 | BitField<4, 5, u32> index; |
| 1355 | }; | 1355 | }; |
| 1356 | INSERT_UNION_PADDING_WORDS(7); | 1356 | INSERT_PADDING_WORDS_NOINIT(7); |
| 1357 | } cb_bind[MaxShaderStage]; | 1357 | } cb_bind[MaxShaderStage]; |
| 1358 | 1358 | ||
| 1359 | INSERT_UNION_PADDING_WORDS(0x56); | 1359 | INSERT_PADDING_WORDS_NOINIT(0x56); |
| 1360 | 1360 | ||
| 1361 | u32 tex_cb_index; | 1361 | u32 tex_cb_index; |
| 1362 | 1362 | ||
| 1363 | INSERT_UNION_PADDING_WORDS(0x7D); | 1363 | INSERT_PADDING_WORDS_NOINIT(0x7D); |
| 1364 | 1364 | ||
| 1365 | std::array<std::array<u8, 128>, NumTransformFeedbackBuffers> tfb_varying_locs; | 1365 | std::array<std::array<u8, 128>, NumTransformFeedbackBuffers> tfb_varying_locs; |
| 1366 | 1366 | ||
| 1367 | INSERT_UNION_PADDING_WORDS(0x298); | 1367 | INSERT_PADDING_WORDS_NOINIT(0x298); |
| 1368 | 1368 | ||
| 1369 | struct { | 1369 | struct { |
| 1370 | /// Compressed address of a buffer that holds information about bound SSBOs. | 1370 | /// Compressed address of a buffer that holds information about bound SSBOs. |
| @@ -1376,14 +1376,14 @@ public: | |||
| 1376 | } | 1376 | } |
| 1377 | } ssbo_info; | 1377 | } ssbo_info; |
| 1378 | 1378 | ||
| 1379 | INSERT_UNION_PADDING_WORDS(0x11); | 1379 | INSERT_PADDING_WORDS_NOINIT(0x11); |
| 1380 | 1380 | ||
| 1381 | struct { | 1381 | struct { |
| 1382 | u32 address[MaxShaderStage]; | 1382 | u32 address[MaxShaderStage]; |
| 1383 | u32 size[MaxShaderStage]; | 1383 | u32 size[MaxShaderStage]; |
| 1384 | } tex_info_buffers; | 1384 | } tex_info_buffers; |
| 1385 | 1385 | ||
| 1386 | INSERT_UNION_PADDING_WORDS(0xCC); | 1386 | INSERT_PADDING_WORDS_NOINIT(0xCC); |
| 1387 | }; | 1387 | }; |
| 1388 | std::array<u32, NUM_REGS> reg_array; | 1388 | std::array<u32, NUM_REGS> reg_array; |
| 1389 | }; | 1389 | }; |
diff --git a/src/video_core/engines/shader_header.h b/src/video_core/engines/shader_header.h index ceec05459..e0d7b89c5 100644 --- a/src/video_core/engines/shader_header.h +++ b/src/video_core/engines/shader_header.h | |||
| @@ -68,10 +68,10 @@ struct Header { | |||
| 68 | 68 | ||
| 69 | union { | 69 | union { |
| 70 | struct { | 70 | struct { |
| 71 | INSERT_UNION_PADDING_BYTES(3); // ImapSystemValuesA | 71 | INSERT_PADDING_BYTES_NOINIT(3); // ImapSystemValuesA |
| 72 | INSERT_UNION_PADDING_BYTES(1); // ImapSystemValuesB | 72 | INSERT_PADDING_BYTES_NOINIT(1); // ImapSystemValuesB |
| 73 | INSERT_UNION_PADDING_BYTES(16); // ImapGenericVector[32] | 73 | INSERT_PADDING_BYTES_NOINIT(16); // ImapGenericVector[32] |
| 74 | INSERT_UNION_PADDING_BYTES(2); // ImapColor | 74 | INSERT_PADDING_BYTES_NOINIT(2); // ImapColor |
| 75 | union { | 75 | union { |
| 76 | BitField<0, 8, u16> clip_distances; | 76 | BitField<0, 8, u16> clip_distances; |
| 77 | BitField<8, 1, u16> point_sprite_s; | 77 | BitField<8, 1, u16> point_sprite_s; |
| @@ -82,20 +82,20 @@ struct Header { | |||
| 82 | BitField<14, 1, u16> instance_id; | 82 | BitField<14, 1, u16> instance_id; |
| 83 | BitField<15, 1, u16> vertex_id; | 83 | BitField<15, 1, u16> vertex_id; |
| 84 | }; | 84 | }; |
| 85 | INSERT_UNION_PADDING_BYTES(5); // ImapFixedFncTexture[10] | 85 | INSERT_PADDING_BYTES_NOINIT(5); // ImapFixedFncTexture[10] |
| 86 | INSERT_UNION_PADDING_BYTES(1); // ImapReserved | 86 | INSERT_PADDING_BYTES_NOINIT(1); // ImapReserved |
| 87 | INSERT_UNION_PADDING_BYTES(3); // OmapSystemValuesA | 87 | INSERT_PADDING_BYTES_NOINIT(3); // OmapSystemValuesA |
| 88 | INSERT_UNION_PADDING_BYTES(1); // OmapSystemValuesB | 88 | INSERT_PADDING_BYTES_NOINIT(1); // OmapSystemValuesB |
| 89 | INSERT_UNION_PADDING_BYTES(16); // OmapGenericVector[32] | 89 | INSERT_PADDING_BYTES_NOINIT(16); // OmapGenericVector[32] |
| 90 | INSERT_UNION_PADDING_BYTES(2); // OmapColor | 90 | INSERT_PADDING_BYTES_NOINIT(2); // OmapColor |
| 91 | INSERT_UNION_PADDING_BYTES(2); // OmapSystemValuesC | 91 | INSERT_PADDING_BYTES_NOINIT(2); // OmapSystemValuesC |
| 92 | INSERT_UNION_PADDING_BYTES(5); // OmapFixedFncTexture[10] | 92 | INSERT_PADDING_BYTES_NOINIT(5); // OmapFixedFncTexture[10] |
| 93 | INSERT_UNION_PADDING_BYTES(1); // OmapReserved | 93 | INSERT_PADDING_BYTES_NOINIT(1); // OmapReserved |
| 94 | } vtg; | 94 | } vtg; |
| 95 | 95 | ||
| 96 | struct { | 96 | struct { |
| 97 | INSERT_UNION_PADDING_BYTES(3); // ImapSystemValuesA | 97 | INSERT_PADDING_BYTES_NOINIT(3); // ImapSystemValuesA |
| 98 | INSERT_UNION_PADDING_BYTES(1); // ImapSystemValuesB | 98 | INSERT_PADDING_BYTES_NOINIT(1); // ImapSystemValuesB |
| 99 | 99 | ||
| 100 | union { | 100 | union { |
| 101 | BitField<0, 2, PixelImap> x; | 101 | BitField<0, 2, PixelImap> x; |
| @@ -105,10 +105,10 @@ struct Header { | |||
| 105 | u8 raw; | 105 | u8 raw; |
| 106 | } imap_generic_vector[32]; | 106 | } imap_generic_vector[32]; |
| 107 | 107 | ||
| 108 | INSERT_UNION_PADDING_BYTES(2); // ImapColor | 108 | INSERT_PADDING_BYTES_NOINIT(2); // ImapColor |
| 109 | INSERT_UNION_PADDING_BYTES(2); // ImapSystemValuesC | 109 | INSERT_PADDING_BYTES_NOINIT(2); // ImapSystemValuesC |
| 110 | INSERT_UNION_PADDING_BYTES(10); // ImapFixedFncTexture[10] | 110 | INSERT_PADDING_BYTES_NOINIT(10); // ImapFixedFncTexture[10] |
| 111 | INSERT_UNION_PADDING_BYTES(2); // ImapReserved | 111 | INSERT_PADDING_BYTES_NOINIT(2); // ImapReserved |
| 112 | 112 | ||
| 113 | struct { | 113 | struct { |
| 114 | u32 target; | 114 | u32 target; |
diff --git a/src/video_core/gpu.h b/src/video_core/gpu.h index d81e38680..b4ce6b154 100644 --- a/src/video_core/gpu.h +++ b/src/video_core/gpu.h | |||
| @@ -270,7 +270,7 @@ public: | |||
| 270 | 270 | ||
| 271 | union { | 271 | union { |
| 272 | struct { | 272 | struct { |
| 273 | INSERT_UNION_PADDING_WORDS(0x4); | 273 | INSERT_PADDING_WORDS_NOINIT(0x4); |
| 274 | struct { | 274 | struct { |
| 275 | u32 address_high; | 275 | u32 address_high; |
| 276 | u32 address_low; | 276 | u32 address_low; |
| @@ -283,18 +283,18 @@ public: | |||
| 283 | 283 | ||
| 284 | u32 semaphore_sequence; | 284 | u32 semaphore_sequence; |
| 285 | u32 semaphore_trigger; | 285 | u32 semaphore_trigger; |
| 286 | INSERT_UNION_PADDING_WORDS(0xC); | 286 | INSERT_PADDING_WORDS_NOINIT(0xC); |
| 287 | 287 | ||
| 288 | // The pusher and the puller share the reference counter, the pusher only has read | 288 | // The pusher and the puller share the reference counter, the pusher only has read |
| 289 | // access | 289 | // access |
| 290 | u32 reference_count; | 290 | u32 reference_count; |
| 291 | INSERT_UNION_PADDING_WORDS(0x5); | 291 | INSERT_PADDING_WORDS_NOINIT(0x5); |
| 292 | 292 | ||
| 293 | u32 semaphore_acquire; | 293 | u32 semaphore_acquire; |
| 294 | u32 semaphore_release; | 294 | u32 semaphore_release; |
| 295 | u32 fence_value; | 295 | u32 fence_value; |
| 296 | FenceAction fence_action; | 296 | FenceAction fence_action; |
| 297 | INSERT_UNION_PADDING_WORDS(0xE2); | 297 | INSERT_PADDING_WORDS_NOINIT(0xE2); |
| 298 | 298 | ||
| 299 | // Puller state | 299 | // Puller state |
| 300 | u32 acquire_mode; | 300 | u32 acquire_mode; |
diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp index d7437e185..61796e33a 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp +++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp | |||
| @@ -23,7 +23,6 @@ | |||
| 23 | #include "video_core/renderer_vulkan/renderer_vulkan.h" | 23 | #include "video_core/renderer_vulkan/renderer_vulkan.h" |
| 24 | #include "video_core/renderer_vulkan/vk_blit_screen.h" | 24 | #include "video_core/renderer_vulkan/vk_blit_screen.h" |
| 25 | #include "video_core/renderer_vulkan/vk_master_semaphore.h" | 25 | #include "video_core/renderer_vulkan/vk_master_semaphore.h" |
| 26 | #include "video_core/renderer_vulkan/vk_memory_manager.h" | ||
| 27 | #include "video_core/renderer_vulkan/vk_rasterizer.h" | 26 | #include "video_core/renderer_vulkan/vk_rasterizer.h" |
| 28 | #include "video_core/renderer_vulkan/vk_scheduler.h" | 27 | #include "video_core/renderer_vulkan/vk_scheduler.h" |
| 29 | #include "video_core/renderer_vulkan/vk_state_tracker.h" | 28 | #include "video_core/renderer_vulkan/vk_state_tracker.h" |
| @@ -32,6 +31,7 @@ | |||
| 32 | #include "video_core/vulkan_common/vulkan_device.h" | 31 | #include "video_core/vulkan_common/vulkan_device.h" |
| 33 | #include "video_core/vulkan_common/vulkan_instance.h" | 32 | #include "video_core/vulkan_common/vulkan_instance.h" |
| 34 | #include "video_core/vulkan_common/vulkan_library.h" | 33 | #include "video_core/vulkan_common/vulkan_library.h" |
| 34 | #include "video_core/vulkan_common/vulkan_memory_allocator.h" | ||
| 35 | #include "video_core/vulkan_common/vulkan_surface.h" | 35 | #include "video_core/vulkan_common/vulkan_surface.h" |
| 36 | #include "video_core/vulkan_common/vulkan_wrapper.h" | 36 | #include "video_core/vulkan_common/vulkan_wrapper.h" |
| 37 | 37 | ||
| @@ -137,7 +137,7 @@ bool RendererVulkan::Init() try { | |||
| 137 | InitializeDevice(); | 137 | InitializeDevice(); |
| 138 | Report(); | 138 | Report(); |
| 139 | 139 | ||
| 140 | memory_manager = std::make_unique<VKMemoryManager>(*device); | 140 | memory_allocator = std::make_unique<MemoryAllocator>(*device); |
| 141 | 141 | ||
| 142 | state_tracker = std::make_unique<StateTracker>(gpu); | 142 | state_tracker = std::make_unique<StateTracker>(gpu); |
| 143 | 143 | ||
| @@ -149,11 +149,11 @@ bool RendererVulkan::Init() try { | |||
| 149 | 149 | ||
| 150 | rasterizer = std::make_unique<RasterizerVulkan>(render_window, gpu, gpu.MemoryManager(), | 150 | rasterizer = std::make_unique<RasterizerVulkan>(render_window, gpu, gpu.MemoryManager(), |
| 151 | cpu_memory, screen_info, *device, | 151 | cpu_memory, screen_info, *device, |
| 152 | *memory_manager, *state_tracker, *scheduler); | 152 | *memory_allocator, *state_tracker, *scheduler); |
| 153 | 153 | ||
| 154 | blit_screen = | 154 | blit_screen = |
| 155 | std::make_unique<VKBlitScreen>(cpu_memory, render_window, *rasterizer, *device, | 155 | std::make_unique<VKBlitScreen>(cpu_memory, render_window, *rasterizer, *device, |
| 156 | *memory_manager, *swapchain, *scheduler, screen_info); | 156 | *memory_allocator, *swapchain, *scheduler, screen_info); |
| 157 | return true; | 157 | return true; |
| 158 | 158 | ||
| 159 | } catch (const vk::Exception& exception) { | 159 | } catch (const vk::Exception& exception) { |
| @@ -172,7 +172,7 @@ void RendererVulkan::ShutDown() { | |||
| 172 | blit_screen.reset(); | 172 | blit_screen.reset(); |
| 173 | scheduler.reset(); | 173 | scheduler.reset(); |
| 174 | swapchain.reset(); | 174 | swapchain.reset(); |
| 175 | memory_manager.reset(); | 175 | memory_allocator.reset(); |
| 176 | device.reset(); | 176 | device.reset(); |
| 177 | } | 177 | } |
| 178 | 178 | ||
diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.h b/src/video_core/renderer_vulkan/renderer_vulkan.h index 5575ffc54..daf55b9b4 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.h +++ b/src/video_core/renderer_vulkan/renderer_vulkan.h | |||
| @@ -29,8 +29,8 @@ namespace Vulkan { | |||
| 29 | 29 | ||
| 30 | class Device; | 30 | class Device; |
| 31 | class StateTracker; | 31 | class StateTracker; |
| 32 | class MemoryAllocator; | ||
| 32 | class VKBlitScreen; | 33 | class VKBlitScreen; |
| 33 | class VKMemoryManager; | ||
| 34 | class VKSwapchain; | 34 | class VKSwapchain; |
| 35 | class VKScheduler; | 35 | class VKScheduler; |
| 36 | 36 | ||
| @@ -75,7 +75,7 @@ private: | |||
| 75 | 75 | ||
| 76 | vk::DebugUtilsMessenger debug_callback; | 76 | vk::DebugUtilsMessenger debug_callback; |
| 77 | std::unique_ptr<Device> device; | 77 | std::unique_ptr<Device> device; |
| 78 | std::unique_ptr<VKMemoryManager> memory_manager; | 78 | std::unique_ptr<MemoryAllocator> memory_allocator; |
| 79 | std::unique_ptr<StateTracker> state_tracker; | 79 | std::unique_ptr<StateTracker> state_tracker; |
| 80 | std::unique_ptr<VKScheduler> scheduler; | 80 | std::unique_ptr<VKScheduler> scheduler; |
| 81 | std::unique_ptr<VKSwapchain> swapchain; | 81 | std::unique_ptr<VKSwapchain> swapchain; |
diff --git a/src/video_core/renderer_vulkan/vk_blit_screen.cpp b/src/video_core/renderer_vulkan/vk_blit_screen.cpp index 5e184eb42..3e3b895e0 100644 --- a/src/video_core/renderer_vulkan/vk_blit_screen.cpp +++ b/src/video_core/renderer_vulkan/vk_blit_screen.cpp | |||
| @@ -22,13 +22,13 @@ | |||
| 22 | #include "video_core/renderer_vulkan/renderer_vulkan.h" | 22 | #include "video_core/renderer_vulkan/renderer_vulkan.h" |
| 23 | #include "video_core/renderer_vulkan/vk_blit_screen.h" | 23 | #include "video_core/renderer_vulkan/vk_blit_screen.h" |
| 24 | #include "video_core/renderer_vulkan/vk_master_semaphore.h" | 24 | #include "video_core/renderer_vulkan/vk_master_semaphore.h" |
| 25 | #include "video_core/renderer_vulkan/vk_memory_manager.h" | ||
| 26 | #include "video_core/renderer_vulkan/vk_scheduler.h" | 25 | #include "video_core/renderer_vulkan/vk_scheduler.h" |
| 27 | #include "video_core/renderer_vulkan/vk_shader_util.h" | 26 | #include "video_core/renderer_vulkan/vk_shader_util.h" |
| 28 | #include "video_core/renderer_vulkan/vk_swapchain.h" | 27 | #include "video_core/renderer_vulkan/vk_swapchain.h" |
| 29 | #include "video_core/surface.h" | 28 | #include "video_core/surface.h" |
| 30 | #include "video_core/textures/decoders.h" | 29 | #include "video_core/textures/decoders.h" |
| 31 | #include "video_core/vulkan_common/vulkan_device.h" | 30 | #include "video_core/vulkan_common/vulkan_device.h" |
| 31 | #include "video_core/vulkan_common/vulkan_memory_allocator.h" | ||
| 32 | #include "video_core/vulkan_common/vulkan_wrapper.h" | 32 | #include "video_core/vulkan_common/vulkan_wrapper.h" |
| 33 | 33 | ||
| 34 | namespace Vulkan { | 34 | namespace Vulkan { |
| @@ -115,10 +115,10 @@ struct VKBlitScreen::BufferData { | |||
| 115 | VKBlitScreen::VKBlitScreen(Core::Memory::Memory& cpu_memory_, | 115 | VKBlitScreen::VKBlitScreen(Core::Memory::Memory& cpu_memory_, |
| 116 | Core::Frontend::EmuWindow& render_window_, | 116 | Core::Frontend::EmuWindow& render_window_, |
| 117 | VideoCore::RasterizerInterface& rasterizer_, const Device& device_, | 117 | VideoCore::RasterizerInterface& rasterizer_, const Device& device_, |
| 118 | VKMemoryManager& memory_manager_, VKSwapchain& swapchain_, | 118 | MemoryAllocator& memory_allocator_, VKSwapchain& swapchain_, |
| 119 | VKScheduler& scheduler_, const VKScreenInfo& screen_info_) | 119 | VKScheduler& scheduler_, const VKScreenInfo& screen_info_) |
| 120 | : cpu_memory{cpu_memory_}, render_window{render_window_}, rasterizer{rasterizer_}, | 120 | : cpu_memory{cpu_memory_}, render_window{render_window_}, rasterizer{rasterizer_}, |
| 121 | device{device_}, memory_manager{memory_manager_}, swapchain{swapchain_}, | 121 | device{device_}, memory_allocator{memory_allocator_}, swapchain{swapchain_}, |
| 122 | scheduler{scheduler_}, image_count{swapchain.GetImageCount()}, screen_info{screen_info_} { | 122 | scheduler{scheduler_}, image_count{swapchain.GetImageCount()}, screen_info{screen_info_} { |
| 123 | resource_ticks.resize(image_count); | 123 | resource_ticks.resize(image_count); |
| 124 | 124 | ||
| @@ -150,8 +150,8 @@ VkSemaphore VKBlitScreen::Draw(const Tegra::FramebufferConfig& framebuffer, bool | |||
| 150 | SetUniformData(data, framebuffer); | 150 | SetUniformData(data, framebuffer); |
| 151 | SetVertexData(data, framebuffer); | 151 | SetVertexData(data, framebuffer); |
| 152 | 152 | ||
| 153 | auto map = buffer_commit->Map(); | 153 | const std::span<u8> map = buffer_commit.Map(); |
| 154 | std::memcpy(map.Address(), &data, sizeof(data)); | 154 | std::memcpy(map.data(), &data, sizeof(data)); |
| 155 | 155 | ||
| 156 | if (!use_accelerated) { | 156 | if (!use_accelerated) { |
| 157 | const u64 image_offset = GetRawImageOffset(framebuffer, image_index); | 157 | const u64 image_offset = GetRawImageOffset(framebuffer, image_index); |
| @@ -165,8 +165,8 @@ VkSemaphore VKBlitScreen::Draw(const Tegra::FramebufferConfig& framebuffer, bool | |||
| 165 | constexpr u32 block_height_log2 = 4; | 165 | constexpr u32 block_height_log2 = 4; |
| 166 | const u32 bytes_per_pixel = GetBytesPerPixel(framebuffer); | 166 | const u32 bytes_per_pixel = GetBytesPerPixel(framebuffer); |
| 167 | Tegra::Texture::UnswizzleTexture( | 167 | Tegra::Texture::UnswizzleTexture( |
| 168 | std::span(map.Address() + image_offset, size_bytes), std::span(host_ptr, size_bytes), | 168 | map.subspan(image_offset, size_bytes), std::span(host_ptr, size_bytes), bytes_per_pixel, |
| 169 | bytes_per_pixel, framebuffer.width, framebuffer.height, 1, block_height_log2, 0); | 169 | framebuffer.width, framebuffer.height, 1, block_height_log2, 0); |
| 170 | 170 | ||
| 171 | const VkBufferImageCopy copy{ | 171 | const VkBufferImageCopy copy{ |
| 172 | .bufferOffset = image_offset, | 172 | .bufferOffset = image_offset, |
| @@ -224,8 +224,6 @@ VkSemaphore VKBlitScreen::Draw(const Tegra::FramebufferConfig& framebuffer, bool | |||
| 224 | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, write_barrier); | 224 | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, write_barrier); |
| 225 | }); | 225 | }); |
| 226 | } | 226 | } |
| 227 | map.Release(); | ||
| 228 | |||
| 229 | scheduler.Record([renderpass = *renderpass, framebuffer = *framebuffers[image_index], | 227 | scheduler.Record([renderpass = *renderpass, framebuffer = *framebuffers[image_index], |
| 230 | descriptor_set = descriptor_sets[image_index], buffer = *buffer, | 228 | descriptor_set = descriptor_sets[image_index], buffer = *buffer, |
| 231 | size = swapchain.GetSize(), pipeline = *pipeline, | 229 | size = swapchain.GetSize(), pipeline = *pipeline, |
| @@ -642,7 +640,7 @@ void VKBlitScreen::ReleaseRawImages() { | |||
| 642 | raw_images.clear(); | 640 | raw_images.clear(); |
| 643 | raw_buffer_commits.clear(); | 641 | raw_buffer_commits.clear(); |
| 644 | buffer.reset(); | 642 | buffer.reset(); |
| 645 | buffer_commit.reset(); | 643 | buffer_commit = MemoryCommit{}; |
| 646 | } | 644 | } |
| 647 | 645 | ||
| 648 | void VKBlitScreen::CreateStagingBuffer(const Tegra::FramebufferConfig& framebuffer) { | 646 | void VKBlitScreen::CreateStagingBuffer(const Tegra::FramebufferConfig& framebuffer) { |
| @@ -659,7 +657,7 @@ void VKBlitScreen::CreateStagingBuffer(const Tegra::FramebufferConfig& framebuff | |||
| 659 | }; | 657 | }; |
| 660 | 658 | ||
| 661 | buffer = device.GetLogical().CreateBuffer(ci); | 659 | buffer = device.GetLogical().CreateBuffer(ci); |
| 662 | buffer_commit = memory_manager.Commit(buffer, true); | 660 | buffer_commit = memory_allocator.Commit(buffer, MemoryUsage::Upload); |
| 663 | } | 661 | } |
| 664 | 662 | ||
| 665 | void VKBlitScreen::CreateRawImages(const Tegra::FramebufferConfig& framebuffer) { | 663 | void VKBlitScreen::CreateRawImages(const Tegra::FramebufferConfig& framebuffer) { |
| @@ -690,7 +688,7 @@ void VKBlitScreen::CreateRawImages(const Tegra::FramebufferConfig& framebuffer) | |||
| 690 | .pQueueFamilyIndices = nullptr, | 688 | .pQueueFamilyIndices = nullptr, |
| 691 | .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, | 689 | .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, |
| 692 | }); | 690 | }); |
| 693 | raw_buffer_commits[i] = memory_manager.Commit(raw_images[i], false); | 691 | raw_buffer_commits[i] = memory_allocator.Commit(raw_images[i], MemoryUsage::DeviceLocal); |
| 694 | raw_image_views[i] = device.GetLogical().CreateImageView(VkImageViewCreateInfo{ | 692 | raw_image_views[i] = device.GetLogical().CreateImageView(VkImageViewCreateInfo{ |
| 695 | .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, | 693 | .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, |
| 696 | .pNext = nullptr, | 694 | .pNext = nullptr, |
diff --git a/src/video_core/renderer_vulkan/vk_blit_screen.h b/src/video_core/renderer_vulkan/vk_blit_screen.h index 69ed61770..b52576957 100644 --- a/src/video_core/renderer_vulkan/vk_blit_screen.h +++ b/src/video_core/renderer_vulkan/vk_blit_screen.h | |||
| @@ -6,7 +6,7 @@ | |||
| 6 | 6 | ||
| 7 | #include <memory> | 7 | #include <memory> |
| 8 | 8 | ||
| 9 | #include "video_core/renderer_vulkan/vk_memory_manager.h" | 9 | #include "video_core/vulkan_common/vulkan_memory_allocator.h" |
| 10 | #include "video_core/vulkan_common/vulkan_wrapper.h" | 10 | #include "video_core/vulkan_common/vulkan_wrapper.h" |
| 11 | 11 | ||
| 12 | namespace Core { | 12 | namespace Core { |
| @@ -43,7 +43,7 @@ public: | |||
| 43 | explicit VKBlitScreen(Core::Memory::Memory& cpu_memory, | 43 | explicit VKBlitScreen(Core::Memory::Memory& cpu_memory, |
| 44 | Core::Frontend::EmuWindow& render_window, | 44 | Core::Frontend::EmuWindow& render_window, |
| 45 | VideoCore::RasterizerInterface& rasterizer, const Device& device, | 45 | VideoCore::RasterizerInterface& rasterizer, const Device& device, |
| 46 | VKMemoryManager& memory_manager, VKSwapchain& swapchain, | 46 | MemoryAllocator& memory_allocator, VKSwapchain& swapchain, |
| 47 | VKScheduler& scheduler, const VKScreenInfo& screen_info); | 47 | VKScheduler& scheduler, const VKScreenInfo& screen_info); |
| 48 | ~VKBlitScreen(); | 48 | ~VKBlitScreen(); |
| 49 | 49 | ||
| @@ -86,7 +86,7 @@ private: | |||
| 86 | Core::Frontend::EmuWindow& render_window; | 86 | Core::Frontend::EmuWindow& render_window; |
| 87 | VideoCore::RasterizerInterface& rasterizer; | 87 | VideoCore::RasterizerInterface& rasterizer; |
| 88 | const Device& device; | 88 | const Device& device; |
| 89 | VKMemoryManager& memory_manager; | 89 | MemoryAllocator& memory_allocator; |
| 90 | VKSwapchain& swapchain; | 90 | VKSwapchain& swapchain; |
| 91 | VKScheduler& scheduler; | 91 | VKScheduler& scheduler; |
| 92 | const std::size_t image_count; | 92 | const std::size_t image_count; |
| @@ -104,14 +104,14 @@ private: | |||
| 104 | vk::Sampler sampler; | 104 | vk::Sampler sampler; |
| 105 | 105 | ||
| 106 | vk::Buffer buffer; | 106 | vk::Buffer buffer; |
| 107 | VKMemoryCommit buffer_commit; | 107 | MemoryCommit buffer_commit; |
| 108 | 108 | ||
| 109 | std::vector<u64> resource_ticks; | 109 | std::vector<u64> resource_ticks; |
| 110 | 110 | ||
| 111 | std::vector<vk::Semaphore> semaphores; | 111 | std::vector<vk::Semaphore> semaphores; |
| 112 | std::vector<vk::Image> raw_images; | 112 | std::vector<vk::Image> raw_images; |
| 113 | std::vector<vk::ImageView> raw_image_views; | 113 | std::vector<vk::ImageView> raw_image_views; |
| 114 | std::vector<VKMemoryCommit> raw_buffer_commits; | 114 | std::vector<MemoryCommit> raw_buffer_commits; |
| 115 | u32 raw_width = 0; | 115 | u32 raw_width = 0; |
| 116 | u32 raw_height = 0; | 116 | u32 raw_height = 0; |
| 117 | }; | 117 | }; |
diff --git a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp index 4d517c547..d8ad40a0f 100644 --- a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp | |||
| @@ -34,17 +34,13 @@ constexpr VkAccessFlags UPLOAD_ACCESS_BARRIERS = | |||
| 34 | constexpr VkAccessFlags TRANSFORM_FEEDBACK_WRITE_ACCESS = | 34 | constexpr VkAccessFlags TRANSFORM_FEEDBACK_WRITE_ACCESS = |
| 35 | VK_ACCESS_TRANSFORM_FEEDBACK_WRITE_BIT_EXT | VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_WRITE_BIT_EXT; | 35 | VK_ACCESS_TRANSFORM_FEEDBACK_WRITE_BIT_EXT | VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_WRITE_BIT_EXT; |
| 36 | 36 | ||
| 37 | std::unique_ptr<VKStreamBuffer> CreateStreamBuffer(const Device& device, VKScheduler& scheduler) { | ||
| 38 | return std::make_unique<VKStreamBuffer>(device, scheduler); | ||
| 39 | } | ||
| 40 | |||
| 41 | } // Anonymous namespace | 37 | } // Anonymous namespace |
| 42 | 38 | ||
| 43 | Buffer::Buffer(const Device& device_, VKMemoryManager& memory_manager, VKScheduler& scheduler_, | 39 | Buffer::Buffer(const Device& device_, MemoryAllocator& memory_allocator, VKScheduler& scheduler_, |
| 44 | VKStagingBufferPool& staging_pool_, VAddr cpu_addr_, std::size_t size_) | 40 | StagingBufferPool& staging_pool_, VAddr cpu_addr_, std::size_t size_) |
| 45 | : BufferBlock{cpu_addr_, size_}, device{device_}, scheduler{scheduler_}, staging_pool{ | 41 | : BufferBlock{cpu_addr_, size_}, device{device_}, scheduler{scheduler_}, staging_pool{ |
| 46 | staging_pool_} { | 42 | staging_pool_} { |
| 47 | const VkBufferCreateInfo ci{ | 43 | buffer = device.GetLogical().CreateBuffer(VkBufferCreateInfo{ |
| 48 | .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, | 44 | .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, |
| 49 | .pNext = nullptr, | 45 | .pNext = nullptr, |
| 50 | .flags = 0, | 46 | .flags = 0, |
| @@ -53,22 +49,20 @@ Buffer::Buffer(const Device& device_, VKMemoryManager& memory_manager, VKSchedul | |||
| 53 | .sharingMode = VK_SHARING_MODE_EXCLUSIVE, | 49 | .sharingMode = VK_SHARING_MODE_EXCLUSIVE, |
| 54 | .queueFamilyIndexCount = 0, | 50 | .queueFamilyIndexCount = 0, |
| 55 | .pQueueFamilyIndices = nullptr, | 51 | .pQueueFamilyIndices = nullptr, |
| 56 | }; | 52 | }); |
| 57 | 53 | commit = memory_allocator.Commit(buffer, MemoryUsage::DeviceLocal); | |
| 58 | buffer.handle = device.GetLogical().CreateBuffer(ci); | ||
| 59 | buffer.commit = memory_manager.Commit(buffer.handle, false); | ||
| 60 | } | 54 | } |
| 61 | 55 | ||
| 62 | Buffer::~Buffer() = default; | 56 | Buffer::~Buffer() = default; |
| 63 | 57 | ||
| 64 | void Buffer::Upload(std::size_t offset, std::size_t data_size, const u8* data) { | 58 | void Buffer::Upload(std::size_t offset, std::size_t data_size, const u8* data) { |
| 65 | const auto& staging = staging_pool.GetUnusedBuffer(data_size, true); | 59 | const auto& staging = staging_pool.Request(data_size, MemoryUsage::Upload); |
| 66 | std::memcpy(staging.commit->Map(data_size), data, data_size); | 60 | std::memcpy(staging.mapped_span.data(), data, data_size); |
| 67 | 61 | ||
| 68 | scheduler.RequestOutsideRenderPassOperationContext(); | 62 | scheduler.RequestOutsideRenderPassOperationContext(); |
| 69 | 63 | ||
| 70 | const VkBuffer handle = Handle(); | 64 | const VkBuffer handle = Handle(); |
| 71 | scheduler.Record([staging = *staging.handle, handle, offset, data_size, | 65 | scheduler.Record([staging = staging.buffer, handle, offset, data_size, |
| 72 | &device = device](vk::CommandBuffer cmdbuf) { | 66 | &device = device](vk::CommandBuffer cmdbuf) { |
| 73 | const VkBufferMemoryBarrier read_barrier{ | 67 | const VkBufferMemoryBarrier read_barrier{ |
| 74 | .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, | 68 | .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, |
| @@ -104,12 +98,12 @@ void Buffer::Upload(std::size_t offset, std::size_t data_size, const u8* data) { | |||
| 104 | } | 98 | } |
| 105 | 99 | ||
| 106 | void Buffer::Download(std::size_t offset, std::size_t data_size, u8* data) { | 100 | void Buffer::Download(std::size_t offset, std::size_t data_size, u8* data) { |
| 107 | const auto& staging = staging_pool.GetUnusedBuffer(data_size, true); | 101 | auto staging = staging_pool.Request(data_size, MemoryUsage::Download); |
| 108 | scheduler.RequestOutsideRenderPassOperationContext(); | 102 | scheduler.RequestOutsideRenderPassOperationContext(); |
| 109 | 103 | ||
| 110 | const VkBuffer handle = Handle(); | 104 | const VkBuffer handle = Handle(); |
| 111 | scheduler.Record( | 105 | scheduler.Record( |
| 112 | [staging = *staging.handle, handle, offset, data_size](vk::CommandBuffer cmdbuf) { | 106 | [staging = staging.buffer, handle, offset, data_size](vk::CommandBuffer cmdbuf) { |
| 113 | const VkBufferMemoryBarrier barrier{ | 107 | const VkBufferMemoryBarrier barrier{ |
| 114 | .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, | 108 | .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, |
| 115 | .pNext = nullptr, | 109 | .pNext = nullptr, |
| @@ -130,7 +124,7 @@ void Buffer::Download(std::size_t offset, std::size_t data_size, u8* data) { | |||
| 130 | }); | 124 | }); |
| 131 | scheduler.Finish(); | 125 | scheduler.Finish(); |
| 132 | 126 | ||
| 133 | std::memcpy(data, staging.commit->Map(data_size), data_size); | 127 | std::memcpy(data, staging.mapped_span.data(), data_size); |
| 134 | } | 128 | } |
| 135 | 129 | ||
| 136 | void Buffer::CopyFrom(const Buffer& src, std::size_t src_offset, std::size_t dst_offset, | 130 | void Buffer::CopyFrom(const Buffer& src, std::size_t src_offset, std::size_t dst_offset, |
| @@ -168,29 +162,29 @@ void Buffer::CopyFrom(const Buffer& src, std::size_t src_offset, std::size_t dst | |||
| 168 | 162 | ||
| 169 | VKBufferCache::VKBufferCache(VideoCore::RasterizerInterface& rasterizer_, | 163 | VKBufferCache::VKBufferCache(VideoCore::RasterizerInterface& rasterizer_, |
| 170 | Tegra::MemoryManager& gpu_memory_, Core::Memory::Memory& cpu_memory_, | 164 | Tegra::MemoryManager& gpu_memory_, Core::Memory::Memory& cpu_memory_, |
| 171 | const Device& device_, VKMemoryManager& memory_manager_, | 165 | const Device& device_, MemoryAllocator& memory_allocator_, |
| 172 | VKScheduler& scheduler_, VKStreamBuffer& stream_buffer_, | 166 | VKScheduler& scheduler_, VKStreamBuffer& stream_buffer_, |
| 173 | VKStagingBufferPool& staging_pool_) | 167 | StagingBufferPool& staging_pool_) |
| 174 | : VideoCommon::BufferCache<Buffer, VkBuffer, VKStreamBuffer>{rasterizer_, gpu_memory_, | 168 | : VideoCommon::BufferCache<Buffer, VkBuffer, VKStreamBuffer>{rasterizer_, gpu_memory_, |
| 175 | cpu_memory_, stream_buffer_}, | 169 | cpu_memory_, stream_buffer_}, |
| 176 | device{device_}, memory_manager{memory_manager_}, scheduler{scheduler_}, staging_pool{ | 170 | device{device_}, memory_allocator{memory_allocator_}, scheduler{scheduler_}, |
| 177 | staging_pool_} {} | 171 | staging_pool{staging_pool_} {} |
| 178 | 172 | ||
| 179 | VKBufferCache::~VKBufferCache() = default; | 173 | VKBufferCache::~VKBufferCache() = default; |
| 180 | 174 | ||
| 181 | std::shared_ptr<Buffer> VKBufferCache::CreateBlock(VAddr cpu_addr, std::size_t size) { | 175 | std::shared_ptr<Buffer> VKBufferCache::CreateBlock(VAddr cpu_addr, std::size_t size) { |
| 182 | return std::make_shared<Buffer>(device, memory_manager, scheduler, staging_pool, cpu_addr, | 176 | return std::make_shared<Buffer>(device, memory_allocator, scheduler, staging_pool, cpu_addr, |
| 183 | size); | 177 | size); |
| 184 | } | 178 | } |
| 185 | 179 | ||
| 186 | VKBufferCache::BufferInfo VKBufferCache::GetEmptyBuffer(std::size_t size) { | 180 | VKBufferCache::BufferInfo VKBufferCache::GetEmptyBuffer(std::size_t size) { |
| 187 | size = std::max(size, std::size_t(4)); | 181 | size = std::max(size, std::size_t(4)); |
| 188 | const auto& empty = staging_pool.GetUnusedBuffer(size, false); | 182 | const auto& empty = staging_pool.Request(size, MemoryUsage::DeviceLocal); |
| 189 | scheduler.RequestOutsideRenderPassOperationContext(); | 183 | scheduler.RequestOutsideRenderPassOperationContext(); |
| 190 | scheduler.Record([size, buffer = *empty.handle](vk::CommandBuffer cmdbuf) { | 184 | scheduler.Record([size, buffer = empty.buffer](vk::CommandBuffer cmdbuf) { |
| 191 | cmdbuf.FillBuffer(buffer, 0, size, 0); | 185 | cmdbuf.FillBuffer(buffer, 0, size, 0); |
| 192 | }); | 186 | }); |
| 193 | return {*empty.handle, 0, 0}; | 187 | return {empty.buffer, 0, 0}; |
| 194 | } | 188 | } |
| 195 | 189 | ||
| 196 | } // namespace Vulkan | 190 | } // namespace Vulkan |
diff --git a/src/video_core/renderer_vulkan/vk_buffer_cache.h b/src/video_core/renderer_vulkan/vk_buffer_cache.h index 1c39aed34..41d577510 100644 --- a/src/video_core/renderer_vulkan/vk_buffer_cache.h +++ b/src/video_core/renderer_vulkan/vk_buffer_cache.h | |||
| @@ -8,21 +8,20 @@ | |||
| 8 | 8 | ||
| 9 | #include "common/common_types.h" | 9 | #include "common/common_types.h" |
| 10 | #include "video_core/buffer_cache/buffer_cache.h" | 10 | #include "video_core/buffer_cache/buffer_cache.h" |
| 11 | #include "video_core/renderer_vulkan/vk_memory_manager.h" | ||
| 12 | #include "video_core/renderer_vulkan/vk_staging_buffer_pool.h" | 11 | #include "video_core/renderer_vulkan/vk_staging_buffer_pool.h" |
| 13 | #include "video_core/renderer_vulkan/vk_stream_buffer.h" | 12 | #include "video_core/renderer_vulkan/vk_stream_buffer.h" |
| 13 | #include "video_core/vulkan_common/vulkan_memory_allocator.h" | ||
| 14 | #include "video_core/vulkan_common/vulkan_wrapper.h" | 14 | #include "video_core/vulkan_common/vulkan_wrapper.h" |
| 15 | 15 | ||
| 16 | namespace Vulkan { | 16 | namespace Vulkan { |
| 17 | 17 | ||
| 18 | class Device; | 18 | class Device; |
| 19 | class VKMemoryManager; | ||
| 20 | class VKScheduler; | 19 | class VKScheduler; |
| 21 | 20 | ||
| 22 | class Buffer final : public VideoCommon::BufferBlock { | 21 | class Buffer final : public VideoCommon::BufferBlock { |
| 23 | public: | 22 | public: |
| 24 | explicit Buffer(const Device& device, VKMemoryManager& memory_manager, VKScheduler& scheduler, | 23 | explicit Buffer(const Device& device, MemoryAllocator& memory_allocator, VKScheduler& scheduler, |
| 25 | VKStagingBufferPool& staging_pool, VAddr cpu_addr_, std::size_t size_); | 24 | StagingBufferPool& staging_pool, VAddr cpu_addr_, std::size_t size_); |
| 26 | ~Buffer(); | 25 | ~Buffer(); |
| 27 | 26 | ||
| 28 | void Upload(std::size_t offset, std::size_t data_size, const u8* data); | 27 | void Upload(std::size_t offset, std::size_t data_size, const u8* data); |
| @@ -33,7 +32,7 @@ public: | |||
| 33 | std::size_t copy_size); | 32 | std::size_t copy_size); |
| 34 | 33 | ||
| 35 | VkBuffer Handle() const { | 34 | VkBuffer Handle() const { |
| 36 | return *buffer.handle; | 35 | return *buffer; |
| 37 | } | 36 | } |
| 38 | 37 | ||
| 39 | u64 Address() const { | 38 | u64 Address() const { |
| @@ -43,18 +42,19 @@ public: | |||
| 43 | private: | 42 | private: |
| 44 | const Device& device; | 43 | const Device& device; |
| 45 | VKScheduler& scheduler; | 44 | VKScheduler& scheduler; |
| 46 | VKStagingBufferPool& staging_pool; | 45 | StagingBufferPool& staging_pool; |
| 47 | 46 | ||
| 48 | VKBuffer buffer; | 47 | vk::Buffer buffer; |
| 48 | MemoryCommit commit; | ||
| 49 | }; | 49 | }; |
| 50 | 50 | ||
| 51 | class VKBufferCache final : public VideoCommon::BufferCache<Buffer, VkBuffer, VKStreamBuffer> { | 51 | class VKBufferCache final : public VideoCommon::BufferCache<Buffer, VkBuffer, VKStreamBuffer> { |
| 52 | public: | 52 | public: |
| 53 | explicit VKBufferCache(VideoCore::RasterizerInterface& rasterizer, | 53 | explicit VKBufferCache(VideoCore::RasterizerInterface& rasterizer, |
| 54 | Tegra::MemoryManager& gpu_memory, Core::Memory::Memory& cpu_memory, | 54 | Tegra::MemoryManager& gpu_memory, Core::Memory::Memory& cpu_memory, |
| 55 | const Device& device, VKMemoryManager& memory_manager, | 55 | const Device& device, MemoryAllocator& memory_allocator, |
| 56 | VKScheduler& scheduler, VKStreamBuffer& stream_buffer, | 56 | VKScheduler& scheduler, VKStreamBuffer& stream_buffer, |
| 57 | VKStagingBufferPool& staging_pool); | 57 | StagingBufferPool& staging_pool); |
| 58 | ~VKBufferCache(); | 58 | ~VKBufferCache(); |
| 59 | 59 | ||
| 60 | BufferInfo GetEmptyBuffer(std::size_t size) override; | 60 | BufferInfo GetEmptyBuffer(std::size_t size) override; |
| @@ -64,9 +64,9 @@ protected: | |||
| 64 | 64 | ||
| 65 | private: | 65 | private: |
| 66 | const Device& device; | 66 | const Device& device; |
| 67 | VKMemoryManager& memory_manager; | 67 | MemoryAllocator& memory_allocator; |
| 68 | VKScheduler& scheduler; | 68 | VKScheduler& scheduler; |
| 69 | VKStagingBufferPool& staging_pool; | 69 | StagingBufferPool& staging_pool; |
| 70 | }; | 70 | }; |
| 71 | 71 | ||
| 72 | } // namespace Vulkan | 72 | } // namespace Vulkan |
diff --git a/src/video_core/renderer_vulkan/vk_compute_pass.cpp b/src/video_core/renderer_vulkan/vk_compute_pass.cpp index 02a6d54b7..5eb6a54be 100644 --- a/src/video_core/renderer_vulkan/vk_compute_pass.cpp +++ b/src/video_core/renderer_vulkan/vk_compute_pass.cpp | |||
| @@ -164,7 +164,7 @@ VkDescriptorSet VKComputePass::CommitDescriptorSet( | |||
| 164 | 164 | ||
| 165 | QuadArrayPass::QuadArrayPass(const Device& device_, VKScheduler& scheduler_, | 165 | QuadArrayPass::QuadArrayPass(const Device& device_, VKScheduler& scheduler_, |
| 166 | VKDescriptorPool& descriptor_pool_, | 166 | VKDescriptorPool& descriptor_pool_, |
| 167 | VKStagingBufferPool& staging_buffer_pool_, | 167 | StagingBufferPool& staging_buffer_pool_, |
| 168 | VKUpdateDescriptorQueue& update_descriptor_queue_) | 168 | VKUpdateDescriptorQueue& update_descriptor_queue_) |
| 169 | : VKComputePass(device_, descriptor_pool_, BuildQuadArrayPassDescriptorSetLayoutBinding(), | 169 | : VKComputePass(device_, descriptor_pool_, BuildQuadArrayPassDescriptorSetLayoutBinding(), |
| 170 | BuildQuadArrayPassDescriptorUpdateTemplateEntry(), | 170 | BuildQuadArrayPassDescriptorUpdateTemplateEntry(), |
| @@ -177,18 +177,18 @@ QuadArrayPass::~QuadArrayPass() = default; | |||
| 177 | std::pair<VkBuffer, VkDeviceSize> QuadArrayPass::Assemble(u32 num_vertices, u32 first) { | 177 | std::pair<VkBuffer, VkDeviceSize> QuadArrayPass::Assemble(u32 num_vertices, u32 first) { |
| 178 | const u32 num_triangle_vertices = (num_vertices / 4) * 6; | 178 | const u32 num_triangle_vertices = (num_vertices / 4) * 6; |
| 179 | const std::size_t staging_size = num_triangle_vertices * sizeof(u32); | 179 | const std::size_t staging_size = num_triangle_vertices * sizeof(u32); |
| 180 | auto& buffer = staging_buffer_pool.GetUnusedBuffer(staging_size, false); | 180 | const auto staging_ref = staging_buffer_pool.Request(staging_size, MemoryUsage::DeviceLocal); |
| 181 | 181 | ||
| 182 | update_descriptor_queue.Acquire(); | 182 | update_descriptor_queue.Acquire(); |
| 183 | update_descriptor_queue.AddBuffer(*buffer.handle, 0, staging_size); | 183 | update_descriptor_queue.AddBuffer(staging_ref.buffer, 0, staging_size); |
| 184 | const VkDescriptorSet set = CommitDescriptorSet(update_descriptor_queue); | 184 | const VkDescriptorSet set = CommitDescriptorSet(update_descriptor_queue); |
| 185 | 185 | ||
| 186 | scheduler.RequestOutsideRenderPassOperationContext(); | 186 | scheduler.RequestOutsideRenderPassOperationContext(); |
| 187 | 187 | ||
| 188 | ASSERT(num_vertices % 4 == 0); | 188 | ASSERT(num_vertices % 4 == 0); |
| 189 | const u32 num_quads = num_vertices / 4; | 189 | const u32 num_quads = num_vertices / 4; |
| 190 | scheduler.Record([layout = *layout, pipeline = *pipeline, buffer = *buffer.handle, num_quads, | 190 | scheduler.Record([layout = *layout, pipeline = *pipeline, buffer = staging_ref.buffer, |
| 191 | first, set](vk::CommandBuffer cmdbuf) { | 191 | num_quads, first, set](vk::CommandBuffer cmdbuf) { |
| 192 | constexpr u32 dispatch_size = 1024; | 192 | constexpr u32 dispatch_size = 1024; |
| 193 | cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_COMPUTE, pipeline); | 193 | cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_COMPUTE, pipeline); |
| 194 | cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_COMPUTE, layout, 0, set, {}); | 194 | cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_COMPUTE, layout, 0, set, {}); |
| @@ -208,11 +208,11 @@ std::pair<VkBuffer, VkDeviceSize> QuadArrayPass::Assemble(u32 num_vertices, u32 | |||
| 208 | cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, | 208 | cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, |
| 209 | VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, 0, {}, {barrier}, {}); | 209 | VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, 0, {}, {barrier}, {}); |
| 210 | }); | 210 | }); |
| 211 | return {*buffer.handle, 0}; | 211 | return {staging_ref.buffer, 0}; |
| 212 | } | 212 | } |
| 213 | 213 | ||
| 214 | Uint8Pass::Uint8Pass(const Device& device, VKScheduler& scheduler_, | 214 | Uint8Pass::Uint8Pass(const Device& device, VKScheduler& scheduler_, |
| 215 | VKDescriptorPool& descriptor_pool, VKStagingBufferPool& staging_buffer_pool_, | 215 | VKDescriptorPool& descriptor_pool, StagingBufferPool& staging_buffer_pool_, |
| 216 | VKUpdateDescriptorQueue& update_descriptor_queue_) | 216 | VKUpdateDescriptorQueue& update_descriptor_queue_) |
| 217 | : VKComputePass(device, descriptor_pool, BuildInputOutputDescriptorSetBindings(), | 217 | : VKComputePass(device, descriptor_pool, BuildInputOutputDescriptorSetBindings(), |
| 218 | BuildInputOutputDescriptorUpdateTemplate(), {}, VULKAN_UINT8_COMP_SPV), | 218 | BuildInputOutputDescriptorUpdateTemplate(), {}, VULKAN_UINT8_COMP_SPV), |
| @@ -224,15 +224,15 @@ Uint8Pass::~Uint8Pass() = default; | |||
| 224 | std::pair<VkBuffer, u64> Uint8Pass::Assemble(u32 num_vertices, VkBuffer src_buffer, | 224 | std::pair<VkBuffer, u64> Uint8Pass::Assemble(u32 num_vertices, VkBuffer src_buffer, |
| 225 | u64 src_offset) { | 225 | u64 src_offset) { |
| 226 | const u32 staging_size = static_cast<u32>(num_vertices * sizeof(u16)); | 226 | const u32 staging_size = static_cast<u32>(num_vertices * sizeof(u16)); |
| 227 | auto& buffer = staging_buffer_pool.GetUnusedBuffer(staging_size, false); | 227 | const auto staging_ref = staging_buffer_pool.Request(staging_size, MemoryUsage::DeviceLocal); |
| 228 | 228 | ||
| 229 | update_descriptor_queue.Acquire(); | 229 | update_descriptor_queue.Acquire(); |
| 230 | update_descriptor_queue.AddBuffer(src_buffer, src_offset, num_vertices); | 230 | update_descriptor_queue.AddBuffer(src_buffer, src_offset, num_vertices); |
| 231 | update_descriptor_queue.AddBuffer(*buffer.handle, 0, staging_size); | 231 | update_descriptor_queue.AddBuffer(staging_ref.buffer, 0, staging_size); |
| 232 | const VkDescriptorSet set = CommitDescriptorSet(update_descriptor_queue); | 232 | const VkDescriptorSet set = CommitDescriptorSet(update_descriptor_queue); |
| 233 | 233 | ||
| 234 | scheduler.RequestOutsideRenderPassOperationContext(); | 234 | scheduler.RequestOutsideRenderPassOperationContext(); |
| 235 | scheduler.Record([layout = *layout, pipeline = *pipeline, buffer = *buffer.handle, set, | 235 | scheduler.Record([layout = *layout, pipeline = *pipeline, buffer = staging_ref.buffer, set, |
| 236 | num_vertices](vk::CommandBuffer cmdbuf) { | 236 | num_vertices](vk::CommandBuffer cmdbuf) { |
| 237 | constexpr u32 dispatch_size = 1024; | 237 | constexpr u32 dispatch_size = 1024; |
| 238 | cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_COMPUTE, pipeline); | 238 | cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_COMPUTE, pipeline); |
| @@ -252,12 +252,12 @@ std::pair<VkBuffer, u64> Uint8Pass::Assemble(u32 num_vertices, VkBuffer src_buff | |||
| 252 | cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, | 252 | cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, |
| 253 | VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, 0, {}, barrier, {}); | 253 | VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, 0, {}, barrier, {}); |
| 254 | }); | 254 | }); |
| 255 | return {*buffer.handle, 0}; | 255 | return {staging_ref.buffer, 0}; |
| 256 | } | 256 | } |
| 257 | 257 | ||
| 258 | QuadIndexedPass::QuadIndexedPass(const Device& device_, VKScheduler& scheduler_, | 258 | QuadIndexedPass::QuadIndexedPass(const Device& device_, VKScheduler& scheduler_, |
| 259 | VKDescriptorPool& descriptor_pool_, | 259 | VKDescriptorPool& descriptor_pool_, |
| 260 | VKStagingBufferPool& staging_buffer_pool_, | 260 | StagingBufferPool& staging_buffer_pool_, |
| 261 | VKUpdateDescriptorQueue& update_descriptor_queue_) | 261 | VKUpdateDescriptorQueue& update_descriptor_queue_) |
| 262 | : VKComputePass(device_, descriptor_pool_, BuildInputOutputDescriptorSetBindings(), | 262 | : VKComputePass(device_, descriptor_pool_, BuildInputOutputDescriptorSetBindings(), |
| 263 | BuildInputOutputDescriptorUpdateTemplate(), | 263 | BuildInputOutputDescriptorUpdateTemplate(), |
| @@ -286,15 +286,15 @@ std::pair<VkBuffer, u64> QuadIndexedPass::Assemble( | |||
| 286 | const u32 num_tri_vertices = (num_vertices / 4) * 6; | 286 | const u32 num_tri_vertices = (num_vertices / 4) * 6; |
| 287 | 287 | ||
| 288 | const std::size_t staging_size = num_tri_vertices * sizeof(u32); | 288 | const std::size_t staging_size = num_tri_vertices * sizeof(u32); |
| 289 | auto& buffer = staging_buffer_pool.GetUnusedBuffer(staging_size, false); | 289 | const auto staging_ref = staging_buffer_pool.Request(staging_size, MemoryUsage::DeviceLocal); |
| 290 | 290 | ||
| 291 | update_descriptor_queue.Acquire(); | 291 | update_descriptor_queue.Acquire(); |
| 292 | update_descriptor_queue.AddBuffer(src_buffer, src_offset, input_size); | 292 | update_descriptor_queue.AddBuffer(src_buffer, src_offset, input_size); |
| 293 | update_descriptor_queue.AddBuffer(*buffer.handle, 0, staging_size); | 293 | update_descriptor_queue.AddBuffer(staging_ref.buffer, 0, staging_size); |
| 294 | const VkDescriptorSet set = CommitDescriptorSet(update_descriptor_queue); | 294 | const VkDescriptorSet set = CommitDescriptorSet(update_descriptor_queue); |
| 295 | 295 | ||
| 296 | scheduler.RequestOutsideRenderPassOperationContext(); | 296 | scheduler.RequestOutsideRenderPassOperationContext(); |
| 297 | scheduler.Record([layout = *layout, pipeline = *pipeline, buffer = *buffer.handle, set, | 297 | scheduler.Record([layout = *layout, pipeline = *pipeline, buffer = staging_ref.buffer, set, |
| 298 | num_tri_vertices, base_vertex, index_shift](vk::CommandBuffer cmdbuf) { | 298 | num_tri_vertices, base_vertex, index_shift](vk::CommandBuffer cmdbuf) { |
| 299 | static constexpr u32 dispatch_size = 1024; | 299 | static constexpr u32 dispatch_size = 1024; |
| 300 | const std::array push_constants = {base_vertex, index_shift}; | 300 | const std::array push_constants = {base_vertex, index_shift}; |
| @@ -317,7 +317,7 @@ std::pair<VkBuffer, u64> QuadIndexedPass::Assemble( | |||
| 317 | cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, | 317 | cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, |
| 318 | VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, 0, {}, barrier, {}); | 318 | VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, 0, {}, barrier, {}); |
| 319 | }); | 319 | }); |
| 320 | return {*buffer.handle, 0}; | 320 | return {staging_ref.buffer, 0}; |
| 321 | } | 321 | } |
| 322 | 322 | ||
| 323 | } // namespace Vulkan | 323 | } // namespace Vulkan |
diff --git a/src/video_core/renderer_vulkan/vk_compute_pass.h b/src/video_core/renderer_vulkan/vk_compute_pass.h index 7ddb09afb..f5c6f5f17 100644 --- a/src/video_core/renderer_vulkan/vk_compute_pass.h +++ b/src/video_core/renderer_vulkan/vk_compute_pass.h | |||
| @@ -16,8 +16,8 @@ | |||
| 16 | namespace Vulkan { | 16 | namespace Vulkan { |
| 17 | 17 | ||
| 18 | class Device; | 18 | class Device; |
| 19 | class StagingBufferPool; | ||
| 19 | class VKScheduler; | 20 | class VKScheduler; |
| 20 | class VKStagingBufferPool; | ||
| 21 | class VKUpdateDescriptorQueue; | 21 | class VKUpdateDescriptorQueue; |
| 22 | 22 | ||
| 23 | class VKComputePass { | 23 | class VKComputePass { |
| @@ -45,7 +45,7 @@ class QuadArrayPass final : public VKComputePass { | |||
| 45 | public: | 45 | public: |
| 46 | explicit QuadArrayPass(const Device& device_, VKScheduler& scheduler_, | 46 | explicit QuadArrayPass(const Device& device_, VKScheduler& scheduler_, |
| 47 | VKDescriptorPool& descriptor_pool_, | 47 | VKDescriptorPool& descriptor_pool_, |
| 48 | VKStagingBufferPool& staging_buffer_pool_, | 48 | StagingBufferPool& staging_buffer_pool_, |
| 49 | VKUpdateDescriptorQueue& update_descriptor_queue_); | 49 | VKUpdateDescriptorQueue& update_descriptor_queue_); |
| 50 | ~QuadArrayPass(); | 50 | ~QuadArrayPass(); |
| 51 | 51 | ||
| @@ -53,15 +53,14 @@ public: | |||
| 53 | 53 | ||
| 54 | private: | 54 | private: |
| 55 | VKScheduler& scheduler; | 55 | VKScheduler& scheduler; |
| 56 | VKStagingBufferPool& staging_buffer_pool; | 56 | StagingBufferPool& staging_buffer_pool; |
| 57 | VKUpdateDescriptorQueue& update_descriptor_queue; | 57 | VKUpdateDescriptorQueue& update_descriptor_queue; |
| 58 | }; | 58 | }; |
| 59 | 59 | ||
| 60 | class Uint8Pass final : public VKComputePass { | 60 | class Uint8Pass final : public VKComputePass { |
| 61 | public: | 61 | public: |
| 62 | explicit Uint8Pass(const Device& device_, VKScheduler& scheduler_, | 62 | explicit Uint8Pass(const Device& device_, VKScheduler& scheduler_, |
| 63 | VKDescriptorPool& descriptor_pool_, | 63 | VKDescriptorPool& descriptor_pool_, StagingBufferPool& staging_buffer_pool_, |
| 64 | VKStagingBufferPool& staging_buffer_pool_, | ||
| 65 | VKUpdateDescriptorQueue& update_descriptor_queue_); | 64 | VKUpdateDescriptorQueue& update_descriptor_queue_); |
| 66 | ~Uint8Pass(); | 65 | ~Uint8Pass(); |
| 67 | 66 | ||
| @@ -69,7 +68,7 @@ public: | |||
| 69 | 68 | ||
| 70 | private: | 69 | private: |
| 71 | VKScheduler& scheduler; | 70 | VKScheduler& scheduler; |
| 72 | VKStagingBufferPool& staging_buffer_pool; | 71 | StagingBufferPool& staging_buffer_pool; |
| 73 | VKUpdateDescriptorQueue& update_descriptor_queue; | 72 | VKUpdateDescriptorQueue& update_descriptor_queue; |
| 74 | }; | 73 | }; |
| 75 | 74 | ||
| @@ -77,7 +76,7 @@ class QuadIndexedPass final : public VKComputePass { | |||
| 77 | public: | 76 | public: |
| 78 | explicit QuadIndexedPass(const Device& device_, VKScheduler& scheduler_, | 77 | explicit QuadIndexedPass(const Device& device_, VKScheduler& scheduler_, |
| 79 | VKDescriptorPool& descriptor_pool_, | 78 | VKDescriptorPool& descriptor_pool_, |
| 80 | VKStagingBufferPool& staging_buffer_pool_, | 79 | StagingBufferPool& staging_buffer_pool_, |
| 81 | VKUpdateDescriptorQueue& update_descriptor_queue_); | 80 | VKUpdateDescriptorQueue& update_descriptor_queue_); |
| 82 | ~QuadIndexedPass(); | 81 | ~QuadIndexedPass(); |
| 83 | 82 | ||
| @@ -87,7 +86,7 @@ public: | |||
| 87 | 86 | ||
| 88 | private: | 87 | private: |
| 89 | VKScheduler& scheduler; | 88 | VKScheduler& scheduler; |
| 90 | VKStagingBufferPool& staging_buffer_pool; | 89 | StagingBufferPool& staging_buffer_pool; |
| 91 | VKUpdateDescriptorQueue& update_descriptor_queue; | 90 | VKUpdateDescriptorQueue& update_descriptor_queue; |
| 92 | }; | 91 | }; |
| 93 | 92 | ||
diff --git a/src/video_core/renderer_vulkan/vk_fence_manager.cpp b/src/video_core/renderer_vulkan/vk_fence_manager.cpp index 4c5bc0aa1..6cd00884d 100644 --- a/src/video_core/renderer_vulkan/vk_fence_manager.cpp +++ b/src/video_core/renderer_vulkan/vk_fence_manager.cpp | |||
| @@ -3,7 +3,6 @@ | |||
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include <memory> | 5 | #include <memory> |
| 6 | #include <thread> | ||
| 7 | 6 | ||
| 8 | #include "video_core/renderer_vulkan/vk_buffer_cache.h" | 7 | #include "video_core/renderer_vulkan/vk_buffer_cache.h" |
| 9 | #include "video_core/renderer_vulkan/vk_fence_manager.h" | 8 | #include "video_core/renderer_vulkan/vk_fence_manager.h" |
| @@ -14,13 +13,11 @@ | |||
| 14 | 13 | ||
| 15 | namespace Vulkan { | 14 | namespace Vulkan { |
| 16 | 15 | ||
| 17 | InnerFence::InnerFence(const Device& device_, VKScheduler& scheduler_, u32 payload_, | 16 | InnerFence::InnerFence(VKScheduler& scheduler_, u32 payload_, bool is_stubbed_) |
| 18 | bool is_stubbed_) | 17 | : FenceBase{payload_, is_stubbed_}, scheduler{scheduler_} {} |
| 19 | : FenceBase{payload_, is_stubbed_}, device{device_}, scheduler{scheduler_} {} | ||
| 20 | 18 | ||
| 21 | InnerFence::InnerFence(const Device& device_, VKScheduler& scheduler_, GPUVAddr address_, | 19 | InnerFence::InnerFence(VKScheduler& scheduler_, GPUVAddr address_, u32 payload_, bool is_stubbed_) |
| 22 | u32 payload_, bool is_stubbed_) | 20 | : FenceBase{address_, payload_, is_stubbed_}, scheduler{scheduler_} {} |
| 23 | : FenceBase{address_, payload_, is_stubbed_}, device{device_}, scheduler{scheduler_} {} | ||
| 24 | 21 | ||
| 25 | InnerFence::~InnerFence() = default; | 22 | InnerFence::~InnerFence() = default; |
| 26 | 23 | ||
| @@ -28,63 +25,38 @@ void InnerFence::Queue() { | |||
| 28 | if (is_stubbed) { | 25 | if (is_stubbed) { |
| 29 | return; | 26 | return; |
| 30 | } | 27 | } |
| 31 | ASSERT(!event); | 28 | // Get the current tick so we can wait for it |
| 32 | 29 | wait_tick = scheduler.CurrentTick(); | |
| 33 | event = device.GetLogical().CreateEvent(); | 30 | scheduler.Flush(); |
| 34 | ticks = scheduler.CurrentTick(); | ||
| 35 | |||
| 36 | scheduler.RequestOutsideRenderPassOperationContext(); | ||
| 37 | scheduler.Record([event = *event](vk::CommandBuffer cmdbuf) { | ||
| 38 | cmdbuf.SetEvent(event, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT); | ||
| 39 | }); | ||
| 40 | } | 31 | } |
| 41 | 32 | ||
| 42 | bool InnerFence::IsSignaled() const { | 33 | bool InnerFence::IsSignaled() const { |
| 43 | if (is_stubbed) { | 34 | if (is_stubbed) { |
| 44 | return true; | 35 | return true; |
| 45 | } | 36 | } |
| 46 | ASSERT(event); | 37 | return scheduler.IsFree(wait_tick); |
| 47 | return IsEventSignalled(); | ||
| 48 | } | 38 | } |
| 49 | 39 | ||
| 50 | void InnerFence::Wait() { | 40 | void InnerFence::Wait() { |
| 51 | if (is_stubbed) { | 41 | if (is_stubbed) { |
| 52 | return; | 42 | return; |
| 53 | } | 43 | } |
| 54 | ASSERT(event); | 44 | scheduler.Wait(wait_tick); |
| 55 | |||
| 56 | if (ticks >= scheduler.CurrentTick()) { | ||
| 57 | scheduler.Flush(); | ||
| 58 | } | ||
| 59 | while (!IsEventSignalled()) { | ||
| 60 | std::this_thread::yield(); | ||
| 61 | } | ||
| 62 | } | ||
| 63 | |||
| 64 | bool InnerFence::IsEventSignalled() const { | ||
| 65 | switch (const VkResult result = event.GetStatus()) { | ||
| 66 | case VK_EVENT_SET: | ||
| 67 | return true; | ||
| 68 | case VK_EVENT_RESET: | ||
| 69 | return false; | ||
| 70 | default: | ||
| 71 | throw vk::Exception(result); | ||
| 72 | } | ||
| 73 | } | 45 | } |
| 74 | 46 | ||
| 75 | VKFenceManager::VKFenceManager(VideoCore::RasterizerInterface& rasterizer_, Tegra::GPU& gpu_, | 47 | VKFenceManager::VKFenceManager(VideoCore::RasterizerInterface& rasterizer_, Tegra::GPU& gpu_, |
| 76 | Tegra::MemoryManager& memory_manager_, TextureCache& texture_cache_, | 48 | Tegra::MemoryManager& memory_manager_, TextureCache& texture_cache_, |
| 77 | VKBufferCache& buffer_cache_, VKQueryCache& query_cache_, | 49 | VKBufferCache& buffer_cache_, VKQueryCache& query_cache_, |
| 78 | const Device& device_, VKScheduler& scheduler_) | 50 | VKScheduler& scheduler_) |
| 79 | : GenericFenceManager{rasterizer_, gpu_, texture_cache_, buffer_cache_, query_cache_}, | 51 | : GenericFenceManager{rasterizer_, gpu_, texture_cache_, buffer_cache_, query_cache_}, |
| 80 | device{device_}, scheduler{scheduler_} {} | 52 | scheduler{scheduler_} {} |
| 81 | 53 | ||
| 82 | Fence VKFenceManager::CreateFence(u32 value, bool is_stubbed) { | 54 | Fence VKFenceManager::CreateFence(u32 value, bool is_stubbed) { |
| 83 | return std::make_shared<InnerFence>(device, scheduler, value, is_stubbed); | 55 | return std::make_shared<InnerFence>(scheduler, value, is_stubbed); |
| 84 | } | 56 | } |
| 85 | 57 | ||
| 86 | Fence VKFenceManager::CreateFence(GPUVAddr addr, u32 value, bool is_stubbed) { | 58 | Fence VKFenceManager::CreateFence(GPUVAddr addr, u32 value, bool is_stubbed) { |
| 87 | return std::make_shared<InnerFence>(device, scheduler, addr, value, is_stubbed); | 59 | return std::make_shared<InnerFence>(scheduler, addr, value, is_stubbed); |
| 88 | } | 60 | } |
| 89 | 61 | ||
| 90 | void VKFenceManager::QueueFence(Fence& fence) { | 62 | void VKFenceManager::QueueFence(Fence& fence) { |
diff --git a/src/video_core/renderer_vulkan/vk_fence_manager.h b/src/video_core/renderer_vulkan/vk_fence_manager.h index 6b51e4587..9c5e5aa8f 100644 --- a/src/video_core/renderer_vulkan/vk_fence_manager.h +++ b/src/video_core/renderer_vulkan/vk_fence_manager.h | |||
| @@ -28,10 +28,8 @@ class VKScheduler; | |||
| 28 | 28 | ||
| 29 | class InnerFence : public VideoCommon::FenceBase { | 29 | class InnerFence : public VideoCommon::FenceBase { |
| 30 | public: | 30 | public: |
| 31 | explicit InnerFence(const Device& device_, VKScheduler& scheduler_, u32 payload_, | 31 | explicit InnerFence(VKScheduler& scheduler_, u32 payload_, bool is_stubbed_); |
| 32 | bool is_stubbed_); | 32 | explicit InnerFence(VKScheduler& scheduler_, GPUVAddr address_, u32 payload_, bool is_stubbed_); |
| 33 | explicit InnerFence(const Device& device_, VKScheduler& scheduler_, GPUVAddr address_, | ||
| 34 | u32 payload_, bool is_stubbed_); | ||
| 35 | ~InnerFence(); | 33 | ~InnerFence(); |
| 36 | 34 | ||
| 37 | void Queue(); | 35 | void Queue(); |
| @@ -41,12 +39,8 @@ public: | |||
| 41 | void Wait(); | 39 | void Wait(); |
| 42 | 40 | ||
| 43 | private: | 41 | private: |
| 44 | bool IsEventSignalled() const; | ||
| 45 | |||
| 46 | const Device& device; | ||
| 47 | VKScheduler& scheduler; | 42 | VKScheduler& scheduler; |
| 48 | vk::Event event; | 43 | u64 wait_tick = 0; |
| 49 | u64 ticks = 0; | ||
| 50 | }; | 44 | }; |
| 51 | using Fence = std::shared_ptr<InnerFence>; | 45 | using Fence = std::shared_ptr<InnerFence>; |
| 52 | 46 | ||
| @@ -58,7 +52,7 @@ public: | |||
| 58 | explicit VKFenceManager(VideoCore::RasterizerInterface& rasterizer_, Tegra::GPU& gpu_, | 52 | explicit VKFenceManager(VideoCore::RasterizerInterface& rasterizer_, Tegra::GPU& gpu_, |
| 59 | Tegra::MemoryManager& memory_manager_, TextureCache& texture_cache_, | 53 | Tegra::MemoryManager& memory_manager_, TextureCache& texture_cache_, |
| 60 | VKBufferCache& buffer_cache_, VKQueryCache& query_cache_, | 54 | VKBufferCache& buffer_cache_, VKQueryCache& query_cache_, |
| 61 | const Device& device_, VKScheduler& scheduler_); | 55 | VKScheduler& scheduler_); |
| 62 | 56 | ||
| 63 | protected: | 57 | protected: |
| 64 | Fence CreateFence(u32 value, bool is_stubbed) override; | 58 | Fence CreateFence(u32 value, bool is_stubbed) override; |
| @@ -68,7 +62,6 @@ protected: | |||
| 68 | void WaitFence(Fence& fence) override; | 62 | void WaitFence(Fence& fence) override; |
| 69 | 63 | ||
| 70 | private: | 64 | private: |
| 71 | const Device& device; | ||
| 72 | VKScheduler& scheduler; | 65 | VKScheduler& scheduler; |
| 73 | }; | 66 | }; |
| 74 | 67 | ||
diff --git a/src/video_core/renderer_vulkan/vk_memory_manager.cpp b/src/video_core/renderer_vulkan/vk_memory_manager.cpp deleted file mode 100644 index a6abd0eee..000000000 --- a/src/video_core/renderer_vulkan/vk_memory_manager.cpp +++ /dev/null | |||
| @@ -1,230 +0,0 @@ | |||
| 1 | // Copyright 2018 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <algorithm> | ||
| 6 | #include <optional> | ||
| 7 | #include <tuple> | ||
| 8 | #include <vector> | ||
| 9 | |||
| 10 | #include "common/alignment.h" | ||
| 11 | #include "common/assert.h" | ||
| 12 | #include "common/common_types.h" | ||
| 13 | #include "common/logging/log.h" | ||
| 14 | #include "video_core/renderer_vulkan/vk_memory_manager.h" | ||
| 15 | #include "video_core/vulkan_common/vulkan_device.h" | ||
| 16 | #include "video_core/vulkan_common/vulkan_wrapper.h" | ||
| 17 | |||
| 18 | namespace Vulkan { | ||
| 19 | |||
| 20 | namespace { | ||
| 21 | |||
| 22 | u64 GetAllocationChunkSize(u64 required_size) { | ||
| 23 | static constexpr u64 sizes[] = {16ULL << 20, 32ULL << 20, 64ULL << 20, 128ULL << 20}; | ||
| 24 | auto it = std::lower_bound(std::begin(sizes), std::end(sizes), required_size); | ||
| 25 | return it != std::end(sizes) ? *it : Common::AlignUp(required_size, 256ULL << 20); | ||
| 26 | } | ||
| 27 | |||
| 28 | } // Anonymous namespace | ||
| 29 | |||
| 30 | class VKMemoryAllocation final { | ||
| 31 | public: | ||
| 32 | explicit VKMemoryAllocation(const Device& device_, vk::DeviceMemory memory_, | ||
| 33 | VkMemoryPropertyFlags properties_, u64 allocation_size_, u32 type_) | ||
| 34 | : device{device_}, memory{std::move(memory_)}, properties{properties_}, | ||
| 35 | allocation_size{allocation_size_}, shifted_type{ShiftType(type_)} {} | ||
| 36 | |||
| 37 | VKMemoryCommit Commit(VkDeviceSize commit_size, VkDeviceSize alignment) { | ||
| 38 | auto found = TryFindFreeSection(free_iterator, allocation_size, | ||
| 39 | static_cast<u64>(commit_size), static_cast<u64>(alignment)); | ||
| 40 | if (!found) { | ||
| 41 | found = TryFindFreeSection(0, free_iterator, static_cast<u64>(commit_size), | ||
| 42 | static_cast<u64>(alignment)); | ||
| 43 | if (!found) { | ||
| 44 | // Signal out of memory, it'll try to do more allocations. | ||
| 45 | return nullptr; | ||
| 46 | } | ||
| 47 | } | ||
| 48 | auto commit = std::make_unique<VKMemoryCommitImpl>(device, this, memory, *found, | ||
| 49 | *found + commit_size); | ||
| 50 | commits.push_back(commit.get()); | ||
| 51 | |||
| 52 | // Last commit's address is highly probable to be free. | ||
| 53 | free_iterator = *found + commit_size; | ||
| 54 | |||
| 55 | return commit; | ||
| 56 | } | ||
| 57 | |||
| 58 | void Free(const VKMemoryCommitImpl* commit) { | ||
| 59 | ASSERT(commit); | ||
| 60 | |||
| 61 | const auto it = std::find(std::begin(commits), std::end(commits), commit); | ||
| 62 | if (it == commits.end()) { | ||
| 63 | UNREACHABLE_MSG("Freeing unallocated commit!"); | ||
| 64 | return; | ||
| 65 | } | ||
| 66 | commits.erase(it); | ||
| 67 | } | ||
| 68 | |||
| 69 | /// Returns whether this allocation is compatible with the arguments. | ||
| 70 | bool IsCompatible(VkMemoryPropertyFlags wanted_properties, u32 type_mask) const { | ||
| 71 | return (wanted_properties & properties) && (type_mask & shifted_type) != 0; | ||
| 72 | } | ||
| 73 | |||
| 74 | private: | ||
| 75 | static constexpr u32 ShiftType(u32 type) { | ||
| 76 | return 1U << type; | ||
| 77 | } | ||
| 78 | |||
| 79 | /// A memory allocator, it may return a free region between "start" and "end" with the solicited | ||
| 80 | /// requirements. | ||
| 81 | std::optional<u64> TryFindFreeSection(u64 start, u64 end, u64 size, u64 alignment) const { | ||
| 82 | u64 iterator = Common::AlignUp(start, alignment); | ||
| 83 | while (iterator + size <= end) { | ||
| 84 | const u64 try_left = iterator; | ||
| 85 | const u64 try_right = try_left + size; | ||
| 86 | |||
| 87 | bool overlap = false; | ||
| 88 | for (const auto& commit : commits) { | ||
| 89 | const auto [commit_left, commit_right] = commit->interval; | ||
| 90 | if (try_left < commit_right && commit_left < try_right) { | ||
| 91 | // There's an overlap, continue the search where the overlapping commit ends. | ||
| 92 | iterator = Common::AlignUp(commit_right, alignment); | ||
| 93 | overlap = true; | ||
| 94 | break; | ||
| 95 | } | ||
| 96 | } | ||
| 97 | if (!overlap) { | ||
| 98 | // A free address has been found. | ||
| 99 | return try_left; | ||
| 100 | } | ||
| 101 | } | ||
| 102 | |||
| 103 | // No free regions where found, return an empty optional. | ||
| 104 | return std::nullopt; | ||
| 105 | } | ||
| 106 | |||
| 107 | const Device& device; ///< Vulkan device. | ||
| 108 | const vk::DeviceMemory memory; ///< Vulkan memory allocation handler. | ||
| 109 | const VkMemoryPropertyFlags properties; ///< Vulkan properties. | ||
| 110 | const u64 allocation_size; ///< Size of this allocation. | ||
| 111 | const u32 shifted_type; ///< Stored Vulkan type of this allocation, shifted. | ||
| 112 | |||
| 113 | /// Hints where the next free region is likely going to be. | ||
| 114 | u64 free_iterator{}; | ||
| 115 | |||
| 116 | /// Stores all commits done from this allocation. | ||
| 117 | std::vector<const VKMemoryCommitImpl*> commits; | ||
| 118 | }; | ||
| 119 | |||
| 120 | VKMemoryManager::VKMemoryManager(const Device& device_) | ||
| 121 | : device{device_}, properties{device_.GetPhysical().GetMemoryProperties()} {} | ||
| 122 | |||
| 123 | VKMemoryManager::~VKMemoryManager() = default; | ||
| 124 | |||
| 125 | VKMemoryCommit VKMemoryManager::Commit(const VkMemoryRequirements& requirements, | ||
| 126 | bool host_visible) { | ||
| 127 | const u64 chunk_size = GetAllocationChunkSize(requirements.size); | ||
| 128 | |||
| 129 | // When a host visible commit is asked, search for host visible and coherent, otherwise search | ||
| 130 | // for a fast device local type. | ||
| 131 | const VkMemoryPropertyFlags wanted_properties = | ||
| 132 | host_visible ? VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | ||
| 133 | : VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; | ||
| 134 | |||
| 135 | if (auto commit = TryAllocCommit(requirements, wanted_properties)) { | ||
| 136 | return commit; | ||
| 137 | } | ||
| 138 | |||
| 139 | // Commit has failed, allocate more memory. | ||
| 140 | if (!AllocMemory(wanted_properties, requirements.memoryTypeBits, chunk_size)) { | ||
| 141 | // TODO(Rodrigo): Handle these situations in some way like flushing to guest memory. | ||
| 142 | // Allocation has failed, panic. | ||
| 143 | UNREACHABLE_MSG("Ran out of VRAM!"); | ||
| 144 | return {}; | ||
| 145 | } | ||
| 146 | |||
| 147 | // Commit again, this time it won't fail since there's a fresh allocation above. If it does, | ||
| 148 | // there's a bug. | ||
| 149 | auto commit = TryAllocCommit(requirements, wanted_properties); | ||
| 150 | ASSERT(commit); | ||
| 151 | return commit; | ||
| 152 | } | ||
| 153 | |||
| 154 | VKMemoryCommit VKMemoryManager::Commit(const vk::Buffer& buffer, bool host_visible) { | ||
| 155 | auto commit = Commit(device.GetLogical().GetBufferMemoryRequirements(*buffer), host_visible); | ||
| 156 | buffer.BindMemory(commit->GetMemory(), commit->GetOffset()); | ||
| 157 | return commit; | ||
| 158 | } | ||
| 159 | |||
| 160 | VKMemoryCommit VKMemoryManager::Commit(const vk::Image& image, bool host_visible) { | ||
| 161 | auto commit = Commit(device.GetLogical().GetImageMemoryRequirements(*image), host_visible); | ||
| 162 | image.BindMemory(commit->GetMemory(), commit->GetOffset()); | ||
| 163 | return commit; | ||
| 164 | } | ||
| 165 | |||
| 166 | bool VKMemoryManager::AllocMemory(VkMemoryPropertyFlags wanted_properties, u32 type_mask, | ||
| 167 | u64 size) { | ||
| 168 | const u32 type = [&] { | ||
| 169 | for (u32 type_index = 0; type_index < properties.memoryTypeCount; ++type_index) { | ||
| 170 | const auto flags = properties.memoryTypes[type_index].propertyFlags; | ||
| 171 | if ((type_mask & (1U << type_index)) && (flags & wanted_properties)) { | ||
| 172 | // The type matches in type and in the wanted properties. | ||
| 173 | return type_index; | ||
| 174 | } | ||
| 175 | } | ||
| 176 | UNREACHABLE_MSG("Couldn't find a compatible memory type!"); | ||
| 177 | return 0U; | ||
| 178 | }(); | ||
| 179 | |||
| 180 | // Try to allocate found type. | ||
| 181 | vk::DeviceMemory memory = device.GetLogical().TryAllocateMemory({ | ||
| 182 | .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, | ||
| 183 | .pNext = nullptr, | ||
| 184 | .allocationSize = size, | ||
| 185 | .memoryTypeIndex = type, | ||
| 186 | }); | ||
| 187 | if (!memory) { | ||
| 188 | LOG_CRITICAL(Render_Vulkan, "Device allocation failed!"); | ||
| 189 | return false; | ||
| 190 | } | ||
| 191 | |||
| 192 | allocations.push_back(std::make_unique<VKMemoryAllocation>(device, std::move(memory), | ||
| 193 | wanted_properties, size, type)); | ||
| 194 | return true; | ||
| 195 | } | ||
| 196 | |||
| 197 | VKMemoryCommit VKMemoryManager::TryAllocCommit(const VkMemoryRequirements& requirements, | ||
| 198 | VkMemoryPropertyFlags wanted_properties) { | ||
| 199 | for (auto& allocation : allocations) { | ||
| 200 | if (!allocation->IsCompatible(wanted_properties, requirements.memoryTypeBits)) { | ||
| 201 | continue; | ||
| 202 | } | ||
| 203 | if (auto commit = allocation->Commit(requirements.size, requirements.alignment)) { | ||
| 204 | return commit; | ||
| 205 | } | ||
| 206 | } | ||
| 207 | return {}; | ||
| 208 | } | ||
| 209 | |||
| 210 | VKMemoryCommitImpl::VKMemoryCommitImpl(const Device& device_, VKMemoryAllocation* allocation_, | ||
| 211 | const vk::DeviceMemory& memory_, u64 begin_, u64 end_) | ||
| 212 | : device{device_}, memory{memory_}, interval{begin_, end_}, allocation{allocation_} {} | ||
| 213 | |||
| 214 | VKMemoryCommitImpl::~VKMemoryCommitImpl() { | ||
| 215 | allocation->Free(this); | ||
| 216 | } | ||
| 217 | |||
| 218 | MemoryMap VKMemoryCommitImpl::Map(u64 size, u64 offset_) const { | ||
| 219 | return MemoryMap(this, std::span<u8>(memory.Map(interval.first + offset_, size), size)); | ||
| 220 | } | ||
| 221 | |||
| 222 | void VKMemoryCommitImpl::Unmap() const { | ||
| 223 | memory.Unmap(); | ||
| 224 | } | ||
| 225 | |||
| 226 | MemoryMap VKMemoryCommitImpl::Map() const { | ||
| 227 | return Map(interval.second - interval.first); | ||
| 228 | } | ||
| 229 | |||
| 230 | } // namespace Vulkan | ||
diff --git a/src/video_core/renderer_vulkan/vk_memory_manager.h b/src/video_core/renderer_vulkan/vk_memory_manager.h deleted file mode 100644 index 2452bca4e..000000000 --- a/src/video_core/renderer_vulkan/vk_memory_manager.h +++ /dev/null | |||
| @@ -1,132 +0,0 @@ | |||
| 1 | // Copyright 2019 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 <memory> | ||
| 8 | #include <span> | ||
| 9 | #include <utility> | ||
| 10 | #include <vector> | ||
| 11 | #include "common/common_types.h" | ||
| 12 | #include "video_core/vulkan_common/vulkan_wrapper.h" | ||
| 13 | |||
| 14 | namespace Vulkan { | ||
| 15 | |||
| 16 | class Device; | ||
| 17 | class MemoryMap; | ||
| 18 | class VKMemoryAllocation; | ||
| 19 | class VKMemoryCommitImpl; | ||
| 20 | |||
| 21 | using VKMemoryCommit = std::unique_ptr<VKMemoryCommitImpl>; | ||
| 22 | |||
| 23 | class VKMemoryManager final { | ||
| 24 | public: | ||
| 25 | explicit VKMemoryManager(const Device& device_); | ||
| 26 | VKMemoryManager(const VKMemoryManager&) = delete; | ||
| 27 | ~VKMemoryManager(); | ||
| 28 | |||
| 29 | /** | ||
| 30 | * Commits a memory with the specified requeriments. | ||
| 31 | * @param requirements Requirements returned from a Vulkan call. | ||
| 32 | * @param host_visible Signals the allocator that it *must* use host visible and coherent | ||
| 33 | * memory. When passing false, it will try to allocate device local memory. | ||
| 34 | * @returns A memory commit. | ||
| 35 | */ | ||
| 36 | VKMemoryCommit Commit(const VkMemoryRequirements& requirements, bool host_visible); | ||
| 37 | |||
| 38 | /// Commits memory required by the buffer and binds it. | ||
| 39 | VKMemoryCommit Commit(const vk::Buffer& buffer, bool host_visible); | ||
| 40 | |||
| 41 | /// Commits memory required by the image and binds it. | ||
| 42 | VKMemoryCommit Commit(const vk::Image& image, bool host_visible); | ||
| 43 | |||
| 44 | private: | ||
| 45 | /// Allocates a chunk of memory. | ||
| 46 | bool AllocMemory(VkMemoryPropertyFlags wanted_properties, u32 type_mask, u64 size); | ||
| 47 | |||
| 48 | /// Tries to allocate a memory commit. | ||
| 49 | VKMemoryCommit TryAllocCommit(const VkMemoryRequirements& requirements, | ||
| 50 | VkMemoryPropertyFlags wanted_properties); | ||
| 51 | |||
| 52 | const Device& device; ///< Device handler. | ||
| 53 | const VkPhysicalDeviceMemoryProperties properties; ///< Physical device properties. | ||
| 54 | std::vector<std::unique_ptr<VKMemoryAllocation>> allocations; ///< Current allocations. | ||
| 55 | }; | ||
| 56 | |||
| 57 | class VKMemoryCommitImpl final { | ||
| 58 | friend VKMemoryAllocation; | ||
| 59 | friend MemoryMap; | ||
| 60 | |||
| 61 | public: | ||
| 62 | explicit VKMemoryCommitImpl(const Device& device_, VKMemoryAllocation* allocation_, | ||
| 63 | const vk::DeviceMemory& memory_, u64 begin_, u64 end_); | ||
| 64 | ~VKMemoryCommitImpl(); | ||
| 65 | |||
| 66 | /// Maps a memory region and returns a pointer to it. | ||
| 67 | /// It's illegal to have more than one memory map at the same time. | ||
| 68 | MemoryMap Map(u64 size, u64 offset = 0) const; | ||
| 69 | |||
| 70 | /// Maps the whole commit and returns a pointer to it. | ||
| 71 | /// It's illegal to have more than one memory map at the same time. | ||
| 72 | MemoryMap Map() const; | ||
| 73 | |||
| 74 | /// Returns the Vulkan memory handler. | ||
| 75 | VkDeviceMemory GetMemory() const { | ||
| 76 | return *memory; | ||
| 77 | } | ||
| 78 | |||
| 79 | /// Returns the start position of the commit relative to the allocation. | ||
| 80 | VkDeviceSize GetOffset() const { | ||
| 81 | return static_cast<VkDeviceSize>(interval.first); | ||
| 82 | } | ||
| 83 | |||
| 84 | private: | ||
| 85 | /// Unmaps memory. | ||
| 86 | void Unmap() const; | ||
| 87 | |||
| 88 | const Device& device; ///< Vulkan device. | ||
| 89 | const vk::DeviceMemory& memory; ///< Vulkan device memory handler. | ||
| 90 | std::pair<u64, u64> interval{}; ///< Interval where the commit exists. | ||
| 91 | VKMemoryAllocation* allocation{}; ///< Pointer to the large memory allocation. | ||
| 92 | }; | ||
| 93 | |||
| 94 | /// Holds ownership of a memory map. | ||
| 95 | class MemoryMap final { | ||
| 96 | public: | ||
| 97 | explicit MemoryMap(const VKMemoryCommitImpl* commit_, std::span<u8> span_) | ||
| 98 | : commit{commit_}, span{span_} {} | ||
| 99 | |||
| 100 | ~MemoryMap() { | ||
| 101 | if (commit) { | ||
| 102 | commit->Unmap(); | ||
| 103 | } | ||
| 104 | } | ||
| 105 | |||
| 106 | /// Prematurely releases the memory map. | ||
| 107 | void Release() { | ||
| 108 | commit->Unmap(); | ||
| 109 | commit = nullptr; | ||
| 110 | } | ||
| 111 | |||
| 112 | /// Returns a span to the memory map. | ||
| 113 | [[nodiscard]] std::span<u8> Span() const noexcept { | ||
| 114 | return span; | ||
| 115 | } | ||
| 116 | |||
| 117 | /// Returns the address of the memory map. | ||
| 118 | [[nodiscard]] u8* Address() const noexcept { | ||
| 119 | return span.data(); | ||
| 120 | } | ||
| 121 | |||
| 122 | /// Returns the address of the memory map; | ||
| 123 | [[nodiscard]] operator u8*() const noexcept { | ||
| 124 | return span.data(); | ||
| 125 | } | ||
| 126 | |||
| 127 | private: | ||
| 128 | const VKMemoryCommitImpl* commit{}; ///< Mapped memory commit. | ||
| 129 | std::span<u8> span; ///< Address to the mapped memory. | ||
| 130 | }; | ||
| 131 | |||
| 132 | } // namespace Vulkan | ||
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index 93fbea510..f0a111829 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp | |||
| @@ -409,27 +409,26 @@ void RasterizerVulkan::DrawParameters::Draw(vk::CommandBuffer cmdbuf) const { | |||
| 409 | RasterizerVulkan::RasterizerVulkan(Core::Frontend::EmuWindow& emu_window_, Tegra::GPU& gpu_, | 409 | RasterizerVulkan::RasterizerVulkan(Core::Frontend::EmuWindow& emu_window_, Tegra::GPU& gpu_, |
| 410 | Tegra::MemoryManager& gpu_memory_, | 410 | Tegra::MemoryManager& gpu_memory_, |
| 411 | Core::Memory::Memory& cpu_memory_, VKScreenInfo& screen_info_, | 411 | Core::Memory::Memory& cpu_memory_, VKScreenInfo& screen_info_, |
| 412 | const Device& device_, VKMemoryManager& memory_manager_, | 412 | const Device& device_, MemoryAllocator& memory_allocator_, |
| 413 | StateTracker& state_tracker_, VKScheduler& scheduler_) | 413 | StateTracker& state_tracker_, VKScheduler& scheduler_) |
| 414 | : RasterizerAccelerated{cpu_memory_}, gpu{gpu_}, | 414 | : RasterizerAccelerated{cpu_memory_}, gpu{gpu_}, |
| 415 | gpu_memory{gpu_memory_}, maxwell3d{gpu.Maxwell3D()}, kepler_compute{gpu.KeplerCompute()}, | 415 | gpu_memory{gpu_memory_}, maxwell3d{gpu.Maxwell3D()}, kepler_compute{gpu.KeplerCompute()}, |
| 416 | screen_info{screen_info_}, device{device_}, memory_manager{memory_manager_}, | 416 | screen_info{screen_info_}, device{device_}, memory_allocator{memory_allocator_}, |
| 417 | state_tracker{state_tracker_}, scheduler{scheduler_}, stream_buffer(device, scheduler), | 417 | state_tracker{state_tracker_}, scheduler{scheduler_}, stream_buffer(device, scheduler), |
| 418 | staging_pool(device, memory_manager, scheduler), descriptor_pool(device, scheduler), | 418 | staging_pool(device, memory_allocator, scheduler), descriptor_pool(device, scheduler), |
| 419 | update_descriptor_queue(device, scheduler), | 419 | update_descriptor_queue(device, scheduler), |
| 420 | blit_image(device, scheduler, state_tracker, descriptor_pool), | 420 | blit_image(device, scheduler, state_tracker, descriptor_pool), |
| 421 | quad_array_pass(device, scheduler, descriptor_pool, staging_pool, update_descriptor_queue), | 421 | quad_array_pass(device, scheduler, descriptor_pool, staging_pool, update_descriptor_queue), |
| 422 | quad_indexed_pass(device, scheduler, descriptor_pool, staging_pool, update_descriptor_queue), | 422 | quad_indexed_pass(device, scheduler, descriptor_pool, staging_pool, update_descriptor_queue), |
| 423 | uint8_pass(device, scheduler, descriptor_pool, staging_pool, update_descriptor_queue), | 423 | uint8_pass(device, scheduler, descriptor_pool, staging_pool, update_descriptor_queue), |
| 424 | texture_cache_runtime{device, scheduler, memory_manager, staging_pool, blit_image}, | 424 | texture_cache_runtime{device, scheduler, memory_allocator, staging_pool, blit_image}, |
| 425 | texture_cache(texture_cache_runtime, *this, maxwell3d, kepler_compute, gpu_memory), | 425 | texture_cache(texture_cache_runtime, *this, maxwell3d, kepler_compute, gpu_memory), |
| 426 | pipeline_cache(*this, gpu, maxwell3d, kepler_compute, gpu_memory, device, scheduler, | 426 | pipeline_cache(*this, gpu, maxwell3d, kepler_compute, gpu_memory, device, scheduler, |
| 427 | descriptor_pool, update_descriptor_queue), | 427 | descriptor_pool, update_descriptor_queue), |
| 428 | buffer_cache(*this, gpu_memory, cpu_memory_, device, memory_manager, scheduler, stream_buffer, | 428 | buffer_cache(*this, gpu_memory, cpu_memory_, device, memory_allocator, scheduler, |
| 429 | staging_pool), | 429 | stream_buffer, staging_pool), |
| 430 | query_cache{*this, maxwell3d, gpu_memory, device, scheduler}, | 430 | query_cache{*this, maxwell3d, gpu_memory, device, scheduler}, |
| 431 | fence_manager(*this, gpu, gpu_memory, texture_cache, buffer_cache, query_cache, device, | 431 | fence_manager(*this, gpu, gpu_memory, texture_cache, buffer_cache, query_cache, scheduler), |
| 432 | scheduler), | ||
| 433 | wfi_event(device.GetLogical().CreateEvent()), async_shaders(emu_window_) { | 432 | wfi_event(device.GetLogical().CreateEvent()), async_shaders(emu_window_) { |
| 434 | scheduler.SetQueryCache(query_cache); | 433 | scheduler.SetQueryCache(query_cache); |
| 435 | if (device.UseAsynchronousShaders()) { | 434 | if (device.UseAsynchronousShaders()) { |
| @@ -1446,7 +1445,7 @@ VkBuffer RasterizerVulkan::DefaultBuffer() { | |||
| 1446 | .queueFamilyIndexCount = 0, | 1445 | .queueFamilyIndexCount = 0, |
| 1447 | .pQueueFamilyIndices = nullptr, | 1446 | .pQueueFamilyIndices = nullptr, |
| 1448 | }); | 1447 | }); |
| 1449 | default_buffer_commit = memory_manager.Commit(default_buffer, false); | 1448 | default_buffer_commit = memory_allocator.Commit(default_buffer, MemoryUsage::DeviceLocal); |
| 1450 | 1449 | ||
| 1451 | scheduler.RequestOutsideRenderPassOperationContext(); | 1450 | scheduler.RequestOutsideRenderPassOperationContext(); |
| 1452 | scheduler.Record([buffer = *default_buffer](vk::CommandBuffer cmdbuf) { | 1451 | scheduler.Record([buffer = *default_buffer](vk::CommandBuffer cmdbuf) { |
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.h b/src/video_core/renderer_vulkan/vk_rasterizer.h index 4695718e9..8e261b9bd 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.h +++ b/src/video_core/renderer_vulkan/vk_rasterizer.h | |||
| @@ -21,7 +21,6 @@ | |||
| 21 | #include "video_core/renderer_vulkan/vk_compute_pass.h" | 21 | #include "video_core/renderer_vulkan/vk_compute_pass.h" |
| 22 | #include "video_core/renderer_vulkan/vk_descriptor_pool.h" | 22 | #include "video_core/renderer_vulkan/vk_descriptor_pool.h" |
| 23 | #include "video_core/renderer_vulkan/vk_fence_manager.h" | 23 | #include "video_core/renderer_vulkan/vk_fence_manager.h" |
| 24 | #include "video_core/renderer_vulkan/vk_memory_manager.h" | ||
| 25 | #include "video_core/renderer_vulkan/vk_pipeline_cache.h" | 24 | #include "video_core/renderer_vulkan/vk_pipeline_cache.h" |
| 26 | #include "video_core/renderer_vulkan/vk_query_cache.h" | 25 | #include "video_core/renderer_vulkan/vk_query_cache.h" |
| 27 | #include "video_core/renderer_vulkan/vk_scheduler.h" | 26 | #include "video_core/renderer_vulkan/vk_scheduler.h" |
| @@ -30,6 +29,7 @@ | |||
| 30 | #include "video_core/renderer_vulkan/vk_texture_cache.h" | 29 | #include "video_core/renderer_vulkan/vk_texture_cache.h" |
| 31 | #include "video_core/renderer_vulkan/vk_update_descriptor.h" | 30 | #include "video_core/renderer_vulkan/vk_update_descriptor.h" |
| 32 | #include "video_core/shader/async_shaders.h" | 31 | #include "video_core/shader/async_shaders.h" |
| 32 | #include "video_core/vulkan_common/vulkan_memory_allocator.h" | ||
| 33 | #include "video_core/vulkan_common/vulkan_wrapper.h" | 33 | #include "video_core/vulkan_common/vulkan_wrapper.h" |
| 34 | 34 | ||
| 35 | namespace Core { | 35 | namespace Core { |
| @@ -56,7 +56,7 @@ public: | |||
| 56 | explicit RasterizerVulkan(Core::Frontend::EmuWindow& emu_window_, Tegra::GPU& gpu_, | 56 | explicit RasterizerVulkan(Core::Frontend::EmuWindow& emu_window_, Tegra::GPU& gpu_, |
| 57 | Tegra::MemoryManager& gpu_memory_, Core::Memory::Memory& cpu_memory_, | 57 | Tegra::MemoryManager& gpu_memory_, Core::Memory::Memory& cpu_memory_, |
| 58 | VKScreenInfo& screen_info_, const Device& device_, | 58 | VKScreenInfo& screen_info_, const Device& device_, |
| 59 | VKMemoryManager& memory_manager_, StateTracker& state_tracker_, | 59 | MemoryAllocator& memory_allocator_, StateTracker& state_tracker_, |
| 60 | VKScheduler& scheduler_); | 60 | VKScheduler& scheduler_); |
| 61 | ~RasterizerVulkan() override; | 61 | ~RasterizerVulkan() override; |
| 62 | 62 | ||
| @@ -213,12 +213,12 @@ private: | |||
| 213 | 213 | ||
| 214 | VKScreenInfo& screen_info; | 214 | VKScreenInfo& screen_info; |
| 215 | const Device& device; | 215 | const Device& device; |
| 216 | VKMemoryManager& memory_manager; | 216 | MemoryAllocator& memory_allocator; |
| 217 | StateTracker& state_tracker; | 217 | StateTracker& state_tracker; |
| 218 | VKScheduler& scheduler; | 218 | VKScheduler& scheduler; |
| 219 | 219 | ||
| 220 | VKStreamBuffer stream_buffer; | 220 | VKStreamBuffer stream_buffer; |
| 221 | VKStagingBufferPool staging_pool; | 221 | StagingBufferPool staging_pool; |
| 222 | VKDescriptorPool descriptor_pool; | 222 | VKDescriptorPool descriptor_pool; |
| 223 | VKUpdateDescriptorQueue update_descriptor_queue; | 223 | VKUpdateDescriptorQueue update_descriptor_queue; |
| 224 | BlitImageHelper blit_image; | 224 | BlitImageHelper blit_image; |
| @@ -234,7 +234,7 @@ private: | |||
| 234 | VKFenceManager fence_manager; | 234 | VKFenceManager fence_manager; |
| 235 | 235 | ||
| 236 | vk::Buffer default_buffer; | 236 | vk::Buffer default_buffer; |
| 237 | VKMemoryCommit default_buffer_commit; | 237 | MemoryCommit default_buffer_commit; |
| 238 | vk::Event wfi_event; | 238 | vk::Event wfi_event; |
| 239 | VideoCommon::Shader::AsyncShaders async_shaders; | 239 | VideoCommon::Shader::AsyncShaders async_shaders; |
| 240 | 240 | ||
diff --git a/src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp b/src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp index 1e0b8b922..97fd41cc1 100644 --- a/src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp +++ b/src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp | |||
| @@ -3,10 +3,12 @@ | |||
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include <algorithm> | 5 | #include <algorithm> |
| 6 | #include <unordered_map> | ||
| 7 | #include <utility> | 6 | #include <utility> |
| 8 | #include <vector> | 7 | #include <vector> |
| 9 | 8 | ||
| 9 | #include <fmt/format.h> | ||
| 10 | |||
| 11 | #include "common/assert.h" | ||
| 10 | #include "common/bit_util.h" | 12 | #include "common/bit_util.h" |
| 11 | #include "common/common_types.h" | 13 | #include "common/common_types.h" |
| 12 | #include "video_core/renderer_vulkan/vk_scheduler.h" | 14 | #include "video_core/renderer_vulkan/vk_scheduler.h" |
| @@ -16,45 +18,51 @@ | |||
| 16 | 18 | ||
| 17 | namespace Vulkan { | 19 | namespace Vulkan { |
| 18 | 20 | ||
| 19 | VKStagingBufferPool::StagingBuffer::StagingBuffer(std::unique_ptr<VKBuffer> buffer_) | 21 | StagingBufferPool::StagingBufferPool(const Device& device_, MemoryAllocator& memory_allocator_, |
| 20 | : buffer{std::move(buffer_)} {} | 22 | VKScheduler& scheduler_) |
| 21 | 23 | : device{device_}, memory_allocator{memory_allocator_}, scheduler{scheduler_} {} | |
| 22 | VKStagingBufferPool::VKStagingBufferPool(const Device& device_, VKMemoryManager& memory_manager_, | ||
| 23 | VKScheduler& scheduler_) | ||
| 24 | : device{device_}, memory_manager{memory_manager_}, scheduler{scheduler_} {} | ||
| 25 | 24 | ||
| 26 | VKStagingBufferPool::~VKStagingBufferPool() = default; | 25 | StagingBufferPool::~StagingBufferPool() = default; |
| 27 | 26 | ||
| 28 | VKBuffer& VKStagingBufferPool::GetUnusedBuffer(std::size_t size, bool host_visible) { | 27 | StagingBufferRef StagingBufferPool::Request(size_t size, MemoryUsage usage) { |
| 29 | if (const auto buffer = TryGetReservedBuffer(size, host_visible)) { | 28 | if (const std::optional<StagingBufferRef> ref = TryGetReservedBuffer(size, usage)) { |
| 30 | return *buffer; | 29 | return *ref; |
| 31 | } | 30 | } |
| 32 | return CreateStagingBuffer(size, host_visible); | 31 | return CreateStagingBuffer(size, usage); |
| 33 | } | 32 | } |
| 34 | 33 | ||
| 35 | void VKStagingBufferPool::TickFrame() { | 34 | void StagingBufferPool::TickFrame() { |
| 36 | current_delete_level = (current_delete_level + 1) % NumLevels; | 35 | current_delete_level = (current_delete_level + 1) % NUM_LEVELS; |
| 37 | 36 | ||
| 38 | ReleaseCache(true); | 37 | ReleaseCache(MemoryUsage::DeviceLocal); |
| 39 | ReleaseCache(false); | 38 | ReleaseCache(MemoryUsage::Upload); |
| 39 | ReleaseCache(MemoryUsage::Download); | ||
| 40 | } | 40 | } |
| 41 | 41 | ||
| 42 | VKBuffer* VKStagingBufferPool::TryGetReservedBuffer(std::size_t size, bool host_visible) { | 42 | std::optional<StagingBufferRef> StagingBufferPool::TryGetReservedBuffer(size_t size, |
| 43 | for (StagingBuffer& entry : GetCache(host_visible)[Common::Log2Ceil64(size)].entries) { | 43 | MemoryUsage usage) { |
| 44 | if (!scheduler.IsFree(entry.tick)) { | 44 | StagingBuffers& cache_level = GetCache(usage)[Common::Log2Ceil64(size)]; |
| 45 | continue; | 45 | |
| 46 | const auto is_free = [this](const StagingBuffer& entry) { | ||
| 47 | return scheduler.IsFree(entry.tick); | ||
| 48 | }; | ||
| 49 | auto& entries = cache_level.entries; | ||
| 50 | const auto hint_it = entries.begin() + cache_level.iterate_index; | ||
| 51 | auto it = std::find_if(entries.begin() + cache_level.iterate_index, entries.end(), is_free); | ||
| 52 | if (it == entries.end()) { | ||
| 53 | it = std::find_if(entries.begin(), hint_it, is_free); | ||
| 54 | if (it == hint_it) { | ||
| 55 | return std::nullopt; | ||
| 46 | } | 56 | } |
| 47 | entry.tick = scheduler.CurrentTick(); | ||
| 48 | return &*entry.buffer; | ||
| 49 | } | 57 | } |
| 50 | return nullptr; | 58 | cache_level.iterate_index = std::distance(entries.begin(), it) + 1; |
| 59 | it->tick = scheduler.CurrentTick(); | ||
| 60 | return it->Ref(); | ||
| 51 | } | 61 | } |
| 52 | 62 | ||
| 53 | VKBuffer& VKStagingBufferPool::CreateStagingBuffer(std::size_t size, bool host_visible) { | 63 | StagingBufferRef StagingBufferPool::CreateStagingBuffer(size_t size, MemoryUsage usage) { |
| 54 | const u32 log2 = Common::Log2Ceil64(size); | 64 | const u32 log2 = Common::Log2Ceil64(size); |
| 55 | 65 | vk::Buffer buffer = device.GetLogical().CreateBuffer({ | |
| 56 | auto buffer = std::make_unique<VKBuffer>(); | ||
| 57 | buffer->handle = device.GetLogical().CreateBuffer({ | ||
| 58 | .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, | 66 | .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, |
| 59 | .pNext = nullptr, | 67 | .pNext = nullptr, |
| 60 | .flags = 0, | 68 | .flags = 0, |
| @@ -66,49 +74,63 @@ VKBuffer& VKStagingBufferPool::CreateStagingBuffer(std::size_t size, bool host_v | |||
| 66 | .queueFamilyIndexCount = 0, | 74 | .queueFamilyIndexCount = 0, |
| 67 | .pQueueFamilyIndices = nullptr, | 75 | .pQueueFamilyIndices = nullptr, |
| 68 | }); | 76 | }); |
| 69 | buffer->commit = memory_manager.Commit(buffer->handle, host_visible); | 77 | if (device.HasDebuggingToolAttached()) { |
| 70 | 78 | ++buffer_index; | |
| 71 | std::vector<StagingBuffer>& entries = GetCache(host_visible)[log2].entries; | 79 | buffer.SetObjectNameEXT(fmt::format("Staging Buffer {}", buffer_index).c_str()); |
| 72 | StagingBuffer& entry = entries.emplace_back(std::move(buffer)); | 80 | } |
| 73 | entry.tick = scheduler.CurrentTick(); | 81 | MemoryCommit commit = memory_allocator.Commit(buffer, usage); |
| 74 | return *entry.buffer; | 82 | const std::span<u8> mapped_span = IsHostVisible(usage) ? commit.Map() : std::span<u8>{}; |
| 75 | } | 83 | |
| 76 | 84 | StagingBuffer& entry = GetCache(usage)[log2].entries.emplace_back(StagingBuffer{ | |
| 77 | VKStagingBufferPool::StagingBuffersCache& VKStagingBufferPool::GetCache(bool host_visible) { | 85 | .buffer = std::move(buffer), |
| 78 | return host_visible ? host_staging_buffers : device_staging_buffers; | 86 | .commit = std::move(commit), |
| 87 | .mapped_span = mapped_span, | ||
| 88 | .tick = scheduler.CurrentTick(), | ||
| 89 | }); | ||
| 90 | return entry.Ref(); | ||
| 79 | } | 91 | } |
| 80 | 92 | ||
| 81 | void VKStagingBufferPool::ReleaseCache(bool host_visible) { | 93 | StagingBufferPool::StagingBuffersCache& StagingBufferPool::GetCache(MemoryUsage usage) { |
| 82 | auto& cache = GetCache(host_visible); | 94 | switch (usage) { |
| 83 | const u64 size = ReleaseLevel(cache, current_delete_level); | 95 | case MemoryUsage::DeviceLocal: |
| 84 | if (size == 0) { | 96 | return device_local_cache; |
| 85 | return; | 97 | case MemoryUsage::Upload: |
| 98 | return upload_cache; | ||
| 99 | case MemoryUsage::Download: | ||
| 100 | return download_cache; | ||
| 101 | default: | ||
| 102 | UNREACHABLE_MSG("Invalid memory usage={}", usage); | ||
| 103 | return upload_cache; | ||
| 86 | } | 104 | } |
| 87 | } | 105 | } |
| 88 | 106 | ||
| 89 | u64 VKStagingBufferPool::ReleaseLevel(StagingBuffersCache& cache, std::size_t log2) { | 107 | void StagingBufferPool::ReleaseCache(MemoryUsage usage) { |
| 90 | static constexpr std::size_t deletions_per_tick = 16; | 108 | ReleaseLevel(GetCache(usage), current_delete_level); |
| 109 | } | ||
| 91 | 110 | ||
| 111 | void StagingBufferPool::ReleaseLevel(StagingBuffersCache& cache, size_t log2) { | ||
| 112 | constexpr size_t deletions_per_tick = 16; | ||
| 92 | auto& staging = cache[log2]; | 113 | auto& staging = cache[log2]; |
| 93 | auto& entries = staging.entries; | 114 | auto& entries = staging.entries; |
| 94 | const std::size_t old_size = entries.size(); | 115 | const size_t old_size = entries.size(); |
| 95 | 116 | ||
| 96 | const auto is_deleteable = [this](const StagingBuffer& entry) { | 117 | const auto is_deleteable = [this](const StagingBuffer& entry) { |
| 97 | return scheduler.IsFree(entry.tick); | 118 | return scheduler.IsFree(entry.tick); |
| 98 | }; | 119 | }; |
| 99 | const std::size_t begin_offset = staging.delete_index; | 120 | const size_t begin_offset = staging.delete_index; |
| 100 | const std::size_t end_offset = std::min(begin_offset + deletions_per_tick, old_size); | 121 | const size_t end_offset = std::min(begin_offset + deletions_per_tick, old_size); |
| 101 | const auto begin = std::begin(entries) + begin_offset; | 122 | const auto begin = entries.begin() + begin_offset; |
| 102 | const auto end = std::begin(entries) + end_offset; | 123 | const auto end = entries.begin() + end_offset; |
| 103 | entries.erase(std::remove_if(begin, end, is_deleteable), end); | 124 | entries.erase(std::remove_if(begin, end, is_deleteable), end); |
| 104 | 125 | ||
| 105 | const std::size_t new_size = entries.size(); | 126 | const size_t new_size = entries.size(); |
| 106 | staging.delete_index += deletions_per_tick; | 127 | staging.delete_index += deletions_per_tick; |
| 107 | if (staging.delete_index >= new_size) { | 128 | if (staging.delete_index >= new_size) { |
| 108 | staging.delete_index = 0; | 129 | staging.delete_index = 0; |
| 109 | } | 130 | } |
| 110 | 131 | if (staging.iterate_index > new_size) { | |
| 111 | return (1ULL << log2) * (old_size - new_size); | 132 | staging.iterate_index = 0; |
| 133 | } | ||
| 112 | } | 134 | } |
| 113 | 135 | ||
| 114 | } // namespace Vulkan | 136 | } // namespace Vulkan |
diff --git a/src/video_core/renderer_vulkan/vk_staging_buffer_pool.h b/src/video_core/renderer_vulkan/vk_staging_buffer_pool.h index 90dadcbbe..d42918a47 100644 --- a/src/video_core/renderer_vulkan/vk_staging_buffer_pool.h +++ b/src/video_core/renderer_vulkan/vk_staging_buffer_pool.h | |||
| @@ -9,7 +9,7 @@ | |||
| 9 | 9 | ||
| 10 | #include "common/common_types.h" | 10 | #include "common/common_types.h" |
| 11 | 11 | ||
| 12 | #include "video_core/renderer_vulkan/vk_memory_manager.h" | 12 | #include "video_core/vulkan_common/vulkan_memory_allocator.h" |
| 13 | #include "video_core/vulkan_common/vulkan_wrapper.h" | 13 | #include "video_core/vulkan_common/vulkan_wrapper.h" |
| 14 | 14 | ||
| 15 | namespace Vulkan { | 15 | namespace Vulkan { |
| @@ -17,55 +17,65 @@ namespace Vulkan { | |||
| 17 | class Device; | 17 | class Device; |
| 18 | class VKScheduler; | 18 | class VKScheduler; |
| 19 | 19 | ||
| 20 | struct VKBuffer final { | 20 | struct StagingBufferRef { |
| 21 | vk::Buffer handle; | 21 | VkBuffer buffer; |
| 22 | VKMemoryCommit commit; | 22 | std::span<u8> mapped_span; |
| 23 | }; | 23 | }; |
| 24 | 24 | ||
| 25 | class VKStagingBufferPool final { | 25 | class StagingBufferPool { |
| 26 | public: | 26 | public: |
| 27 | explicit VKStagingBufferPool(const Device& device, VKMemoryManager& memory_manager, | 27 | explicit StagingBufferPool(const Device& device, MemoryAllocator& memory_allocator, |
| 28 | VKScheduler& scheduler); | 28 | VKScheduler& scheduler); |
| 29 | ~VKStagingBufferPool(); | 29 | ~StagingBufferPool(); |
| 30 | 30 | ||
| 31 | VKBuffer& GetUnusedBuffer(std::size_t size, bool host_visible); | 31 | StagingBufferRef Request(size_t size, MemoryUsage usage); |
| 32 | 32 | ||
| 33 | void TickFrame(); | 33 | void TickFrame(); |
| 34 | 34 | ||
| 35 | private: | 35 | private: |
| 36 | struct StagingBuffer final { | 36 | struct StagingBuffer { |
| 37 | explicit StagingBuffer(std::unique_ptr<VKBuffer> buffer); | 37 | vk::Buffer buffer; |
| 38 | 38 | MemoryCommit commit; | |
| 39 | std::unique_ptr<VKBuffer> buffer; | 39 | std::span<u8> mapped_span; |
| 40 | u64 tick = 0; | 40 | u64 tick = 0; |
| 41 | |||
| 42 | StagingBufferRef Ref() const noexcept { | ||
| 43 | return { | ||
| 44 | .buffer = *buffer, | ||
| 45 | .mapped_span = mapped_span, | ||
| 46 | }; | ||
| 47 | } | ||
| 41 | }; | 48 | }; |
| 42 | 49 | ||
| 43 | struct StagingBuffers final { | 50 | struct StagingBuffers { |
| 44 | std::vector<StagingBuffer> entries; | 51 | std::vector<StagingBuffer> entries; |
| 45 | std::size_t delete_index = 0; | 52 | size_t delete_index = 0; |
| 53 | size_t iterate_index = 0; | ||
| 46 | }; | 54 | }; |
| 47 | 55 | ||
| 48 | static constexpr std::size_t NumLevels = sizeof(std::size_t) * CHAR_BIT; | 56 | static constexpr size_t NUM_LEVELS = sizeof(size_t) * CHAR_BIT; |
| 49 | using StagingBuffersCache = std::array<StagingBuffers, NumLevels>; | 57 | using StagingBuffersCache = std::array<StagingBuffers, NUM_LEVELS>; |
| 50 | 58 | ||
| 51 | VKBuffer* TryGetReservedBuffer(std::size_t size, bool host_visible); | 59 | std::optional<StagingBufferRef> TryGetReservedBuffer(size_t size, MemoryUsage usage); |
| 52 | 60 | ||
| 53 | VKBuffer& CreateStagingBuffer(std::size_t size, bool host_visible); | 61 | StagingBufferRef CreateStagingBuffer(size_t size, MemoryUsage usage); |
| 54 | 62 | ||
| 55 | StagingBuffersCache& GetCache(bool host_visible); | 63 | StagingBuffersCache& GetCache(MemoryUsage usage); |
| 56 | 64 | ||
| 57 | void ReleaseCache(bool host_visible); | 65 | void ReleaseCache(MemoryUsage usage); |
| 58 | 66 | ||
| 59 | u64 ReleaseLevel(StagingBuffersCache& cache, std::size_t log2); | 67 | void ReleaseLevel(StagingBuffersCache& cache, size_t log2); |
| 60 | 68 | ||
| 61 | const Device& device; | 69 | const Device& device; |
| 62 | VKMemoryManager& memory_manager; | 70 | MemoryAllocator& memory_allocator; |
| 63 | VKScheduler& scheduler; | 71 | VKScheduler& scheduler; |
| 64 | 72 | ||
| 65 | StagingBuffersCache host_staging_buffers; | 73 | StagingBuffersCache device_local_cache; |
| 66 | StagingBuffersCache device_staging_buffers; | 74 | StagingBuffersCache upload_cache; |
| 75 | StagingBuffersCache download_cache; | ||
| 67 | 76 | ||
| 68 | std::size_t current_delete_level = 0; | 77 | size_t current_delete_level = 0; |
| 78 | u64 buffer_index = 0; | ||
| 69 | }; | 79 | }; |
| 70 | 80 | ||
| 71 | } // namespace Vulkan | 81 | } // namespace Vulkan |
diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp index bd11de012..ab14922d7 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp | |||
| @@ -10,12 +10,12 @@ | |||
| 10 | #include "video_core/engines/fermi_2d.h" | 10 | #include "video_core/engines/fermi_2d.h" |
| 11 | #include "video_core/renderer_vulkan/blit_image.h" | 11 | #include "video_core/renderer_vulkan/blit_image.h" |
| 12 | #include "video_core/renderer_vulkan/maxwell_to_vk.h" | 12 | #include "video_core/renderer_vulkan/maxwell_to_vk.h" |
| 13 | #include "video_core/renderer_vulkan/vk_memory_manager.h" | ||
| 14 | #include "video_core/renderer_vulkan/vk_rasterizer.h" | 13 | #include "video_core/renderer_vulkan/vk_rasterizer.h" |
| 15 | #include "video_core/renderer_vulkan/vk_scheduler.h" | 14 | #include "video_core/renderer_vulkan/vk_scheduler.h" |
| 16 | #include "video_core/renderer_vulkan/vk_staging_buffer_pool.h" | 15 | #include "video_core/renderer_vulkan/vk_staging_buffer_pool.h" |
| 17 | #include "video_core/renderer_vulkan/vk_texture_cache.h" | 16 | #include "video_core/renderer_vulkan/vk_texture_cache.h" |
| 18 | #include "video_core/vulkan_common/vulkan_device.h" | 17 | #include "video_core/vulkan_common/vulkan_device.h" |
| 18 | #include "video_core/vulkan_common/vulkan_memory_allocator.h" | ||
| 19 | #include "video_core/vulkan_common/vulkan_wrapper.h" | 19 | #include "video_core/vulkan_common/vulkan_wrapper.h" |
| 20 | 20 | ||
| 21 | namespace Vulkan { | 21 | namespace Vulkan { |
| @@ -554,10 +554,18 @@ void TextureCacheRuntime::Finish() { | |||
| 554 | } | 554 | } |
| 555 | 555 | ||
| 556 | ImageBufferMap TextureCacheRuntime::MapUploadBuffer(size_t size) { | 556 | ImageBufferMap TextureCacheRuntime::MapUploadBuffer(size_t size) { |
| 557 | const auto& buffer = staging_buffer_pool.GetUnusedBuffer(size, true); | 557 | const auto staging_ref = staging_buffer_pool.Request(size, MemoryUsage::Upload); |
| 558 | return ImageBufferMap{ | 558 | return { |
| 559 | .handle = *buffer.handle, | 559 | .handle = staging_ref.buffer, |
| 560 | .map = buffer.commit->Map(size), | 560 | .span = staging_ref.mapped_span, |
| 561 | }; | ||
| 562 | } | ||
| 563 | |||
| 564 | ImageBufferMap TextureCacheRuntime::MapDownloadBuffer(size_t size) { | ||
| 565 | const auto staging_ref = staging_buffer_pool.Request(size, MemoryUsage::Download); | ||
| 566 | return { | ||
| 567 | .handle = staging_ref.buffer, | ||
| 568 | .span = staging_ref.mapped_span, | ||
| 561 | }; | 569 | }; |
| 562 | } | 570 | } |
| 563 | 571 | ||
| @@ -788,9 +796,9 @@ Image::Image(TextureCacheRuntime& runtime, const ImageInfo& info_, GPUVAddr gpu_ | |||
| 788 | image(MakeImage(runtime.device, info)), buffer(MakeBuffer(runtime.device, info)), | 796 | image(MakeImage(runtime.device, info)), buffer(MakeBuffer(runtime.device, info)), |
| 789 | aspect_mask(ImageAspectMask(info.format)) { | 797 | aspect_mask(ImageAspectMask(info.format)) { |
| 790 | if (image) { | 798 | if (image) { |
| 791 | commit = runtime.memory_manager.Commit(image, false); | 799 | commit = runtime.memory_allocator.Commit(image, MemoryUsage::DeviceLocal); |
| 792 | } else { | 800 | } else { |
| 793 | commit = runtime.memory_manager.Commit(buffer, false); | 801 | commit = runtime.memory_allocator.Commit(buffer, MemoryUsage::DeviceLocal); |
| 794 | } | 802 | } |
| 795 | if (IsPixelFormatASTC(info.format) && !runtime.device.IsOptimalAstcSupported()) { | 803 | if (IsPixelFormatASTC(info.format) && !runtime.device.IsOptimalAstcSupported()) { |
| 796 | flags |= VideoCommon::ImageFlagBits::Converted; | 804 | flags |= VideoCommon::ImageFlagBits::Converted; |
diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.h b/src/video_core/renderer_vulkan/vk_texture_cache.h index 92a7aad8b..a55d405d1 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.h +++ b/src/video_core/renderer_vulkan/vk_texture_cache.h | |||
| @@ -7,8 +7,8 @@ | |||
| 7 | #include <compare> | 7 | #include <compare> |
| 8 | #include <span> | 8 | #include <span> |
| 9 | 9 | ||
| 10 | #include "video_core/renderer_vulkan/vk_memory_manager.h" | ||
| 11 | #include "video_core/texture_cache/texture_cache.h" | 10 | #include "video_core/texture_cache/texture_cache.h" |
| 11 | #include "video_core/vulkan_common/vulkan_memory_allocator.h" | ||
| 12 | #include "video_core/vulkan_common/vulkan_wrapper.h" | 12 | #include "video_core/vulkan_common/vulkan_wrapper.h" |
| 13 | 13 | ||
| 14 | namespace Vulkan { | 14 | namespace Vulkan { |
| @@ -19,14 +19,13 @@ using VideoCommon::Offset2D; | |||
| 19 | using VideoCommon::RenderTargets; | 19 | using VideoCommon::RenderTargets; |
| 20 | using VideoCore::Surface::PixelFormat; | 20 | using VideoCore::Surface::PixelFormat; |
| 21 | 21 | ||
| 22 | class VKScheduler; | ||
| 23 | class VKStagingBufferPool; | ||
| 24 | |||
| 25 | class BlitImageHelper; | 22 | class BlitImageHelper; |
| 26 | class Device; | 23 | class Device; |
| 27 | class Image; | 24 | class Image; |
| 28 | class ImageView; | 25 | class ImageView; |
| 29 | class Framebuffer; | 26 | class Framebuffer; |
| 27 | class StagingBufferPool; | ||
| 28 | class VKScheduler; | ||
| 30 | 29 | ||
| 31 | struct RenderPassKey { | 30 | struct RenderPassKey { |
| 32 | constexpr auto operator<=>(const RenderPassKey&) const noexcept = default; | 31 | constexpr auto operator<=>(const RenderPassKey&) const noexcept = default; |
| @@ -60,18 +59,18 @@ struct ImageBufferMap { | |||
| 60 | } | 59 | } |
| 61 | 60 | ||
| 62 | [[nodiscard]] std::span<u8> Span() const noexcept { | 61 | [[nodiscard]] std::span<u8> Span() const noexcept { |
| 63 | return map.Span(); | 62 | return span; |
| 64 | } | 63 | } |
| 65 | 64 | ||
| 66 | VkBuffer handle; | 65 | VkBuffer handle; |
| 67 | MemoryMap map; | 66 | std::span<u8> span; |
| 68 | }; | 67 | }; |
| 69 | 68 | ||
| 70 | struct TextureCacheRuntime { | 69 | struct TextureCacheRuntime { |
| 71 | const Device& device; | 70 | const Device& device; |
| 72 | VKScheduler& scheduler; | 71 | VKScheduler& scheduler; |
| 73 | VKMemoryManager& memory_manager; | 72 | MemoryAllocator& memory_allocator; |
| 74 | VKStagingBufferPool& staging_buffer_pool; | 73 | StagingBufferPool& staging_buffer_pool; |
| 75 | BlitImageHelper& blit_image_helper; | 74 | BlitImageHelper& blit_image_helper; |
| 76 | std::unordered_map<RenderPassKey, vk::RenderPass> renderpass_cache; | 75 | std::unordered_map<RenderPassKey, vk::RenderPass> renderpass_cache; |
| 77 | 76 | ||
| @@ -79,10 +78,7 @@ struct TextureCacheRuntime { | |||
| 79 | 78 | ||
| 80 | [[nodiscard]] ImageBufferMap MapUploadBuffer(size_t size); | 79 | [[nodiscard]] ImageBufferMap MapUploadBuffer(size_t size); |
| 81 | 80 | ||
| 82 | [[nodiscard]] ImageBufferMap MapDownloadBuffer(size_t size) { | 81 | [[nodiscard]] ImageBufferMap MapDownloadBuffer(size_t size); |
| 83 | // TODO: Have a special function for this | ||
| 84 | return MapUploadBuffer(size); | ||
| 85 | } | ||
| 86 | 82 | ||
| 87 | void BlitImage(Framebuffer* dst_framebuffer, ImageView& dst, ImageView& src, | 83 | void BlitImage(Framebuffer* dst_framebuffer, ImageView& dst, ImageView& src, |
| 88 | const std::array<Offset2D, 2>& dst_region, | 84 | const std::array<Offset2D, 2>& dst_region, |
| @@ -141,7 +137,7 @@ private: | |||
| 141 | VKScheduler* scheduler; | 137 | VKScheduler* scheduler; |
| 142 | vk::Image image; | 138 | vk::Image image; |
| 143 | vk::Buffer buffer; | 139 | vk::Buffer buffer; |
| 144 | VKMemoryCommit commit; | 140 | MemoryCommit commit; |
| 145 | VkImageAspectFlags aspect_mask = 0; | 141 | VkImageAspectFlags aspect_mask = 0; |
| 146 | bool initialized = false; | 142 | bool initialized = false; |
| 147 | }; | 143 | }; |
diff --git a/src/video_core/texture_cache/accelerated_swizzle.cpp b/src/video_core/texture_cache/accelerated_swizzle.cpp index a4fc1184b..15585caeb 100644 --- a/src/video_core/texture_cache/accelerated_swizzle.cpp +++ b/src/video_core/texture_cache/accelerated_swizzle.cpp | |||
| @@ -27,7 +27,7 @@ BlockLinearSwizzle2DParams MakeBlockLinearSwizzle2DParams(const SwizzleParameter | |||
| 27 | const Extent3D num_tiles = swizzle.num_tiles; | 27 | const Extent3D num_tiles = swizzle.num_tiles; |
| 28 | const u32 bytes_per_block = BytesPerBlock(info.format); | 28 | const u32 bytes_per_block = BytesPerBlock(info.format); |
| 29 | const u32 stride_alignment = CalculateLevelStrideAlignment(info, swizzle.level); | 29 | const u32 stride_alignment = CalculateLevelStrideAlignment(info, swizzle.level); |
| 30 | const u32 stride = Common::AlignBits(num_tiles.width, stride_alignment) * bytes_per_block; | 30 | const u32 stride = Common::AlignUpLog2(num_tiles.width, stride_alignment) * bytes_per_block; |
| 31 | const u32 gobs_in_x = Common::DivCeilLog2(stride, GOB_SIZE_X_SHIFT); | 31 | const u32 gobs_in_x = Common::DivCeilLog2(stride, GOB_SIZE_X_SHIFT); |
| 32 | return BlockLinearSwizzle2DParams{ | 32 | return BlockLinearSwizzle2DParams{ |
| 33 | .origin{0, 0, 0}, | 33 | .origin{0, 0, 0}, |
| @@ -47,7 +47,7 @@ BlockLinearSwizzle3DParams MakeBlockLinearSwizzle3DParams(const SwizzleParameter | |||
| 47 | const Extent3D num_tiles = swizzle.num_tiles; | 47 | const Extent3D num_tiles = swizzle.num_tiles; |
| 48 | const u32 bytes_per_block = BytesPerBlock(info.format); | 48 | const u32 bytes_per_block = BytesPerBlock(info.format); |
| 49 | const u32 stride_alignment = CalculateLevelStrideAlignment(info, swizzle.level); | 49 | const u32 stride_alignment = CalculateLevelStrideAlignment(info, swizzle.level); |
| 50 | const u32 stride = Common::AlignBits(num_tiles.width, stride_alignment) * bytes_per_block; | 50 | const u32 stride = Common::AlignUpLog2(num_tiles.width, stride_alignment) * bytes_per_block; |
| 51 | 51 | ||
| 52 | const u32 gobs_in_x = (stride + GOB_SIZE_X - 1) >> GOB_SIZE_X_SHIFT; | 52 | const u32 gobs_in_x = (stride + GOB_SIZE_X - 1) >> GOB_SIZE_X_SHIFT; |
| 53 | const u32 block_size = gobs_in_x << (GOB_SIZE_SHIFT + block.height + block.depth); | 53 | const u32 block_size = gobs_in_x << (GOB_SIZE_SHIFT + block.height + block.depth); |
diff --git a/src/video_core/texture_cache/util.cpp b/src/video_core/texture_cache/util.cpp index 279932778..ce8fcfe0a 100644 --- a/src/video_core/texture_cache/util.cpp +++ b/src/video_core/texture_cache/util.cpp | |||
| @@ -279,7 +279,7 @@ template <u32 GOB_EXTENT> | |||
| 279 | const bool is_small = IsSmallerThanGobSize(blocks, gob, info.block.depth); | 279 | const bool is_small = IsSmallerThanGobSize(blocks, gob, info.block.depth); |
| 280 | const u32 alignment = is_small ? 0 : info.tile_width_spacing; | 280 | const u32 alignment = is_small ? 0 : info.tile_width_spacing; |
| 281 | return Extent2D{ | 281 | return Extent2D{ |
| 282 | .width = Common::AlignBits(gobs.width, alignment), | 282 | .width = Common::AlignUpLog2(gobs.width, alignment), |
| 283 | .height = gobs.height, | 283 | .height = gobs.height, |
| 284 | }; | 284 | }; |
| 285 | } | 285 | } |
| @@ -352,7 +352,7 @@ template <u32 GOB_EXTENT> | |||
| 352 | // https://github.com/Ryujinx/Ryujinx/blob/1c9aba6de1520aea5480c032e0ff5664ac1bb36f/Ryujinx.Graphics.Texture/SizeCalculator.cs#L134 | 352 | // https://github.com/Ryujinx/Ryujinx/blob/1c9aba6de1520aea5480c032e0ff5664ac1bb36f/Ryujinx.Graphics.Texture/SizeCalculator.cs#L134 |
| 353 | if (tile_width_spacing > 0) { | 353 | if (tile_width_spacing > 0) { |
| 354 | const u32 alignment_log2 = GOB_SIZE_SHIFT + tile_width_spacing + block.height + block.depth; | 354 | const u32 alignment_log2 = GOB_SIZE_SHIFT + tile_width_spacing + block.height + block.depth; |
| 355 | return Common::AlignBits(size_bytes, alignment_log2); | 355 | return Common::AlignUpLog2(size_bytes, alignment_log2); |
| 356 | } | 356 | } |
| 357 | const u32 aligned_height = Common::AlignUp(size.height, tile_size_y); | 357 | const u32 aligned_height = Common::AlignUp(size.height, tile_size_y); |
| 358 | while (block.height != 0 && aligned_height <= (1U << (block.height - 1)) * GOB_SIZE_Y) { | 358 | while (block.height != 0 && aligned_height <= (1U << (block.height - 1)) * GOB_SIZE_Y) { |
| @@ -528,9 +528,9 @@ template <u32 GOB_EXTENT> | |||
| 528 | const u32 alignment = StrideAlignment(num_tiles, info.block, bpp_log2, info.tile_width_spacing); | 528 | const u32 alignment = StrideAlignment(num_tiles, info.block, bpp_log2, info.tile_width_spacing); |
| 529 | const Extent3D mip_block = AdjustMipBlockSize(num_tiles, info.block, 0); | 529 | const Extent3D mip_block = AdjustMipBlockSize(num_tiles, info.block, 0); |
| 530 | return Extent3D{ | 530 | return Extent3D{ |
| 531 | .width = Common::AlignBits(num_tiles.width, alignment), | 531 | .width = Common::AlignUpLog2(num_tiles.width, alignment), |
| 532 | .height = Common::AlignBits(num_tiles.height, GOB_SIZE_Y_SHIFT + mip_block.height), | 532 | .height = Common::AlignUpLog2(num_tiles.height, GOB_SIZE_Y_SHIFT + mip_block.height), |
| 533 | .depth = Common::AlignBits(num_tiles.depth, GOB_SIZE_Z_SHIFT + mip_block.depth), | 533 | .depth = Common::AlignUpLog2(num_tiles.depth, GOB_SIZE_Z_SHIFT + mip_block.depth), |
| 534 | }; | 534 | }; |
| 535 | } | 535 | } |
| 536 | 536 | ||
diff --git a/src/video_core/textures/astc.cpp b/src/video_core/textures/astc.cpp index acd5bdd78..3625b666c 100644 --- a/src/video_core/textures/astc.cpp +++ b/src/video_core/textures/astc.cpp | |||
| @@ -42,21 +42,24 @@ constexpr u32 Popcnt(u32 n) { | |||
| 42 | 42 | ||
| 43 | class InputBitStream { | 43 | class InputBitStream { |
| 44 | public: | 44 | public: |
| 45 | constexpr explicit InputBitStream(const u8* ptr, std::size_t start_offset = 0) | 45 | constexpr explicit InputBitStream(std::span<const u8> data, size_t start_offset = 0) |
| 46 | : cur_byte{ptr}, next_bit{start_offset % 8} {} | 46 | : cur_byte{data.data()}, total_bits{data.size()}, next_bit{start_offset % 8} {} |
| 47 | 47 | ||
| 48 | constexpr std::size_t GetBitsRead() const { | 48 | constexpr size_t GetBitsRead() const { |
| 49 | return bits_read; | 49 | return bits_read; |
| 50 | } | 50 | } |
| 51 | 51 | ||
| 52 | constexpr bool ReadBit() { | 52 | constexpr bool ReadBit() { |
| 53 | const bool bit = (*cur_byte >> next_bit++) & 1; | 53 | if (bits_read >= total_bits * 8) { |
| 54 | return 0; | ||
| 55 | } | ||
| 56 | const bool bit = ((*cur_byte >> next_bit) & 1) != 0; | ||
| 57 | ++next_bit; | ||
| 54 | while (next_bit >= 8) { | 58 | while (next_bit >= 8) { |
| 55 | next_bit -= 8; | 59 | next_bit -= 8; |
| 56 | cur_byte++; | 60 | ++cur_byte; |
| 57 | } | 61 | } |
| 58 | 62 | ++bits_read; | |
| 59 | bits_read++; | ||
| 60 | return bit; | 63 | return bit; |
| 61 | } | 64 | } |
| 62 | 65 | ||
| @@ -79,8 +82,9 @@ public: | |||
| 79 | 82 | ||
| 80 | private: | 83 | private: |
| 81 | const u8* cur_byte; | 84 | const u8* cur_byte; |
| 82 | std::size_t next_bit = 0; | 85 | size_t total_bits = 0; |
| 83 | std::size_t bits_read = 0; | 86 | size_t next_bit = 0; |
| 87 | size_t bits_read = 0; | ||
| 84 | }; | 88 | }; |
| 85 | 89 | ||
| 86 | class OutputBitStream { | 90 | class OutputBitStream { |
| @@ -193,15 +197,15 @@ struct IntegerEncodedValue { | |||
| 193 | }; | 197 | }; |
| 194 | }; | 198 | }; |
| 195 | using IntegerEncodedVector = boost::container::static_vector< | 199 | using IntegerEncodedVector = boost::container::static_vector< |
| 196 | IntegerEncodedValue, 64, | 200 | IntegerEncodedValue, 256, |
| 197 | boost::container::static_vector_options< | 201 | boost::container::static_vector_options< |
| 198 | boost::container::inplace_alignment<alignof(IntegerEncodedValue)>, | 202 | boost::container::inplace_alignment<alignof(IntegerEncodedValue)>, |
| 199 | boost::container::throw_on_overflow<false>>::type>; | 203 | boost::container::throw_on_overflow<false>>::type>; |
| 200 | 204 | ||
| 201 | static void DecodeTritBlock(InputBitStream& bits, IntegerEncodedVector& result, u32 nBitsPerValue) { | 205 | static void DecodeTritBlock(InputBitStream& bits, IntegerEncodedVector& result, u32 nBitsPerValue) { |
| 202 | // Implement the algorithm in section C.2.12 | 206 | // Implement the algorithm in section C.2.12 |
| 203 | u32 m[5]; | 207 | std::array<u32, 5> m; |
| 204 | u32 t[5]; | 208 | std::array<u32, 5> t; |
| 205 | u32 T; | 209 | u32 T; |
| 206 | 210 | ||
| 207 | // Read the trit encoded block according to | 211 | // Read the trit encoded block according to |
| @@ -866,7 +870,7 @@ public: | |||
| 866 | } | 870 | } |
| 867 | }; | 871 | }; |
| 868 | 872 | ||
| 869 | static void DecodeColorValues(u32* out, u8* data, const u32* modes, const u32 nPartitions, | 873 | static void DecodeColorValues(u32* out, std::span<u8> data, const u32* modes, const u32 nPartitions, |
| 870 | const u32 nBitsForColorData) { | 874 | const u32 nBitsForColorData) { |
| 871 | // First figure out how many color values we have | 875 | // First figure out how many color values we have |
| 872 | u32 nValues = 0; | 876 | u32 nValues = 0; |
| @@ -898,7 +902,7 @@ static void DecodeColorValues(u32* out, u8* data, const u32* modes, const u32 nP | |||
| 898 | // We now have enough to decode our integer sequence. | 902 | // We now have enough to decode our integer sequence. |
| 899 | IntegerEncodedVector decodedColorValues; | 903 | IntegerEncodedVector decodedColorValues; |
| 900 | 904 | ||
| 901 | InputBitStream colorStream(data); | 905 | InputBitStream colorStream(data, 0); |
| 902 | DecodeIntegerSequence(decodedColorValues, colorStream, range, nValues); | 906 | DecodeIntegerSequence(decodedColorValues, colorStream, range, nValues); |
| 903 | 907 | ||
| 904 | // Once we have the decoded values, we need to dequantize them to the 0-255 range | 908 | // Once we have the decoded values, we need to dequantize them to the 0-255 range |
| @@ -1441,7 +1445,7 @@ static void ComputeEndpos32s(Pixel& ep1, Pixel& ep2, const u32*& colorValues, | |||
| 1441 | 1445 | ||
| 1442 | static void DecompressBlock(std::span<const u8, 16> inBuf, const u32 blockWidth, | 1446 | static void DecompressBlock(std::span<const u8, 16> inBuf, const u32 blockWidth, |
| 1443 | const u32 blockHeight, std::span<u32, 12 * 12> outBuf) { | 1447 | const u32 blockHeight, std::span<u32, 12 * 12> outBuf) { |
| 1444 | InputBitStream strm(inBuf.data()); | 1448 | InputBitStream strm(inBuf); |
| 1445 | TexelWeightParams weightParams = DecodeBlockInfo(strm); | 1449 | TexelWeightParams weightParams = DecodeBlockInfo(strm); |
| 1446 | 1450 | ||
| 1447 | // Was there an error? | 1451 | // Was there an error? |
| @@ -1619,15 +1623,16 @@ static void DecompressBlock(std::span<const u8, 16> inBuf, const u32 blockWidth, | |||
| 1619 | 1623 | ||
| 1620 | // Make sure that higher non-texel bits are set to zero | 1624 | // Make sure that higher non-texel bits are set to zero |
| 1621 | const u32 clearByteStart = (weightParams.GetPackedBitSize() >> 3) + 1; | 1625 | const u32 clearByteStart = (weightParams.GetPackedBitSize() >> 3) + 1; |
| 1622 | if (clearByteStart > 0) { | 1626 | if (clearByteStart > 0 && clearByteStart <= texelWeightData.size()) { |
| 1623 | texelWeightData[clearByteStart - 1] &= | 1627 | texelWeightData[clearByteStart - 1] &= |
| 1624 | static_cast<u8>((1 << (weightParams.GetPackedBitSize() % 8)) - 1); | 1628 | static_cast<u8>((1 << (weightParams.GetPackedBitSize() % 8)) - 1); |
| 1629 | std::memset(texelWeightData.data() + clearByteStart, 0, | ||
| 1630 | std::min(16U - clearByteStart, 16U)); | ||
| 1625 | } | 1631 | } |
| 1626 | std::memset(texelWeightData.data() + clearByteStart, 0, std::min(16U - clearByteStart, 16U)); | ||
| 1627 | 1632 | ||
| 1628 | IntegerEncodedVector texelWeightValues; | 1633 | IntegerEncodedVector texelWeightValues; |
| 1629 | 1634 | ||
| 1630 | InputBitStream weightStream(texelWeightData.data()); | 1635 | InputBitStream weightStream(texelWeightData); |
| 1631 | 1636 | ||
| 1632 | DecodeIntegerSequence(texelWeightValues, weightStream, weightParams.m_MaxWeight, | 1637 | DecodeIntegerSequence(texelWeightValues, weightStream, weightParams.m_MaxWeight, |
| 1633 | weightParams.GetNumWeightValues()); | 1638 | weightParams.GetNumWeightValues()); |
diff --git a/src/video_core/textures/decoders.cpp b/src/video_core/textures/decoders.cpp index 9f5181318..62685a183 100644 --- a/src/video_core/textures/decoders.cpp +++ b/src/video_core/textures/decoders.cpp | |||
| @@ -49,7 +49,7 @@ void Swizzle(std::span<u8> output, std::span<const u8> input, u32 bytes_per_pixe | |||
| 49 | // We can configure here a custom pitch | 49 | // We can configure here a custom pitch |
| 50 | // As it's not exposed 'width * bpp' will be the expected pitch. | 50 | // As it's not exposed 'width * bpp' will be the expected pitch. |
| 51 | const u32 pitch = width * bytes_per_pixel; | 51 | const u32 pitch = width * bytes_per_pixel; |
| 52 | const u32 stride = Common::AlignBits(width, stride_alignment) * bytes_per_pixel; | 52 | const u32 stride = Common::AlignUpLog2(width, stride_alignment) * bytes_per_pixel; |
| 53 | 53 | ||
| 54 | const u32 gobs_in_x = Common::DivCeilLog2(stride, GOB_SIZE_X_SHIFT); | 54 | const u32 gobs_in_x = Common::DivCeilLog2(stride, GOB_SIZE_X_SHIFT); |
| 55 | const u32 block_size = gobs_in_x << (GOB_SIZE_SHIFT + block_height + block_depth); | 55 | const u32 block_size = gobs_in_x << (GOB_SIZE_SHIFT + block_height + block_depth); |
| @@ -217,9 +217,9 @@ void SwizzleKepler(const u32 width, const u32 height, const u32 dst_x, const u32 | |||
| 217 | std::size_t CalculateSize(bool tiled, u32 bytes_per_pixel, u32 width, u32 height, u32 depth, | 217 | std::size_t CalculateSize(bool tiled, u32 bytes_per_pixel, u32 width, u32 height, u32 depth, |
| 218 | u32 block_height, u32 block_depth) { | 218 | u32 block_height, u32 block_depth) { |
| 219 | if (tiled) { | 219 | if (tiled) { |
| 220 | const u32 aligned_width = Common::AlignBits(width * bytes_per_pixel, GOB_SIZE_X_SHIFT); | 220 | const u32 aligned_width = Common::AlignUpLog2(width * bytes_per_pixel, GOB_SIZE_X_SHIFT); |
| 221 | const u32 aligned_height = Common::AlignBits(height, GOB_SIZE_Y_SHIFT + block_height); | 221 | const u32 aligned_height = Common::AlignUpLog2(height, GOB_SIZE_Y_SHIFT + block_height); |
| 222 | const u32 aligned_depth = Common::AlignBits(depth, GOB_SIZE_Z_SHIFT + block_depth); | 222 | const u32 aligned_depth = Common::AlignUpLog2(depth, GOB_SIZE_Z_SHIFT + block_depth); |
| 223 | return aligned_width * aligned_height * aligned_depth; | 223 | return aligned_width * aligned_height * aligned_depth; |
| 224 | } else { | 224 | } else { |
| 225 | return width * height * depth * bytes_per_pixel; | 225 | return width * height * depth * bytes_per_pixel; |
diff --git a/src/video_core/vulkan_common/vulkan_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp index 75173324e..37d7b45a3 100644 --- a/src/video_core/vulkan_common/vulkan_device.cpp +++ b/src/video_core/vulkan_common/vulkan_device.cpp | |||
| @@ -99,8 +99,7 @@ VkFormatFeatureFlags GetFormatFeatures(VkFormatProperties properties, FormatType | |||
| 99 | }); | 99 | }); |
| 100 | } | 100 | } |
| 101 | 101 | ||
| 102 | std::unordered_map<VkFormat, VkFormatProperties> GetFormatProperties( | 102 | std::unordered_map<VkFormat, VkFormatProperties> GetFormatProperties(vk::PhysicalDevice physical) { |
| 103 | vk::PhysicalDevice physical, const vk::InstanceDispatch& dld) { | ||
| 104 | static constexpr std::array formats{ | 103 | static constexpr std::array formats{ |
| 105 | VK_FORMAT_A8B8G8R8_UNORM_PACK32, | 104 | VK_FORMAT_A8B8G8R8_UNORM_PACK32, |
| 106 | VK_FORMAT_A8B8G8R8_UINT_PACK32, | 105 | VK_FORMAT_A8B8G8R8_UINT_PACK32, |
| @@ -210,7 +209,7 @@ std::unordered_map<VkFormat, VkFormatProperties> GetFormatProperties( | |||
| 210 | Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR surface, | 209 | Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR surface, |
| 211 | const vk::InstanceDispatch& dld_) | 210 | const vk::InstanceDispatch& dld_) |
| 212 | : instance{instance_}, dld{dld_}, physical{physical_}, properties{physical.GetProperties()}, | 211 | : instance{instance_}, dld{dld_}, physical{physical_}, properties{physical.GetProperties()}, |
| 213 | format_properties{GetFormatProperties(physical, dld)} { | 212 | format_properties{GetFormatProperties(physical)} { |
| 214 | CheckSuitability(); | 213 | CheckSuitability(); |
| 215 | SetupFamilies(surface); | 214 | SetupFamilies(surface); |
| 216 | SetupFeatures(); | 215 | SetupFeatures(); |
| @@ -221,6 +220,7 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR | |||
| 221 | VkPhysicalDeviceFeatures2 features2{ | 220 | VkPhysicalDeviceFeatures2 features2{ |
| 222 | .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2, | 221 | .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2, |
| 223 | .pNext = nullptr, | 222 | .pNext = nullptr, |
| 223 | .features{}, | ||
| 224 | }; | 224 | }; |
| 225 | const void* first_next = &features2; | 225 | const void* first_next = &features2; |
| 226 | void** next = &features2.pNext; | 226 | void** next = &features2.pNext; |
| @@ -256,7 +256,7 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR | |||
| 256 | .shaderTessellationAndGeometryPointSize = false, | 256 | .shaderTessellationAndGeometryPointSize = false, |
| 257 | .shaderImageGatherExtended = true, | 257 | .shaderImageGatherExtended = true, |
| 258 | .shaderStorageImageExtendedFormats = false, | 258 | .shaderStorageImageExtendedFormats = false, |
| 259 | .shaderStorageImageMultisample = true, | 259 | .shaderStorageImageMultisample = is_shader_storage_image_multisample, |
| 260 | .shaderStorageImageReadWithoutFormat = is_formatless_image_load_supported, | 260 | .shaderStorageImageReadWithoutFormat = is_formatless_image_load_supported, |
| 261 | .shaderStorageImageWriteWithoutFormat = true, | 261 | .shaderStorageImageWriteWithoutFormat = true, |
| 262 | .shaderUniformBufferArrayDynamicIndexing = false, | 262 | .shaderUniformBufferArrayDynamicIndexing = false, |
| @@ -310,6 +310,7 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR | |||
| 310 | 310 | ||
| 311 | VkPhysicalDeviceHostQueryResetFeaturesEXT host_query_reset{ | 311 | VkPhysicalDeviceHostQueryResetFeaturesEXT host_query_reset{ |
| 312 | .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_QUERY_RESET_FEATURES_EXT, | 312 | .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_QUERY_RESET_FEATURES_EXT, |
| 313 | .pNext = nullptr, | ||
| 313 | .hostQueryReset = true, | 314 | .hostQueryReset = true, |
| 314 | }; | 315 | }; |
| 315 | SetNext(next, host_query_reset); | 316 | SetNext(next, host_query_reset); |
| @@ -604,7 +605,6 @@ void Device::CheckSuitability() const { | |||
| 604 | std::make_pair(features.occlusionQueryPrecise, "occlusionQueryPrecise"), | 605 | std::make_pair(features.occlusionQueryPrecise, "occlusionQueryPrecise"), |
| 605 | std::make_pair(features.fragmentStoresAndAtomics, "fragmentStoresAndAtomics"), | 606 | std::make_pair(features.fragmentStoresAndAtomics, "fragmentStoresAndAtomics"), |
| 606 | std::make_pair(features.shaderImageGatherExtended, "shaderImageGatherExtended"), | 607 | std::make_pair(features.shaderImageGatherExtended, "shaderImageGatherExtended"), |
| 607 | std::make_pair(features.shaderStorageImageMultisample, "shaderStorageImageMultisample"), | ||
| 608 | std::make_pair(features.shaderStorageImageWriteWithoutFormat, | 608 | std::make_pair(features.shaderStorageImageWriteWithoutFormat, |
| 609 | "shaderStorageImageWriteWithoutFormat"), | 609 | "shaderStorageImageWriteWithoutFormat"), |
| 610 | }; | 610 | }; |
| @@ -804,6 +804,7 @@ void Device::SetupFamilies(VkSurfaceKHR surface) { | |||
| 804 | void Device::SetupFeatures() { | 804 | void Device::SetupFeatures() { |
| 805 | const auto supported_features{physical.GetFeatures()}; | 805 | const auto supported_features{physical.GetFeatures()}; |
| 806 | is_formatless_image_load_supported = supported_features.shaderStorageImageReadWithoutFormat; | 806 | is_formatless_image_load_supported = supported_features.shaderStorageImageReadWithoutFormat; |
| 807 | is_shader_storage_image_multisample = supported_features.shaderStorageImageMultisample; | ||
| 807 | is_blit_depth_stencil_supported = TestDepthStencilBlits(); | 808 | is_blit_depth_stencil_supported = TestDepthStencilBlits(); |
| 808 | is_optimal_astc_supported = IsOptimalAstcSupported(supported_features); | 809 | is_optimal_astc_supported = IsOptimalAstcSupported(supported_features); |
| 809 | } | 810 | } |
diff --git a/src/video_core/vulkan_common/vulkan_device.h b/src/video_core/vulkan_common/vulkan_device.h index a973c3ce4..4b66dba7a 100644 --- a/src/video_core/vulkan_common/vulkan_device.h +++ b/src/video_core/vulkan_common/vulkan_device.h | |||
| @@ -272,23 +272,24 @@ private: | |||
| 272 | bool is_optimal_astc_supported{}; ///< Support for native ASTC. | 272 | bool is_optimal_astc_supported{}; ///< Support for native ASTC. |
| 273 | bool is_float16_supported{}; ///< Support for float16 arithmetics. | 273 | bool is_float16_supported{}; ///< Support for float16 arithmetics. |
| 274 | bool is_warp_potentially_bigger{}; ///< Host warp size can be bigger than guest. | 274 | bool is_warp_potentially_bigger{}; ///< Host warp size can be bigger than guest. |
| 275 | bool is_formatless_image_load_supported{}; ///< Support for shader image read without format. | 275 | bool is_formatless_image_load_supported{}; ///< Support for shader image read without format. |
| 276 | bool is_blit_depth_stencil_supported{}; ///< Support for blitting from and to depth stencil. | 276 | bool is_shader_storage_image_multisample{}; ///< Support for image operations on MSAA images. |
| 277 | bool nv_viewport_swizzle{}; ///< Support for VK_NV_viewport_swizzle. | 277 | bool is_blit_depth_stencil_supported{}; ///< Support for blitting from and to depth stencil. |
| 278 | bool khr_uniform_buffer_standard_layout{}; ///< Support for std430 on UBOs. | 278 | bool nv_viewport_swizzle{}; ///< Support for VK_NV_viewport_swizzle. |
| 279 | bool ext_index_type_uint8{}; ///< Support for VK_EXT_index_type_uint8. | 279 | bool khr_uniform_buffer_standard_layout{}; ///< Support for std430 on UBOs. |
| 280 | bool ext_sampler_filter_minmax{}; ///< Support for VK_EXT_sampler_filter_minmax. | 280 | bool ext_index_type_uint8{}; ///< Support for VK_EXT_index_type_uint8. |
| 281 | bool ext_depth_range_unrestricted{}; ///< Support for VK_EXT_depth_range_unrestricted. | 281 | bool ext_sampler_filter_minmax{}; ///< Support for VK_EXT_sampler_filter_minmax. |
| 282 | bool ext_shader_viewport_index_layer{}; ///< Support for VK_EXT_shader_viewport_index_layer. | 282 | bool ext_depth_range_unrestricted{}; ///< Support for VK_EXT_depth_range_unrestricted. |
| 283 | bool ext_tooling_info{}; ///< Support for VK_EXT_tooling_info. | 283 | bool ext_shader_viewport_index_layer{}; ///< Support for VK_EXT_shader_viewport_index_layer. |
| 284 | bool ext_transform_feedback{}; ///< Support for VK_EXT_transform_feedback. | 284 | bool ext_tooling_info{}; ///< Support for VK_EXT_tooling_info. |
| 285 | bool ext_custom_border_color{}; ///< Support for VK_EXT_custom_border_color. | 285 | bool ext_transform_feedback{}; ///< Support for VK_EXT_transform_feedback. |
| 286 | bool ext_extended_dynamic_state{}; ///< Support for VK_EXT_extended_dynamic_state. | 286 | bool ext_custom_border_color{}; ///< Support for VK_EXT_custom_border_color. |
| 287 | bool ext_robustness2{}; ///< Support for VK_EXT_robustness2. | 287 | bool ext_extended_dynamic_state{}; ///< Support for VK_EXT_extended_dynamic_state. |
| 288 | bool ext_shader_stencil_export{}; ///< Support for VK_EXT_shader_stencil_export. | 288 | bool ext_robustness2{}; ///< Support for VK_EXT_robustness2. |
| 289 | bool nv_device_diagnostics_config{}; ///< Support for VK_NV_device_diagnostics_config. | 289 | bool ext_shader_stencil_export{}; ///< Support for VK_EXT_shader_stencil_export. |
| 290 | bool has_renderdoc{}; ///< Has RenderDoc attached | 290 | bool nv_device_diagnostics_config{}; ///< Support for VK_NV_device_diagnostics_config. |
| 291 | bool has_nsight_graphics{}; ///< Has Nsight Graphics attached | 291 | bool has_renderdoc{}; ///< Has RenderDoc attached |
| 292 | bool has_nsight_graphics{}; ///< Has Nsight Graphics attached | ||
| 292 | 293 | ||
| 293 | // Asynchronous Graphics Pipeline setting | 294 | // Asynchronous Graphics Pipeline setting |
| 294 | bool use_asynchronous_shaders{}; ///< Setting to use asynchronous shaders/graphics pipeline | 295 | bool use_asynchronous_shaders{}; ///< Setting to use asynchronous shaders/graphics pipeline |
diff --git a/src/video_core/vulkan_common/vulkan_memory_allocator.cpp b/src/video_core/vulkan_common/vulkan_memory_allocator.cpp new file mode 100644 index 000000000..d6eb3af31 --- /dev/null +++ b/src/video_core/vulkan_common/vulkan_memory_allocator.cpp | |||
| @@ -0,0 +1,268 @@ | |||
| 1 | // Copyright 2018 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <algorithm> | ||
| 6 | #include <bit> | ||
| 7 | #include <optional> | ||
| 8 | #include <vector> | ||
| 9 | |||
| 10 | #include "common/alignment.h" | ||
| 11 | #include "common/assert.h" | ||
| 12 | #include "common/common_types.h" | ||
| 13 | #include "common/logging/log.h" | ||
| 14 | #include "video_core/vulkan_common/vulkan_device.h" | ||
| 15 | #include "video_core/vulkan_common/vulkan_memory_allocator.h" | ||
| 16 | #include "video_core/vulkan_common/vulkan_wrapper.h" | ||
| 17 | |||
| 18 | namespace Vulkan { | ||
| 19 | namespace { | ||
| 20 | struct Range { | ||
| 21 | u64 begin; | ||
| 22 | u64 end; | ||
| 23 | |||
| 24 | [[nodiscard]] bool Contains(u64 iterator, u64 size) const noexcept { | ||
| 25 | return iterator < end && begin < iterator + size; | ||
| 26 | } | ||
| 27 | }; | ||
| 28 | |||
| 29 | [[nodiscard]] u64 AllocationChunkSize(u64 required_size) { | ||
| 30 | static constexpr std::array sizes{ | ||
| 31 | 0x1000ULL << 10, 0x1400ULL << 10, 0x1800ULL << 10, 0x1c00ULL << 10, 0x2000ULL << 10, | ||
| 32 | 0x3200ULL << 10, 0x4000ULL << 10, 0x6000ULL << 10, 0x8000ULL << 10, 0xA000ULL << 10, | ||
| 33 | 0x10000ULL << 10, 0x18000ULL << 10, 0x20000ULL << 10, | ||
| 34 | }; | ||
| 35 | static_assert(std::is_sorted(sizes.begin(), sizes.end())); | ||
| 36 | |||
| 37 | const auto it = std::ranges::lower_bound(sizes, required_size); | ||
| 38 | return it != sizes.end() ? *it : Common::AlignUp(required_size, 4ULL << 20); | ||
| 39 | } | ||
| 40 | |||
| 41 | [[nodiscard]] VkMemoryPropertyFlags MemoryUsagePropertyFlags(MemoryUsage usage) { | ||
| 42 | switch (usage) { | ||
| 43 | case MemoryUsage::DeviceLocal: | ||
| 44 | return VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; | ||
| 45 | case MemoryUsage::Upload: | ||
| 46 | return VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; | ||
| 47 | case MemoryUsage::Download: | ||
| 48 | return VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | | ||
| 49 | VK_MEMORY_PROPERTY_HOST_CACHED_BIT; | ||
| 50 | } | ||
| 51 | UNREACHABLE_MSG("Invalid memory usage={}", usage); | ||
| 52 | return VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; | ||
| 53 | } | ||
| 54 | } // Anonymous namespace | ||
| 55 | |||
| 56 | class MemoryAllocation { | ||
| 57 | public: | ||
| 58 | explicit MemoryAllocation(const Device& device_, vk::DeviceMemory memory_, | ||
| 59 | VkMemoryPropertyFlags properties, u64 allocation_size_, u32 type) | ||
| 60 | : device{device_}, memory{std::move(memory_)}, allocation_size{allocation_size_}, | ||
| 61 | property_flags{properties}, shifted_memory_type{1U << type} {} | ||
| 62 | |||
| 63 | [[nodiscard]] std::optional<MemoryCommit> Commit(VkDeviceSize size, VkDeviceSize alignment) { | ||
| 64 | const std::optional<u64> alloc = FindFreeRegion(size, alignment); | ||
| 65 | if (!alloc) { | ||
| 66 | // Signal out of memory, it'll try to do more allocations. | ||
| 67 | return std::nullopt; | ||
| 68 | } | ||
| 69 | const Range range{ | ||
| 70 | .begin = *alloc, | ||
| 71 | .end = *alloc + size, | ||
| 72 | }; | ||
| 73 | commits.insert(std::ranges::upper_bound(commits, *alloc, {}, &Range::begin), range); | ||
| 74 | return std::make_optional<MemoryCommit>(this, *memory, *alloc, *alloc + size); | ||
| 75 | } | ||
| 76 | |||
| 77 | void Free(u64 begin) { | ||
| 78 | const auto it = std::ranges::find(commits, begin, &Range::begin); | ||
| 79 | ASSERT_MSG(it != commits.end(), "Invalid commit"); | ||
| 80 | commits.erase(it); | ||
| 81 | } | ||
| 82 | |||
| 83 | [[nodiscard]] std::span<u8> Map() { | ||
| 84 | if (memory_mapped_span.empty()) { | ||
| 85 | u8* const raw_pointer = memory.Map(0, allocation_size); | ||
| 86 | memory_mapped_span = std::span<u8>(raw_pointer, allocation_size); | ||
| 87 | } | ||
| 88 | return memory_mapped_span; | ||
| 89 | } | ||
| 90 | |||
| 91 | /// Returns whether this allocation is compatible with the arguments. | ||
| 92 | [[nodiscard]] bool IsCompatible(VkMemoryPropertyFlags flags, u32 type_mask) const { | ||
| 93 | return (flags & property_flags) && (type_mask & shifted_memory_type) != 0; | ||
| 94 | } | ||
| 95 | |||
| 96 | private: | ||
| 97 | [[nodiscard]] static constexpr u32 ShiftType(u32 type) { | ||
| 98 | return 1U << type; | ||
| 99 | } | ||
| 100 | |||
| 101 | [[nodiscard]] std::optional<u64> FindFreeRegion(u64 size, u64 alignment) noexcept { | ||
| 102 | ASSERT(std::has_single_bit(alignment)); | ||
| 103 | const u64 alignment_log2 = std::countr_zero(alignment); | ||
| 104 | std::optional<u64> candidate; | ||
| 105 | u64 iterator = 0; | ||
| 106 | auto commit = commits.begin(); | ||
| 107 | while (iterator + size <= allocation_size) { | ||
| 108 | candidate = candidate.value_or(iterator); | ||
| 109 | if (commit == commits.end()) { | ||
| 110 | break; | ||
| 111 | } | ||
| 112 | if (commit->Contains(*candidate, size)) { | ||
| 113 | candidate = std::nullopt; | ||
| 114 | } | ||
| 115 | iterator = Common::AlignUpLog2(commit->end, alignment_log2); | ||
| 116 | ++commit; | ||
| 117 | } | ||
| 118 | return candidate; | ||
| 119 | } | ||
| 120 | |||
| 121 | const Device& device; ///< Vulkan device. | ||
| 122 | const vk::DeviceMemory memory; ///< Vulkan memory allocation handler. | ||
| 123 | const u64 allocation_size; ///< Size of this allocation. | ||
| 124 | const VkMemoryPropertyFlags property_flags; ///< Vulkan memory property flags. | ||
| 125 | const u32 shifted_memory_type; ///< Shifted Vulkan memory type. | ||
| 126 | std::vector<Range> commits; ///< All commit ranges done from this allocation. | ||
| 127 | std::span<u8> memory_mapped_span; ///< Memory mapped span. Empty if not queried before. | ||
| 128 | }; | ||
| 129 | |||
| 130 | MemoryCommit::MemoryCommit(MemoryAllocation* allocation_, VkDeviceMemory memory_, u64 begin_, | ||
| 131 | u64 end_) noexcept | ||
| 132 | : allocation{allocation_}, memory{memory_}, begin{begin_}, end{end_} {} | ||
| 133 | |||
| 134 | MemoryCommit::~MemoryCommit() { | ||
| 135 | Release(); | ||
| 136 | } | ||
| 137 | |||
| 138 | MemoryCommit& MemoryCommit::operator=(MemoryCommit&& rhs) noexcept { | ||
| 139 | Release(); | ||
| 140 | allocation = std::exchange(rhs.allocation, nullptr); | ||
| 141 | memory = rhs.memory; | ||
| 142 | begin = rhs.begin; | ||
| 143 | end = rhs.end; | ||
| 144 | span = std::exchange(rhs.span, std::span<u8>{}); | ||
| 145 | return *this; | ||
| 146 | } | ||
| 147 | |||
| 148 | MemoryCommit::MemoryCommit(MemoryCommit&& rhs) noexcept | ||
| 149 | : allocation{std::exchange(rhs.allocation, nullptr)}, memory{rhs.memory}, begin{rhs.begin}, | ||
| 150 | end{rhs.end}, span{std::exchange(rhs.span, std::span<u8>{})} {} | ||
| 151 | |||
| 152 | std::span<u8> MemoryCommit::Map() { | ||
| 153 | if (span.empty()) { | ||
| 154 | span = allocation->Map().subspan(begin, end - begin); | ||
| 155 | } | ||
| 156 | return span; | ||
| 157 | } | ||
| 158 | |||
| 159 | void MemoryCommit::Release() { | ||
| 160 | if (allocation) { | ||
| 161 | allocation->Free(begin); | ||
| 162 | } | ||
| 163 | } | ||
| 164 | |||
| 165 | MemoryAllocator::MemoryAllocator(const Device& device_) | ||
| 166 | : device{device_}, properties{device_.GetPhysical().GetMemoryProperties()} {} | ||
| 167 | |||
| 168 | MemoryAllocator::~MemoryAllocator() = default; | ||
| 169 | |||
| 170 | MemoryCommit MemoryAllocator::Commit(const VkMemoryRequirements& requirements, MemoryUsage usage) { | ||
| 171 | // Find the fastest memory flags we can afford with the current requirements | ||
| 172 | const VkMemoryPropertyFlags flags = MemoryPropertyFlags(requirements.memoryTypeBits, usage); | ||
| 173 | if (std::optional<MemoryCommit> commit = TryCommit(requirements, flags)) { | ||
| 174 | return std::move(*commit); | ||
| 175 | } | ||
| 176 | // Commit has failed, allocate more memory. | ||
| 177 | // TODO(Rodrigo): Handle out of memory situations in some way like flushing to guest memory. | ||
| 178 | AllocMemory(flags, requirements.memoryTypeBits, AllocationChunkSize(requirements.size)); | ||
| 179 | |||
| 180 | // Commit again, this time it won't fail since there's a fresh allocation above. | ||
| 181 | // If it does, there's a bug. | ||
| 182 | return TryCommit(requirements, flags).value(); | ||
| 183 | } | ||
| 184 | |||
| 185 | MemoryCommit MemoryAllocator::Commit(const vk::Buffer& buffer, MemoryUsage usage) { | ||
| 186 | auto commit = Commit(device.GetLogical().GetBufferMemoryRequirements(*buffer), usage); | ||
| 187 | buffer.BindMemory(commit.Memory(), commit.Offset()); | ||
| 188 | return commit; | ||
| 189 | } | ||
| 190 | |||
| 191 | MemoryCommit MemoryAllocator::Commit(const vk::Image& image, MemoryUsage usage) { | ||
| 192 | auto commit = Commit(device.GetLogical().GetImageMemoryRequirements(*image), usage); | ||
| 193 | image.BindMemory(commit.Memory(), commit.Offset()); | ||
| 194 | return commit; | ||
| 195 | } | ||
| 196 | |||
| 197 | void MemoryAllocator::AllocMemory(VkMemoryPropertyFlags flags, u32 type_mask, u64 size) { | ||
| 198 | const u32 type = FindType(flags, type_mask).value(); | ||
| 199 | vk::DeviceMemory memory = device.GetLogical().AllocateMemory({ | ||
| 200 | .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, | ||
| 201 | .pNext = nullptr, | ||
| 202 | .allocationSize = size, | ||
| 203 | .memoryTypeIndex = type, | ||
| 204 | }); | ||
| 205 | allocations.push_back( | ||
| 206 | std::make_unique<MemoryAllocation>(device, std::move(memory), flags, size, type)); | ||
| 207 | } | ||
| 208 | |||
| 209 | std::optional<MemoryCommit> MemoryAllocator::TryCommit(const VkMemoryRequirements& requirements, | ||
| 210 | VkMemoryPropertyFlags flags) { | ||
| 211 | for (auto& allocation : allocations) { | ||
| 212 | if (!allocation->IsCompatible(flags, requirements.memoryTypeBits)) { | ||
| 213 | continue; | ||
| 214 | } | ||
| 215 | if (auto commit = allocation->Commit(requirements.size, requirements.alignment)) { | ||
| 216 | return commit; | ||
| 217 | } | ||
| 218 | } | ||
| 219 | return std::nullopt; | ||
| 220 | } | ||
| 221 | |||
| 222 | VkMemoryPropertyFlags MemoryAllocator::MemoryPropertyFlags(u32 type_mask, MemoryUsage usage) const { | ||
| 223 | return MemoryPropertyFlags(type_mask, MemoryUsagePropertyFlags(usage)); | ||
| 224 | } | ||
| 225 | |||
| 226 | VkMemoryPropertyFlags MemoryAllocator::MemoryPropertyFlags(u32 type_mask, | ||
| 227 | VkMemoryPropertyFlags flags) const { | ||
| 228 | if (FindType(flags, type_mask)) { | ||
| 229 | // Found a memory type with those requirements | ||
| 230 | return flags; | ||
| 231 | } | ||
| 232 | if (flags & VK_MEMORY_PROPERTY_HOST_CACHED_BIT) { | ||
| 233 | // Remove host cached bit in case it's not supported | ||
| 234 | return MemoryPropertyFlags(type_mask, flags & ~VK_MEMORY_PROPERTY_HOST_CACHED_BIT); | ||
| 235 | } | ||
| 236 | if (flags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) { | ||
| 237 | // Remove device local, if it's not supported by the requested resource | ||
| 238 | return MemoryPropertyFlags(type_mask, flags & ~VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); | ||
| 239 | } | ||
| 240 | UNREACHABLE_MSG("No compatible memory types found"); | ||
| 241 | return 0; | ||
| 242 | } | ||
| 243 | |||
| 244 | std::optional<u32> MemoryAllocator::FindType(VkMemoryPropertyFlags flags, u32 type_mask) const { | ||
| 245 | for (u32 type_index = 0; type_index < properties.memoryTypeCount; ++type_index) { | ||
| 246 | const VkMemoryPropertyFlags type_flags = properties.memoryTypes[type_index].propertyFlags; | ||
| 247 | if ((type_mask & (1U << type_index)) && (type_flags & flags)) { | ||
| 248 | // The type matches in type and in the wanted properties. | ||
| 249 | return type_index; | ||
| 250 | } | ||
| 251 | } | ||
| 252 | // Failed to find index | ||
| 253 | return std::nullopt; | ||
| 254 | } | ||
| 255 | |||
| 256 | bool IsHostVisible(MemoryUsage usage) noexcept { | ||
| 257 | switch (usage) { | ||
| 258 | case MemoryUsage::DeviceLocal: | ||
| 259 | return false; | ||
| 260 | case MemoryUsage::Upload: | ||
| 261 | case MemoryUsage::Download: | ||
| 262 | return true; | ||
| 263 | } | ||
| 264 | UNREACHABLE_MSG("Invalid memory usage={}", usage); | ||
| 265 | return false; | ||
| 266 | } | ||
| 267 | |||
| 268 | } // namespace Vulkan | ||
diff --git a/src/video_core/vulkan_common/vulkan_memory_allocator.h b/src/video_core/vulkan_common/vulkan_memory_allocator.h new file mode 100644 index 000000000..53b3b275a --- /dev/null +++ b/src/video_core/vulkan_common/vulkan_memory_allocator.h | |||
| @@ -0,0 +1,118 @@ | |||
| 1 | // Copyright 2019 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 <memory> | ||
| 8 | #include <span> | ||
| 9 | #include <utility> | ||
| 10 | #include <vector> | ||
| 11 | #include "common/common_types.h" | ||
| 12 | #include "video_core/vulkan_common/vulkan_wrapper.h" | ||
| 13 | |||
| 14 | namespace Vulkan { | ||
| 15 | |||
| 16 | class Device; | ||
| 17 | class MemoryMap; | ||
| 18 | class MemoryAllocation; | ||
| 19 | |||
| 20 | /// Hints and requirements for the backing memory type of a commit | ||
| 21 | enum class MemoryUsage { | ||
| 22 | DeviceLocal, ///< Hints device local usages, fastest memory type to read and write from the GPU | ||
| 23 | Upload, ///< Requires a host visible memory type optimized for CPU to GPU uploads | ||
| 24 | Download, ///< Requires a host visible memory type optimized for GPU to CPU readbacks | ||
| 25 | }; | ||
| 26 | |||
| 27 | /// Ownership handle of a memory commitment. | ||
| 28 | /// Points to a subregion of a memory allocation. | ||
| 29 | class MemoryCommit { | ||
| 30 | public: | ||
| 31 | explicit MemoryCommit() noexcept = default; | ||
| 32 | explicit MemoryCommit(MemoryAllocation* allocation_, VkDeviceMemory memory_, u64 begin_, | ||
| 33 | u64 end_) noexcept; | ||
| 34 | ~MemoryCommit(); | ||
| 35 | |||
| 36 | MemoryCommit& operator=(MemoryCommit&&) noexcept; | ||
| 37 | MemoryCommit(MemoryCommit&&) noexcept; | ||
| 38 | |||
| 39 | MemoryCommit& operator=(const MemoryCommit&) = delete; | ||
| 40 | MemoryCommit(const MemoryCommit&) = delete; | ||
| 41 | |||
| 42 | /// Returns a host visible memory map. | ||
| 43 | /// It will map the backing allocation if it hasn't been mapped before. | ||
| 44 | std::span<u8> Map(); | ||
| 45 | |||
| 46 | /// Returns the Vulkan memory handler. | ||
| 47 | VkDeviceMemory Memory() const { | ||
| 48 | return memory; | ||
| 49 | } | ||
| 50 | |||
| 51 | /// Returns the start position of the commit relative to the allocation. | ||
| 52 | VkDeviceSize Offset() const { | ||
| 53 | return static_cast<VkDeviceSize>(begin); | ||
| 54 | } | ||
| 55 | |||
| 56 | private: | ||
| 57 | void Release(); | ||
| 58 | |||
| 59 | MemoryAllocation* allocation{}; ///< Pointer to the large memory allocation. | ||
| 60 | VkDeviceMemory memory{}; ///< Vulkan device memory handler. | ||
| 61 | u64 begin{}; ///< Beginning offset in bytes to where the commit exists. | ||
| 62 | u64 end{}; ///< Offset in bytes where the commit ends. | ||
| 63 | std::span<u8> span; ///< Host visible memory span. Empty if not queried before. | ||
| 64 | }; | ||
| 65 | |||
| 66 | /// Memory allocator container. | ||
| 67 | /// Allocates and releases memory allocations on demand. | ||
| 68 | class MemoryAllocator { | ||
| 69 | public: | ||
| 70 | explicit MemoryAllocator(const Device& device_); | ||
| 71 | ~MemoryAllocator(); | ||
| 72 | |||
| 73 | MemoryAllocator& operator=(const MemoryAllocator&) = delete; | ||
| 74 | MemoryAllocator(const MemoryAllocator&) = delete; | ||
| 75 | |||
| 76 | /** | ||
| 77 | * Commits a memory with the specified requeriments. | ||
| 78 | * | ||
| 79 | * @param requirements Requirements returned from a Vulkan call. | ||
| 80 | * @param host_visible Signals the allocator that it *must* use host visible and coherent | ||
| 81 | * memory. When passing false, it will try to allocate device local memory. | ||
| 82 | * | ||
| 83 | * @returns A memory commit. | ||
| 84 | */ | ||
| 85 | MemoryCommit Commit(const VkMemoryRequirements& requirements, MemoryUsage usage); | ||
| 86 | |||
| 87 | /// Commits memory required by the buffer and binds it. | ||
| 88 | MemoryCommit Commit(const vk::Buffer& buffer, MemoryUsage usage); | ||
| 89 | |||
| 90 | /// Commits memory required by the image and binds it. | ||
| 91 | MemoryCommit Commit(const vk::Image& image, MemoryUsage usage); | ||
| 92 | |||
| 93 | private: | ||
| 94 | /// Allocates a chunk of memory. | ||
| 95 | void AllocMemory(VkMemoryPropertyFlags flags, u32 type_mask, u64 size); | ||
| 96 | |||
| 97 | /// Tries to allocate a memory commit. | ||
| 98 | std::optional<MemoryCommit> TryCommit(const VkMemoryRequirements& requirements, | ||
| 99 | VkMemoryPropertyFlags flags); | ||
| 100 | |||
| 101 | /// Returns the fastest compatible memory property flags from a wanted usage. | ||
| 102 | VkMemoryPropertyFlags MemoryPropertyFlags(u32 type_mask, MemoryUsage usage) const; | ||
| 103 | |||
| 104 | /// Returns the fastest compatible memory property flags from the wanted flags. | ||
| 105 | VkMemoryPropertyFlags MemoryPropertyFlags(u32 type_mask, VkMemoryPropertyFlags flags) const; | ||
| 106 | |||
| 107 | /// Returns index to the fastest memory type compatible with the passed requirements. | ||
| 108 | std::optional<u32> FindType(VkMemoryPropertyFlags flags, u32 type_mask) const; | ||
| 109 | |||
| 110 | const Device& device; ///< Device handle. | ||
| 111 | const VkPhysicalDeviceMemoryProperties properties; ///< Physical device properties. | ||
| 112 | std::vector<std::unique_ptr<MemoryAllocation>> allocations; ///< Current allocations. | ||
| 113 | }; | ||
| 114 | |||
| 115 | /// Returns true when a memory usage is guaranteed to be host visible. | ||
| 116 | bool IsHostVisible(MemoryUsage usage) noexcept; | ||
| 117 | |||
| 118 | } // namespace Vulkan | ||
diff --git a/src/video_core/vulkan_common/vulkan_wrapper.h b/src/video_core/vulkan_common/vulkan_wrapper.h index 912cab46c..9689de0cb 100644 --- a/src/video_core/vulkan_common/vulkan_wrapper.h +++ b/src/video_core/vulkan_common/vulkan_wrapper.h | |||
| @@ -144,152 +144,152 @@ inline VkResult Filter(VkResult result) { | |||
| 144 | 144 | ||
| 145 | /// Table holding Vulkan instance function pointers. | 145 | /// Table holding Vulkan instance function pointers. |
| 146 | struct InstanceDispatch { | 146 | struct InstanceDispatch { |
| 147 | PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr; | 147 | PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr{}; |
| 148 | 148 | ||
| 149 | PFN_vkCreateInstance vkCreateInstance; | 149 | PFN_vkCreateInstance vkCreateInstance{}; |
| 150 | PFN_vkDestroyInstance vkDestroyInstance; | 150 | PFN_vkDestroyInstance vkDestroyInstance{}; |
| 151 | PFN_vkEnumerateInstanceExtensionProperties vkEnumerateInstanceExtensionProperties; | 151 | PFN_vkEnumerateInstanceExtensionProperties vkEnumerateInstanceExtensionProperties{}; |
| 152 | PFN_vkEnumerateInstanceLayerProperties vkEnumerateInstanceLayerProperties; | 152 | PFN_vkEnumerateInstanceLayerProperties vkEnumerateInstanceLayerProperties{}; |
| 153 | 153 | ||
| 154 | PFN_vkCreateDebugUtilsMessengerEXT vkCreateDebugUtilsMessengerEXT; | 154 | PFN_vkCreateDebugUtilsMessengerEXT vkCreateDebugUtilsMessengerEXT{}; |
| 155 | PFN_vkCreateDevice vkCreateDevice; | 155 | PFN_vkCreateDevice vkCreateDevice{}; |
| 156 | PFN_vkDestroyDebugUtilsMessengerEXT vkDestroyDebugUtilsMessengerEXT; | 156 | PFN_vkDestroyDebugUtilsMessengerEXT vkDestroyDebugUtilsMessengerEXT{}; |
| 157 | PFN_vkDestroyDevice vkDestroyDevice; | 157 | PFN_vkDestroyDevice vkDestroyDevice{}; |
| 158 | PFN_vkDestroySurfaceKHR vkDestroySurfaceKHR; | 158 | PFN_vkDestroySurfaceKHR vkDestroySurfaceKHR{}; |
| 159 | PFN_vkEnumerateDeviceExtensionProperties vkEnumerateDeviceExtensionProperties; | 159 | PFN_vkEnumerateDeviceExtensionProperties vkEnumerateDeviceExtensionProperties{}; |
| 160 | PFN_vkEnumeratePhysicalDevices vkEnumeratePhysicalDevices; | 160 | PFN_vkEnumeratePhysicalDevices vkEnumeratePhysicalDevices{}; |
| 161 | PFN_vkGetDeviceProcAddr vkGetDeviceProcAddr; | 161 | PFN_vkGetDeviceProcAddr vkGetDeviceProcAddr{}; |
| 162 | PFN_vkGetPhysicalDeviceFeatures2KHR vkGetPhysicalDeviceFeatures2KHR; | 162 | PFN_vkGetPhysicalDeviceFeatures2KHR vkGetPhysicalDeviceFeatures2KHR{}; |
| 163 | PFN_vkGetPhysicalDeviceFormatProperties vkGetPhysicalDeviceFormatProperties; | 163 | PFN_vkGetPhysicalDeviceFormatProperties vkGetPhysicalDeviceFormatProperties{}; |
| 164 | PFN_vkGetPhysicalDeviceMemoryProperties vkGetPhysicalDeviceMemoryProperties; | 164 | PFN_vkGetPhysicalDeviceMemoryProperties vkGetPhysicalDeviceMemoryProperties{}; |
| 165 | PFN_vkGetPhysicalDeviceProperties vkGetPhysicalDeviceProperties; | 165 | PFN_vkGetPhysicalDeviceProperties vkGetPhysicalDeviceProperties{}; |
| 166 | PFN_vkGetPhysicalDeviceProperties2KHR vkGetPhysicalDeviceProperties2KHR; | 166 | PFN_vkGetPhysicalDeviceProperties2KHR vkGetPhysicalDeviceProperties2KHR{}; |
| 167 | PFN_vkGetPhysicalDeviceQueueFamilyProperties vkGetPhysicalDeviceQueueFamilyProperties; | 167 | PFN_vkGetPhysicalDeviceQueueFamilyProperties vkGetPhysicalDeviceQueueFamilyProperties{}; |
| 168 | PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR vkGetPhysicalDeviceSurfaceCapabilitiesKHR; | 168 | PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR vkGetPhysicalDeviceSurfaceCapabilitiesKHR{}; |
| 169 | PFN_vkGetPhysicalDeviceSurfaceFormatsKHR vkGetPhysicalDeviceSurfaceFormatsKHR; | 169 | PFN_vkGetPhysicalDeviceSurfaceFormatsKHR vkGetPhysicalDeviceSurfaceFormatsKHR{}; |
| 170 | PFN_vkGetPhysicalDeviceSurfacePresentModesKHR vkGetPhysicalDeviceSurfacePresentModesKHR; | 170 | PFN_vkGetPhysicalDeviceSurfacePresentModesKHR vkGetPhysicalDeviceSurfacePresentModesKHR{}; |
| 171 | PFN_vkGetPhysicalDeviceSurfaceSupportKHR vkGetPhysicalDeviceSurfaceSupportKHR; | 171 | PFN_vkGetPhysicalDeviceSurfaceSupportKHR vkGetPhysicalDeviceSurfaceSupportKHR{}; |
| 172 | PFN_vkGetSwapchainImagesKHR vkGetSwapchainImagesKHR; | 172 | PFN_vkGetSwapchainImagesKHR vkGetSwapchainImagesKHR{}; |
| 173 | PFN_vkQueuePresentKHR vkQueuePresentKHR; | 173 | PFN_vkQueuePresentKHR vkQueuePresentKHR{}; |
| 174 | }; | 174 | }; |
| 175 | 175 | ||
| 176 | /// Table holding Vulkan device function pointers. | 176 | /// Table holding Vulkan device function pointers. |
| 177 | struct DeviceDispatch : public InstanceDispatch { | 177 | struct DeviceDispatch : public InstanceDispatch { |
| 178 | PFN_vkAcquireNextImageKHR vkAcquireNextImageKHR; | 178 | PFN_vkAcquireNextImageKHR vkAcquireNextImageKHR{}; |
| 179 | PFN_vkAllocateCommandBuffers vkAllocateCommandBuffers; | 179 | PFN_vkAllocateCommandBuffers vkAllocateCommandBuffers{}; |
| 180 | PFN_vkAllocateDescriptorSets vkAllocateDescriptorSets; | 180 | PFN_vkAllocateDescriptorSets vkAllocateDescriptorSets{}; |
| 181 | PFN_vkAllocateMemory vkAllocateMemory; | 181 | PFN_vkAllocateMemory vkAllocateMemory{}; |
| 182 | PFN_vkBeginCommandBuffer vkBeginCommandBuffer; | 182 | PFN_vkBeginCommandBuffer vkBeginCommandBuffer{}; |
| 183 | PFN_vkBindBufferMemory vkBindBufferMemory; | 183 | PFN_vkBindBufferMemory vkBindBufferMemory{}; |
| 184 | PFN_vkBindImageMemory vkBindImageMemory; | 184 | PFN_vkBindImageMemory vkBindImageMemory{}; |
| 185 | PFN_vkCmdBeginQuery vkCmdBeginQuery; | 185 | PFN_vkCmdBeginQuery vkCmdBeginQuery{}; |
| 186 | PFN_vkCmdBeginRenderPass vkCmdBeginRenderPass; | 186 | PFN_vkCmdBeginRenderPass vkCmdBeginRenderPass{}; |
| 187 | PFN_vkCmdBeginTransformFeedbackEXT vkCmdBeginTransformFeedbackEXT; | 187 | PFN_vkCmdBeginTransformFeedbackEXT vkCmdBeginTransformFeedbackEXT{}; |
| 188 | PFN_vkCmdBeginDebugUtilsLabelEXT vkCmdBeginDebugUtilsLabelEXT; | 188 | PFN_vkCmdBeginDebugUtilsLabelEXT vkCmdBeginDebugUtilsLabelEXT{}; |
| 189 | PFN_vkCmdBindDescriptorSets vkCmdBindDescriptorSets; | 189 | PFN_vkCmdBindDescriptorSets vkCmdBindDescriptorSets{}; |
| 190 | PFN_vkCmdBindIndexBuffer vkCmdBindIndexBuffer; | 190 | PFN_vkCmdBindIndexBuffer vkCmdBindIndexBuffer{}; |
| 191 | PFN_vkCmdBindPipeline vkCmdBindPipeline; | 191 | PFN_vkCmdBindPipeline vkCmdBindPipeline{}; |
| 192 | PFN_vkCmdBindTransformFeedbackBuffersEXT vkCmdBindTransformFeedbackBuffersEXT; | 192 | PFN_vkCmdBindTransformFeedbackBuffersEXT vkCmdBindTransformFeedbackBuffersEXT{}; |
| 193 | PFN_vkCmdBindVertexBuffers vkCmdBindVertexBuffers; | 193 | PFN_vkCmdBindVertexBuffers vkCmdBindVertexBuffers{}; |
| 194 | PFN_vkCmdBlitImage vkCmdBlitImage; | 194 | PFN_vkCmdBlitImage vkCmdBlitImage{}; |
| 195 | PFN_vkCmdClearAttachments vkCmdClearAttachments; | 195 | PFN_vkCmdClearAttachments vkCmdClearAttachments{}; |
| 196 | PFN_vkCmdCopyBuffer vkCmdCopyBuffer; | 196 | PFN_vkCmdCopyBuffer vkCmdCopyBuffer{}; |
| 197 | PFN_vkCmdCopyBufferToImage vkCmdCopyBufferToImage; | 197 | PFN_vkCmdCopyBufferToImage vkCmdCopyBufferToImage{}; |
| 198 | PFN_vkCmdCopyImage vkCmdCopyImage; | 198 | PFN_vkCmdCopyImage vkCmdCopyImage{}; |
| 199 | PFN_vkCmdCopyImageToBuffer vkCmdCopyImageToBuffer; | 199 | PFN_vkCmdCopyImageToBuffer vkCmdCopyImageToBuffer{}; |
| 200 | PFN_vkCmdDispatch vkCmdDispatch; | 200 | PFN_vkCmdDispatch vkCmdDispatch{}; |
| 201 | PFN_vkCmdDraw vkCmdDraw; | 201 | PFN_vkCmdDraw vkCmdDraw{}; |
| 202 | PFN_vkCmdDrawIndexed vkCmdDrawIndexed; | 202 | PFN_vkCmdDrawIndexed vkCmdDrawIndexed{}; |
| 203 | PFN_vkCmdEndQuery vkCmdEndQuery; | 203 | PFN_vkCmdEndQuery vkCmdEndQuery{}; |
| 204 | PFN_vkCmdEndRenderPass vkCmdEndRenderPass; | 204 | PFN_vkCmdEndRenderPass vkCmdEndRenderPass{}; |
| 205 | PFN_vkCmdEndTransformFeedbackEXT vkCmdEndTransformFeedbackEXT; | 205 | PFN_vkCmdEndTransformFeedbackEXT vkCmdEndTransformFeedbackEXT{}; |
| 206 | PFN_vkCmdEndDebugUtilsLabelEXT vkCmdEndDebugUtilsLabelEXT; | 206 | PFN_vkCmdEndDebugUtilsLabelEXT vkCmdEndDebugUtilsLabelEXT{}; |
| 207 | PFN_vkCmdFillBuffer vkCmdFillBuffer; | 207 | PFN_vkCmdFillBuffer vkCmdFillBuffer{}; |
| 208 | PFN_vkCmdPipelineBarrier vkCmdPipelineBarrier; | 208 | PFN_vkCmdPipelineBarrier vkCmdPipelineBarrier{}; |
| 209 | PFN_vkCmdPushConstants vkCmdPushConstants; | 209 | PFN_vkCmdPushConstants vkCmdPushConstants{}; |
| 210 | PFN_vkCmdSetBlendConstants vkCmdSetBlendConstants; | 210 | PFN_vkCmdSetBlendConstants vkCmdSetBlendConstants{}; |
| 211 | PFN_vkCmdSetDepthBias vkCmdSetDepthBias; | 211 | PFN_vkCmdSetDepthBias vkCmdSetDepthBias{}; |
| 212 | PFN_vkCmdSetDepthBounds vkCmdSetDepthBounds; | 212 | PFN_vkCmdSetDepthBounds vkCmdSetDepthBounds{}; |
| 213 | PFN_vkCmdSetEvent vkCmdSetEvent; | 213 | PFN_vkCmdSetEvent vkCmdSetEvent{}; |
| 214 | PFN_vkCmdSetScissor vkCmdSetScissor; | 214 | PFN_vkCmdSetScissor vkCmdSetScissor{}; |
| 215 | PFN_vkCmdSetStencilCompareMask vkCmdSetStencilCompareMask; | 215 | PFN_vkCmdSetStencilCompareMask vkCmdSetStencilCompareMask{}; |
| 216 | PFN_vkCmdSetStencilReference vkCmdSetStencilReference; | 216 | PFN_vkCmdSetStencilReference vkCmdSetStencilReference{}; |
| 217 | PFN_vkCmdSetStencilWriteMask vkCmdSetStencilWriteMask; | 217 | PFN_vkCmdSetStencilWriteMask vkCmdSetStencilWriteMask{}; |
| 218 | PFN_vkCmdSetViewport vkCmdSetViewport; | 218 | PFN_vkCmdSetViewport vkCmdSetViewport{}; |
| 219 | PFN_vkCmdWaitEvents vkCmdWaitEvents; | 219 | PFN_vkCmdWaitEvents vkCmdWaitEvents{}; |
| 220 | PFN_vkCmdBindVertexBuffers2EXT vkCmdBindVertexBuffers2EXT; | 220 | PFN_vkCmdBindVertexBuffers2EXT vkCmdBindVertexBuffers2EXT{}; |
| 221 | PFN_vkCmdSetCullModeEXT vkCmdSetCullModeEXT; | 221 | PFN_vkCmdSetCullModeEXT vkCmdSetCullModeEXT{}; |
| 222 | PFN_vkCmdSetDepthBoundsTestEnableEXT vkCmdSetDepthBoundsTestEnableEXT; | 222 | PFN_vkCmdSetDepthBoundsTestEnableEXT vkCmdSetDepthBoundsTestEnableEXT{}; |
| 223 | PFN_vkCmdSetDepthCompareOpEXT vkCmdSetDepthCompareOpEXT; | 223 | PFN_vkCmdSetDepthCompareOpEXT vkCmdSetDepthCompareOpEXT{}; |
| 224 | PFN_vkCmdSetDepthTestEnableEXT vkCmdSetDepthTestEnableEXT; | 224 | PFN_vkCmdSetDepthTestEnableEXT vkCmdSetDepthTestEnableEXT{}; |
| 225 | PFN_vkCmdSetDepthWriteEnableEXT vkCmdSetDepthWriteEnableEXT; | 225 | PFN_vkCmdSetDepthWriteEnableEXT vkCmdSetDepthWriteEnableEXT{}; |
| 226 | PFN_vkCmdSetFrontFaceEXT vkCmdSetFrontFaceEXT; | 226 | PFN_vkCmdSetFrontFaceEXT vkCmdSetFrontFaceEXT{}; |
| 227 | PFN_vkCmdSetPrimitiveTopologyEXT vkCmdSetPrimitiveTopologyEXT; | 227 | PFN_vkCmdSetPrimitiveTopologyEXT vkCmdSetPrimitiveTopologyEXT{}; |
| 228 | PFN_vkCmdSetStencilOpEXT vkCmdSetStencilOpEXT; | 228 | PFN_vkCmdSetStencilOpEXT vkCmdSetStencilOpEXT{}; |
| 229 | PFN_vkCmdSetStencilTestEnableEXT vkCmdSetStencilTestEnableEXT; | 229 | PFN_vkCmdSetStencilTestEnableEXT vkCmdSetStencilTestEnableEXT{}; |
| 230 | PFN_vkCmdResolveImage vkCmdResolveImage; | 230 | PFN_vkCmdResolveImage vkCmdResolveImage{}; |
| 231 | PFN_vkCreateBuffer vkCreateBuffer; | 231 | PFN_vkCreateBuffer vkCreateBuffer{}; |
| 232 | PFN_vkCreateBufferView vkCreateBufferView; | 232 | PFN_vkCreateBufferView vkCreateBufferView{}; |
| 233 | PFN_vkCreateCommandPool vkCreateCommandPool; | 233 | PFN_vkCreateCommandPool vkCreateCommandPool{}; |
| 234 | PFN_vkCreateComputePipelines vkCreateComputePipelines; | 234 | PFN_vkCreateComputePipelines vkCreateComputePipelines{}; |
| 235 | PFN_vkCreateDescriptorPool vkCreateDescriptorPool; | 235 | PFN_vkCreateDescriptorPool vkCreateDescriptorPool{}; |
| 236 | PFN_vkCreateDescriptorSetLayout vkCreateDescriptorSetLayout; | 236 | PFN_vkCreateDescriptorSetLayout vkCreateDescriptorSetLayout{}; |
| 237 | PFN_vkCreateDescriptorUpdateTemplateKHR vkCreateDescriptorUpdateTemplateKHR; | 237 | PFN_vkCreateDescriptorUpdateTemplateKHR vkCreateDescriptorUpdateTemplateKHR{}; |
| 238 | PFN_vkCreateEvent vkCreateEvent; | 238 | PFN_vkCreateEvent vkCreateEvent{}; |
| 239 | PFN_vkCreateFence vkCreateFence; | 239 | PFN_vkCreateFence vkCreateFence{}; |
| 240 | PFN_vkCreateFramebuffer vkCreateFramebuffer; | 240 | PFN_vkCreateFramebuffer vkCreateFramebuffer{}; |
| 241 | PFN_vkCreateGraphicsPipelines vkCreateGraphicsPipelines; | 241 | PFN_vkCreateGraphicsPipelines vkCreateGraphicsPipelines{}; |
| 242 | PFN_vkCreateImage vkCreateImage; | 242 | PFN_vkCreateImage vkCreateImage{}; |
| 243 | PFN_vkCreateImageView vkCreateImageView; | 243 | PFN_vkCreateImageView vkCreateImageView{}; |
| 244 | PFN_vkCreatePipelineLayout vkCreatePipelineLayout; | 244 | PFN_vkCreatePipelineLayout vkCreatePipelineLayout{}; |
| 245 | PFN_vkCreateQueryPool vkCreateQueryPool; | 245 | PFN_vkCreateQueryPool vkCreateQueryPool{}; |
| 246 | PFN_vkCreateRenderPass vkCreateRenderPass; | 246 | PFN_vkCreateRenderPass vkCreateRenderPass{}; |
| 247 | PFN_vkCreateSampler vkCreateSampler; | 247 | PFN_vkCreateSampler vkCreateSampler{}; |
| 248 | PFN_vkCreateSemaphore vkCreateSemaphore; | 248 | PFN_vkCreateSemaphore vkCreateSemaphore{}; |
| 249 | PFN_vkCreateShaderModule vkCreateShaderModule; | 249 | PFN_vkCreateShaderModule vkCreateShaderModule{}; |
| 250 | PFN_vkCreateSwapchainKHR vkCreateSwapchainKHR; | 250 | PFN_vkCreateSwapchainKHR vkCreateSwapchainKHR{}; |
| 251 | PFN_vkDestroyBuffer vkDestroyBuffer; | 251 | PFN_vkDestroyBuffer vkDestroyBuffer{}; |
| 252 | PFN_vkDestroyBufferView vkDestroyBufferView; | 252 | PFN_vkDestroyBufferView vkDestroyBufferView{}; |
| 253 | PFN_vkDestroyCommandPool vkDestroyCommandPool; | 253 | PFN_vkDestroyCommandPool vkDestroyCommandPool{}; |
| 254 | PFN_vkDestroyDescriptorPool vkDestroyDescriptorPool; | 254 | PFN_vkDestroyDescriptorPool vkDestroyDescriptorPool{}; |
| 255 | PFN_vkDestroyDescriptorSetLayout vkDestroyDescriptorSetLayout; | 255 | PFN_vkDestroyDescriptorSetLayout vkDestroyDescriptorSetLayout{}; |
| 256 | PFN_vkDestroyDescriptorUpdateTemplateKHR vkDestroyDescriptorUpdateTemplateKHR; | 256 | PFN_vkDestroyDescriptorUpdateTemplateKHR vkDestroyDescriptorUpdateTemplateKHR{}; |
| 257 | PFN_vkDestroyEvent vkDestroyEvent; | 257 | PFN_vkDestroyEvent vkDestroyEvent{}; |
| 258 | PFN_vkDestroyFence vkDestroyFence; | 258 | PFN_vkDestroyFence vkDestroyFence{}; |
| 259 | PFN_vkDestroyFramebuffer vkDestroyFramebuffer; | 259 | PFN_vkDestroyFramebuffer vkDestroyFramebuffer{}; |
| 260 | PFN_vkDestroyImage vkDestroyImage; | 260 | PFN_vkDestroyImage vkDestroyImage{}; |
| 261 | PFN_vkDestroyImageView vkDestroyImageView; | 261 | PFN_vkDestroyImageView vkDestroyImageView{}; |
| 262 | PFN_vkDestroyPipeline vkDestroyPipeline; | 262 | PFN_vkDestroyPipeline vkDestroyPipeline{}; |
| 263 | PFN_vkDestroyPipelineLayout vkDestroyPipelineLayout; | 263 | PFN_vkDestroyPipelineLayout vkDestroyPipelineLayout{}; |
| 264 | PFN_vkDestroyQueryPool vkDestroyQueryPool; | 264 | PFN_vkDestroyQueryPool vkDestroyQueryPool{}; |
| 265 | PFN_vkDestroyRenderPass vkDestroyRenderPass; | 265 | PFN_vkDestroyRenderPass vkDestroyRenderPass{}; |
| 266 | PFN_vkDestroySampler vkDestroySampler; | 266 | PFN_vkDestroySampler vkDestroySampler{}; |
| 267 | PFN_vkDestroySemaphore vkDestroySemaphore; | 267 | PFN_vkDestroySemaphore vkDestroySemaphore{}; |
| 268 | PFN_vkDestroyShaderModule vkDestroyShaderModule; | 268 | PFN_vkDestroyShaderModule vkDestroyShaderModule{}; |
| 269 | PFN_vkDestroySwapchainKHR vkDestroySwapchainKHR; | 269 | PFN_vkDestroySwapchainKHR vkDestroySwapchainKHR{}; |
| 270 | PFN_vkDeviceWaitIdle vkDeviceWaitIdle; | 270 | PFN_vkDeviceWaitIdle vkDeviceWaitIdle{}; |
| 271 | PFN_vkEndCommandBuffer vkEndCommandBuffer; | 271 | PFN_vkEndCommandBuffer vkEndCommandBuffer{}; |
| 272 | PFN_vkFreeCommandBuffers vkFreeCommandBuffers; | 272 | PFN_vkFreeCommandBuffers vkFreeCommandBuffers{}; |
| 273 | PFN_vkFreeDescriptorSets vkFreeDescriptorSets; | 273 | PFN_vkFreeDescriptorSets vkFreeDescriptorSets{}; |
| 274 | PFN_vkFreeMemory vkFreeMemory; | 274 | PFN_vkFreeMemory vkFreeMemory{}; |
| 275 | PFN_vkGetBufferMemoryRequirements vkGetBufferMemoryRequirements; | 275 | PFN_vkGetBufferMemoryRequirements vkGetBufferMemoryRequirements{}; |
| 276 | PFN_vkGetDeviceQueue vkGetDeviceQueue; | 276 | PFN_vkGetDeviceQueue vkGetDeviceQueue{}; |
| 277 | PFN_vkGetEventStatus vkGetEventStatus; | 277 | PFN_vkGetEventStatus vkGetEventStatus{}; |
| 278 | PFN_vkGetFenceStatus vkGetFenceStatus; | 278 | PFN_vkGetFenceStatus vkGetFenceStatus{}; |
| 279 | PFN_vkGetImageMemoryRequirements vkGetImageMemoryRequirements; | 279 | PFN_vkGetImageMemoryRequirements vkGetImageMemoryRequirements{}; |
| 280 | PFN_vkGetQueryPoolResults vkGetQueryPoolResults; | 280 | PFN_vkGetQueryPoolResults vkGetQueryPoolResults{}; |
| 281 | PFN_vkGetSemaphoreCounterValueKHR vkGetSemaphoreCounterValueKHR; | 281 | PFN_vkGetSemaphoreCounterValueKHR vkGetSemaphoreCounterValueKHR{}; |
| 282 | PFN_vkMapMemory vkMapMemory; | 282 | PFN_vkMapMemory vkMapMemory{}; |
| 283 | PFN_vkQueueSubmit vkQueueSubmit; | 283 | PFN_vkQueueSubmit vkQueueSubmit{}; |
| 284 | PFN_vkResetFences vkResetFences; | 284 | PFN_vkResetFences vkResetFences{}; |
| 285 | PFN_vkResetQueryPoolEXT vkResetQueryPoolEXT; | 285 | PFN_vkResetQueryPoolEXT vkResetQueryPoolEXT{}; |
| 286 | PFN_vkSetDebugUtilsObjectNameEXT vkSetDebugUtilsObjectNameEXT; | 286 | PFN_vkSetDebugUtilsObjectNameEXT vkSetDebugUtilsObjectNameEXT{}; |
| 287 | PFN_vkSetDebugUtilsObjectTagEXT vkSetDebugUtilsObjectTagEXT; | 287 | PFN_vkSetDebugUtilsObjectTagEXT vkSetDebugUtilsObjectTagEXT{}; |
| 288 | PFN_vkUnmapMemory vkUnmapMemory; | 288 | PFN_vkUnmapMemory vkUnmapMemory{}; |
| 289 | PFN_vkUpdateDescriptorSetWithTemplateKHR vkUpdateDescriptorSetWithTemplateKHR; | 289 | PFN_vkUpdateDescriptorSetWithTemplateKHR vkUpdateDescriptorSetWithTemplateKHR{}; |
| 290 | PFN_vkUpdateDescriptorSets vkUpdateDescriptorSets; | 290 | PFN_vkUpdateDescriptorSets vkUpdateDescriptorSets{}; |
| 291 | PFN_vkWaitForFences vkWaitForFences; | 291 | PFN_vkWaitForFences vkWaitForFences{}; |
| 292 | PFN_vkWaitSemaphoresKHR vkWaitSemaphoresKHR; | 292 | PFN_vkWaitSemaphoresKHR vkWaitSemaphoresKHR{}; |
| 293 | }; | 293 | }; |
| 294 | 294 | ||
| 295 | /// Loads instance agnostic function pointers. | 295 | /// Loads instance agnostic function pointers. |
diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp index 85ee2577d..e6c8f18af 100644 --- a/src/yuzu/bootmanager.cpp +++ b/src/yuzu/bootmanager.cpp | |||
| @@ -290,8 +290,8 @@ GRenderWindow::GRenderWindow(GMainWindow* parent, EmuThread* emu_thread_, | |||
| 290 | QString::fromUtf8(Common::g_scm_branch), | 290 | QString::fromUtf8(Common::g_scm_branch), |
| 291 | QString::fromUtf8(Common::g_scm_desc))); | 291 | QString::fromUtf8(Common::g_scm_desc))); |
| 292 | setAttribute(Qt::WA_AcceptTouchEvents); | 292 | setAttribute(Qt::WA_AcceptTouchEvents); |
| 293 | auto layout = new QHBoxLayout(this); | 293 | auto* layout = new QHBoxLayout(this); |
| 294 | layout->setMargin(0); | 294 | layout->setContentsMargins(0, 0, 0, 0); |
| 295 | setLayout(layout); | 295 | setLayout(layout); |
| 296 | input_subsystem->Initialize(); | 296 | input_subsystem->Initialize(); |
| 297 | 297 | ||
diff --git a/src/yuzu/configuration/configure_dialog.cpp b/src/yuzu/configuration/configure_dialog.cpp index b33f8437a..d6b17a28d 100644 --- a/src/yuzu/configuration/configure_dialog.cpp +++ b/src/yuzu/configuration/configure_dialog.cpp | |||
| @@ -117,31 +117,13 @@ void ConfigureDialog::UpdateVisibleTabs() { | |||
| 117 | return; | 117 | return; |
| 118 | } | 118 | } |
| 119 | 119 | ||
| 120 | const std::map<QWidget*, QString> widgets = { | ||
| 121 | {ui->generalTab, tr("General")}, | ||
| 122 | {ui->systemTab, tr("System")}, | ||
| 123 | {ui->profileManagerTab, tr("Profiles")}, | ||
| 124 | {ui->inputTab, tr("Controls")}, | ||
| 125 | {ui->hotkeysTab, tr("Hotkeys")}, | ||
| 126 | {ui->cpuTab, tr("CPU")}, | ||
| 127 | {ui->cpuDebugTab, tr("Debug")}, | ||
| 128 | {ui->graphicsTab, tr("Graphics")}, | ||
| 129 | {ui->graphicsAdvancedTab, tr("Advanced")}, | ||
| 130 | {ui->audioTab, tr("Audio")}, | ||
| 131 | {ui->debugTab, tr("Debug")}, | ||
| 132 | {ui->webTab, tr("Web")}, | ||
| 133 | {ui->uiTab, tr("UI")}, | ||
| 134 | {ui->filesystemTab, tr("Filesystem")}, | ||
| 135 | {ui->serviceTab, tr("Services")}, | ||
| 136 | }; | ||
| 137 | |||
| 138 | [[maybe_unused]] const QSignalBlocker blocker(ui->tabWidget); | 120 | [[maybe_unused]] const QSignalBlocker blocker(ui->tabWidget); |
| 139 | 121 | ||
| 140 | ui->tabWidget->clear(); | 122 | ui->tabWidget->clear(); |
| 141 | 123 | ||
| 142 | const QList<QWidget*> tabs = qvariant_cast<QList<QWidget*>>(items[0]->data(Qt::UserRole)); | 124 | const auto tabs = qvariant_cast<QList<QWidget*>>(items[0]->data(Qt::UserRole)); |
| 143 | 125 | ||
| 144 | for (const auto tab : tabs) { | 126 | for (auto* const tab : tabs) { |
| 145 | ui->tabWidget->addTab(tab, tab->accessibleName()); | 127 | ui->tabWidget->addTab(tab, tab->accessibleName()); |
| 146 | } | 128 | } |
| 147 | } | 129 | } |
diff --git a/src/yuzu/configuration/configure_motion_touch.cpp b/src/yuzu/configuration/configure_motion_touch.cpp index eb8eacbf9..caaa85930 100644 --- a/src/yuzu/configuration/configure_motion_touch.cpp +++ b/src/yuzu/configuration/configure_motion_touch.cpp | |||
| @@ -4,12 +4,15 @@ | |||
| 4 | 4 | ||
| 5 | #include <array> | 5 | #include <array> |
| 6 | #include <sstream> | 6 | #include <sstream> |
| 7 | |||
| 7 | #include <QCloseEvent> | 8 | #include <QCloseEvent> |
| 8 | #include <QLabel> | 9 | #include <QLabel> |
| 9 | #include <QMessageBox> | 10 | #include <QMessageBox> |
| 10 | #include <QPushButton> | 11 | #include <QPushButton> |
| 12 | #include <QRegularExpression> | ||
| 11 | #include <QStringListModel> | 13 | #include <QStringListModel> |
| 12 | #include <QVBoxLayout> | 14 | #include <QVBoxLayout> |
| 15 | |||
| 13 | #include "common/logging/log.h" | 16 | #include "common/logging/log.h" |
| 14 | #include "core/settings.h" | 17 | #include "core/settings.h" |
| 15 | #include "input_common/main.h" | 18 | #include "input_common/main.h" |
| @@ -109,7 +112,6 @@ ConfigureMotionTouch::~ConfigureMotionTouch() = default; | |||
| 109 | void ConfigureMotionTouch::SetConfiguration() { | 112 | void ConfigureMotionTouch::SetConfiguration() { |
| 110 | const Common::ParamPackage motion_param(Settings::values.motion_device); | 113 | const Common::ParamPackage motion_param(Settings::values.motion_device); |
| 111 | const Common::ParamPackage touch_param(Settings::values.touch_device); | 114 | const Common::ParamPackage touch_param(Settings::values.touch_device); |
| 112 | const std::string motion_engine = motion_param.Get("engine", "motion_emu"); | ||
| 113 | const std::string touch_engine = touch_param.Get("engine", "emu_window"); | 115 | const std::string touch_engine = touch_param.Get("engine", "emu_window"); |
| 114 | 116 | ||
| 115 | ui->touch_provider->setCurrentIndex( | 117 | ui->touch_provider->setCurrentIndex( |
| @@ -185,14 +187,15 @@ void ConfigureMotionTouch::ConnectEvents() { | |||
| 185 | } | 187 | } |
| 186 | 188 | ||
| 187 | void ConfigureMotionTouch::OnUDPAddServer() { | 189 | void ConfigureMotionTouch::OnUDPAddServer() { |
| 188 | QRegExp re(tr(R"re(^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4]" | 190 | // Validator for IP address |
| 189 | "[0-9]|[01]?[0-9][0-9]?)$)re")); // a valid ip address | 191 | const QRegularExpression re(QStringLiteral( |
| 192 | R"re(^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$)re")); | ||
| 190 | bool ok; | 193 | bool ok; |
| 191 | QString port_text = ui->udp_port->text(); | 194 | const QString port_text = ui->udp_port->text(); |
| 192 | QString server_text = ui->udp_server->text(); | 195 | const QString server_text = ui->udp_server->text(); |
| 193 | const QString server_string = tr("%1:%2").arg(server_text, port_text); | 196 | const QString server_string = tr("%1:%2").arg(server_text, port_text); |
| 194 | int port_number = port_text.toInt(&ok, 10); | 197 | const int port_number = port_text.toInt(&ok, 10); |
| 195 | int row = udp_server_list_model->rowCount(); | 198 | const int row = udp_server_list_model->rowCount(); |
| 196 | 199 | ||
| 197 | if (!ok) { | 200 | if (!ok) { |
| 198 | QMessageBox::warning(this, tr("yuzu"), tr("Port number has invalid characters")); | 201 | QMessageBox::warning(this, tr("yuzu"), tr("Port number has invalid characters")); |
| @@ -202,7 +205,7 @@ void ConfigureMotionTouch::OnUDPAddServer() { | |||
| 202 | QMessageBox::warning(this, tr("yuzu"), tr("Port has to be in range 0 and 65353")); | 205 | QMessageBox::warning(this, tr("yuzu"), tr("Port has to be in range 0 and 65353")); |
| 203 | return; | 206 | return; |
| 204 | } | 207 | } |
| 205 | if (!re.exactMatch(server_text)) { | 208 | if (!re.match(server_text).hasMatch()) { |
| 206 | QMessageBox::warning(this, tr("yuzu"), tr("IP address is not valid")); | 209 | QMessageBox::warning(this, tr("yuzu"), tr("IP address is not valid")); |
| 207 | return; | 210 | return; |
| 208 | } | 211 | } |
| @@ -327,14 +330,13 @@ void ConfigureMotionTouch::ApplyConfiguration() { | |||
| 327 | std::string touch_engine = ui->touch_provider->currentData().toString().toStdString(); | 330 | std::string touch_engine = ui->touch_provider->currentData().toString().toStdString(); |
| 328 | 331 | ||
| 329 | Common::ParamPackage touch_param{}; | 332 | Common::ParamPackage touch_param{}; |
| 330 | touch_param.Set("engine", std::move(touch_engine)); | ||
| 331 | |||
| 332 | if (touch_engine == "cemuhookudp") { | 333 | if (touch_engine == "cemuhookudp") { |
| 333 | touch_param.Set("min_x", min_x); | 334 | touch_param.Set("min_x", min_x); |
| 334 | touch_param.Set("min_y", min_y); | 335 | touch_param.Set("min_y", min_y); |
| 335 | touch_param.Set("max_x", max_x); | 336 | touch_param.Set("max_x", max_x); |
| 336 | touch_param.Set("max_y", max_y); | 337 | touch_param.Set("max_y", max_y); |
| 337 | } | 338 | } |
| 339 | touch_param.Set("engine", std::move(touch_engine)); | ||
| 338 | 340 | ||
| 339 | Settings::values.touch_device = touch_param.Serialize(); | 341 | Settings::values.touch_device = touch_param.Serialize(); |
| 340 | Settings::values.use_touch_from_button = ui->touch_from_button_checkbox->isChecked(); | 342 | Settings::values.use_touch_from_button = ui->touch_from_button_checkbox->isChecked(); |
diff --git a/src/yuzu/game_list.cpp b/src/yuzu/game_list.cpp index 70d865112..37b0d1a0e 100644 --- a/src/yuzu/game_list.cpp +++ b/src/yuzu/game_list.cpp | |||
| @@ -119,7 +119,7 @@ void GameListSearchField::setFocus() { | |||
| 119 | GameListSearchField::GameListSearchField(GameList* parent) : QWidget{parent} { | 119 | GameListSearchField::GameListSearchField(GameList* parent) : QWidget{parent} { |
| 120 | auto* const key_release_eater = new KeyReleaseEater(parent, this); | 120 | auto* const key_release_eater = new KeyReleaseEater(parent, this); |
| 121 | layout_filter = new QHBoxLayout; | 121 | layout_filter = new QHBoxLayout; |
| 122 | layout_filter->setMargin(8); | 122 | layout_filter->setContentsMargins(8, 8, 8, 8); |
| 123 | label_filter = new QLabel; | 123 | label_filter = new QLabel; |
| 124 | label_filter->setText(tr("Filter:")); | 124 | label_filter->setText(tr("Filter:")); |
| 125 | edit_filter = new QLineEdit; | 125 | edit_filter = new QLineEdit; |
diff --git a/src/yuzu_tester/CMakeLists.txt b/src/yuzu_tester/CMakeLists.txt deleted file mode 100644 index d8a2a1511..000000000 --- a/src/yuzu_tester/CMakeLists.txt +++ /dev/null | |||
| @@ -1,32 +0,0 @@ | |||
| 1 | set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${PROJECT_SOURCE_DIR}/CMakeModules) | ||
| 2 | |||
| 3 | add_executable(yuzu-tester | ||
| 4 | config.cpp | ||
| 5 | config.h | ||
| 6 | default_ini.h | ||
| 7 | emu_window/emu_window_sdl2_hide.cpp | ||
| 8 | emu_window/emu_window_sdl2_hide.h | ||
| 9 | resource.h | ||
| 10 | service/yuzutest.cpp | ||
| 11 | service/yuzutest.h | ||
| 12 | yuzu.cpp | ||
| 13 | yuzu.rc | ||
| 14 | ) | ||
| 15 | |||
| 16 | create_target_directory_groups(yuzu-tester) | ||
| 17 | |||
| 18 | target_link_libraries(yuzu-tester PRIVATE common core input_common) | ||
| 19 | target_link_libraries(yuzu-tester PRIVATE inih glad) | ||
| 20 | if (MSVC) | ||
| 21 | target_link_libraries(yuzu-tester PRIVATE getopt) | ||
| 22 | endif() | ||
| 23 | target_link_libraries(yuzu-tester PRIVATE ${PLATFORM_LIBRARIES} SDL2 Threads::Threads) | ||
| 24 | |||
| 25 | if(UNIX AND NOT APPLE) | ||
| 26 | install(TARGETS yuzu-tester RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}/bin") | ||
| 27 | endif() | ||
| 28 | |||
| 29 | if (MSVC) | ||
| 30 | include(CopyYuzuSDLDeps) | ||
| 31 | copy_yuzu_SDL_deps(yuzu-tester) | ||
| 32 | endif() | ||
diff --git a/src/yuzu_tester/config.cpp b/src/yuzu_tester/config.cpp deleted file mode 100644 index 0aa143e1f..000000000 --- a/src/yuzu_tester/config.cpp +++ /dev/null | |||
| @@ -1,194 +0,0 @@ | |||
| 1 | // Copyright 2019 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <memory> | ||
| 6 | #include <sstream> | ||
| 7 | #include <SDL.h> | ||
| 8 | #include <inih/cpp/INIReader.h> | ||
| 9 | #include "common/file_util.h" | ||
| 10 | #include "common/logging/log.h" | ||
| 11 | #include "common/param_package.h" | ||
| 12 | #include "core/hle/service/acc/profile_manager.h" | ||
| 13 | #include "core/settings.h" | ||
| 14 | #include "input_common/main.h" | ||
| 15 | #include "yuzu_tester/config.h" | ||
| 16 | #include "yuzu_tester/default_ini.h" | ||
| 17 | |||
| 18 | namespace FS = Common::FS; | ||
| 19 | |||
| 20 | Config::Config() { | ||
| 21 | // TODO: Don't hardcode the path; let the frontend decide where to put the config files. | ||
| 22 | sdl2_config_loc = FS::GetUserPath(FS::UserPath::ConfigDir) + "sdl2-tester-config.ini"; | ||
| 23 | sdl2_config = std::make_unique<INIReader>(sdl2_config_loc); | ||
| 24 | |||
| 25 | Reload(); | ||
| 26 | } | ||
| 27 | |||
| 28 | Config::~Config() = default; | ||
| 29 | |||
| 30 | bool Config::LoadINI(const std::string& default_contents, bool retry) { | ||
| 31 | const char* location = this->sdl2_config_loc.c_str(); | ||
| 32 | if (sdl2_config->ParseError() < 0) { | ||
| 33 | if (retry) { | ||
| 34 | LOG_WARNING(Config, "Failed to load {}. Creating file from defaults...", location); | ||
| 35 | FS::CreateFullPath(location); | ||
| 36 | FS::WriteStringToFile(true, default_contents, location); | ||
| 37 | sdl2_config = std::make_unique<INIReader>(location); // Reopen file | ||
| 38 | |||
| 39 | return LoadINI(default_contents, false); | ||
| 40 | } | ||
| 41 | LOG_ERROR(Config, "Failed."); | ||
| 42 | return false; | ||
| 43 | } | ||
| 44 | LOG_INFO(Config, "Successfully loaded {}", location); | ||
| 45 | return true; | ||
| 46 | } | ||
| 47 | |||
| 48 | void Config::ReadValues() { | ||
| 49 | // Controls | ||
| 50 | for (std::size_t p = 0; p < Settings::values.players.GetValue().size(); ++p) { | ||
| 51 | for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) { | ||
| 52 | Settings::values.players.GetValue()[p].buttons[i] = ""; | ||
| 53 | } | ||
| 54 | |||
| 55 | for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) { | ||
| 56 | Settings::values.players.GetValue()[p].analogs[i] = ""; | ||
| 57 | } | ||
| 58 | } | ||
| 59 | |||
| 60 | Settings::values.mouse_enabled = false; | ||
| 61 | for (int i = 0; i < Settings::NativeMouseButton::NumMouseButtons; ++i) { | ||
| 62 | Settings::values.mouse_buttons[i] = ""; | ||
| 63 | } | ||
| 64 | |||
| 65 | Settings::values.motion_device = ""; | ||
| 66 | |||
| 67 | Settings::values.keyboard_enabled = false; | ||
| 68 | |||
| 69 | Settings::values.debug_pad_enabled = false; | ||
| 70 | for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) { | ||
| 71 | Settings::values.debug_pad_buttons[i] = ""; | ||
| 72 | } | ||
| 73 | |||
| 74 | for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) { | ||
| 75 | Settings::values.debug_pad_analogs[i] = ""; | ||
| 76 | } | ||
| 77 | |||
| 78 | Settings::values.vibration_enabled.SetValue(true); | ||
| 79 | Settings::values.enable_accurate_vibrations.SetValue(false); | ||
| 80 | Settings::values.motion_enabled.SetValue(true); | ||
| 81 | Settings::values.touchscreen.enabled = ""; | ||
| 82 | Settings::values.touchscreen.device = ""; | ||
| 83 | Settings::values.touchscreen.finger = 0; | ||
| 84 | Settings::values.touchscreen.rotation_angle = 0; | ||
| 85 | Settings::values.touchscreen.diameter_x = 15; | ||
| 86 | Settings::values.touchscreen.diameter_y = 15; | ||
| 87 | |||
| 88 | Settings::values.use_docked_mode.SetValue( | ||
| 89 | sdl2_config->GetBoolean("Controls", "use_docked_mode", true)); | ||
| 90 | |||
| 91 | // Data Storage | ||
| 92 | Settings::values.use_virtual_sd = | ||
| 93 | sdl2_config->GetBoolean("Data Storage", "use_virtual_sd", true); | ||
| 94 | FS::GetUserPath(Common::FS::UserPath::NANDDir, | ||
| 95 | sdl2_config->Get("Data Storage", "nand_directory", | ||
| 96 | Common::FS::GetUserPath(Common::FS::UserPath::NANDDir))); | ||
| 97 | FS::GetUserPath(Common::FS::UserPath::SDMCDir, | ||
| 98 | sdl2_config->Get("Data Storage", "sdmc_directory", | ||
| 99 | Common::FS::GetUserPath(Common::FS::UserPath::SDMCDir))); | ||
| 100 | |||
| 101 | // System | ||
| 102 | Settings::values.current_user = std::clamp<int>( | ||
| 103 | sdl2_config->GetInteger("System", "current_user", 0), 0, Service::Account::MAX_USERS - 1); | ||
| 104 | |||
| 105 | const auto rng_seed_enabled = sdl2_config->GetBoolean("System", "rng_seed_enabled", false); | ||
| 106 | if (rng_seed_enabled) { | ||
| 107 | Settings::values.rng_seed.SetValue(sdl2_config->GetInteger("System", "rng_seed", 0)); | ||
| 108 | } else { | ||
| 109 | Settings::values.rng_seed.SetValue(std::nullopt); | ||
| 110 | } | ||
| 111 | |||
| 112 | const auto custom_rtc_enabled = sdl2_config->GetBoolean("System", "custom_rtc_enabled", false); | ||
| 113 | if (custom_rtc_enabled) { | ||
| 114 | Settings::values.custom_rtc.SetValue( | ||
| 115 | std::chrono::seconds(sdl2_config->GetInteger("System", "custom_rtc", 0))); | ||
| 116 | } else { | ||
| 117 | Settings::values.custom_rtc.SetValue(std::nullopt); | ||
| 118 | } | ||
| 119 | |||
| 120 | // Core | ||
| 121 | Settings::values.use_multi_core.SetValue( | ||
| 122 | sdl2_config->GetBoolean("Core", "use_multi_core", false)); | ||
| 123 | |||
| 124 | // Renderer | ||
| 125 | Settings::values.aspect_ratio.SetValue( | ||
| 126 | static_cast<int>(sdl2_config->GetInteger("Renderer", "aspect_ratio", 0))); | ||
| 127 | Settings::values.max_anisotropy.SetValue( | ||
| 128 | static_cast<int>(sdl2_config->GetInteger("Renderer", "max_anisotropy", 0))); | ||
| 129 | Settings::values.use_frame_limit.SetValue(false); | ||
| 130 | Settings::values.frame_limit.SetValue(100); | ||
| 131 | Settings::values.use_disk_shader_cache.SetValue( | ||
| 132 | sdl2_config->GetBoolean("Renderer", "use_disk_shader_cache", false)); | ||
| 133 | const int gpu_accuracy_level = sdl2_config->GetInteger("Renderer", "gpu_accuracy", 0); | ||
| 134 | Settings::values.gpu_accuracy.SetValue(static_cast<Settings::GPUAccuracy>(gpu_accuracy_level)); | ||
| 135 | Settings::values.use_asynchronous_gpu_emulation.SetValue( | ||
| 136 | sdl2_config->GetBoolean("Renderer", "use_asynchronous_gpu_emulation", false)); | ||
| 137 | Settings::values.use_fast_gpu_time.SetValue( | ||
| 138 | sdl2_config->GetBoolean("Renderer", "use_fast_gpu_time", true)); | ||
| 139 | |||
| 140 | Settings::values.bg_red.SetValue( | ||
| 141 | static_cast<float>(sdl2_config->GetReal("Renderer", "bg_red", 0.0))); | ||
| 142 | Settings::values.bg_green.SetValue( | ||
| 143 | static_cast<float>(sdl2_config->GetReal("Renderer", "bg_green", 0.0))); | ||
| 144 | Settings::values.bg_blue.SetValue( | ||
| 145 | static_cast<float>(sdl2_config->GetReal("Renderer", "bg_blue", 0.0))); | ||
| 146 | |||
| 147 | // Audio | ||
| 148 | Settings::values.sink_id = "null"; | ||
| 149 | Settings::values.enable_audio_stretching.SetValue(false); | ||
| 150 | Settings::values.audio_device_id = "auto"; | ||
| 151 | Settings::values.volume.SetValue(0); | ||
| 152 | |||
| 153 | Settings::values.language_index.SetValue( | ||
| 154 | sdl2_config->GetInteger("System", "language_index", 1)); | ||
| 155 | |||
| 156 | // Miscellaneous | ||
| 157 | Settings::values.log_filter = sdl2_config->Get("Miscellaneous", "log_filter", "*:Trace"); | ||
| 158 | Settings::values.use_dev_keys = sdl2_config->GetBoolean("Miscellaneous", "use_dev_keys", false); | ||
| 159 | |||
| 160 | // Debugging | ||
| 161 | Settings::values.program_args = ""; | ||
| 162 | Settings::values.dump_exefs = sdl2_config->GetBoolean("Debugging", "dump_exefs", false); | ||
| 163 | Settings::values.dump_nso = sdl2_config->GetBoolean("Debugging", "dump_nso", false); | ||
| 164 | |||
| 165 | const auto title_list = sdl2_config->Get("AddOns", "title_ids", ""); | ||
| 166 | std::stringstream ss(title_list); | ||
| 167 | std::string line; | ||
| 168 | while (std::getline(ss, line, '|')) { | ||
| 169 | const auto title_id = std::stoul(line, nullptr, 16); | ||
| 170 | const auto disabled_list = sdl2_config->Get("AddOns", "disabled_" + line, ""); | ||
| 171 | |||
| 172 | std::stringstream inner_ss(disabled_list); | ||
| 173 | std::string inner_line; | ||
| 174 | std::vector<std::string> out; | ||
| 175 | while (std::getline(inner_ss, inner_line, '|')) { | ||
| 176 | out.push_back(inner_line); | ||
| 177 | } | ||
| 178 | |||
| 179 | Settings::values.disabled_addons.insert_or_assign(title_id, out); | ||
| 180 | } | ||
| 181 | |||
| 182 | // Web Service | ||
| 183 | Settings::values.enable_telemetry = | ||
| 184 | sdl2_config->GetBoolean("WebService", "enable_telemetry", true); | ||
| 185 | Settings::values.web_api_url = | ||
| 186 | sdl2_config->Get("WebService", "web_api_url", "https://api.yuzu-emu.org"); | ||
| 187 | Settings::values.yuzu_username = sdl2_config->Get("WebService", "yuzu_username", ""); | ||
| 188 | Settings::values.yuzu_token = sdl2_config->Get("WebService", "yuzu_token", ""); | ||
| 189 | } | ||
| 190 | |||
| 191 | void Config::Reload() { | ||
| 192 | LoadINI(DefaultINI::sdl2_config_file); | ||
| 193 | ReadValues(); | ||
| 194 | } | ||
diff --git a/src/yuzu_tester/config.h b/src/yuzu_tester/config.h deleted file mode 100644 index 3b68e5bc9..000000000 --- a/src/yuzu_tester/config.h +++ /dev/null | |||
| @@ -1,24 +0,0 @@ | |||
| 1 | // Copyright 2019 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 <memory> | ||
| 8 | #include <string> | ||
| 9 | |||
| 10 | class INIReader; | ||
| 11 | |||
| 12 | class Config { | ||
| 13 | std::unique_ptr<INIReader> sdl2_config; | ||
| 14 | std::string sdl2_config_loc; | ||
| 15 | |||
| 16 | bool LoadINI(const std::string& default_contents = "", bool retry = true); | ||
| 17 | void ReadValues(); | ||
| 18 | |||
| 19 | public: | ||
| 20 | Config(); | ||
| 21 | ~Config(); | ||
| 22 | |||
| 23 | void Reload(); | ||
| 24 | }; | ||
diff --git a/src/yuzu_tester/default_ini.h b/src/yuzu_tester/default_ini.h deleted file mode 100644 index 779c3791b..000000000 --- a/src/yuzu_tester/default_ini.h +++ /dev/null | |||
| @@ -1,182 +0,0 @@ | |||
| 1 | // Copyright 2019 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 | namespace DefaultINI { | ||
| 8 | |||
| 9 | const char* sdl2_config_file = R"( | ||
| 10 | [Core] | ||
| 11 | # Whether to use multi-core for CPU emulation | ||
| 12 | # 0 (default): Disabled, 1: Enabled | ||
| 13 | use_multi_core= | ||
| 14 | |||
| 15 | [Cpu] | ||
| 16 | # Enable inline page tables optimization (faster guest memory access) | ||
| 17 | # 0: Disabled, 1 (default): Enabled | ||
| 18 | cpuopt_page_tables = | ||
| 19 | |||
| 20 | # Enable block linking CPU optimization (reduce block dispatcher use during predictable jumps) | ||
| 21 | # 0: Disabled, 1 (default): Enabled | ||
| 22 | cpuopt_block_linking = | ||
| 23 | |||
| 24 | # Enable return stack buffer CPU optimization (reduce block dispatcher use during predictable returns) | ||
| 25 | # 0: Disabled, 1 (default): Enabled | ||
| 26 | cpuopt_return_stack_buffer = | ||
| 27 | |||
| 28 | # Enable fast dispatcher CPU optimization (use a two-tiered dispatcher architecture) | ||
| 29 | # 0: Disabled, 1 (default): Enabled | ||
| 30 | cpuopt_fast_dispatcher = | ||
| 31 | |||
| 32 | # Enable context elimination CPU Optimization (reduce host memory use for guest context) | ||
| 33 | # 0: Disabled, 1 (default): Enabled | ||
| 34 | cpuopt_context_elimination = | ||
| 35 | |||
| 36 | # Enable constant propagation CPU optimization (basic IR optimization) | ||
| 37 | # 0: Disabled, 1 (default): Enabled | ||
| 38 | cpuopt_const_prop = | ||
| 39 | |||
| 40 | # Enable miscellaneous CPU optimizations (basic IR optimization) | ||
| 41 | # 0: Disabled, 1 (default): Enabled | ||
| 42 | cpuopt_misc_ir = | ||
| 43 | |||
| 44 | # Enable reduction of memory misalignment checks (reduce memory fallbacks for misaligned access) | ||
| 45 | # 0: Disabled, 1 (default): Enabled | ||
| 46 | cpuopt_reduce_misalign_checks = | ||
| 47 | |||
| 48 | [Renderer] | ||
| 49 | # Whether to use software or hardware rendering. | ||
| 50 | # 0: Software, 1 (default): Hardware | ||
| 51 | use_hw_renderer = | ||
| 52 | |||
| 53 | # Whether to use the Just-In-Time (JIT) compiler for shader emulation | ||
| 54 | # 0: Interpreter (slow), 1 (default): JIT (fast) | ||
| 55 | use_shader_jit = | ||
| 56 | |||
| 57 | # Aspect ratio | ||
| 58 | # 0: Default (16:9), 1: Force 4:3, 2: Force 21:9, 3: Stretch to Window | ||
| 59 | aspect_ratio = | ||
| 60 | |||
| 61 | # Anisotropic filtering | ||
| 62 | # 0: Default, 1: 2x, 2: 4x, 3: 8x, 4: 16x | ||
| 63 | max_anisotropy = | ||
| 64 | |||
| 65 | # Whether to enable V-Sync (caps the framerate at 60FPS) or not. | ||
| 66 | # 0 (default): Off, 1: On | ||
| 67 | use_vsync = | ||
| 68 | |||
| 69 | # Whether to use disk based shader cache | ||
| 70 | # 0 (default): Off, 1 : On | ||
| 71 | use_disk_shader_cache = | ||
| 72 | |||
| 73 | # Whether to use accurate GPU emulation | ||
| 74 | # 0 (default): Off (fast), 1 : On (slow) | ||
| 75 | use_accurate_gpu_emulation = | ||
| 76 | |||
| 77 | # Whether to use asynchronous GPU emulation | ||
| 78 | # 0 : Off (slow), 1 (default): On (fast) | ||
| 79 | use_asynchronous_gpu_emulation = | ||
| 80 | |||
| 81 | # The clear color for the renderer. What shows up on the sides of the bottom screen. | ||
| 82 | # Must be in range of 0.0-1.0. Defaults to 1.0 for all. | ||
| 83 | bg_red = | ||
| 84 | bg_blue = | ||
| 85 | bg_green = | ||
| 86 | |||
| 87 | [Layout] | ||
| 88 | # Layout for the screen inside the render window. | ||
| 89 | # 0 (default): Default Top Bottom Screen, 1: Single Screen Only, 2: Large Screen Small Screen | ||
| 90 | layout_option = | ||
| 91 | |||
| 92 | # Toggle custom layout (using the settings below) on or off. | ||
| 93 | # 0 (default): Off, 1: On | ||
| 94 | custom_layout = | ||
| 95 | |||
| 96 | # Screen placement when using Custom layout option | ||
| 97 | # 0x, 0y is the top left corner of the render window. | ||
| 98 | custom_top_left = | ||
| 99 | custom_top_top = | ||
| 100 | custom_top_right = | ||
| 101 | custom_top_bottom = | ||
| 102 | custom_bottom_left = | ||
| 103 | custom_bottom_top = | ||
| 104 | custom_bottom_right = | ||
| 105 | custom_bottom_bottom = | ||
| 106 | |||
| 107 | # Swaps the prominent screen with the other screen. | ||
| 108 | # For example, if Single Screen is chosen, setting this to 1 will display the bottom screen instead of the top screen. | ||
| 109 | # 0 (default): Top Screen is prominent, 1: Bottom Screen is prominent | ||
| 110 | swap_screen = | ||
| 111 | |||
| 112 | [Data Storage] | ||
| 113 | # Whether to create a virtual SD card. | ||
| 114 | # 1 (default): Yes, 0: No | ||
| 115 | use_virtual_sd = | ||
| 116 | |||
| 117 | [System] | ||
| 118 | # Whether the system is docked | ||
| 119 | # 1 (default): Yes, 0: No | ||
| 120 | use_docked_mode = | ||
| 121 | |||
| 122 | # Allow the use of NFC in games | ||
| 123 | # 1 (default): Yes, 0 : No | ||
| 124 | enable_nfc = | ||
| 125 | |||
| 126 | # Sets the seed for the RNG generator built into the switch | ||
| 127 | # rng_seed will be ignored and randomly generated if rng_seed_enabled is false | ||
| 128 | rng_seed_enabled = | ||
| 129 | rng_seed = | ||
| 130 | |||
| 131 | # Sets the current time (in seconds since 12:00 AM Jan 1, 1970) that will be used by the time service | ||
| 132 | # This will auto-increment, with the time set being the time the game is started | ||
| 133 | # This override will only occur if custom_rtc_enabled is true, otherwise the current time is used | ||
| 134 | custom_rtc_enabled = | ||
| 135 | custom_rtc = | ||
| 136 | |||
| 137 | # Sets the account username, max length is 32 characters | ||
| 138 | # yuzu (default) | ||
| 139 | username = yuzu | ||
| 140 | |||
| 141 | # Sets the systems language index | ||
| 142 | # 0: Japanese, 1: English (default), 2: French, 3: German, 4: Italian, 5: Spanish, 6: Chinese, | ||
| 143 | # 7: Korean, 8: Dutch, 9: Portuguese, 10: Russian, 11: Taiwanese, 12: British English, 13: Canadian French, | ||
| 144 | # 14: Latin American Spanish, 15: Simplified Chinese, 16: Traditional Chinese | ||
| 145 | language_index = | ||
| 146 | |||
| 147 | # The system region that yuzu will use during emulation | ||
| 148 | # -1: Auto-select (default), 0: Japan, 1: USA, 2: Europe, 3: Australia, 4: China, 5: Korea, 6: Taiwan | ||
| 149 | region_value = | ||
| 150 | |||
| 151 | [Miscellaneous] | ||
| 152 | # A filter which removes logs below a certain logging level. | ||
| 153 | # Examples: *:Debug Kernel.SVC:Trace Service.*:Critical | ||
| 154 | log_filter = *:Trace | ||
| 155 | |||
| 156 | [Debugging] | ||
| 157 | # Arguments to be passed to argv/argc in the emulated program. It is preferable to use the testing service datastring | ||
| 158 | program_args= | ||
| 159 | # Determines whether or not yuzu will dump the ExeFS of all games it attempts to load while loading them | ||
| 160 | dump_exefs=false | ||
| 161 | # Determines whether or not yuzu will dump all NSOs it attempts to load while loading them | ||
| 162 | dump_nso=false | ||
| 163 | |||
| 164 | [WebService] | ||
| 165 | # Whether or not to enable telemetry | ||
| 166 | # 0: No, 1 (default): Yes | ||
| 167 | enable_telemetry = | ||
| 168 | # URL for Web API | ||
| 169 | web_api_url = https://api.yuzu-emu.org | ||
| 170 | # Username and token for yuzu Web Service | ||
| 171 | # See https://profile.yuzu-emu.org/ for more info | ||
| 172 | yuzu_username = | ||
| 173 | yuzu_token = | ||
| 174 | |||
| 175 | [AddOns] | ||
| 176 | # Used to disable add-ons | ||
| 177 | # List of title IDs of games that will have add-ons disabled (separated by '|'): | ||
| 178 | title_ids = | ||
| 179 | # For each title ID, have a key/value pair called `disabled_<title_id>` equal to the names of the add-ons to disable (sep. by '|') | ||
| 180 | # e.x. disabled_0100000000010000 = Update|DLC <- disables Updates and DLC on Super Mario Odyssey | ||
| 181 | )"; | ||
| 182 | } | ||
diff --git a/src/yuzu_tester/emu_window/emu_window_sdl2_hide.cpp b/src/yuzu_tester/emu_window/emu_window_sdl2_hide.cpp deleted file mode 100644 index 358e03870..000000000 --- a/src/yuzu_tester/emu_window/emu_window_sdl2_hide.cpp +++ /dev/null | |||
| @@ -1,146 +0,0 @@ | |||
| 1 | // Copyright 2019 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <algorithm> | ||
| 6 | #include <cstdlib> | ||
| 7 | #include <string> | ||
| 8 | |||
| 9 | #include <fmt/format.h> | ||
| 10 | |||
| 11 | #define SDL_MAIN_HANDLED | ||
| 12 | #include <SDL.h> | ||
| 13 | |||
| 14 | #include <glad/glad.h> | ||
| 15 | |||
| 16 | #include "common/logging/log.h" | ||
| 17 | #include "common/scm_rev.h" | ||
| 18 | #include "core/settings.h" | ||
| 19 | #include "input_common/main.h" | ||
| 20 | #include "yuzu_tester/emu_window/emu_window_sdl2_hide.h" | ||
| 21 | |||
| 22 | bool EmuWindow_SDL2_Hide::SupportsRequiredGLExtensions() { | ||
| 23 | std::vector<std::string> unsupported_ext; | ||
| 24 | |||
| 25 | if (!GLAD_GL_ARB_direct_state_access) | ||
| 26 | unsupported_ext.push_back("ARB_direct_state_access"); | ||
| 27 | if (!GLAD_GL_ARB_vertex_type_10f_11f_11f_rev) | ||
| 28 | unsupported_ext.push_back("ARB_vertex_type_10f_11f_11f_rev"); | ||
| 29 | if (!GLAD_GL_ARB_texture_mirror_clamp_to_edge) | ||
| 30 | unsupported_ext.push_back("ARB_texture_mirror_clamp_to_edge"); | ||
| 31 | if (!GLAD_GL_ARB_multi_bind) | ||
| 32 | unsupported_ext.push_back("ARB_multi_bind"); | ||
| 33 | |||
| 34 | // Extensions required to support some texture formats. | ||
| 35 | if (!GLAD_GL_EXT_texture_compression_s3tc) | ||
| 36 | unsupported_ext.push_back("EXT_texture_compression_s3tc"); | ||
| 37 | if (!GLAD_GL_ARB_texture_compression_rgtc) | ||
| 38 | unsupported_ext.push_back("ARB_texture_compression_rgtc"); | ||
| 39 | if (!GLAD_GL_ARB_depth_buffer_float) | ||
| 40 | unsupported_ext.push_back("ARB_depth_buffer_float"); | ||
| 41 | |||
| 42 | for (const std::string& ext : unsupported_ext) | ||
| 43 | LOG_CRITICAL(Frontend, "Unsupported GL extension: {}", ext); | ||
| 44 | |||
| 45 | return unsupported_ext.empty(); | ||
| 46 | } | ||
| 47 | |||
| 48 | EmuWindow_SDL2_Hide::EmuWindow_SDL2_Hide() { | ||
| 49 | // Initialize the window | ||
| 50 | if (SDL_Init(SDL_INIT_VIDEO) < 0) { | ||
| 51 | LOG_CRITICAL(Frontend, "Failed to initialize SDL2! Exiting..."); | ||
| 52 | exit(1); | ||
| 53 | } | ||
| 54 | |||
| 55 | input_subsystem->Initialize(); | ||
| 56 | |||
| 57 | SDL_SetMainReady(); | ||
| 58 | |||
| 59 | SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4); | ||
| 60 | SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3); | ||
| 61 | SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); | ||
| 62 | SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); | ||
| 63 | SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8); | ||
| 64 | SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8); | ||
| 65 | SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8); | ||
| 66 | SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 0); | ||
| 67 | |||
| 68 | std::string window_title = fmt::format("yuzu-tester {} | {}-{}", Common::g_build_fullname, | ||
| 69 | Common::g_scm_branch, Common::g_scm_desc); | ||
| 70 | render_window = SDL_CreateWindow(window_title.c_str(), | ||
| 71 | SDL_WINDOWPOS_UNDEFINED, // x position | ||
| 72 | SDL_WINDOWPOS_UNDEFINED, // y position | ||
| 73 | Layout::ScreenUndocked::Width, Layout::ScreenUndocked::Height, | ||
| 74 | SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE | | ||
| 75 | SDL_WINDOW_ALLOW_HIGHDPI | SDL_WINDOW_HIDDEN); | ||
| 76 | |||
| 77 | if (render_window == nullptr) { | ||
| 78 | LOG_CRITICAL(Frontend, "Failed to create SDL2 window! {}", SDL_GetError()); | ||
| 79 | exit(1); | ||
| 80 | } | ||
| 81 | |||
| 82 | gl_context = SDL_GL_CreateContext(render_window); | ||
| 83 | |||
| 84 | if (gl_context == nullptr) { | ||
| 85 | LOG_CRITICAL(Frontend, "Failed to create SDL2 GL context! {}", SDL_GetError()); | ||
| 86 | exit(1); | ||
| 87 | } | ||
| 88 | |||
| 89 | if (!gladLoadGLLoader(static_cast<GLADloadproc>(SDL_GL_GetProcAddress))) { | ||
| 90 | LOG_CRITICAL(Frontend, "Failed to initialize GL functions! {}", SDL_GetError()); | ||
| 91 | exit(1); | ||
| 92 | } | ||
| 93 | |||
| 94 | if (!SupportsRequiredGLExtensions()) { | ||
| 95 | LOG_CRITICAL(Frontend, "GPU does not support all required OpenGL extensions! Exiting..."); | ||
| 96 | exit(1); | ||
| 97 | } | ||
| 98 | |||
| 99 | SDL_PumpEvents(); | ||
| 100 | SDL_GL_SetSwapInterval(false); | ||
| 101 | LOG_INFO(Frontend, "yuzu-tester Version: {} | {}-{}", Common::g_build_fullname, | ||
| 102 | Common::g_scm_branch, Common::g_scm_desc); | ||
| 103 | Settings::LogSettings(); | ||
| 104 | } | ||
| 105 | |||
| 106 | EmuWindow_SDL2_Hide::~EmuWindow_SDL2_Hide() { | ||
| 107 | input_subsystem->Shutdown(); | ||
| 108 | SDL_GL_DeleteContext(gl_context); | ||
| 109 | SDL_Quit(); | ||
| 110 | } | ||
| 111 | |||
| 112 | bool EmuWindow_SDL2_Hide::IsShown() const { | ||
| 113 | return false; | ||
| 114 | } | ||
| 115 | |||
| 116 | class SDLGLContext : public Core::Frontend::GraphicsContext { | ||
| 117 | public: | ||
| 118 | explicit SDLGLContext() { | ||
| 119 | // create a hidden window to make the shared context against | ||
| 120 | window = SDL_CreateWindow(NULL, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 0, 0, | ||
| 121 | SDL_WINDOW_HIDDEN | SDL_WINDOW_OPENGL); | ||
| 122 | context = SDL_GL_CreateContext(window); | ||
| 123 | } | ||
| 124 | |||
| 125 | ~SDLGLContext() { | ||
| 126 | DoneCurrent(); | ||
| 127 | SDL_GL_DeleteContext(context); | ||
| 128 | SDL_DestroyWindow(window); | ||
| 129 | } | ||
| 130 | |||
| 131 | void MakeCurrent() override { | ||
| 132 | SDL_GL_MakeCurrent(window, context); | ||
| 133 | } | ||
| 134 | |||
| 135 | void DoneCurrent() override { | ||
| 136 | SDL_GL_MakeCurrent(window, nullptr); | ||
| 137 | } | ||
| 138 | |||
| 139 | private: | ||
| 140 | SDL_Window* window; | ||
| 141 | SDL_GLContext context; | ||
| 142 | }; | ||
| 143 | |||
| 144 | std::unique_ptr<Core::Frontend::GraphicsContext> EmuWindow_SDL2_Hide::CreateSharedContext() const { | ||
| 145 | return std::make_unique<SDLGLContext>(); | ||
| 146 | } | ||
diff --git a/src/yuzu_tester/emu_window/emu_window_sdl2_hide.h b/src/yuzu_tester/emu_window/emu_window_sdl2_hide.h deleted file mode 100644 index adccdf35e..000000000 --- a/src/yuzu_tester/emu_window/emu_window_sdl2_hide.h +++ /dev/null | |||
| @@ -1,37 +0,0 @@ | |||
| 1 | // Copyright 2019 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 "core/frontend/emu_window.h" | ||
| 8 | |||
| 9 | struct SDL_Window; | ||
| 10 | |||
| 11 | namespace InputCommon { | ||
| 12 | class InputSubsystem; | ||
| 13 | } | ||
| 14 | |||
| 15 | class EmuWindow_SDL2_Hide : public Core::Frontend::EmuWindow { | ||
| 16 | public: | ||
| 17 | explicit EmuWindow_SDL2_Hide(); | ||
| 18 | ~EmuWindow_SDL2_Hide(); | ||
| 19 | |||
| 20 | /// Whether the screen is being shown or not. | ||
| 21 | bool IsShown() const override; | ||
| 22 | |||
| 23 | std::unique_ptr<Core::Frontend::GraphicsContext> CreateSharedContext() const override; | ||
| 24 | |||
| 25 | private: | ||
| 26 | /// Whether the GPU and driver supports the OpenGL extension required | ||
| 27 | bool SupportsRequiredGLExtensions(); | ||
| 28 | |||
| 29 | std::unique_ptr<InputCommon::InputSubsystem> input_subsystem; | ||
| 30 | |||
| 31 | /// Internal SDL2 render window | ||
| 32 | SDL_Window* render_window; | ||
| 33 | |||
| 34 | using SDL_GLContext = void*; | ||
| 35 | /// The OpenGL context associated with the window | ||
| 36 | SDL_GLContext gl_context; | ||
| 37 | }; | ||
diff --git a/src/yuzu_tester/resource.h b/src/yuzu_tester/resource.h deleted file mode 100644 index df8e459e4..000000000 --- a/src/yuzu_tester/resource.h +++ /dev/null | |||
| @@ -1,16 +0,0 @@ | |||
| 1 | //{{NO_DEPENDENCIES}} | ||
| 2 | // Microsoft Visual C++ generated include file. | ||
| 3 | // Used by pcafe.rc | ||
| 4 | // | ||
| 5 | #define IDI_ICON3 103 | ||
| 6 | |||
| 7 | // Next default values for new objects | ||
| 8 | // | ||
| 9 | #ifdef APSTUDIO_INVOKED | ||
| 10 | #ifndef APSTUDIO_READONLY_SYMBOLS | ||
| 11 | #define _APS_NEXT_RESOURCE_VALUE 105 | ||
| 12 | #define _APS_NEXT_COMMAND_VALUE 40001 | ||
| 13 | #define _APS_NEXT_CONTROL_VALUE 1001 | ||
| 14 | #define _APS_NEXT_SYMED_VALUE 101 | ||
| 15 | #endif | ||
| 16 | #endif | ||
diff --git a/src/yuzu_tester/service/yuzutest.cpp b/src/yuzu_tester/service/yuzutest.cpp deleted file mode 100644 index e257fae25..000000000 --- a/src/yuzu_tester/service/yuzutest.cpp +++ /dev/null | |||
| @@ -1,115 +0,0 @@ | |||
| 1 | // Copyright 2019 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <memory> | ||
| 6 | #include "common/string_util.h" | ||
| 7 | #include "core/core.h" | ||
| 8 | #include "core/hle/ipc_helpers.h" | ||
| 9 | #include "core/hle/service/service.h" | ||
| 10 | #include "core/hle/service/sm/sm.h" | ||
| 11 | #include "yuzu_tester/service/yuzutest.h" | ||
| 12 | |||
| 13 | namespace Service::Yuzu { | ||
| 14 | |||
| 15 | constexpr u64 SERVICE_VERSION = 0x00000002; | ||
| 16 | |||
| 17 | class YuzuTest final : public ServiceFramework<YuzuTest> { | ||
| 18 | public: | ||
| 19 | explicit YuzuTest(Core::System& system_, std::string data_, | ||
| 20 | std::function<void(std::vector<TestResult>)> finish_callback_) | ||
| 21 | : ServiceFramework{system_, "yuzutest"}, data{std::move(data_)}, finish_callback{std::move( | ||
| 22 | finish_callback_)} { | ||
| 23 | static const FunctionInfo functions[] = { | ||
| 24 | {0, &YuzuTest::Initialize, "Initialize"}, | ||
| 25 | {1, &YuzuTest::GetServiceVersion, "GetServiceVersion"}, | ||
| 26 | {2, &YuzuTest::GetData, "GetData"}, | ||
| 27 | {10, &YuzuTest::StartIndividual, "StartIndividual"}, | ||
| 28 | {20, &YuzuTest::FinishIndividual, "FinishIndividual"}, | ||
| 29 | {100, &YuzuTest::ExitProgram, "ExitProgram"}, | ||
| 30 | }; | ||
| 31 | |||
| 32 | RegisterHandlers(functions); | ||
| 33 | } | ||
| 34 | |||
| 35 | private: | ||
| 36 | void Initialize(Kernel::HLERequestContext& ctx) { | ||
| 37 | LOG_DEBUG(Frontend, "called"); | ||
| 38 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 39 | rb.Push(RESULT_SUCCESS); | ||
| 40 | } | ||
| 41 | |||
| 42 | void GetServiceVersion(Kernel::HLERequestContext& ctx) { | ||
| 43 | LOG_DEBUG(Frontend, "called"); | ||
| 44 | IPC::ResponseBuilder rb{ctx, 4}; | ||
| 45 | rb.Push(RESULT_SUCCESS); | ||
| 46 | rb.Push(SERVICE_VERSION); | ||
| 47 | } | ||
| 48 | |||
| 49 | void GetData(Kernel::HLERequestContext& ctx) { | ||
| 50 | LOG_DEBUG(Frontend, "called"); | ||
| 51 | const auto size = ctx.GetWriteBufferSize(); | ||
| 52 | const auto write_size = std::min(size, data.size()); | ||
| 53 | ctx.WriteBuffer(data.data(), write_size); | ||
| 54 | |||
| 55 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 56 | rb.Push(RESULT_SUCCESS); | ||
| 57 | rb.Push<u32>(static_cast<u32>(write_size)); | ||
| 58 | } | ||
| 59 | |||
| 60 | void StartIndividual(Kernel::HLERequestContext& ctx) { | ||
| 61 | const auto name_raw = ctx.ReadBuffer(); | ||
| 62 | |||
| 63 | const auto name = Common::StringFromFixedZeroTerminatedBuffer( | ||
| 64 | reinterpret_cast<const char*>(name_raw.data()), name_raw.size()); | ||
| 65 | |||
| 66 | LOG_DEBUG(Frontend, "called, name={}", name); | ||
| 67 | |||
| 68 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 69 | rb.Push(RESULT_SUCCESS); | ||
| 70 | } | ||
| 71 | |||
| 72 | void FinishIndividual(Kernel::HLERequestContext& ctx) { | ||
| 73 | IPC::RequestParser rp{ctx}; | ||
| 74 | |||
| 75 | const auto code = rp.PopRaw<u32>(); | ||
| 76 | |||
| 77 | const auto result_data_raw = ctx.ReadBuffer(); | ||
| 78 | const auto test_name_raw = ctx.ReadBuffer(1); | ||
| 79 | |||
| 80 | const auto data = Common::StringFromFixedZeroTerminatedBuffer( | ||
| 81 | reinterpret_cast<const char*>(result_data_raw.data()), result_data_raw.size()); | ||
| 82 | const auto test_name = Common::StringFromFixedZeroTerminatedBuffer( | ||
| 83 | reinterpret_cast<const char*>(test_name_raw.data()), test_name_raw.size()); | ||
| 84 | |||
| 85 | LOG_INFO(Frontend, "called, result_code={:08X}, data={}, name={}", code, data, test_name); | ||
| 86 | |||
| 87 | results.push_back({code, data, test_name}); | ||
| 88 | |||
| 89 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 90 | rb.Push(RESULT_SUCCESS); | ||
| 91 | } | ||
| 92 | |||
| 93 | void ExitProgram(Kernel::HLERequestContext& ctx) { | ||
| 94 | LOG_DEBUG(Frontend, "called"); | ||
| 95 | |||
| 96 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 97 | rb.Push(RESULT_SUCCESS); | ||
| 98 | |||
| 99 | finish_callback(std::move(results)); | ||
| 100 | } | ||
| 101 | |||
| 102 | std::string data; | ||
| 103 | |||
| 104 | std::vector<TestResult> results; | ||
| 105 | std::function<void(std::vector<TestResult>)> finish_callback; | ||
| 106 | }; | ||
| 107 | |||
| 108 | void InstallInterfaces(Core::System& system, std::string data, | ||
| 109 | std::function<void(std::vector<TestResult>)> finish_callback) { | ||
| 110 | auto& sm = system.ServiceManager(); | ||
| 111 | std::make_shared<YuzuTest>(system, std::move(data), std::move(finish_callback)) | ||
| 112 | ->InstallAsService(sm); | ||
| 113 | } | ||
| 114 | |||
| 115 | } // namespace Service::Yuzu | ||
diff --git a/src/yuzu_tester/service/yuzutest.h b/src/yuzu_tester/service/yuzutest.h deleted file mode 100644 index 7794814fa..000000000 --- a/src/yuzu_tester/service/yuzutest.h +++ /dev/null | |||
| @@ -1,25 +0,0 @@ | |||
| 1 | // Copyright 2019 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 <functional> | ||
| 8 | #include <string> | ||
| 9 | |||
| 10 | namespace Core { | ||
| 11 | class System; | ||
| 12 | } | ||
| 13 | |||
| 14 | namespace Service::Yuzu { | ||
| 15 | |||
| 16 | struct TestResult { | ||
| 17 | u32 code; | ||
| 18 | std::string data; | ||
| 19 | std::string name; | ||
| 20 | }; | ||
| 21 | |||
| 22 | void InstallInterfaces(Core::System& system, std::string data, | ||
| 23 | std::function<void(std::vector<TestResult>)> finish_callback); | ||
| 24 | |||
| 25 | } // namespace Service::Yuzu | ||
diff --git a/src/yuzu_tester/yuzu.cpp b/src/yuzu_tester/yuzu.cpp deleted file mode 100644 index 09cf2ad77..000000000 --- a/src/yuzu_tester/yuzu.cpp +++ /dev/null | |||
| @@ -1,268 +0,0 @@ | |||
| 1 | // Copyright 2019 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <chrono> | ||
| 6 | #include <iostream> | ||
| 7 | #include <memory> | ||
| 8 | #include <string> | ||
| 9 | #include <thread> | ||
| 10 | |||
| 11 | #include <fmt/ostream.h> | ||
| 12 | |||
| 13 | #include "common/common_paths.h" | ||
| 14 | #include "common/detached_tasks.h" | ||
| 15 | #include "common/file_util.h" | ||
| 16 | #include "common/logging/backend.h" | ||
| 17 | #include "common/logging/filter.h" | ||
| 18 | #include "common/logging/log.h" | ||
| 19 | #include "common/microprofile.h" | ||
| 20 | #include "common/scm_rev.h" | ||
| 21 | #include "common/scope_exit.h" | ||
| 22 | #include "common/string_util.h" | ||
| 23 | #include "common/telemetry.h" | ||
| 24 | #include "core/core.h" | ||
| 25 | #include "core/crypto/key_manager.h" | ||
| 26 | #include "core/file_sys/registered_cache.h" | ||
| 27 | #include "core/file_sys/vfs_real.h" | ||
| 28 | #include "core/hle/service/filesystem/filesystem.h" | ||
| 29 | #include "core/loader/loader.h" | ||
| 30 | #include "core/settings.h" | ||
| 31 | #include "core/telemetry_session.h" | ||
| 32 | #include "video_core/renderer_base.h" | ||
| 33 | #include "yuzu_tester/config.h" | ||
| 34 | #include "yuzu_tester/emu_window/emu_window_sdl2_hide.h" | ||
| 35 | #include "yuzu_tester/service/yuzutest.h" | ||
| 36 | |||
| 37 | #ifdef _WIN32 | ||
| 38 | // windows.h needs to be included before shellapi.h | ||
| 39 | #include <windows.h> | ||
| 40 | |||
| 41 | #include <shellapi.h> | ||
| 42 | #endif | ||
| 43 | |||
| 44 | #undef _UNICODE | ||
| 45 | #include <getopt.h> | ||
| 46 | #ifndef _MSC_VER | ||
| 47 | #include <unistd.h> | ||
| 48 | #endif | ||
| 49 | |||
| 50 | #ifdef _WIN32 | ||
| 51 | extern "C" { | ||
| 52 | // tells Nvidia and AMD drivers to use the dedicated GPU by default on laptops with switchable | ||
| 53 | // graphics | ||
| 54 | __declspec(dllexport) unsigned long NvOptimusEnablement = 0x00000001; | ||
| 55 | __declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1; | ||
| 56 | } | ||
| 57 | #endif | ||
| 58 | |||
| 59 | static void PrintHelp(const char* argv0) { | ||
| 60 | std::cout << "Usage: " << argv0 | ||
| 61 | << " [options] <filename>\n" | ||
| 62 | "-h, --help Display this help and exit\n" | ||
| 63 | "-v, --version Output version information and exit\n" | ||
| 64 | "-d, --datastring Pass following string as data to test service command #2\n" | ||
| 65 | "-l, --log Log to console in addition to file (will log to file only " | ||
| 66 | "by default)\n"; | ||
| 67 | } | ||
| 68 | |||
| 69 | static void PrintVersion() { | ||
| 70 | std::cout << "yuzu [Test Utility] " << Common::g_scm_branch << " " << Common::g_scm_desc | ||
| 71 | << std::endl; | ||
| 72 | } | ||
| 73 | |||
| 74 | static void InitializeLogging(bool console) { | ||
| 75 | Log::Filter log_filter(Log::Level::Debug); | ||
| 76 | log_filter.ParseFilterString(Settings::values.log_filter); | ||
| 77 | Log::SetGlobalFilter(log_filter); | ||
| 78 | |||
| 79 | if (console) | ||
| 80 | Log::AddBackend(std::make_unique<Log::ColorConsoleBackend>()); | ||
| 81 | |||
| 82 | const std::string& log_dir = Common::FS::GetUserPath(Common::FS::UserPath::LogDir); | ||
| 83 | Common::FS::CreateFullPath(log_dir); | ||
| 84 | Log::AddBackend(std::make_unique<Log::FileBackend>(log_dir + LOG_FILE)); | ||
| 85 | #ifdef _WIN32 | ||
| 86 | Log::AddBackend(std::make_unique<Log::DebuggerBackend>()); | ||
| 87 | #endif | ||
| 88 | } | ||
| 89 | |||
| 90 | /// Application entry point | ||
| 91 | int main(int argc, char** argv) { | ||
| 92 | Common::DetachedTasks detached_tasks; | ||
| 93 | Config config; | ||
| 94 | |||
| 95 | int option_index = 0; | ||
| 96 | |||
| 97 | #ifdef _WIN32 | ||
| 98 | int argc_w; | ||
| 99 | auto argv_w = CommandLineToArgvW(GetCommandLineW(), &argc_w); | ||
| 100 | |||
| 101 | if (argv_w == nullptr) { | ||
| 102 | std::cout << "Failed to get command line arguments" << std::endl; | ||
| 103 | return -1; | ||
| 104 | } | ||
| 105 | #endif | ||
| 106 | std::string filepath; | ||
| 107 | |||
| 108 | static struct option long_options[] = { | ||
| 109 | {"help", no_argument, 0, 'h'}, | ||
| 110 | {"version", no_argument, 0, 'v'}, | ||
| 111 | {"datastring", optional_argument, 0, 'd'}, | ||
| 112 | {"log", no_argument, 0, 'l'}, | ||
| 113 | {0, 0, 0, 0}, | ||
| 114 | }; | ||
| 115 | |||
| 116 | bool console_log = false; | ||
| 117 | std::string datastring; | ||
| 118 | |||
| 119 | while (optind < argc) { | ||
| 120 | int arg = getopt_long(argc, argv, "hvdl::", long_options, &option_index); | ||
| 121 | if (arg != -1) { | ||
| 122 | switch (static_cast<char>(arg)) { | ||
| 123 | case 'h': | ||
| 124 | PrintHelp(argv[0]); | ||
| 125 | return 0; | ||
| 126 | case 'v': | ||
| 127 | PrintVersion(); | ||
| 128 | return 0; | ||
| 129 | case 'd': | ||
| 130 | datastring = argv[optind]; | ||
| 131 | ++optind; | ||
| 132 | break; | ||
| 133 | case 'l': | ||
| 134 | console_log = true; | ||
| 135 | break; | ||
| 136 | } | ||
| 137 | } else { | ||
| 138 | #ifdef _WIN32 | ||
| 139 | filepath = Common::UTF16ToUTF8(argv_w[optind]); | ||
| 140 | #else | ||
| 141 | filepath = argv[optind]; | ||
| 142 | #endif | ||
| 143 | optind++; | ||
| 144 | } | ||
| 145 | } | ||
| 146 | |||
| 147 | InitializeLogging(console_log); | ||
| 148 | |||
| 149 | #ifdef _WIN32 | ||
| 150 | LocalFree(argv_w); | ||
| 151 | #endif | ||
| 152 | |||
| 153 | MicroProfileOnThreadCreate("EmuThread"); | ||
| 154 | SCOPE_EXIT({ MicroProfileShutdown(); }); | ||
| 155 | |||
| 156 | if (filepath.empty()) { | ||
| 157 | LOG_CRITICAL(Frontend, "Failed to load application: No application specified"); | ||
| 158 | std::cout << "Failed to load application: No application specified" << std::endl; | ||
| 159 | PrintHelp(argv[0]); | ||
| 160 | return -1; | ||
| 161 | } | ||
| 162 | |||
| 163 | Core::System& system{Core::System::GetInstance()}; | ||
| 164 | |||
| 165 | Settings::Apply(system); | ||
| 166 | |||
| 167 | const auto emu_window{std::make_unique<EmuWindow_SDL2_Hide>()}; | ||
| 168 | |||
| 169 | bool finished = false; | ||
| 170 | int return_value = 0; | ||
| 171 | const auto callback = [&finished, | ||
| 172 | &return_value](std::vector<Service::Yuzu::TestResult> results) { | ||
| 173 | finished = true; | ||
| 174 | return_value = 0; | ||
| 175 | |||
| 176 | // Find the minimum length needed to fully enclose all test names (and the header field) in | ||
| 177 | // the fmt::format column by first finding the maximum size of any test name and comparing | ||
| 178 | // that to 9, the string length of 'Test Name' | ||
| 179 | const auto needed_length_name = | ||
| 180 | std::max<u64>(std::max_element(results.begin(), results.end(), | ||
| 181 | [](const auto& lhs, const auto& rhs) { | ||
| 182 | return lhs.name.size() < rhs.name.size(); | ||
| 183 | }) | ||
| 184 | ->name.size(), | ||
| 185 | 9ull); | ||
| 186 | |||
| 187 | std::size_t passed = 0; | ||
| 188 | std::size_t failed = 0; | ||
| 189 | |||
| 190 | std::cout << fmt::format("Result [Res Code] | {:<{}} | Extra Data", "Test Name", | ||
| 191 | needed_length_name) | ||
| 192 | << std::endl; | ||
| 193 | |||
| 194 | for (const auto& res : results) { | ||
| 195 | const auto main_res = res.code == 0 ? "PASSED" : "FAILED"; | ||
| 196 | if (res.code == 0) | ||
| 197 | ++passed; | ||
| 198 | else | ||
| 199 | ++failed; | ||
| 200 | std::cout << fmt::format("{} [{:08X}] | {:<{}} | {}", main_res, res.code, res.name, | ||
| 201 | needed_length_name, res.data) | ||
| 202 | << std::endl; | ||
| 203 | } | ||
| 204 | |||
| 205 | std::cout << std::endl | ||
| 206 | << fmt::format("{:4d} Passed | {:4d} Failed | {:4d} Total | {:2.2f} Passed Ratio", | ||
| 207 | passed, failed, passed + failed, | ||
| 208 | static_cast<float>(passed) / (passed + failed)) | ||
| 209 | << std::endl | ||
| 210 | << (failed == 0 ? "PASSED" : "FAILED") << std::endl; | ||
| 211 | |||
| 212 | if (failed > 0) | ||
| 213 | return_value = -1; | ||
| 214 | }; | ||
| 215 | |||
| 216 | system.SetContentProvider(std::make_unique<FileSys::ContentProviderUnion>()); | ||
| 217 | system.SetFilesystem(std::make_shared<FileSys::RealVfsFilesystem>()); | ||
| 218 | system.GetFileSystemController().CreateFactories(*system.GetFilesystem()); | ||
| 219 | |||
| 220 | SCOPE_EXIT({ system.Shutdown(); }); | ||
| 221 | |||
| 222 | const Core::System::ResultStatus load_result{system.Load(*emu_window, filepath)}; | ||
| 223 | |||
| 224 | switch (load_result) { | ||
| 225 | case Core::System::ResultStatus::ErrorGetLoader: | ||
| 226 | LOG_CRITICAL(Frontend, "Failed to obtain loader for {}!", filepath); | ||
| 227 | return -1; | ||
| 228 | case Core::System::ResultStatus::ErrorLoader: | ||
| 229 | LOG_CRITICAL(Frontend, "Failed to load ROM!"); | ||
| 230 | return -1; | ||
| 231 | case Core::System::ResultStatus::ErrorNotInitialized: | ||
| 232 | LOG_CRITICAL(Frontend, "CPUCore not initialized"); | ||
| 233 | return -1; | ||
| 234 | case Core::System::ResultStatus::ErrorVideoCore: | ||
| 235 | LOG_CRITICAL(Frontend, "Failed to initialize VideoCore!"); | ||
| 236 | return -1; | ||
| 237 | case Core::System::ResultStatus::Success: | ||
| 238 | break; // Expected case | ||
| 239 | default: | ||
| 240 | if (static_cast<u32>(load_result) > | ||
| 241 | static_cast<u32>(Core::System::ResultStatus::ErrorLoader)) { | ||
| 242 | const u16 loader_id = static_cast<u16>(Core::System::ResultStatus::ErrorLoader); | ||
| 243 | const u16 error_id = static_cast<u16>(load_result) - loader_id; | ||
| 244 | LOG_CRITICAL(Frontend, | ||
| 245 | "While attempting to load the ROM requested, an error occurred. Please " | ||
| 246 | "refer to the yuzu wiki for more information or the yuzu discord for " | ||
| 247 | "additional help.\n\nError Code: {:04X}-{:04X}\nError Description: {}", | ||
| 248 | loader_id, error_id, static_cast<Loader::ResultStatus>(error_id)); | ||
| 249 | } | ||
| 250 | break; | ||
| 251 | } | ||
| 252 | |||
| 253 | Service::Yuzu::InstallInterfaces(system, datastring, callback); | ||
| 254 | |||
| 255 | system.TelemetrySession().AddField(Common::Telemetry::FieldType::App, "Frontend", | ||
| 256 | "SDLHideTester"); | ||
| 257 | |||
| 258 | system.GPU().Start(); | ||
| 259 | |||
| 260 | void(system.Run()); | ||
| 261 | while (!finished) { | ||
| 262 | std::this_thread::sleep_for(std::chrono::milliseconds(1)); | ||
| 263 | } | ||
| 264 | void(system.Pause()); | ||
| 265 | |||
| 266 | detached_tasks.WaitForAllTasks(); | ||
| 267 | return return_value; | ||
| 268 | } | ||
diff --git a/src/yuzu_tester/yuzu.rc b/src/yuzu_tester/yuzu.rc deleted file mode 100644 index 0cde75e2f..000000000 --- a/src/yuzu_tester/yuzu.rc +++ /dev/null | |||
| @@ -1,17 +0,0 @@ | |||
| 1 | #include "winresrc.h" | ||
| 2 | ///////////////////////////////////////////////////////////////////////////// | ||
| 3 | // | ||
| 4 | // Icon | ||
| 5 | // | ||
| 6 | |||
| 7 | // Icon with lowest ID value placed first to ensure application icon | ||
| 8 | // remains consistent on all systems. | ||
| 9 | YUZU_ICON ICON "../../dist/yuzu.ico" | ||
| 10 | |||
| 11 | |||
| 12 | ///////////////////////////////////////////////////////////////////////////// | ||
| 13 | // | ||
| 14 | // RT_MANIFEST | ||
| 15 | // | ||
| 16 | |||
| 17 | 0 RT_MANIFEST "../../dist/yuzu.manifest" | ||