summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/audio_core/cubeb_sink.cpp2
-rw-r--r--src/common/algorithm.h3
-rw-r--r--src/common/alignment.h14
-rw-r--r--src/common/atomic_ops.h10
-rw-r--r--src/common/bit_field.h19
-rw-r--r--src/common/bit_util.h34
-rw-r--r--src/common/cityhash.h23
-rw-r--r--src/common/color.h34
-rw-r--r--src/common/common_funcs.h14
-rw-r--r--src/common/concepts.h10
-rw-r--r--src/common/detached_tasks.cpp3
-rw-r--r--src/common/dynamic_library.h13
-rw-r--r--src/common/fiber.h2
-rw-r--r--src/common/file_util.h61
-rw-r--r--src/common/hash.h25
-rw-r--r--src/common/hex_util.cpp34
-rw-r--r--src/common/hex_util.h33
-rw-r--r--src/common/lz4_compression.cpp16
-rw-r--r--src/common/lz4_compression.h24
-rw-r--r--src/common/math_util.h12
-rw-r--r--src/common/memory_detect.h2
-rw-r--r--src/common/multi_level_queue.h37
-rw-r--r--src/common/page_table.h4
-rw-r--r--src/common/param_package.h10
-rw-r--r--src/common/quaternion.h15
-rw-r--r--src/common/ring_buffer.h4
-rw-r--r--src/common/spin_lock.h2
-rw-r--r--src/common/string_util.h34
-rw-r--r--src/common/telemetry.h12
-rw-r--r--src/common/thread_queue_list.h10
-rw-r--r--src/common/threadsafe_queue.h12
-rw-r--r--src/common/time_zone.h4
-rw-r--r--src/common/timer.h16
-rw-r--r--src/common/uint128.h6
-rw-r--r--src/common/uuid.h14
-rw-r--r--src/common/vector_math.h204
-rw-r--r--src/common/virtual_buffer.cpp9
-rw-r--r--src/common/virtual_buffer.h10
-rw-r--r--src/common/wall_clock.h16
-rw-r--r--src/common/zstd_compression.cpp1
-rw-r--r--src/common/zstd_compression.h17
-rw-r--r--src/core/crypto/key_manager.cpp10
-rw-r--r--src/core/crypto/partition_data_manager.cpp206
-rw-r--r--src/core/file_sys/registered_cache.h6
-rw-r--r--src/core/file_sys/system_archive/mii_model.cpp18
-rw-r--r--src/core/file_sys/system_archive/ng_word.cpp42
-rw-r--r--src/core/file_sys/system_archive/time_zone_binary.cpp9
-rw-r--r--src/core/file_sys/vfs_vector.h13
-rw-r--r--src/core/frontend/emu_window.h4
-rw-r--r--src/core/hle/kernel/address_arbiter.cpp2
-rw-r--r--src/core/hle/kernel/hle_ipc.cpp46
-rw-r--r--src/core/hle/kernel/memory/page_table.cpp23
-rw-r--r--src/core/hle/kernel/memory/system_control.cpp21
-rw-r--r--src/core/hle/kernel/memory/system_control.h5
-rw-r--r--src/core/hle/kernel/scheduler.cpp31
-rw-r--r--src/core/hle/kernel/scheduler.h2
-rw-r--r--src/core/hle/result.h12
-rw-r--r--src/core/hle/service/am/am.cpp6
-rw-r--r--src/core/hle/service/am/am.h7
-rw-r--r--src/core/hle/service/am/applets/software_keyboard.cpp3
-rw-r--r--src/core/hle/service/am/applets/web_browser.cpp3
-rw-r--r--src/core/hle/service/audio/audout_u.cpp2
-rw-r--r--src/core/hle/service/bcat/backend/boxcat.cpp6
-rw-r--r--src/core/hle/service/hid/controllers/npad.cpp4
-rw-r--r--src/core/hle/service/nvdrv/devices/nvdevice.h3
-rw-r--r--src/core/hle/service/nvflinger/nvflinger.h10
-rw-r--r--src/core/hle/service/sm/sm.h2
-rw-r--r--src/core/hle/service/time/time_zone_content_manager.cpp4
-rw-r--r--src/core/loader/loader.cpp2
-rw-r--r--src/core/memory/cheat_engine.cpp26
-rw-r--r--src/core/tools/freezer.cpp31
-rw-r--r--src/core/tools/freezer.h7
-rw-r--r--src/input_common/gcadapter/gc_poller.cpp14
-rw-r--r--src/input_common/sdl/sdl_impl.cpp25
-rw-r--r--src/input_common/udp/client.cpp6
-rw-r--r--src/video_core/engines/maxwell_3d.h2
-rw-r--r--src/video_core/engines/maxwell_dma.cpp21
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp10
-rw-r--r--src/video_core/renderer_opengl/gl_shader_cache.cpp2
-rw-r--r--src/video_core/renderer_vulkan/vk_device.cpp2
-rw-r--r--src/video_core/renderer_vulkan/vk_device.h8
-rw-r--r--src/video_core/renderer_vulkan/vk_fence_manager.cpp2
-rw-r--r--src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp9
-rw-r--r--src/video_core/renderer_vulkan/vk_graphics_pipeline.h28
-rw-r--r--src/video_core/renderer_vulkan/vk_pipeline_cache.cpp37
-rw-r--r--src/video_core/renderer_vulkan/vk_pipeline_cache.h31
-rw-r--r--src/video_core/renderer_vulkan/vk_rasterizer.cpp26
-rw-r--r--src/video_core/renderer_vulkan/vk_rasterizer.h10
-rw-r--r--src/video_core/renderer_vulkan/wrapper.cpp2
-rw-r--r--src/video_core/renderer_vulkan/wrapper.h30
-rw-r--r--src/video_core/shader/async_shaders.cpp94
-rw-r--r--src/video_core/shader/async_shaders.h39
-rw-r--r--src/video_core/shader/control_flow.cpp30
-rw-r--r--src/video_core/shader/decode/memory.cpp6
-rw-r--r--src/video_core/texture_cache/surface_params.cpp1
-rw-r--r--src/video_core/textures/decoders.cpp42
-rw-r--r--src/video_core/textures/decoders.h5
-rw-r--r--src/yuzu/configuration/configure_graphics_advanced.ui2
-rw-r--r--src/yuzu/configuration/configure_input_player.cpp61
-rw-r--r--src/yuzu/configuration/configure_mouse_advanced.cpp11
-rw-r--r--src/yuzu/debugger/profiler.cpp3
-rw-r--r--src/yuzu/game_list.cpp2
-rw-r--r--src/yuzu/game_list_worker.cpp4
-rw-r--r--src/yuzu/main.cpp55
-rw-r--r--src/yuzu/main.h2
-rw-r--r--src/yuzu/main.ui9
-rw-r--r--src/yuzu/uisettings.h8
107 files changed, 1097 insertions, 933 deletions
diff --git a/src/audio_core/cubeb_sink.cpp b/src/audio_core/cubeb_sink.cpp
index 41bf5cd4d..c27df946c 100644
--- a/src/audio_core/cubeb_sink.cpp
+++ b/src/audio_core/cubeb_sink.cpp
@@ -78,7 +78,7 @@ public:
78 const s16 surround_left{samples[i + 4]}; 78 const s16 surround_left{samples[i + 4]};
79 const s16 surround_right{samples[i + 5]}; 79 const s16 surround_right{samples[i + 5]};
80 // Not used in the ATSC reference implementation 80 // Not used in the ATSC reference implementation
81 [[maybe_unused]] const s16 low_frequency_effects { samples[i + 3] }; 81 [[maybe_unused]] const s16 low_frequency_effects{samples[i + 3]};
82 82
83 constexpr s32 clev{707}; // center mixing level coefficient 83 constexpr s32 clev{707}; // center mixing level coefficient
84 constexpr s32 slev{707}; // surround mixing level coefficient 84 constexpr s32 slev{707}; // surround mixing level coefficient
diff --git a/src/common/algorithm.h b/src/common/algorithm.h
index e21b1373c..4804a3421 100644
--- a/src/common/algorithm.h
+++ b/src/common/algorithm.h
@@ -15,7 +15,8 @@
15namespace Common { 15namespace Common {
16 16
17template <class ForwardIt, class T, class Compare = std::less<>> 17template <class ForwardIt, class T, class Compare = std::less<>>
18ForwardIt BinaryFind(ForwardIt first, ForwardIt last, const T& value, Compare comp = {}) { 18[[nodiscard]] ForwardIt BinaryFind(ForwardIt first, ForwardIt last, const T& value,
19 Compare comp = {}) {
19 // Note: BOTH type T and the type after ForwardIt is dereferenced 20 // Note: BOTH type T and the type after ForwardIt is dereferenced
20 // must be implicitly convertible to BOTH Type1 and Type2, used in Compare. 21 // must be implicitly convertible to BOTH Type1 and Type2, used in Compare.
21 // This is stricter than lower_bound requirement (see above) 22 // This is stricter than lower_bound requirement (see above)
diff --git a/src/common/alignment.h b/src/common/alignment.h
index ef4d6f896..5040043de 100644
--- a/src/common/alignment.h
+++ b/src/common/alignment.h
@@ -9,7 +9,7 @@
9namespace Common { 9namespace Common {
10 10
11template <typename T> 11template <typename T>
12constexpr T AlignUp(T value, std::size_t size) { 12[[nodiscard]] constexpr T AlignUp(T value, std::size_t size) {
13 static_assert(std::is_unsigned_v<T>, "T must be an unsigned value."); 13 static_assert(std::is_unsigned_v<T>, "T must be an unsigned value.");
14 auto mod{static_cast<T>(value % size)}; 14 auto mod{static_cast<T>(value % size)};
15 value -= mod; 15 value -= mod;
@@ -17,31 +17,31 @@ constexpr T AlignUp(T value, std::size_t size) {
17} 17}
18 18
19template <typename T> 19template <typename T>
20constexpr T AlignDown(T value, std::size_t size) { 20[[nodiscard]] constexpr T AlignDown(T value, std::size_t size) {
21 static_assert(std::is_unsigned_v<T>, "T must be an unsigned value."); 21 static_assert(std::is_unsigned_v<T>, "T must be an unsigned value.");
22 return static_cast<T>(value - value % size); 22 return static_cast<T>(value - value % size);
23} 23}
24 24
25template <typename T> 25template <typename T>
26constexpr T AlignBits(T value, std::size_t align) { 26[[nodiscard]] constexpr T AlignBits(T value, std::size_t align) {
27 static_assert(std::is_unsigned_v<T>, "T must be an unsigned value."); 27 static_assert(std::is_unsigned_v<T>, "T must be an unsigned value.");
28 return static_cast<T>((value + ((1ULL << align) - 1)) >> align << align); 28 return static_cast<T>((value + ((1ULL << align) - 1)) >> align << align);
29} 29}
30 30
31template <typename T> 31template <typename T>
32constexpr bool Is4KBAligned(T value) { 32[[nodiscard]] constexpr bool Is4KBAligned(T value) {
33 static_assert(std::is_unsigned_v<T>, "T must be an unsigned value."); 33 static_assert(std::is_unsigned_v<T>, "T must be an unsigned value.");
34 return (value & 0xFFF) == 0; 34 return (value & 0xFFF) == 0;
35} 35}
36 36
37template <typename T> 37template <typename T>
38constexpr bool IsWordAligned(T value) { 38[[nodiscard]] constexpr bool IsWordAligned(T value) {
39 static_assert(std::is_unsigned_v<T>, "T must be an unsigned value."); 39 static_assert(std::is_unsigned_v<T>, "T must be an unsigned value.");
40 return (value & 0b11) == 0; 40 return (value & 0b11) == 0;
41} 41}
42 42
43template <typename T> 43template <typename T>
44constexpr bool IsAligned(T value, std::size_t alignment) { 44[[nodiscard]] constexpr bool IsAligned(T value, std::size_t alignment) {
45 using U = typename std::make_unsigned<T>::type; 45 using U = typename std::make_unsigned<T>::type;
46 const U mask = static_cast<U>(alignment - 1); 46 const U mask = static_cast<U>(alignment - 1);
47 return (value & mask) == 0; 47 return (value & mask) == 0;
@@ -64,7 +64,7 @@ public:
64 template <typename T2> 64 template <typename T2>
65 constexpr AlignmentAllocator(const AlignmentAllocator<T2, Align>&) noexcept {} 65 constexpr AlignmentAllocator(const AlignmentAllocator<T2, Align>&) noexcept {}
66 66
67 T* allocate(size_type n) { 67 [[nodiscard]] T* allocate(size_type n) {
68 return static_cast<T*>(::operator new (n * sizeof(T), std::align_val_t{Align})); 68 return static_cast<T*>(::operator new (n * sizeof(T), std::align_val_t{Align}));
69 } 69 }
70 70
diff --git a/src/common/atomic_ops.h b/src/common/atomic_ops.h
index 8d6b73c00..b46888589 100644
--- a/src/common/atomic_ops.h
+++ b/src/common/atomic_ops.h
@@ -8,10 +8,10 @@
8 8
9namespace Common { 9namespace Common {
10 10
11bool AtomicCompareAndSwap(volatile u8* pointer, u8 value, u8 expected); 11[[nodiscard]] bool AtomicCompareAndSwap(volatile u8* pointer, u8 value, u8 expected);
12bool AtomicCompareAndSwap(volatile u16* pointer, u16 value, u16 expected); 12[[nodiscard]] bool AtomicCompareAndSwap(volatile u16* pointer, u16 value, u16 expected);
13bool AtomicCompareAndSwap(volatile u32* pointer, u32 value, u32 expected); 13[[nodiscard]] bool AtomicCompareAndSwap(volatile u32* pointer, u32 value, u32 expected);
14bool AtomicCompareAndSwap(volatile u64* pointer, u64 value, u64 expected); 14[[nodiscard]] bool AtomicCompareAndSwap(volatile u64* pointer, u64 value, u64 expected);
15bool AtomicCompareAndSwap(volatile u64* pointer, u128 value, u128 expected); 15[[nodiscard]] bool AtomicCompareAndSwap(volatile u64* pointer, u128 value, u128 expected);
16 16
17} // namespace Common 17} // namespace Common
diff --git a/src/common/bit_field.h b/src/common/bit_field.h
index 26ae6c7fc..0f0661172 100644
--- a/src/common/bit_field.h
+++ b/src/common/bit_field.h
@@ -36,13 +36,6 @@
36#include "common/common_funcs.h" 36#include "common/common_funcs.h"
37#include "common/swap.h" 37#include "common/swap.h"
38 38
39// Inlining
40#ifdef _WIN32
41#define FORCE_INLINE __forceinline
42#else
43#define FORCE_INLINE inline __attribute__((always_inline))
44#endif
45
46/* 39/*
47 * Abstract bitfield class 40 * Abstract bitfield class
48 * 41 *
@@ -142,8 +135,8 @@ public:
142 * containing several bitfields can be assembled by formatting each of their values and ORing 135 * containing several bitfields can be assembled by formatting each of their values and ORing
143 * the results together. 136 * the results together.
144 */ 137 */
145 static constexpr FORCE_INLINE StorageType FormatValue(const T& value) { 138 [[nodiscard]] static constexpr StorageType FormatValue(const T& value) {
146 return ((StorageType)value << position) & mask; 139 return (static_cast<StorageType>(value) << position) & mask;
147 } 140 }
148 141
149 /** 142 /**
@@ -151,7 +144,7 @@ public:
151 * (such as Value() or operator T), but this can be used to extract a value from a bitfield 144 * (such as Value() or operator T), but this can be used to extract a value from a bitfield
152 * union in a constexpr context. 145 * union in a constexpr context.
153 */ 146 */
154 static constexpr FORCE_INLINE T ExtractValue(const StorageType& storage) { 147 [[nodiscard]] static constexpr T ExtractValue(const StorageType& storage) {
155 if constexpr (std::numeric_limits<UnderlyingType>::is_signed) { 148 if constexpr (std::numeric_limits<UnderlyingType>::is_signed) {
156 std::size_t shift = 8 * sizeof(T) - bits; 149 std::size_t shift = 8 * sizeof(T) - bits;
157 return static_cast<T>(static_cast<UnderlyingType>(storage << (shift - position)) >> 150 return static_cast<T>(static_cast<UnderlyingType>(storage << (shift - position)) >>
@@ -175,7 +168,7 @@ public:
175 constexpr BitField(BitField&&) noexcept = default; 168 constexpr BitField(BitField&&) noexcept = default;
176 constexpr BitField& operator=(BitField&&) noexcept = default; 169 constexpr BitField& operator=(BitField&&) noexcept = default;
177 170
178 constexpr operator T() const { 171 [[nodiscard]] constexpr operator T() const {
179 return Value(); 172 return Value();
180 } 173 }
181 174
@@ -183,11 +176,11 @@ public:
183 storage = static_cast<StorageType>((storage & ~mask) | FormatValue(value)); 176 storage = static_cast<StorageType>((storage & ~mask) | FormatValue(value));
184 } 177 }
185 178
186 constexpr T Value() const { 179 [[nodiscard]] constexpr T Value() const {
187 return ExtractValue(storage); 180 return ExtractValue(storage);
188 } 181 }
189 182
190 constexpr explicit operator bool() const { 183 [[nodiscard]] constexpr explicit operator bool() const {
191 return Value() != 0; 184 return Value() != 0;
192 } 185 }
193 186
diff --git a/src/common/bit_util.h b/src/common/bit_util.h
index 6f7d5a947..29f59a9a3 100644
--- a/src/common/bit_util.h
+++ b/src/common/bit_util.h
@@ -17,12 +17,12 @@ namespace Common {
17 17
18/// Gets the size of a specified type T in bits. 18/// Gets the size of a specified type T in bits.
19template <typename T> 19template <typename T>
20constexpr std::size_t BitSize() { 20[[nodiscard]] constexpr std::size_t BitSize() {
21 return sizeof(T) * CHAR_BIT; 21 return sizeof(T) * CHAR_BIT;
22} 22}
23 23
24#ifdef _MSC_VER 24#ifdef _MSC_VER
25inline u32 CountLeadingZeroes32(u32 value) { 25[[nodiscard]] inline u32 CountLeadingZeroes32(u32 value) {
26 unsigned long leading_zero = 0; 26 unsigned long leading_zero = 0;
27 27
28 if (_BitScanReverse(&leading_zero, value) != 0) { 28 if (_BitScanReverse(&leading_zero, value) != 0) {
@@ -32,7 +32,7 @@ inline u32 CountLeadingZeroes32(u32 value) {
32 return 32; 32 return 32;
33} 33}
34 34
35inline u32 CountLeadingZeroes64(u64 value) { 35[[nodiscard]] inline u32 CountLeadingZeroes64(u64 value) {
36 unsigned long leading_zero = 0; 36 unsigned long leading_zero = 0;
37 37
38 if (_BitScanReverse64(&leading_zero, value) != 0) { 38 if (_BitScanReverse64(&leading_zero, value) != 0) {
@@ -42,7 +42,7 @@ inline u32 CountLeadingZeroes64(u64 value) {
42 return 64; 42 return 64;
43} 43}
44#else 44#else
45inline u32 CountLeadingZeroes32(u32 value) { 45[[nodiscard]] inline u32 CountLeadingZeroes32(u32 value) {
46 if (value == 0) { 46 if (value == 0) {
47 return 32; 47 return 32;
48 } 48 }
@@ -50,7 +50,7 @@ inline u32 CountLeadingZeroes32(u32 value) {
50 return static_cast<u32>(__builtin_clz(value)); 50 return static_cast<u32>(__builtin_clz(value));
51} 51}
52 52
53inline u32 CountLeadingZeroes64(u64 value) { 53[[nodiscard]] inline u32 CountLeadingZeroes64(u64 value) {
54 if (value == 0) { 54 if (value == 0) {
55 return 64; 55 return 64;
56 } 56 }
@@ -60,7 +60,7 @@ inline u32 CountLeadingZeroes64(u64 value) {
60#endif 60#endif
61 61
62#ifdef _MSC_VER 62#ifdef _MSC_VER
63inline u32 CountTrailingZeroes32(u32 value) { 63[[nodiscard]] inline u32 CountTrailingZeroes32(u32 value) {
64 unsigned long trailing_zero = 0; 64 unsigned long trailing_zero = 0;
65 65
66 if (_BitScanForward(&trailing_zero, value) != 0) { 66 if (_BitScanForward(&trailing_zero, value) != 0) {
@@ -70,7 +70,7 @@ inline u32 CountTrailingZeroes32(u32 value) {
70 return 32; 70 return 32;
71} 71}
72 72
73inline u32 CountTrailingZeroes64(u64 value) { 73[[nodiscard]] inline u32 CountTrailingZeroes64(u64 value) {
74 unsigned long trailing_zero = 0; 74 unsigned long trailing_zero = 0;
75 75
76 if (_BitScanForward64(&trailing_zero, value) != 0) { 76 if (_BitScanForward64(&trailing_zero, value) != 0) {
@@ -80,7 +80,7 @@ inline u32 CountTrailingZeroes64(u64 value) {
80 return 64; 80 return 64;
81} 81}
82#else 82#else
83inline u32 CountTrailingZeroes32(u32 value) { 83[[nodiscard]] inline u32 CountTrailingZeroes32(u32 value) {
84 if (value == 0) { 84 if (value == 0) {
85 return 32; 85 return 32;
86 } 86 }
@@ -88,7 +88,7 @@ inline u32 CountTrailingZeroes32(u32 value) {
88 return static_cast<u32>(__builtin_ctz(value)); 88 return static_cast<u32>(__builtin_ctz(value));
89} 89}
90 90
91inline u32 CountTrailingZeroes64(u64 value) { 91[[nodiscard]] inline u32 CountTrailingZeroes64(u64 value) {
92 if (value == 0) { 92 if (value == 0) {
93 return 64; 93 return 64;
94 } 94 }
@@ -99,13 +99,13 @@ inline u32 CountTrailingZeroes64(u64 value) {
99 99
100#ifdef _MSC_VER 100#ifdef _MSC_VER
101 101
102inline u32 MostSignificantBit32(const u32 value) { 102[[nodiscard]] inline u32 MostSignificantBit32(const u32 value) {
103 unsigned long result; 103 unsigned long result;
104 _BitScanReverse(&result, value); 104 _BitScanReverse(&result, value);
105 return static_cast<u32>(result); 105 return static_cast<u32>(result);
106} 106}
107 107
108inline u32 MostSignificantBit64(const u64 value) { 108[[nodiscard]] inline u32 MostSignificantBit64(const u64 value) {
109 unsigned long result; 109 unsigned long result;
110 _BitScanReverse64(&result, value); 110 _BitScanReverse64(&result, value);
111 return static_cast<u32>(result); 111 return static_cast<u32>(result);
@@ -113,30 +113,30 @@ inline u32 MostSignificantBit64(const u64 value) {
113 113
114#else 114#else
115 115
116inline u32 MostSignificantBit32(const u32 value) { 116[[nodiscard]] inline u32 MostSignificantBit32(const u32 value) {
117 return 31U - static_cast<u32>(__builtin_clz(value)); 117 return 31U - static_cast<u32>(__builtin_clz(value));
118} 118}
119 119
120inline u32 MostSignificantBit64(const u64 value) { 120[[nodiscard]] inline u32 MostSignificantBit64(const u64 value) {
121 return 63U - static_cast<u32>(__builtin_clzll(value)); 121 return 63U - static_cast<u32>(__builtin_clzll(value));
122} 122}
123 123
124#endif 124#endif
125 125
126inline u32 Log2Floor32(const u32 value) { 126[[nodiscard]] inline u32 Log2Floor32(const u32 value) {
127 return MostSignificantBit32(value); 127 return MostSignificantBit32(value);
128} 128}
129 129
130inline u32 Log2Ceil32(const u32 value) { 130[[nodiscard]] inline u32 Log2Ceil32(const u32 value) {
131 const u32 log2_f = Log2Floor32(value); 131 const u32 log2_f = Log2Floor32(value);
132 return log2_f + ((value ^ (1U << log2_f)) != 0U); 132 return log2_f + ((value ^ (1U << log2_f)) != 0U);
133} 133}
134 134
135inline u32 Log2Floor64(const u64 value) { 135[[nodiscard]] inline u32 Log2Floor64(const u64 value) {
136 return MostSignificantBit64(value); 136 return MostSignificantBit64(value);
137} 137}
138 138
139inline u32 Log2Ceil64(const u64 value) { 139[[nodiscard]] inline u32 Log2Ceil64(const u64 value) {
140 const u64 log2_f = static_cast<u64>(Log2Floor64(value)); 140 const u64 log2_f = static_cast<u64>(Log2Floor64(value));
141 return static_cast<u32>(log2_f + ((value ^ (1ULL << log2_f)) != 0ULL)); 141 return static_cast<u32>(log2_f + ((value ^ (1ULL << log2_f)) != 0ULL));
142} 142}
diff --git a/src/common/cityhash.h b/src/common/cityhash.h
index 4b94f8e18..a00804e01 100644
--- a/src/common/cityhash.h
+++ b/src/common/cityhash.h
@@ -61,42 +61,43 @@
61 61
62#pragma once 62#pragma once
63 63
64#include <cstddef>
65#include <cstdint>
64#include <utility> 66#include <utility>
65#include <stdint.h>
66#include <stdlib.h> // for std::size_t.
67 67
68namespace Common { 68namespace Common {
69 69
70typedef std::pair<uint64_t, uint64_t> uint128; 70using uint128 = std::pair<uint64_t, uint64_t>;
71 71
72inline uint64_t Uint128Low64(const uint128& x) { 72[[nodiscard]] inline uint64_t Uint128Low64(const uint128& x) {
73 return x.first; 73 return x.first;
74} 74}
75inline uint64_t Uint128High64(const uint128& x) { 75[[nodiscard]] inline uint64_t Uint128High64(const uint128& x) {
76 return x.second; 76 return x.second;
77} 77}
78 78
79// Hash function for a byte array. 79// Hash function for a byte array.
80uint64_t CityHash64(const char* buf, std::size_t len); 80[[nodiscard]] uint64_t CityHash64(const char* buf, std::size_t len);
81 81
82// Hash function for a byte array. For convenience, a 64-bit seed is also 82// Hash function for a byte array. For convenience, a 64-bit seed is also
83// hashed into the result. 83// hashed into the result.
84uint64_t CityHash64WithSeed(const char* buf, std::size_t len, uint64_t seed); 84[[nodiscard]] uint64_t CityHash64WithSeed(const char* buf, std::size_t len, uint64_t seed);
85 85
86// Hash function for a byte array. For convenience, two seeds are also 86// Hash function for a byte array. For convenience, two seeds are also
87// hashed into the result. 87// hashed into the result.
88uint64_t CityHash64WithSeeds(const char* buf, std::size_t len, uint64_t seed0, uint64_t seed1); 88[[nodiscard]] uint64_t CityHash64WithSeeds(const char* buf, std::size_t len, uint64_t seed0,
89 uint64_t seed1);
89 90
90// Hash function for a byte array. 91// Hash function for a byte array.
91uint128 CityHash128(const char* s, std::size_t len); 92[[nodiscard]] uint128 CityHash128(const char* s, std::size_t len);
92 93
93// Hash function for a byte array. For convenience, a 128-bit seed is also 94// Hash function for a byte array. For convenience, a 128-bit seed is also
94// hashed into the result. 95// hashed into the result.
95uint128 CityHash128WithSeed(const char* s, std::size_t len, uint128 seed); 96[[nodiscard]] uint128 CityHash128WithSeed(const char* s, std::size_t len, uint128 seed);
96 97
97// Hash 128 input bits down to 64 bits of output. 98// Hash 128 input bits down to 64 bits of output.
98// This is intended to be a reasonably good hash function. 99// This is intended to be a reasonably good hash function.
99inline uint64_t Hash128to64(const uint128& x) { 100[[nodiscard]] inline uint64_t Hash128to64(const uint128& x) {
100 // Murmur-inspired hashing. 101 // Murmur-inspired hashing.
101 const uint64_t kMul = 0x9ddfea08eb382d69ULL; 102 const uint64_t kMul = 0x9ddfea08eb382d69ULL;
102 uint64_t a = (Uint128Low64(x) ^ Uint128High64(x)) * kMul; 103 uint64_t a = (Uint128Low64(x) ^ Uint128High64(x)) * kMul;
diff --git a/src/common/color.h b/src/common/color.h
index 3a2222077..381d6332e 100644
--- a/src/common/color.h
+++ b/src/common/color.h
@@ -13,42 +13,42 @@
13namespace Color { 13namespace Color {
14 14
15/// Convert a 1-bit color component to 8 bit 15/// Convert a 1-bit color component to 8 bit
16constexpr u8 Convert1To8(u8 value) { 16[[nodiscard]] constexpr u8 Convert1To8(u8 value) {
17 return value * 255; 17 return value * 255;
18} 18}
19 19
20/// Convert a 4-bit color component to 8 bit 20/// Convert a 4-bit color component to 8 bit
21constexpr u8 Convert4To8(u8 value) { 21[[nodiscard]] constexpr u8 Convert4To8(u8 value) {
22 return (value << 4) | value; 22 return (value << 4) | value;
23} 23}
24 24
25/// Convert a 5-bit color component to 8 bit 25/// Convert a 5-bit color component to 8 bit
26constexpr u8 Convert5To8(u8 value) { 26[[nodiscard]] constexpr u8 Convert5To8(u8 value) {
27 return (value << 3) | (value >> 2); 27 return (value << 3) | (value >> 2);
28} 28}
29 29
30/// Convert a 6-bit color component to 8 bit 30/// Convert a 6-bit color component to 8 bit
31constexpr u8 Convert6To8(u8 value) { 31[[nodiscard]] constexpr u8 Convert6To8(u8 value) {
32 return (value << 2) | (value >> 4); 32 return (value << 2) | (value >> 4);
33} 33}
34 34
35/// Convert a 8-bit color component to 1 bit 35/// Convert a 8-bit color component to 1 bit
36constexpr u8 Convert8To1(u8 value) { 36[[nodiscard]] constexpr u8 Convert8To1(u8 value) {
37 return value >> 7; 37 return value >> 7;
38} 38}
39 39
40/// Convert a 8-bit color component to 4 bit 40/// Convert a 8-bit color component to 4 bit
41constexpr u8 Convert8To4(u8 value) { 41[[nodiscard]] constexpr u8 Convert8To4(u8 value) {
42 return value >> 4; 42 return value >> 4;
43} 43}
44 44
45/// Convert a 8-bit color component to 5 bit 45/// Convert a 8-bit color component to 5 bit
46constexpr u8 Convert8To5(u8 value) { 46[[nodiscard]] constexpr u8 Convert8To5(u8 value) {
47 return value >> 3; 47 return value >> 3;
48} 48}
49 49
50/// Convert a 8-bit color component to 6 bit 50/// Convert a 8-bit color component to 6 bit
51constexpr u8 Convert8To6(u8 value) { 51[[nodiscard]] constexpr u8 Convert8To6(u8 value) {
52 return value >> 2; 52 return value >> 2;
53} 53}
54 54
@@ -57,7 +57,7 @@ constexpr u8 Convert8To6(u8 value) {
57 * @param bytes Pointer to encoded source color 57 * @param bytes Pointer to encoded source color
58 * @return Result color decoded as Common::Vec4<u8> 58 * @return Result color decoded as Common::Vec4<u8>
59 */ 59 */
60inline Common::Vec4<u8> DecodeRGBA8(const u8* bytes) { 60[[nodiscard]] inline Common::Vec4<u8> DecodeRGBA8(const u8* bytes) {
61 return {bytes[3], bytes[2], bytes[1], bytes[0]}; 61 return {bytes[3], bytes[2], bytes[1], bytes[0]};
62} 62}
63 63
@@ -66,7 +66,7 @@ inline Common::Vec4<u8> DecodeRGBA8(const u8* bytes) {
66 * @param bytes Pointer to encoded source color 66 * @param bytes Pointer to encoded source color
67 * @return Result color decoded as Common::Vec4<u8> 67 * @return Result color decoded as Common::Vec4<u8>
68 */ 68 */
69inline Common::Vec4<u8> DecodeRGB8(const u8* bytes) { 69[[nodiscard]] inline Common::Vec4<u8> DecodeRGB8(const u8* bytes) {
70 return {bytes[2], bytes[1], bytes[0], 255}; 70 return {bytes[2], bytes[1], bytes[0], 255};
71} 71}
72 72
@@ -75,7 +75,7 @@ inline Common::Vec4<u8> DecodeRGB8(const u8* bytes) {
75 * @param bytes Pointer to encoded source color 75 * @param bytes Pointer to encoded source color
76 * @return Result color decoded as Common::Vec4<u8> 76 * @return Result color decoded as Common::Vec4<u8>
77 */ 77 */
78inline Common::Vec4<u8> DecodeRG8(const u8* bytes) { 78[[nodiscard]] inline Common::Vec4<u8> DecodeRG8(const u8* bytes) {
79 return {bytes[1], bytes[0], 0, 255}; 79 return {bytes[1], bytes[0], 0, 255};
80} 80}
81 81
@@ -84,7 +84,7 @@ inline Common::Vec4<u8> DecodeRG8(const u8* bytes) {
84 * @param bytes Pointer to encoded source color 84 * @param bytes Pointer to encoded source color
85 * @return Result color decoded as Common::Vec4<u8> 85 * @return Result color decoded as Common::Vec4<u8>
86 */ 86 */
87inline Common::Vec4<u8> DecodeRGB565(const u8* bytes) { 87[[nodiscard]] inline Common::Vec4<u8> DecodeRGB565(const u8* bytes) {
88 u16_le pixel; 88 u16_le pixel;
89 std::memcpy(&pixel, bytes, sizeof(pixel)); 89 std::memcpy(&pixel, bytes, sizeof(pixel));
90 return {Convert5To8((pixel >> 11) & 0x1F), Convert6To8((pixel >> 5) & 0x3F), 90 return {Convert5To8((pixel >> 11) & 0x1F), Convert6To8((pixel >> 5) & 0x3F),
@@ -96,7 +96,7 @@ inline Common::Vec4<u8> DecodeRGB565(const u8* bytes) {
96 * @param bytes Pointer to encoded source color 96 * @param bytes Pointer to encoded source color
97 * @return Result color decoded as Common::Vec4<u8> 97 * @return Result color decoded as Common::Vec4<u8>
98 */ 98 */
99inline Common::Vec4<u8> DecodeRGB5A1(const u8* bytes) { 99[[nodiscard]] inline Common::Vec4<u8> DecodeRGB5A1(const u8* bytes) {
100 u16_le pixel; 100 u16_le pixel;
101 std::memcpy(&pixel, bytes, sizeof(pixel)); 101 std::memcpy(&pixel, bytes, sizeof(pixel));
102 return {Convert5To8((pixel >> 11) & 0x1F), Convert5To8((pixel >> 6) & 0x1F), 102 return {Convert5To8((pixel >> 11) & 0x1F), Convert5To8((pixel >> 6) & 0x1F),
@@ -108,7 +108,7 @@ inline Common::Vec4<u8> DecodeRGB5A1(const u8* bytes) {
108 * @param bytes Pointer to encoded source color 108 * @param bytes Pointer to encoded source color
109 * @return Result color decoded as Common::Vec4<u8> 109 * @return Result color decoded as Common::Vec4<u8>
110 */ 110 */
111inline Common::Vec4<u8> DecodeRGBA4(const u8* bytes) { 111[[nodiscard]] inline Common::Vec4<u8> DecodeRGBA4(const u8* bytes) {
112 u16_le pixel; 112 u16_le pixel;
113 std::memcpy(&pixel, bytes, sizeof(pixel)); 113 std::memcpy(&pixel, bytes, sizeof(pixel));
114 return {Convert4To8((pixel >> 12) & 0xF), Convert4To8((pixel >> 8) & 0xF), 114 return {Convert4To8((pixel >> 12) & 0xF), Convert4To8((pixel >> 8) & 0xF),
@@ -120,7 +120,7 @@ inline Common::Vec4<u8> DecodeRGBA4(const u8* bytes) {
120 * @param bytes Pointer to encoded source value 120 * @param bytes Pointer to encoded source value
121 * @return Depth value as an u32 121 * @return Depth value as an u32
122 */ 122 */
123inline u32 DecodeD16(const u8* bytes) { 123[[nodiscard]] inline u32 DecodeD16(const u8* bytes) {
124 u16_le data; 124 u16_le data;
125 std::memcpy(&data, bytes, sizeof(data)); 125 std::memcpy(&data, bytes, sizeof(data));
126 return data; 126 return data;
@@ -131,7 +131,7 @@ inline u32 DecodeD16(const u8* bytes) {
131 * @param bytes Pointer to encoded source value 131 * @param bytes Pointer to encoded source value
132 * @return Depth value as an u32 132 * @return Depth value as an u32
133 */ 133 */
134inline u32 DecodeD24(const u8* bytes) { 134[[nodiscard]] inline u32 DecodeD24(const u8* bytes) {
135 return (bytes[2] << 16) | (bytes[1] << 8) | bytes[0]; 135 return (bytes[2] << 16) | (bytes[1] << 8) | bytes[0];
136} 136}
137 137
@@ -140,7 +140,7 @@ inline u32 DecodeD24(const u8* bytes) {
140 * @param bytes Pointer to encoded source values 140 * @param bytes Pointer to encoded source values
141 * @return Resulting values stored as a Common::Vec2 141 * @return Resulting values stored as a Common::Vec2
142 */ 142 */
143inline Common::Vec2<u32> DecodeD24S8(const u8* bytes) { 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]}; 144 return {static_cast<u32>((bytes[2] << 16) | (bytes[1] << 8) | bytes[0]), bytes[3]};
145} 145}
146 146
diff --git a/src/common/common_funcs.h b/src/common/common_funcs.h
index 88cf5250a..98421bced 100644
--- a/src/common/common_funcs.h
+++ b/src/common/common_funcs.h
@@ -53,14 +53,14 @@ __declspec(dllimport) void __stdcall DebugBreak(void);
53// Call directly after the command or use the error num. 53// Call directly after the command or use the error num.
54// This function might change the error code. 54// This function might change the error code.
55// Defined in Misc.cpp. 55// Defined in Misc.cpp.
56std::string GetLastErrorMsg(); 56[[nodiscard]] std::string GetLastErrorMsg();
57 57
58#define DECLARE_ENUM_FLAG_OPERATORS(type) \ 58#define DECLARE_ENUM_FLAG_OPERATORS(type) \
59 constexpr type operator|(type a, type b) noexcept { \ 59 [[nodiscard]] constexpr type operator|(type a, type b) noexcept { \
60 using T = std::underlying_type_t<type>; \ 60 using T = std::underlying_type_t<type>; \
61 return static_cast<type>(static_cast<T>(a) | static_cast<T>(b)); \ 61 return static_cast<type>(static_cast<T>(a) | static_cast<T>(b)); \
62 } \ 62 } \
63 constexpr type operator&(type a, type b) noexcept { \ 63 [[nodiscard]] constexpr type operator&(type a, type b) noexcept { \
64 using T = std::underlying_type_t<type>; \ 64 using T = std::underlying_type_t<type>; \
65 return static_cast<type>(static_cast<T>(a) & static_cast<T>(b)); \ 65 return static_cast<type>(static_cast<T>(a) & static_cast<T>(b)); \
66 } \ 66 } \
@@ -74,22 +74,22 @@ std::string GetLastErrorMsg();
74 a = static_cast<type>(static_cast<T>(a) & static_cast<T>(b)); \ 74 a = static_cast<type>(static_cast<T>(a) & static_cast<T>(b)); \
75 return a; \ 75 return a; \
76 } \ 76 } \
77 constexpr type operator~(type key) noexcept { \ 77 [[nodiscard]] constexpr type operator~(type key) noexcept { \
78 using T = std::underlying_type_t<type>; \ 78 using T = std::underlying_type_t<type>; \
79 return static_cast<type>(~static_cast<T>(key)); \ 79 return static_cast<type>(~static_cast<T>(key)); \
80 } \ 80 } \
81 constexpr bool True(type key) noexcept { \ 81 [[nodiscard]] constexpr bool True(type key) noexcept { \
82 using T = std::underlying_type_t<type>; \ 82 using T = std::underlying_type_t<type>; \
83 return static_cast<T>(key) != 0; \ 83 return static_cast<T>(key) != 0; \
84 } \ 84 } \
85 constexpr bool False(type key) noexcept { \ 85 [[nodiscard]] constexpr bool False(type key) noexcept { \
86 using T = std::underlying_type_t<type>; \ 86 using T = std::underlying_type_t<type>; \
87 return static_cast<T>(key) == 0; \ 87 return static_cast<T>(key) == 0; \
88 } 88 }
89 89
90namespace Common { 90namespace Common {
91 91
92constexpr u32 MakeMagic(char a, char b, char c, char d) { 92[[nodiscard]] constexpr u32 MakeMagic(char a, char b, char c, char d) {
93 return u32(a) | u32(b) << 8 | u32(c) << 16 | u32(d) << 24; 93 return u32(a) | u32(b) << 8 | u32(c) << 16 | u32(d) << 24;
94} 94}
95 95
diff --git a/src/common/concepts.h b/src/common/concepts.h
index db5fb373d..54252e778 100644
--- a/src/common/concepts.h
+++ b/src/common/concepts.h
@@ -23,10 +23,12 @@ concept IsSTLContainer = requires(T t) {
23 t.size(); 23 t.size();
24}; 24};
25 25
26// Check if type T is derived from T2 26// TODO: Replace with std::derived_from when the <concepts> header
27template <typename T, typename T2> 27// is available on all supported platforms.
28concept IsBaseOf = requires { 28template <typename Derived, typename Base>
29 std::is_base_of_v<T, T2>; 29concept DerivedFrom = requires {
30 std::is_base_of_v<Base, Derived>;
31 std::is_convertible_v<const volatile Derived*, const volatile Base*>;
30}; 32};
31 33
32} // namespace Common 34} // namespace Common
diff --git a/src/common/detached_tasks.cpp b/src/common/detached_tasks.cpp
index f268d6021..f2b4939df 100644
--- a/src/common/detached_tasks.cpp
+++ b/src/common/detached_tasks.cpp
@@ -34,8 +34,7 @@ void DetachedTasks::AddTask(std::function<void()> task) {
34 std::unique_lock lock{instance->mutex}; 34 std::unique_lock lock{instance->mutex};
35 --instance->count; 35 --instance->count;
36 std::notify_all_at_thread_exit(instance->cv, std::move(lock)); 36 std::notify_all_at_thread_exit(instance->cv, std::move(lock));
37 }) 37 }).detach();
38 .detach();
39} 38}
40 39
41} // namespace Common 40} // namespace Common
diff --git a/src/common/dynamic_library.h b/src/common/dynamic_library.h
index 2a06372fd..3512da940 100644
--- a/src/common/dynamic_library.h
+++ b/src/common/dynamic_library.h
@@ -33,7 +33,7 @@ public:
33 ~DynamicLibrary(); 33 ~DynamicLibrary();
34 34
35 /// Returns the specified library name with the platform-specific suffix added. 35 /// Returns the specified library name with the platform-specific suffix added.
36 static std::string GetUnprefixedFilename(const char* filename); 36 [[nodiscard]] static std::string GetUnprefixedFilename(const char* filename);
37 37
38 /// Returns the specified library name in platform-specific format. 38 /// Returns the specified library name in platform-specific format.
39 /// Major/minor versions will not be included if set to -1. 39 /// Major/minor versions will not be included if set to -1.
@@ -41,28 +41,29 @@ public:
41 /// Windows: LIBNAME-MAJOR-MINOR.dll 41 /// Windows: LIBNAME-MAJOR-MINOR.dll
42 /// Linux: libLIBNAME.so.MAJOR.MINOR 42 /// Linux: libLIBNAME.so.MAJOR.MINOR
43 /// Mac: libLIBNAME.MAJOR.MINOR.dylib 43 /// Mac: libLIBNAME.MAJOR.MINOR.dylib
44 static std::string GetVersionedFilename(const char* libname, int major = -1, int minor = -1); 44 [[nodiscard]] static std::string GetVersionedFilename(const char* libname, int major = -1,
45 int minor = -1);
45 46
46 /// Returns true if a module is loaded, otherwise false. 47 /// Returns true if a module is loaded, otherwise false.
47 bool IsOpen() const { 48 [[nodiscard]] bool IsOpen() const {
48 return handle != nullptr; 49 return handle != nullptr;
49 } 50 }
50 51
51 /// Loads (or replaces) the handle with the specified library file name. 52 /// Loads (or replaces) the handle with the specified library file name.
52 /// Returns true if the library was loaded and can be used. 53 /// Returns true if the library was loaded and can be used.
53 bool Open(const char* filename); 54 [[nodiscard]] bool Open(const char* filename);
54 55
55 /// Unloads the library, any function pointers from this library are no longer valid. 56 /// Unloads the library, any function pointers from this library are no longer valid.
56 void Close(); 57 void Close();
57 58
58 /// Returns the address of the specified symbol (function or variable) as an untyped pointer. 59 /// Returns the address of the specified symbol (function or variable) as an untyped pointer.
59 /// If the specified symbol does not exist in this library, nullptr is returned. 60 /// If the specified symbol does not exist in this library, nullptr is returned.
60 void* GetSymbolAddress(const char* name) const; 61 [[nodiscard]] void* GetSymbolAddress(const char* name) const;
61 62
62 /// Obtains the address of the specified symbol, automatically casting to the correct type. 63 /// Obtains the address of the specified symbol, automatically casting to the correct type.
63 /// Returns true if the symbol was found and assigned, otherwise false. 64 /// Returns true if the symbol was found and assigned, otherwise false.
64 template <typename T> 65 template <typename T>
65 bool GetSymbol(const char* name, T* ptr) const { 66 [[nodiscard]] bool GetSymbol(const char* name, T* ptr) const {
66 *ptr = reinterpret_cast<T>(GetSymbolAddress(name)); 67 *ptr = reinterpret_cast<T>(GetSymbolAddress(name));
67 return *ptr != nullptr; 68 return *ptr != nullptr;
68 } 69 }
diff --git a/src/common/fiber.h b/src/common/fiber.h
index dafc1100e..89dde5e36 100644
--- a/src/common/fiber.h
+++ b/src/common/fiber.h
@@ -47,7 +47,7 @@ public:
47 /// Yields control from Fiber 'from' to Fiber 'to' 47 /// Yields control from Fiber 'from' to Fiber 'to'
48 /// Fiber 'from' must be the currently running fiber. 48 /// Fiber 'from' must be the currently running fiber.
49 static void YieldTo(std::shared_ptr<Fiber>& from, std::shared_ptr<Fiber>& to); 49 static void YieldTo(std::shared_ptr<Fiber>& from, std::shared_ptr<Fiber>& to);
50 static std::shared_ptr<Fiber> ThreadToFiber(); 50 [[nodiscard]] static std::shared_ptr<Fiber> ThreadToFiber();
51 51
52 void SetRewindPoint(std::function<void(void*)>&& rewind_func, void* start_parameter); 52 void SetRewindPoint(std::function<void(void*)>&& rewind_func, void* start_parameter);
53 53
diff --git a/src/common/file_util.h b/src/common/file_util.h
index 187b93161..681b28137 100644
--- a/src/common/file_util.h
+++ b/src/common/file_util.h
@@ -48,19 +48,19 @@ struct FSTEntry {
48}; 48};
49 49
50// Returns true if file filename exists 50// Returns true if file filename exists
51bool Exists(const std::string& filename); 51[[nodiscard]] bool Exists(const std::string& filename);
52 52
53// Returns true if filename is a directory 53// Returns true if filename is a directory
54bool IsDirectory(const std::string& filename); 54[[nodiscard]] bool IsDirectory(const std::string& filename);
55 55
56// Returns the size of filename (64bit) 56// Returns the size of filename (64bit)
57u64 GetSize(const std::string& filename); 57[[nodiscard]] u64 GetSize(const std::string& filename);
58 58
59// Overloaded GetSize, accepts file descriptor 59// Overloaded GetSize, accepts file descriptor
60u64 GetSize(const int fd); 60[[nodiscard]] u64 GetSize(int fd);
61 61
62// Overloaded GetSize, accepts FILE* 62// Overloaded GetSize, accepts FILE*
63u64 GetSize(FILE* f); 63[[nodiscard]] u64 GetSize(FILE* f);
64 64
65// Returns true if successful, or path already exists. 65// Returns true if successful, or path already exists.
66bool CreateDir(const std::string& filename); 66bool CreateDir(const std::string& filename);
@@ -120,7 +120,7 @@ u64 ScanDirectoryTree(const std::string& directory, FSTEntry& parent_entry,
120bool DeleteDirRecursively(const std::string& directory, unsigned int recursion = 256); 120bool DeleteDirRecursively(const std::string& directory, unsigned int recursion = 256);
121 121
122// Returns the current directory 122// Returns the current directory
123std::optional<std::string> GetCurrentDir(); 123[[nodiscard]] std::optional<std::string> GetCurrentDir();
124 124
125// Create directory and copy contents (does not overwrite existing files) 125// Create directory and copy contents (does not overwrite existing files)
126void CopyDir(const std::string& source_path, const std::string& dest_path); 126void CopyDir(const std::string& source_path, const std::string& dest_path);
@@ -132,20 +132,20 @@ bool SetCurrentDir(const std::string& directory);
132// directory. To be used in "multi-user" mode (that is, installed). 132// directory. To be used in "multi-user" mode (that is, installed).
133const std::string& GetUserPath(UserPath path, const std::string& new_path = ""); 133const std::string& GetUserPath(UserPath path, const std::string& new_path = "");
134 134
135std::string GetHactoolConfigurationPath(); 135[[nodiscard]] std::string GetHactoolConfigurationPath();
136 136
137std::string GetNANDRegistrationDir(bool system = false); 137[[nodiscard]] std::string GetNANDRegistrationDir(bool system = false);
138 138
139// Returns the path to where the sys file are 139// Returns the path to where the sys file are
140std::string GetSysDirectory(); 140[[nodiscard]] std::string GetSysDirectory();
141 141
142#ifdef __APPLE__ 142#ifdef __APPLE__
143std::string GetBundleDirectory(); 143[[nodiscard]] std::string GetBundleDirectory();
144#endif 144#endif
145 145
146#ifdef _WIN32 146#ifdef _WIN32
147const std::string& GetExeDirectory(); 147[[nodiscard]] const std::string& GetExeDirectory();
148std::string AppDataRoamingDirectory(); 148[[nodiscard]] std::string AppDataRoamingDirectory();
149#endif 149#endif
150 150
151std::size_t WriteStringToFile(bool text_file, const std::string& filename, std::string_view str); 151std::size_t WriteStringToFile(bool text_file, const std::string& filename, std::string_view str);
@@ -164,38 +164,45 @@ void SplitFilename83(const std::string& filename, std::array<char, 9>& short_nam
164 164
165// Splits the path on '/' or '\' and put the components into a vector 165// Splits the path on '/' or '\' and put the components into a vector
166// i.e. "C:\Users\Yuzu\Documents\save.bin" becomes {"C:", "Users", "Yuzu", "Documents", "save.bin" } 166// i.e. "C:\Users\Yuzu\Documents\save.bin" becomes {"C:", "Users", "Yuzu", "Documents", "save.bin" }
167std::vector<std::string> SplitPathComponents(std::string_view filename); 167[[nodiscard]] std::vector<std::string> SplitPathComponents(std::string_view filename);
168 168
169// Gets all of the text up to the last '/' or '\' in the path. 169// Gets all of the text up to the last '/' or '\' in the path.
170std::string_view GetParentPath(std::string_view path); 170[[nodiscard]] std::string_view GetParentPath(std::string_view path);
171 171
172// Gets all of the text after the first '/' or '\' in the path. 172// Gets all of the text after the first '/' or '\' in the path.
173std::string_view GetPathWithoutTop(std::string_view path); 173[[nodiscard]] std::string_view GetPathWithoutTop(std::string_view path);
174 174
175// Gets the filename of the path 175// Gets the filename of the path
176std::string_view GetFilename(std::string_view path); 176[[nodiscard]] std::string_view GetFilename(std::string_view path);
177 177
178// Gets the extension of the filename 178// Gets the extension of the filename
179std::string_view GetExtensionFromFilename(std::string_view name); 179[[nodiscard]] std::string_view GetExtensionFromFilename(std::string_view name);
180 180
181// Removes the final '/' or '\' if one exists 181// Removes the final '/' or '\' if one exists
182std::string_view RemoveTrailingSlash(std::string_view path); 182[[nodiscard]] std::string_view RemoveTrailingSlash(std::string_view path);
183 183
184// Creates a new vector containing indices [first, last) from the original. 184// Creates a new vector containing indices [first, last) from the original.
185template <typename T> 185template <typename T>
186std::vector<T> SliceVector(const std::vector<T>& vector, std::size_t first, std::size_t last) { 186[[nodiscard]] std::vector<T> SliceVector(const std::vector<T>& vector, std::size_t first,
187 if (first >= last) 187 std::size_t last) {
188 if (first >= last) {
188 return {}; 189 return {};
190 }
189 last = std::min<std::size_t>(last, vector.size()); 191 last = std::min<std::size_t>(last, vector.size());
190 return std::vector<T>(vector.begin() + first, vector.begin() + first + last); 192 return std::vector<T>(vector.begin() + first, vector.begin() + first + last);
191} 193}
192 194
193enum class DirectorySeparator { ForwardSlash, BackwardSlash, PlatformDefault }; 195enum class DirectorySeparator {
196 ForwardSlash,
197 BackwardSlash,
198 PlatformDefault,
199};
194 200
195// Removes trailing slash, makes all '\\' into '/', and removes duplicate '/'. Makes '/' into '\\' 201// Removes trailing slash, makes all '\\' into '/', and removes duplicate '/'. Makes '/' into '\\'
196// depending if directory_separator is BackwardSlash or PlatformDefault and running on windows 202// depending if directory_separator is BackwardSlash or PlatformDefault and running on windows
197std::string SanitizePath(std::string_view path, 203[[nodiscard]] std::string SanitizePath(
198 DirectorySeparator directory_separator = DirectorySeparator::ForwardSlash); 204 std::string_view path,
205 DirectorySeparator directory_separator = DirectorySeparator::ForwardSlash);
199 206
200// simple wrapper for cstdlib file functions to 207// simple wrapper for cstdlib file functions to
201// hopefully will make error checking easier 208// hopefully will make error checking easier
@@ -215,7 +222,7 @@ public:
215 222
216 void Swap(IOFile& other) noexcept; 223 void Swap(IOFile& other) noexcept;
217 224
218 bool Open(const std::string& filename, const char openmode[], int flags = 0); 225 [[nodiscard]] bool Open(const std::string& filename, const char openmode[], int flags = 0);
219 bool Close(); 226 bool Close();
220 227
221 template <typename T> 228 template <typename T>
@@ -256,13 +263,13 @@ public:
256 return WriteArray(str.data(), str.length()); 263 return WriteArray(str.data(), str.length());
257 } 264 }
258 265
259 bool IsOpen() const { 266 [[nodiscard]] bool IsOpen() const {
260 return nullptr != m_file; 267 return nullptr != m_file;
261 } 268 }
262 269
263 bool Seek(s64 off, int origin) const; 270 bool Seek(s64 off, int origin) const;
264 u64 Tell() const; 271 [[nodiscard]] u64 Tell() const;
265 u64 GetSize() const; 272 [[nodiscard]] u64 GetSize() const;
266 bool Resize(u64 size); 273 bool Resize(u64 size);
267 bool Flush(); 274 bool Flush();
268 275
diff --git a/src/common/hash.h b/src/common/hash.h
index b2538f3ea..298930702 100644
--- a/src/common/hash.h
+++ b/src/common/hash.h
@@ -5,36 +5,11 @@
5#pragma once 5#pragma once
6 6
7#include <cstddef> 7#include <cstddef>
8#include <cstring>
9#include <utility> 8#include <utility>
10#include <boost/functional/hash.hpp> 9#include <boost/functional/hash.hpp>
11#include "common/cityhash.h"
12#include "common/common_types.h"
13 10
14namespace Common { 11namespace Common {
15 12
16/**
17 * Computes a 64-bit hash over the specified block of data
18 * @param data Block of data to compute hash over
19 * @param len Length of data (in bytes) to compute hash over
20 * @returns 64-bit hash value that was computed over the data block
21 */
22static inline u64 ComputeHash64(const void* data, std::size_t len) {
23 return CityHash64(static_cast<const char*>(data), len);
24}
25
26/**
27 * Computes a 64-bit hash of a struct. In addition to being trivially copyable, it is also critical
28 * that either the struct includes no padding, or that any padding is initialized to a known value
29 * by memsetting the struct to 0 before filling it in.
30 */
31template <typename T>
32static inline u64 ComputeStructHash64(const T& data) {
33 static_assert(std::is_trivially_copyable_v<T>,
34 "Type passed to ComputeStructHash64 must be trivially copyable");
35 return ComputeHash64(&data, sizeof(data));
36}
37
38struct PairHash { 13struct PairHash {
39 template <class T1, class T2> 14 template <class T1, class T2>
40 std::size_t operator()(const std::pair<T1, T2>& pair) const noexcept { 15 std::size_t operator()(const std::pair<T1, T2>& pair) const noexcept {
diff --git a/src/common/hex_util.cpp b/src/common/hex_util.cpp
index c2f6cf0f6..74f52dd11 100644
--- a/src/common/hex_util.cpp
+++ b/src/common/hex_util.cpp
@@ -3,21 +3,9 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "common/hex_util.h" 5#include "common/hex_util.h"
6#include "common/logging/log.h"
7 6
8namespace Common { 7namespace Common {
9 8
10u8 ToHexNibble(char c1) {
11 if (c1 >= 65 && c1 <= 70)
12 return c1 - 55;
13 if (c1 >= 97 && c1 <= 102)
14 return c1 - 87;
15 if (c1 >= 48 && c1 <= 57)
16 return c1 - 48;
17 LOG_ERROR(Common, "Invalid hex digit: 0x{:02X}", c1);
18 return 0;
19}
20
21std::vector<u8> HexStringToVector(std::string_view str, bool little_endian) { 9std::vector<u8> HexStringToVector(std::string_view str, bool little_endian) {
22 std::vector<u8> out(str.size() / 2); 10 std::vector<u8> out(str.size() / 2);
23 if (little_endian) { 11 if (little_endian) {
@@ -30,26 +18,4 @@ std::vector<u8> HexStringToVector(std::string_view str, bool little_endian) {
30 return out; 18 return out;
31} 19}
32 20
33std::array<u8, 16> operator""_array16(const char* str, std::size_t len) {
34 if (len != 32) {
35 LOG_ERROR(Common,
36 "Attempting to parse string to array that is not of correct size (expected=32, "
37 "actual={}).",
38 len);
39 return {};
40 }
41 return HexStringToArray<16>(str);
42}
43
44std::array<u8, 32> operator""_array32(const char* str, std::size_t len) {
45 if (len != 64) {
46 LOG_ERROR(Common,
47 "Attempting to parse string to array that is not of correct size (expected=64, "
48 "actual={}).",
49 len);
50 return {};
51 }
52 return HexStringToArray<32>(str);
53}
54
55} // namespace Common 21} // namespace Common
diff --git a/src/common/hex_util.h b/src/common/hex_util.h
index bb4736f96..120f1a5e6 100644
--- a/src/common/hex_util.h
+++ b/src/common/hex_util.h
@@ -14,25 +14,37 @@
14 14
15namespace Common { 15namespace Common {
16 16
17u8 ToHexNibble(char c1); 17[[nodiscard]] constexpr u8 ToHexNibble(char c) {
18 if (c >= 65 && c <= 70) {
19 return c - 55;
20 }
21
22 if (c >= 97 && c <= 102) {
23 return c - 87;
24 }
25
26 return c - 48;
27}
18 28
19std::vector<u8> HexStringToVector(std::string_view str, bool little_endian); 29[[nodiscard]] std::vector<u8> HexStringToVector(std::string_view str, bool little_endian);
20 30
21template <std::size_t Size, bool le = false> 31template <std::size_t Size, bool le = false>
22std::array<u8, Size> HexStringToArray(std::string_view str) { 32[[nodiscard]] constexpr std::array<u8, Size> HexStringToArray(std::string_view str) {
23 std::array<u8, Size> out{}; 33 std::array<u8, Size> out{};
24 if constexpr (le) { 34 if constexpr (le) {
25 for (std::size_t i = 2 * Size - 2; i <= 2 * Size; i -= 2) 35 for (std::size_t i = 2 * Size - 2; i <= 2 * Size; i -= 2) {
26 out[i / 2] = (ToHexNibble(str[i]) << 4) | ToHexNibble(str[i + 1]); 36 out[i / 2] = (ToHexNibble(str[i]) << 4) | ToHexNibble(str[i + 1]);
37 }
27 } else { 38 } else {
28 for (std::size_t i = 0; i < 2 * Size; i += 2) 39 for (std::size_t i = 0; i < 2 * Size; i += 2) {
29 out[i / 2] = (ToHexNibble(str[i]) << 4) | ToHexNibble(str[i + 1]); 40 out[i / 2] = (ToHexNibble(str[i]) << 4) | ToHexNibble(str[i + 1]);
41 }
30 } 42 }
31 return out; 43 return out;
32} 44}
33 45
34template <typename ContiguousContainer> 46template <typename ContiguousContainer>
35std::string HexToString(const ContiguousContainer& data, bool upper = true) { 47[[nodiscard]] std::string HexToString(const ContiguousContainer& data, bool upper = true) {
36 static_assert(std::is_same_v<typename ContiguousContainer::value_type, u8>, 48 static_assert(std::is_same_v<typename ContiguousContainer::value_type, u8>,
37 "Underlying type within the contiguous container must be u8."); 49 "Underlying type within the contiguous container must be u8.");
38 50
@@ -48,7 +60,12 @@ std::string HexToString(const ContiguousContainer& data, bool upper = true) {
48 return out; 60 return out;
49} 61}
50 62
51std::array<u8, 0x10> operator"" _array16(const char* str, std::size_t len); 63[[nodiscard]] constexpr std::array<u8, 16> AsArray(const char (&data)[17]) {
52std::array<u8, 0x20> operator"" _array32(const char* str, std::size_t len); 64 return HexStringToArray<16>(data);
65}
66
67[[nodiscard]] constexpr std::array<u8, 32> AsArray(const char (&data)[65]) {
68 return HexStringToArray<32>(data);
69}
53 70
54} // namespace Common 71} // namespace Common
diff --git a/src/common/lz4_compression.cpp b/src/common/lz4_compression.cpp
index ade6759bb..25700015a 100644
--- a/src/common/lz4_compression.cpp
+++ b/src/common/lz4_compression.cpp
@@ -14,19 +14,19 @@ std::vector<u8> CompressDataLZ4(const u8* source, std::size_t source_size) {
14 ASSERT_MSG(source_size <= LZ4_MAX_INPUT_SIZE, "Source size exceeds LZ4 maximum input size"); 14 ASSERT_MSG(source_size <= LZ4_MAX_INPUT_SIZE, "Source size exceeds LZ4 maximum input size");
15 15
16 const auto source_size_int = static_cast<int>(source_size); 16 const auto source_size_int = static_cast<int>(source_size);
17 const int max_compressed_size = LZ4_compressBound(source_size_int); 17 const auto max_compressed_size = static_cast<std::size_t>(LZ4_compressBound(source_size_int));
18 std::vector<u8> compressed(max_compressed_size); 18 std::vector<u8> compressed(max_compressed_size);
19 19
20 const int compressed_size = LZ4_compress_default(reinterpret_cast<const char*>(source), 20 const int compressed_size = LZ4_compress_default(
21 reinterpret_cast<char*>(compressed.data()), 21 reinterpret_cast<const char*>(source), reinterpret_cast<char*>(compressed.data()),
22 source_size_int, max_compressed_size); 22 source_size_int, static_cast<int>(max_compressed_size));
23 23
24 if (compressed_size <= 0) { 24 if (compressed_size <= 0) {
25 // Compression failed 25 // Compression failed
26 return {}; 26 return {};
27 } 27 }
28 28
29 compressed.resize(compressed_size); 29 compressed.resize(static_cast<std::size_t>(compressed_size));
30 30
31 return compressed; 31 return compressed;
32} 32}
@@ -38,19 +38,19 @@ std::vector<u8> CompressDataLZ4HC(const u8* source, std::size_t source_size,
38 compression_level = std::clamp(compression_level, LZ4HC_CLEVEL_MIN, LZ4HC_CLEVEL_MAX); 38 compression_level = std::clamp(compression_level, LZ4HC_CLEVEL_MIN, LZ4HC_CLEVEL_MAX);
39 39
40 const auto source_size_int = static_cast<int>(source_size); 40 const auto source_size_int = static_cast<int>(source_size);
41 const int max_compressed_size = LZ4_compressBound(source_size_int); 41 const auto max_compressed_size = static_cast<std::size_t>(LZ4_compressBound(source_size_int));
42 std::vector<u8> compressed(max_compressed_size); 42 std::vector<u8> compressed(max_compressed_size);
43 43
44 const int compressed_size = LZ4_compress_HC( 44 const int compressed_size = LZ4_compress_HC(
45 reinterpret_cast<const char*>(source), reinterpret_cast<char*>(compressed.data()), 45 reinterpret_cast<const char*>(source), reinterpret_cast<char*>(compressed.data()),
46 source_size_int, max_compressed_size, compression_level); 46 source_size_int, static_cast<int>(max_compressed_size), compression_level);
47 47
48 if (compressed_size <= 0) { 48 if (compressed_size <= 0) {
49 // Compression failed 49 // Compression failed
50 return {}; 50 return {};
51 } 51 }
52 52
53 compressed.resize(compressed_size); 53 compressed.resize(static_cast<std::size_t>(compressed_size));
54 54
55 return compressed; 55 return compressed;
56} 56}
diff --git a/src/common/lz4_compression.h b/src/common/lz4_compression.h
index 4c16f6e03..87a4be1b0 100644
--- a/src/common/lz4_compression.h
+++ b/src/common/lz4_compression.h
@@ -13,12 +13,12 @@ namespace Common::Compression {
13/** 13/**
14 * Compresses a source memory region with LZ4 and returns the compressed data in a vector. 14 * Compresses a source memory region with LZ4 and returns the compressed data in a vector.
15 * 15 *
16 * @param source the uncompressed source memory region. 16 * @param source The uncompressed source memory region.
17 * @param source_size the size in bytes of the uncompressed source memory region. 17 * @param source_size The size of the uncompressed source memory region.
18 * 18 *
19 * @return the compressed data. 19 * @return the compressed data.
20 */ 20 */
21std::vector<u8> CompressDataLZ4(const u8* source, std::size_t source_size); 21[[nodiscard]] std::vector<u8> CompressDataLZ4(const u8* source, std::size_t source_size);
22 22
23/** 23/**
24 * Utilizes the LZ4 subalgorithm LZ4HC with the specified compression level. Higher compression 24 * Utilizes the LZ4 subalgorithm LZ4HC with the specified compression level. Higher compression
@@ -26,23 +26,24 @@ std::vector<u8> CompressDataLZ4(const u8* source, std::size_t source_size);
26 * compression level has almost no impact on decompression speed. Data compressed with LZ4HC can 26 * compression level has almost no impact on decompression speed. Data compressed with LZ4HC can
27 * also be decompressed with the default LZ4 decompression. 27 * also be decompressed with the default LZ4 decompression.
28 * 28 *
29 * @param source the uncompressed source memory region. 29 * @param source The uncompressed source memory region.
30 * @param source_size the size in bytes of the uncompressed source memory region. 30 * @param source_size The size of the uncompressed source memory region.
31 * @param compression_level the used compression level. Should be between 3 and 12. 31 * @param compression_level The used compression level. Should be between 3 and 12.
32 * 32 *
33 * @return the compressed data. 33 * @return the compressed data.
34 */ 34 */
35std::vector<u8> CompressDataLZ4HC(const u8* source, std::size_t source_size, s32 compression_level); 35[[nodiscard]] std::vector<u8> CompressDataLZ4HC(const u8* source, std::size_t source_size,
36 s32 compression_level);
36 37
37/** 38/**
38 * Utilizes the LZ4 subalgorithm LZ4HC with the highest possible compression level. 39 * Utilizes the LZ4 subalgorithm LZ4HC with the highest possible compression level.
39 * 40 *
40 * @param source the uncompressed source memory region. 41 * @param source The uncompressed source memory region.
41 * @param source_size the size in bytes of the uncompressed source memory region. 42 * @param source_size The size of the uncompressed source memory region
42 * 43 *
43 * @return the compressed data. 44 * @return the compressed data.
44 */ 45 */
45std::vector<u8> CompressDataLZ4HCMax(const u8* source, std::size_t source_size); 46[[nodiscard]] std::vector<u8> CompressDataLZ4HCMax(const u8* source, std::size_t source_size);
46 47
47/** 48/**
48 * Decompresses a source memory region with LZ4 and returns the uncompressed data in a vector. 49 * Decompresses a source memory region with LZ4 and returns the uncompressed data in a vector.
@@ -52,6 +53,7 @@ std::vector<u8> CompressDataLZ4HCMax(const u8* source, std::size_t source_size);
52 * 53 *
53 * @return the decompressed data. 54 * @return the decompressed data.
54 */ 55 */
55std::vector<u8> DecompressDataLZ4(const std::vector<u8>& compressed, std::size_t uncompressed_size); 56[[nodiscard]] std::vector<u8> DecompressDataLZ4(const std::vector<u8>& compressed,
57 std::size_t uncompressed_size);
56 58
57} // namespace Common::Compression \ No newline at end of file 59} // namespace Common::Compression \ No newline at end of file
diff --git a/src/common/math_util.h b/src/common/math_util.h
index 83ef0201f..cc35c90ee 100644
--- a/src/common/math_util.h
+++ b/src/common/math_util.h
@@ -23,7 +23,7 @@ struct Rectangle {
23 constexpr Rectangle(T left, T top, T right, T bottom) 23 constexpr Rectangle(T left, T top, T right, T bottom)
24 : left(left), top(top), right(right), bottom(bottom) {} 24 : left(left), top(top), right(right), bottom(bottom) {}
25 25
26 T GetWidth() const { 26 [[nodiscard]] T GetWidth() const {
27 if constexpr (std::is_floating_point_v<T>) { 27 if constexpr (std::is_floating_point_v<T>) {
28 return std::abs(right - left); 28 return std::abs(right - left);
29 } else { 29 } else {
@@ -31,7 +31,7 @@ struct Rectangle {
31 } 31 }
32 } 32 }
33 33
34 T GetHeight() const { 34 [[nodiscard]] T GetHeight() const {
35 if constexpr (std::is_floating_point_v<T>) { 35 if constexpr (std::is_floating_point_v<T>) {
36 return std::abs(bottom - top); 36 return std::abs(bottom - top);
37 } else { 37 } else {
@@ -39,21 +39,21 @@ struct Rectangle {
39 } 39 }
40 } 40 }
41 41
42 Rectangle<T> TranslateX(const T x) const { 42 [[nodiscard]] Rectangle<T> TranslateX(const T x) const {
43 return Rectangle{left + x, top, right + x, bottom}; 43 return Rectangle{left + x, top, right + x, bottom};
44 } 44 }
45 45
46 Rectangle<T> TranslateY(const T y) const { 46 [[nodiscard]] Rectangle<T> TranslateY(const T y) const {
47 return Rectangle{left, top + y, right, bottom + y}; 47 return Rectangle{left, top + y, right, bottom + y};
48 } 48 }
49 49
50 Rectangle<T> Scale(const float s) const { 50 [[nodiscard]] Rectangle<T> Scale(const float s) const {
51 return Rectangle{left, top, static_cast<T>(left + GetWidth() * s), 51 return Rectangle{left, top, static_cast<T>(left + GetWidth() * s),
52 static_cast<T>(top + GetHeight() * s)}; 52 static_cast<T>(top + GetHeight() * s)};
53 } 53 }
54}; 54};
55 55
56template <typename T> 56template <typename T>
57Rectangle(T, T, T, T)->Rectangle<T>; 57Rectangle(T, T, T, T) -> Rectangle<T>;
58 58
59} // namespace Common 59} // namespace Common
diff --git a/src/common/memory_detect.h b/src/common/memory_detect.h
index a73c0f3f4..0f73751c8 100644
--- a/src/common/memory_detect.h
+++ b/src/common/memory_detect.h
@@ -17,6 +17,6 @@ struct MemoryInfo {
17 * Gets the memory info of the host system 17 * Gets the memory info of the host system
18 * @return Reference to a MemoryInfo struct with the physical and swap memory sizes in bytes 18 * @return Reference to a MemoryInfo struct with the physical and swap memory sizes in bytes
19 */ 19 */
20const MemoryInfo& GetMemInfo(); 20[[nodiscard]] const MemoryInfo& GetMemInfo();
21 21
22} // namespace Common \ No newline at end of file 22} // namespace Common \ No newline at end of file
diff --git a/src/common/multi_level_queue.h b/src/common/multi_level_queue.h
index 50acfdbf2..4b305bf40 100644
--- a/src/common/multi_level_queue.h
+++ b/src/common/multi_level_queue.h
@@ -223,15 +223,15 @@ public:
223 ListShiftForward(levels[priority], n); 223 ListShiftForward(levels[priority], n);
224 } 224 }
225 225
226 std::size_t depth() const { 226 [[nodiscard]] std::size_t depth() const {
227 return Depth; 227 return Depth;
228 } 228 }
229 229
230 std::size_t size(u32 priority) const { 230 [[nodiscard]] std::size_t size(u32 priority) const {
231 return levels[priority].size(); 231 return levels[priority].size();
232 } 232 }
233 233
234 std::size_t size() const { 234 [[nodiscard]] std::size_t size() const {
235 u64 priorities = used_priorities; 235 u64 priorities = used_priorities;
236 std::size_t size = 0; 236 std::size_t size = 0;
237 while (priorities != 0) { 237 while (priorities != 0) {
@@ -242,64 +242,64 @@ public:
242 return size; 242 return size;
243 } 243 }
244 244
245 bool empty() const { 245 [[nodiscard]] bool empty() const {
246 return used_priorities == 0; 246 return used_priorities == 0;
247 } 247 }
248 248
249 bool empty(u32 priority) const { 249 [[nodiscard]] bool empty(u32 priority) const {
250 return (used_priorities & (1ULL << priority)) == 0; 250 return (used_priorities & (1ULL << priority)) == 0;
251 } 251 }
252 252
253 u32 highest_priority_set(u32 max_priority = 0) const { 253 [[nodiscard]] u32 highest_priority_set(u32 max_priority = 0) const {
254 const u64 priorities = 254 const u64 priorities =
255 max_priority == 0 ? used_priorities : (used_priorities & ~((1ULL << max_priority) - 1)); 255 max_priority == 0 ? used_priorities : (used_priorities & ~((1ULL << max_priority) - 1));
256 return priorities == 0 ? Depth : static_cast<u32>(CountTrailingZeroes64(priorities)); 256 return priorities == 0 ? Depth : static_cast<u32>(CountTrailingZeroes64(priorities));
257 } 257 }
258 258
259 u32 lowest_priority_set(u32 min_priority = Depth - 1) const { 259 [[nodiscard]] u32 lowest_priority_set(u32 min_priority = Depth - 1) const {
260 const u64 priorities = min_priority >= Depth - 1 260 const u64 priorities = min_priority >= Depth - 1
261 ? used_priorities 261 ? used_priorities
262 : (used_priorities & ((1ULL << (min_priority + 1)) - 1)); 262 : (used_priorities & ((1ULL << (min_priority + 1)) - 1));
263 return priorities == 0 ? Depth : 63 - CountLeadingZeroes64(priorities); 263 return priorities == 0 ? Depth : 63 - CountLeadingZeroes64(priorities);
264 } 264 }
265 265
266 const_iterator cbegin(u32 max_prio = 0) const { 266 [[nodiscard]] const_iterator cbegin(u32 max_prio = 0) const {
267 const u32 priority = highest_priority_set(max_prio); 267 const u32 priority = highest_priority_set(max_prio);
268 return priority == Depth ? cend() 268 return priority == Depth ? cend()
269 : const_iterator{*this, levels[priority].cbegin(), priority}; 269 : const_iterator{*this, levels[priority].cbegin(), priority};
270 } 270 }
271 const_iterator begin(u32 max_prio = 0) const { 271 [[nodiscard]] const_iterator begin(u32 max_prio = 0) const {
272 return cbegin(max_prio); 272 return cbegin(max_prio);
273 } 273 }
274 iterator begin(u32 max_prio = 0) { 274 [[nodiscard]] iterator begin(u32 max_prio = 0) {
275 const u32 priority = highest_priority_set(max_prio); 275 const u32 priority = highest_priority_set(max_prio);
276 return priority == Depth ? end() : iterator{*this, levels[priority].begin(), priority}; 276 return priority == Depth ? end() : iterator{*this, levels[priority].begin(), priority};
277 } 277 }
278 278
279 const_iterator cend(u32 min_prio = Depth - 1) const { 279 [[nodiscard]] const_iterator cend(u32 min_prio = Depth - 1) const {
280 return min_prio == Depth - 1 ? const_iterator{*this, Depth} : cbegin(min_prio + 1); 280 return min_prio == Depth - 1 ? const_iterator{*this, Depth} : cbegin(min_prio + 1);
281 } 281 }
282 const_iterator end(u32 min_prio = Depth - 1) const { 282 [[nodiscard]] const_iterator end(u32 min_prio = Depth - 1) const {
283 return cend(min_prio); 283 return cend(min_prio);
284 } 284 }
285 iterator end(u32 min_prio = Depth - 1) { 285 [[nodiscard]] iterator end(u32 min_prio = Depth - 1) {
286 return min_prio == Depth - 1 ? iterator{*this, Depth} : begin(min_prio + 1); 286 return min_prio == Depth - 1 ? iterator{*this, Depth} : begin(min_prio + 1);
287 } 287 }
288 288
289 T& front(u32 max_priority = 0) { 289 [[nodiscard]] T& front(u32 max_priority = 0) {
290 const u32 priority = highest_priority_set(max_priority); 290 const u32 priority = highest_priority_set(max_priority);
291 return levels[priority == Depth ? 0 : priority].front(); 291 return levels[priority == Depth ? 0 : priority].front();
292 } 292 }
293 const T& front(u32 max_priority = 0) const { 293 [[nodiscard]] const T& front(u32 max_priority = 0) const {
294 const u32 priority = highest_priority_set(max_priority); 294 const u32 priority = highest_priority_set(max_priority);
295 return levels[priority == Depth ? 0 : priority].front(); 295 return levels[priority == Depth ? 0 : priority].front();
296 } 296 }
297 297
298 T back(u32 min_priority = Depth - 1) { 298 [[nodiscard]] T& back(u32 min_priority = Depth - 1) {
299 const u32 priority = lowest_priority_set(min_priority); // intended 299 const u32 priority = lowest_priority_set(min_priority); // intended
300 return levels[priority == Depth ? 63 : priority].back(); 300 return levels[priority == Depth ? 63 : priority].back();
301 } 301 }
302 const T& back(u32 min_priority = Depth - 1) const { 302 [[nodiscard]] const T& back(u32 min_priority = Depth - 1) const {
303 const u32 priority = lowest_priority_set(min_priority); // intended 303 const u32 priority = lowest_priority_set(min_priority); // intended
304 return levels[priority == Depth ? 63 : priority].back(); 304 return levels[priority == Depth ? 63 : priority].back();
305 } 305 }
@@ -329,7 +329,8 @@ private:
329 in_list.splice(position, out_list, element); 329 in_list.splice(position, out_list, element);
330 } 330 }
331 331
332 static const_list_iterator ListIterateTo(const std::list<T>& list, const T& element) { 332 [[nodiscard]] static const_list_iterator ListIterateTo(const std::list<T>& list,
333 const T& element) {
333 auto it = list.cbegin(); 334 auto it = list.cbegin();
334 while (it != list.cend() && *it != element) { 335 while (it != list.cend() && *it != element) {
335 ++it; 336 ++it;
diff --git a/src/common/page_table.h b/src/common/page_table.h
index 1e8bd3187..cf5eed780 100644
--- a/src/common/page_table.h
+++ b/src/common/page_table.h
@@ -36,11 +36,11 @@ struct SpecialRegion {
36 36
37 MemoryHookPointer handler; 37 MemoryHookPointer handler;
38 38
39 bool operator<(const SpecialRegion& other) const { 39 [[nodiscard]] bool operator<(const SpecialRegion& other) const {
40 return std::tie(type, handler) < std::tie(other.type, other.handler); 40 return std::tie(type, handler) < std::tie(other.type, other.handler);
41 } 41 }
42 42
43 bool operator==(const SpecialRegion& other) const { 43 [[nodiscard]] bool operator==(const SpecialRegion& other) const {
44 return std::tie(type, handler) == std::tie(other.type, other.handler); 44 return std::tie(type, handler) == std::tie(other.type, other.handler);
45 } 45 }
46}; 46};
diff --git a/src/common/param_package.h b/src/common/param_package.h
index 6a0a9b656..c8a70bfa9 100644
--- a/src/common/param_package.h
+++ b/src/common/param_package.h
@@ -24,14 +24,14 @@ public:
24 ParamPackage& operator=(const ParamPackage& other) = default; 24 ParamPackage& operator=(const ParamPackage& other) = default;
25 ParamPackage& operator=(ParamPackage&& other) = default; 25 ParamPackage& operator=(ParamPackage&& other) = default;
26 26
27 std::string Serialize() const; 27 [[nodiscard]] std::string Serialize() const;
28 std::string Get(const std::string& key, const std::string& default_value) const; 28 [[nodiscard]] std::string Get(const std::string& key, const std::string& default_value) const;
29 int Get(const std::string& key, int default_value) const; 29 [[nodiscard]] int Get(const std::string& key, int default_value) const;
30 float Get(const std::string& key, float default_value) const; 30 [[nodiscard]] float Get(const std::string& key, float default_value) const;
31 void Set(const std::string& key, std::string value); 31 void Set(const std::string& key, std::string value);
32 void Set(const std::string& key, int value); 32 void Set(const std::string& key, int value);
33 void Set(const std::string& key, float value); 33 void Set(const std::string& key, float value);
34 bool Has(const std::string& key) const; 34 [[nodiscard]] bool Has(const std::string& key) const;
35 void Erase(const std::string& key); 35 void Erase(const std::string& key);
36 void Clear(); 36 void Clear();
37 37
diff --git a/src/common/quaternion.h b/src/common/quaternion.h
index 370198ae0..da44f35cd 100644
--- a/src/common/quaternion.h
+++ b/src/common/quaternion.h
@@ -14,35 +14,36 @@ public:
14 Vec3<T> xyz; 14 Vec3<T> xyz;
15 T w{}; 15 T w{};
16 16
17 Quaternion<decltype(-T{})> Inverse() const { 17 [[nodiscard]] Quaternion<decltype(-T{})> Inverse() const {
18 return {-xyz, w}; 18 return {-xyz, w};
19 } 19 }
20 20
21 Quaternion<decltype(T{} + T{})> operator+(const Quaternion& other) const { 21 [[nodiscard]] Quaternion<decltype(T{} + T{})> operator+(const Quaternion& other) const {
22 return {xyz + other.xyz, w + other.w}; 22 return {xyz + other.xyz, w + other.w};
23 } 23 }
24 24
25 Quaternion<decltype(T{} - T{})> operator-(const Quaternion& other) const { 25 [[nodiscard]] Quaternion<decltype(T{} - T{})> operator-(const Quaternion& other) const {
26 return {xyz - other.xyz, w - other.w}; 26 return {xyz - other.xyz, w - other.w};
27 } 27 }
28 28
29 Quaternion<decltype(T{} * T{} - T{} * T{})> operator*(const Quaternion& other) const { 29 [[nodiscard]] Quaternion<decltype(T{} * T{} - T{} * T{})> operator*(
30 const Quaternion& other) const {
30 return {xyz * other.w + other.xyz * w + Cross(xyz, other.xyz), 31 return {xyz * other.w + other.xyz * w + Cross(xyz, other.xyz),
31 w * other.w - Dot(xyz, other.xyz)}; 32 w * other.w - Dot(xyz, other.xyz)};
32 } 33 }
33 34
34 Quaternion<T> Normalized() const { 35 [[nodiscard]] Quaternion<T> Normalized() const {
35 T length = std::sqrt(xyz.Length2() + w * w); 36 T length = std::sqrt(xyz.Length2() + w * w);
36 return {xyz / length, w / length}; 37 return {xyz / length, w / length};
37 } 38 }
38}; 39};
39 40
40template <typename T> 41template <typename T>
41auto QuaternionRotate(const Quaternion<T>& q, const Vec3<T>& v) { 42[[nodiscard]] auto QuaternionRotate(const Quaternion<T>& q, const Vec3<T>& v) {
42 return v + 2 * Cross(q.xyz, Cross(q.xyz, v) + v * q.w); 43 return v + 2 * Cross(q.xyz, Cross(q.xyz, v) + v * q.w);
43} 44}
44 45
45inline Quaternion<float> MakeQuaternion(const Vec3<float>& axis, float angle) { 46[[nodiscard]] inline Quaternion<float> MakeQuaternion(const Vec3<float>& axis, float angle) {
46 return {axis * std::sin(angle / 2), std::cos(angle / 2)}; 47 return {axis * std::sin(angle / 2), std::cos(angle / 2)};
47} 48}
48 49
diff --git a/src/common/ring_buffer.h b/src/common/ring_buffer.h
index abe3b4dc2..138fa0131 100644
--- a/src/common/ring_buffer.h
+++ b/src/common/ring_buffer.h
@@ -91,12 +91,12 @@ public:
91 } 91 }
92 92
93 /// @returns Number of slots used 93 /// @returns Number of slots used
94 std::size_t Size() const { 94 [[nodiscard]] std::size_t Size() const {
95 return m_write_index.load() - m_read_index.load(); 95 return m_write_index.load() - m_read_index.load();
96 } 96 }
97 97
98 /// @returns Maximum size of ring buffer 98 /// @returns Maximum size of ring buffer
99 constexpr std::size_t Capacity() const { 99 [[nodiscard]] constexpr std::size_t Capacity() const {
100 return capacity; 100 return capacity;
101 } 101 }
102 102
diff --git a/src/common/spin_lock.h b/src/common/spin_lock.h
index 1df5528c4..4f946a258 100644
--- a/src/common/spin_lock.h
+++ b/src/common/spin_lock.h
@@ -17,7 +17,7 @@ class SpinLock {
17public: 17public:
18 void lock(); 18 void lock();
19 void unlock(); 19 void unlock();
20 bool try_lock(); 20 [[nodiscard]] bool try_lock();
21 21
22private: 22private:
23 std::atomic_flag lck = ATOMIC_FLAG_INIT; 23 std::atomic_flag lck = ATOMIC_FLAG_INIT;
diff --git a/src/common/string_util.h b/src/common/string_util.h
index 023dff5dc..a32c07c06 100644
--- a/src/common/string_util.h
+++ b/src/common/string_util.h
@@ -12,19 +12,19 @@
12namespace Common { 12namespace Common {
13 13
14/// Make a string lowercase 14/// Make a string lowercase
15std::string ToLower(std::string str); 15[[nodiscard]] std::string ToLower(std::string str);
16 16
17/// Make a string uppercase 17/// Make a string uppercase
18std::string ToUpper(std::string str); 18[[nodiscard]] std::string ToUpper(std::string str);
19 19
20std::string StringFromBuffer(const std::vector<u8>& data); 20[[nodiscard]] std::string StringFromBuffer(const std::vector<u8>& data);
21 21
22std::string StripSpaces(const std::string& s); 22[[nodiscard]] std::string StripSpaces(const std::string& s);
23std::string StripQuotes(const std::string& s); 23[[nodiscard]] std::string StripQuotes(const std::string& s);
24 24
25std::string StringFromBool(bool value); 25[[nodiscard]] std::string StringFromBool(bool value);
26 26
27std::string TabsToSpaces(int tab_size, std::string in); 27[[nodiscard]] std::string TabsToSpaces(int tab_size, std::string in);
28 28
29void SplitString(const std::string& str, char delim, std::vector<std::string>& output); 29void SplitString(const std::string& str, char delim, std::vector<std::string>& output);
30 30
@@ -34,14 +34,15 @@ bool SplitPath(const std::string& full_path, std::string* _pPath, std::string* _
34 34
35void BuildCompleteFilename(std::string& _CompleteFilename, const std::string& _Path, 35void BuildCompleteFilename(std::string& _CompleteFilename, const std::string& _Path,
36 const std::string& _Filename); 36 const std::string& _Filename);
37std::string ReplaceAll(std::string result, const std::string& src, const std::string& dest); 37[[nodiscard]] std::string ReplaceAll(std::string result, const std::string& src,
38 const std::string& dest);
38 39
39std::string UTF16ToUTF8(const std::u16string& input); 40[[nodiscard]] std::string UTF16ToUTF8(const std::u16string& input);
40std::u16string UTF8ToUTF16(const std::string& input); 41[[nodiscard]] std::u16string UTF8ToUTF16(const std::string& input);
41 42
42#ifdef _WIN32 43#ifdef _WIN32
43std::string UTF16ToUTF8(const std::wstring& input); 44[[nodiscard]] std::string UTF16ToUTF8(const std::wstring& input);
44std::wstring UTF8ToUTF16W(const std::string& str); 45[[nodiscard]] std::wstring UTF8ToUTF16W(const std::string& str);
45 46
46#endif 47#endif
47 48
@@ -50,7 +51,7 @@ std::wstring UTF8ToUTF16W(const std::string& str);
50 * `other` for equality. 51 * `other` for equality.
51 */ 52 */
52template <typename InIt> 53template <typename InIt>
53bool ComparePartialString(InIt begin, InIt end, const char* other) { 54[[nodiscard]] bool ComparePartialString(InIt begin, InIt end, const char* other) {
54 for (; begin != end && *other != '\0'; ++begin, ++other) { 55 for (; begin != end && *other != '\0'; ++begin, ++other) {
55 if (*begin != *other) { 56 if (*begin != *other) {
56 return false; 57 return false;
@@ -64,14 +65,15 @@ bool ComparePartialString(InIt begin, InIt end, const char* other) {
64 * Creates a std::string from a fixed-size NUL-terminated char buffer. If the buffer isn't 65 * Creates a std::string from a fixed-size NUL-terminated char buffer. If the buffer isn't
65 * NUL-terminated then the string ends at max_len characters. 66 * NUL-terminated then the string ends at max_len characters.
66 */ 67 */
67std::string StringFromFixedZeroTerminatedBuffer(const char* buffer, std::size_t max_len); 68[[nodiscard]] std::string StringFromFixedZeroTerminatedBuffer(const char* buffer,
69 std::size_t max_len);
68 70
69/** 71/**
70 * Creates a UTF-16 std::u16string from a fixed-size NUL-terminated char buffer. If the buffer isn't 72 * Creates a UTF-16 std::u16string from a fixed-size NUL-terminated char buffer. If the buffer isn't
71 * null-terminated, then the string ends at the greatest multiple of two less then or equal to 73 * null-terminated, then the string ends at the greatest multiple of two less then or equal to
72 * max_len_bytes. 74 * max_len_bytes.
73 */ 75 */
74std::u16string UTF16StringFromFixedZeroTerminatedBuffer(std::u16string_view buffer, 76[[nodiscard]] std::u16string UTF16StringFromFixedZeroTerminatedBuffer(std::u16string_view buffer,
75 std::size_t max_len); 77 std::size_t max_len);
76 78
77} // namespace Common 79} // namespace Common
diff --git a/src/common/telemetry.h b/src/common/telemetry.h
index 854a73fae..4aa299f9a 100644
--- a/src/common/telemetry.h
+++ b/src/common/telemetry.h
@@ -63,30 +63,30 @@ public:
63 63
64 void Accept(VisitorInterface& visitor) const override; 64 void Accept(VisitorInterface& visitor) const override;
65 65
66 const std::string& GetName() const override { 66 [[nodiscard]] const std::string& GetName() const override {
67 return name; 67 return name;
68 } 68 }
69 69
70 /** 70 /**
71 * Returns the type of the field. 71 * Returns the type of the field.
72 */ 72 */
73 FieldType GetType() const { 73 [[nodiscard]] FieldType GetType() const {
74 return type; 74 return type;
75 } 75 }
76 76
77 /** 77 /**
78 * Returns the value of the field. 78 * Returns the value of the field.
79 */ 79 */
80 const T& GetValue() const { 80 [[nodiscard]] const T& GetValue() const {
81 return value; 81 return value;
82 } 82 }
83 83
84 bool operator==(const Field& other) const { 84 [[nodiscard]] bool operator==(const Field& other) const {
85 return (type == other.type) && (name == other.name) && (value == other.value); 85 return (type == other.type) && (name == other.name) && (value == other.value);
86 } 86 }
87 87
88 bool operator!=(const Field& other) const { 88 [[nodiscard]] bool operator!=(const Field& other) const {
89 return !(*this == other); 89 return !operator==(other);
90 } 90 }
91 91
92private: 92private:
diff --git a/src/common/thread_queue_list.h b/src/common/thread_queue_list.h
index 791f99a8c..def9e5d8d 100644
--- a/src/common/thread_queue_list.h
+++ b/src/common/thread_queue_list.h
@@ -18,14 +18,14 @@ struct ThreadQueueList {
18 using Priority = unsigned int; 18 using Priority = unsigned int;
19 19
20 // Number of priority levels. (Valid levels are [0..NUM_QUEUES).) 20 // Number of priority levels. (Valid levels are [0..NUM_QUEUES).)
21 static const Priority NUM_QUEUES = N; 21 static constexpr Priority NUM_QUEUES = N;
22 22
23 ThreadQueueList() { 23 ThreadQueueList() {
24 first = nullptr; 24 first = nullptr;
25 } 25 }
26 26
27 // Only for debugging, returns priority level. 27 // Only for debugging, returns priority level.
28 Priority contains(const T& uid) const { 28 [[nodiscard]] Priority contains(const T& uid) const {
29 for (Priority i = 0; i < NUM_QUEUES; ++i) { 29 for (Priority i = 0; i < NUM_QUEUES; ++i) {
30 const Queue& cur = queues[i]; 30 const Queue& cur = queues[i];
31 if (std::find(cur.data.cbegin(), cur.data.cend(), uid) != cur.data.cend()) { 31 if (std::find(cur.data.cbegin(), cur.data.cend(), uid) != cur.data.cend()) {
@@ -36,7 +36,7 @@ struct ThreadQueueList {
36 return -1; 36 return -1;
37 } 37 }
38 38
39 T get_first() const { 39 [[nodiscard]] T get_first() const {
40 const Queue* cur = first; 40 const Queue* cur = first;
41 while (cur != nullptr) { 41 while (cur != nullptr) {
42 if (!cur->data.empty()) { 42 if (!cur->data.empty()) {
@@ -49,7 +49,7 @@ struct ThreadQueueList {
49 } 49 }
50 50
51 template <typename UnaryPredicate> 51 template <typename UnaryPredicate>
52 T get_first_filter(UnaryPredicate filter) const { 52 [[nodiscard]] T get_first_filter(UnaryPredicate filter) const {
53 const Queue* cur = first; 53 const Queue* cur = first;
54 while (cur != nullptr) { 54 while (cur != nullptr) {
55 if (!cur->data.empty()) { 55 if (!cur->data.empty()) {
@@ -129,7 +129,7 @@ struct ThreadQueueList {
129 first = nullptr; 129 first = nullptr;
130 } 130 }
131 131
132 bool empty(Priority priority) const { 132 [[nodiscard]] bool empty(Priority priority) const {
133 const Queue* cur = &queues[priority]; 133 const Queue* cur = &queues[priority];
134 return cur->data.empty(); 134 return cur->data.empty();
135 } 135 }
diff --git a/src/common/threadsafe_queue.h b/src/common/threadsafe_queue.h
index 8268bbd5c..a4647314a 100644
--- a/src/common/threadsafe_queue.h
+++ b/src/common/threadsafe_queue.h
@@ -25,15 +25,15 @@ public:
25 delete read_ptr; 25 delete read_ptr;
26 } 26 }
27 27
28 std::size_t Size() const { 28 [[nodiscard]] std::size_t Size() const {
29 return size.load(); 29 return size.load();
30 } 30 }
31 31
32 bool Empty() const { 32 [[nodiscard]] bool Empty() const {
33 return Size() == 0; 33 return Size() == 0;
34 } 34 }
35 35
36 T& Front() const { 36 [[nodiscard]] T& Front() const {
37 return read_ptr->current; 37 return read_ptr->current;
38 } 38 }
39 39
@@ -130,15 +130,15 @@ private:
130template <typename T> 130template <typename T>
131class MPSCQueue { 131class MPSCQueue {
132public: 132public:
133 std::size_t Size() const { 133 [[nodiscard]] std::size_t Size() const {
134 return spsc_queue.Size(); 134 return spsc_queue.Size();
135 } 135 }
136 136
137 bool Empty() const { 137 [[nodiscard]] bool Empty() const {
138 return spsc_queue.Empty(); 138 return spsc_queue.Empty();
139 } 139 }
140 140
141 T& Front() const { 141 [[nodiscard]] T& Front() const {
142 return spsc_queue.Front(); 142 return spsc_queue.Front();
143 } 143 }
144 144
diff --git a/src/common/time_zone.h b/src/common/time_zone.h
index 945daa09c..9f5939ca5 100644
--- a/src/common/time_zone.h
+++ b/src/common/time_zone.h
@@ -10,9 +10,9 @@
10namespace Common::TimeZone { 10namespace Common::TimeZone {
11 11
12/// Gets the default timezone, i.e. "GMT" 12/// Gets the default timezone, i.e. "GMT"
13std::string GetDefaultTimeZone(); 13[[nodiscard]] std::string GetDefaultTimeZone();
14 14
15/// Gets the offset of the current timezone (from the default), in seconds 15/// Gets the offset of the current timezone (from the default), in seconds
16std::chrono::seconds GetCurrentOffsetSeconds(); 16[[nodiscard]] std::chrono::seconds GetCurrentOffsetSeconds();
17 17
18} // namespace Common::TimeZone 18} // namespace Common::TimeZone
diff --git a/src/common/timer.h b/src/common/timer.h
index 27b521baa..8894a143d 100644
--- a/src/common/timer.h
+++ b/src/common/timer.h
@@ -19,18 +19,18 @@ public:
19 19
20 // The time difference is always returned in milliseconds, regardless of alternative internal 20 // The time difference is always returned in milliseconds, regardless of alternative internal
21 // representation 21 // representation
22 std::chrono::milliseconds GetTimeDifference(); 22 [[nodiscard]] std::chrono::milliseconds GetTimeDifference();
23 void AddTimeDifference(); 23 void AddTimeDifference();
24 24
25 static std::chrono::seconds GetTimeSinceJan1970(); 25 [[nodiscard]] static std::chrono::seconds GetTimeSinceJan1970();
26 static std::chrono::seconds GetLocalTimeSinceJan1970(); 26 [[nodiscard]] static std::chrono::seconds GetLocalTimeSinceJan1970();
27 static double GetDoubleTime(); 27 [[nodiscard]] static double GetDoubleTime();
28 28
29 static std::string GetTimeFormatted(); 29 [[nodiscard]] static std::string GetTimeFormatted();
30 std::string GetTimeElapsedFormatted() const; 30 [[nodiscard]] std::string GetTimeElapsedFormatted() const;
31 std::chrono::milliseconds GetTimeElapsed(); 31 [[nodiscard]] std::chrono::milliseconds GetTimeElapsed();
32 32
33 static std::chrono::milliseconds GetTimeMs(); 33 [[nodiscard]] static std::chrono::milliseconds GetTimeMs();
34 34
35private: 35private:
36 std::chrono::milliseconds m_LastTime; 36 std::chrono::milliseconds m_LastTime;
diff --git a/src/common/uint128.h b/src/common/uint128.h
index 503cd2d0c..969259ab6 100644
--- a/src/common/uint128.h
+++ b/src/common/uint128.h
@@ -10,13 +10,13 @@
10namespace Common { 10namespace Common {
11 11
12// This function multiplies 2 u64 values and divides it by a u64 value. 12// This function multiplies 2 u64 values and divides it by a u64 value.
13u64 MultiplyAndDivide64(u64 a, u64 b, u64 d); 13[[nodiscard]] u64 MultiplyAndDivide64(u64 a, u64 b, u64 d);
14 14
15// This function multiplies 2 u64 values and produces a u128 value; 15// This function multiplies 2 u64 values and produces a u128 value;
16u128 Multiply64Into128(u64 a, u64 b); 16[[nodiscard]] u128 Multiply64Into128(u64 a, u64 b);
17 17
18// This function divides a u128 by a u32 value and produces two u64 values: 18// This function divides a u128 by a u32 value and produces two u64 values:
19// the result of division and the remainder 19// the result of division and the remainder
20std::pair<u64, u64> Divide128On32(u128 dividend, u32 divisor); 20[[nodiscard]] std::pair<u64, u64> Divide128On32(u128 dividend, u32 divisor);
21 21
22} // namespace Common 22} // namespace Common
diff --git a/src/common/uuid.h b/src/common/uuid.h
index 4d3af8cec..4ab9a25f0 100644
--- a/src/common/uuid.h
+++ b/src/common/uuid.h
@@ -19,21 +19,21 @@ struct UUID {
19 constexpr explicit UUID(const u128& id) : uuid{id} {} 19 constexpr explicit UUID(const u128& id) : uuid{id} {}
20 constexpr explicit UUID(const u64 lo, const u64 hi) : uuid{{lo, hi}} {} 20 constexpr explicit UUID(const u64 lo, const u64 hi) : uuid{{lo, hi}} {}
21 21
22 constexpr explicit operator bool() const { 22 [[nodiscard]] constexpr explicit operator bool() const {
23 return uuid[0] != INVALID_UUID[0] && uuid[1] != INVALID_UUID[1]; 23 return uuid[0] != INVALID_UUID[0] && uuid[1] != INVALID_UUID[1];
24 } 24 }
25 25
26 constexpr bool operator==(const UUID& rhs) const { 26 [[nodiscard]] constexpr bool operator==(const UUID& rhs) const {
27 // TODO(DarkLordZach): Replace with uuid == rhs.uuid with C++20 27 // TODO(DarkLordZach): Replace with uuid == rhs.uuid with C++20
28 return uuid[0] == rhs.uuid[0] && uuid[1] == rhs.uuid[1]; 28 return uuid[0] == rhs.uuid[0] && uuid[1] == rhs.uuid[1];
29 } 29 }
30 30
31 constexpr bool operator!=(const UUID& rhs) const { 31 [[nodiscard]] constexpr bool operator!=(const UUID& rhs) const {
32 return !operator==(rhs); 32 return !operator==(rhs);
33 } 33 }
34 34
35 // TODO(ogniK): Properly generate uuids based on RFC-4122 35 // TODO(ogniK): Properly generate uuids based on RFC-4122
36 static UUID Generate(); 36 [[nodiscard]] static UUID Generate();
37 37
38 // Set the UUID to {0,0} to be considered an invalid user 38 // Set the UUID to {0,0} to be considered an invalid user
39 constexpr void Invalidate() { 39 constexpr void Invalidate() {
@@ -41,12 +41,12 @@ struct UUID {
41 } 41 }
42 42
43 // TODO(ogniK): Properly generate a Nintendo ID 43 // TODO(ogniK): Properly generate a Nintendo ID
44 constexpr u64 GetNintendoID() const { 44 [[nodiscard]] constexpr u64 GetNintendoID() const {
45 return uuid[0]; 45 return uuid[0];
46 } 46 }
47 47
48 std::string Format() const; 48 [[nodiscard]] std::string Format() const;
49 std::string FormatSwitch() const; 49 [[nodiscard]] std::string FormatSwitch() const;
50}; 50};
51static_assert(sizeof(UUID) == 16, "UUID is an invalid size!"); 51static_assert(sizeof(UUID) == 16, "UUID is an invalid size!");
52 52
diff --git a/src/common/vector_math.h b/src/common/vector_math.h
index 429485329..2a0fcf541 100644
--- a/src/common/vector_math.h
+++ b/src/common/vector_math.h
@@ -52,15 +52,15 @@ public:
52 constexpr Vec2(const T& x_, const T& y_) : x(x_), y(y_) {} 52 constexpr Vec2(const T& x_, const T& y_) : x(x_), y(y_) {}
53 53
54 template <typename T2> 54 template <typename T2>
55 constexpr Vec2<T2> Cast() const { 55 [[nodiscard]] constexpr Vec2<T2> Cast() const {
56 return Vec2<T2>(static_cast<T2>(x), static_cast<T2>(y)); 56 return Vec2<T2>(static_cast<T2>(x), static_cast<T2>(y));
57 } 57 }
58 58
59 static constexpr Vec2 AssignToAll(const T& f) { 59 [[nodiscard]] static constexpr Vec2 AssignToAll(const T& f) {
60 return Vec2{f, f}; 60 return Vec2{f, f};
61 } 61 }
62 62
63 constexpr Vec2<decltype(T{} + T{})> operator+(const Vec2& other) const { 63 [[nodiscard]] constexpr Vec2<decltype(T{} + T{})> operator+(const Vec2& other) const {
64 return {x + other.x, y + other.y}; 64 return {x + other.x, y + other.y};
65 } 65 }
66 constexpr Vec2& operator+=(const Vec2& other) { 66 constexpr Vec2& operator+=(const Vec2& other) {
@@ -68,7 +68,7 @@ public:
68 y += other.y; 68 y += other.y;
69 return *this; 69 return *this;
70 } 70 }
71 constexpr Vec2<decltype(T{} - T{})> operator-(const Vec2& other) const { 71 [[nodiscard]] constexpr Vec2<decltype(T{} - T{})> operator-(const Vec2& other) const {
72 return {x - other.x, y - other.y}; 72 return {x - other.x, y - other.y};
73 } 73 }
74 constexpr Vec2& operator-=(const Vec2& other) { 74 constexpr Vec2& operator-=(const Vec2& other) {
@@ -78,15 +78,15 @@ public:
78 } 78 }
79 79
80 template <typename U = T> 80 template <typename U = T>
81 constexpr Vec2<std::enable_if_t<std::is_signed_v<U>, U>> operator-() const { 81 [[nodiscard]] constexpr Vec2<std::enable_if_t<std::is_signed_v<U>, U>> operator-() const {
82 return {-x, -y}; 82 return {-x, -y};
83 } 83 }
84 constexpr Vec2<decltype(T{} * T{})> operator*(const Vec2& other) const { 84 [[nodiscard]] constexpr Vec2<decltype(T{} * T{})> operator*(const Vec2& other) const {
85 return {x * other.x, y * other.y}; 85 return {x * other.x, y * other.y};
86 } 86 }
87 87
88 template <typename V> 88 template <typename V>
89 constexpr Vec2<decltype(T{} * V{})> operator*(const V& f) const { 89 [[nodiscard]] constexpr Vec2<decltype(T{} * V{})> operator*(const V& f) const {
90 return {x * f, y * f}; 90 return {x * f, y * f};
91 } 91 }
92 92
@@ -97,7 +97,7 @@ public:
97 } 97 }
98 98
99 template <typename V> 99 template <typename V>
100 constexpr Vec2<decltype(T{} / V{})> operator/(const V& f) const { 100 [[nodiscard]] constexpr Vec2<decltype(T{} / V{})> operator/(const V& f) const {
101 return {x / f, y / f}; 101 return {x / f, y / f};
102 } 102 }
103 103
@@ -107,18 +107,18 @@ public:
107 return *this; 107 return *this;
108 } 108 }
109 109
110 constexpr T Length2() const { 110 [[nodiscard]] constexpr T Length2() const {
111 return x * x + y * y; 111 return x * x + y * y;
112 } 112 }
113 113
114 // Only implemented for T=float 114 // Only implemented for T=float
115 float Length() const; 115 [[nodiscard]] float Length() const;
116 float Normalize(); // returns the previous length, which is often useful 116 [[nodiscard]] float Normalize(); // returns the previous length, which is often useful
117 117
118 constexpr T& operator[](std::size_t i) { 118 [[nodiscard]] constexpr T& operator[](std::size_t i) {
119 return *((&x) + i); 119 return *((&x) + i);
120 } 120 }
121 constexpr const T& operator[](std::size_t i) const { 121 [[nodiscard]] constexpr const T& operator[](std::size_t i) const {
122 return *((&x) + i); 122 return *((&x) + i);
123 } 123 }
124 124
@@ -128,46 +128,46 @@ public:
128 } 128 }
129 129
130 // Common aliases: UV (texel coordinates), ST (texture coordinates) 130 // Common aliases: UV (texel coordinates), ST (texture coordinates)
131 constexpr T& u() { 131 [[nodiscard]] constexpr T& u() {
132 return x; 132 return x;
133 } 133 }
134 constexpr T& v() { 134 [[nodiscard]] constexpr T& v() {
135 return y; 135 return y;
136 } 136 }
137 constexpr T& s() { 137 [[nodiscard]] constexpr T& s() {
138 return x; 138 return x;
139 } 139 }
140 constexpr T& t() { 140 [[nodiscard]] constexpr T& t() {
141 return y; 141 return y;
142 } 142 }
143 143
144 constexpr const T& u() const { 144 [[nodiscard]] constexpr const T& u() const {
145 return x; 145 return x;
146 } 146 }
147 constexpr const T& v() const { 147 [[nodiscard]] constexpr const T& v() const {
148 return y; 148 return y;
149 } 149 }
150 constexpr const T& s() const { 150 [[nodiscard]] constexpr const T& s() const {
151 return x; 151 return x;
152 } 152 }
153 constexpr const T& t() const { 153 [[nodiscard]] constexpr const T& t() const {
154 return y; 154 return y;
155 } 155 }
156 156
157 // swizzlers - create a subvector of specific components 157 // swizzlers - create a subvector of specific components
158 constexpr Vec2 yx() const { 158 [[nodiscard]] constexpr Vec2 yx() const {
159 return Vec2(y, x); 159 return Vec2(y, x);
160 } 160 }
161 constexpr Vec2 vu() const { 161 [[nodiscard]] constexpr Vec2 vu() const {
162 return Vec2(y, x); 162 return Vec2(y, x);
163 } 163 }
164 constexpr Vec2 ts() const { 164 [[nodiscard]] constexpr Vec2 ts() const {
165 return Vec2(y, x); 165 return Vec2(y, x);
166 } 166 }
167}; 167};
168 168
169template <typename T, typename V> 169template <typename T, typename V>
170constexpr Vec2<T> operator*(const V& f, const Vec2<T>& vec) { 170[[nodiscard]] constexpr Vec2<T> operator*(const V& f, const Vec2<T>& vec) {
171 return Vec2<T>(f * vec.x, f * vec.y); 171 return Vec2<T>(f * vec.x, f * vec.y);
172} 172}
173 173
@@ -196,15 +196,15 @@ public:
196 constexpr Vec3(const T& x_, const T& y_, const T& z_) : x(x_), y(y_), z(z_) {} 196 constexpr Vec3(const T& x_, const T& y_, const T& z_) : x(x_), y(y_), z(z_) {}
197 197
198 template <typename T2> 198 template <typename T2>
199 constexpr Vec3<T2> Cast() const { 199 [[nodiscard]] constexpr Vec3<T2> Cast() const {
200 return Vec3<T2>(static_cast<T2>(x), static_cast<T2>(y), static_cast<T2>(z)); 200 return Vec3<T2>(static_cast<T2>(x), static_cast<T2>(y), static_cast<T2>(z));
201 } 201 }
202 202
203 static constexpr Vec3 AssignToAll(const T& f) { 203 [[nodiscard]] static constexpr Vec3 AssignToAll(const T& f) {
204 return Vec3(f, f, f); 204 return Vec3(f, f, f);
205 } 205 }
206 206
207 constexpr Vec3<decltype(T{} + T{})> operator+(const Vec3& other) const { 207 [[nodiscard]] constexpr Vec3<decltype(T{} + T{})> operator+(const Vec3& other) const {
208 return {x + other.x, y + other.y, z + other.z}; 208 return {x + other.x, y + other.y, z + other.z};
209 } 209 }
210 210
@@ -215,7 +215,7 @@ public:
215 return *this; 215 return *this;
216 } 216 }
217 217
218 constexpr Vec3<decltype(T{} - T{})> operator-(const Vec3& other) const { 218 [[nodiscard]] constexpr Vec3<decltype(T{} - T{})> operator-(const Vec3& other) const {
219 return {x - other.x, y - other.y, z - other.z}; 219 return {x - other.x, y - other.y, z - other.z};
220 } 220 }
221 221
@@ -227,16 +227,16 @@ public:
227 } 227 }
228 228
229 template <typename U = T> 229 template <typename U = T>
230 constexpr Vec3<std::enable_if_t<std::is_signed_v<U>, U>> operator-() const { 230 [[nodiscard]] constexpr Vec3<std::enable_if_t<std::is_signed_v<U>, U>> operator-() const {
231 return {-x, -y, -z}; 231 return {-x, -y, -z};
232 } 232 }
233 233
234 constexpr Vec3<decltype(T{} * T{})> operator*(const Vec3& other) const { 234 [[nodiscard]] constexpr Vec3<decltype(T{} * T{})> operator*(const Vec3& other) const {
235 return {x * other.x, y * other.y, z * other.z}; 235 return {x * other.x, y * other.y, z * other.z};
236 } 236 }
237 237
238 template <typename V> 238 template <typename V>
239 constexpr Vec3<decltype(T{} * V{})> operator*(const V& f) const { 239 [[nodiscard]] constexpr Vec3<decltype(T{} * V{})> operator*(const V& f) const {
240 return {x * f, y * f, z * f}; 240 return {x * f, y * f, z * f};
241 } 241 }
242 242
@@ -246,7 +246,7 @@ public:
246 return *this; 246 return *this;
247 } 247 }
248 template <typename V> 248 template <typename V>
249 constexpr Vec3<decltype(T{} / V{})> operator/(const V& f) const { 249 [[nodiscard]] constexpr Vec3<decltype(T{} / V{})> operator/(const V& f) const {
250 return {x / f, y / f, z / f}; 250 return {x / f, y / f, z / f};
251 } 251 }
252 252
@@ -256,20 +256,20 @@ public:
256 return *this; 256 return *this;
257 } 257 }
258 258
259 constexpr T Length2() const { 259 [[nodiscard]] constexpr T Length2() const {
260 return x * x + y * y + z * z; 260 return x * x + y * y + z * z;
261 } 261 }
262 262
263 // Only implemented for T=float 263 // Only implemented for T=float
264 float Length() const; 264 [[nodiscard]] float Length() const;
265 Vec3 Normalized() const; 265 [[nodiscard]] Vec3 Normalized() const;
266 float Normalize(); // returns the previous length, which is often useful 266 [[nodiscard]] float Normalize(); // returns the previous length, which is often useful
267 267
268 constexpr T& operator[](std::size_t i) { 268 [[nodiscard]] constexpr T& operator[](std::size_t i) {
269 return *((&x) + i); 269 return *((&x) + i);
270 } 270 }
271 271
272 constexpr const T& operator[](std::size_t i) const { 272 [[nodiscard]] constexpr const T& operator[](std::size_t i) const {
273 return *((&x) + i); 273 return *((&x) + i);
274 } 274 }
275 275
@@ -280,63 +280,63 @@ public:
280 } 280 }
281 281
282 // Common aliases: UVW (texel coordinates), RGB (colors), STQ (texture coordinates) 282 // Common aliases: UVW (texel coordinates), RGB (colors), STQ (texture coordinates)
283 constexpr T& u() { 283 [[nodiscard]] constexpr T& u() {
284 return x; 284 return x;
285 } 285 }
286 constexpr T& v() { 286 [[nodiscard]] constexpr T& v() {
287 return y; 287 return y;
288 } 288 }
289 constexpr T& w() { 289 [[nodiscard]] constexpr T& w() {
290 return z; 290 return z;
291 } 291 }
292 292
293 constexpr T& r() { 293 [[nodiscard]] constexpr T& r() {
294 return x; 294 return x;
295 } 295 }
296 constexpr T& g() { 296 [[nodiscard]] constexpr T& g() {
297 return y; 297 return y;
298 } 298 }
299 constexpr T& b() { 299 [[nodiscard]] constexpr T& b() {
300 return z; 300 return z;
301 } 301 }
302 302
303 constexpr T& s() { 303 [[nodiscard]] constexpr T& s() {
304 return x; 304 return x;
305 } 305 }
306 constexpr T& t() { 306 [[nodiscard]] constexpr T& t() {
307 return y; 307 return y;
308 } 308 }
309 constexpr T& q() { 309 [[nodiscard]] constexpr T& q() {
310 return z; 310 return z;
311 } 311 }
312 312
313 constexpr const T& u() const { 313 [[nodiscard]] constexpr const T& u() const {
314 return x; 314 return x;
315 } 315 }
316 constexpr const T& v() const { 316 [[nodiscard]] constexpr const T& v() const {
317 return y; 317 return y;
318 } 318 }
319 constexpr const T& w() const { 319 [[nodiscard]] constexpr const T& w() const {
320 return z; 320 return z;
321 } 321 }
322 322
323 constexpr const T& r() const { 323 [[nodiscard]] constexpr const T& r() const {
324 return x; 324 return x;
325 } 325 }
326 constexpr const T& g() const { 326 [[nodiscard]] constexpr const T& g() const {
327 return y; 327 return y;
328 } 328 }
329 constexpr const T& b() const { 329 [[nodiscard]] constexpr const T& b() const {
330 return z; 330 return z;
331 } 331 }
332 332
333 constexpr const T& s() const { 333 [[nodiscard]] constexpr const T& s() const {
334 return x; 334 return x;
335 } 335 }
336 constexpr const T& t() const { 336 [[nodiscard]] constexpr const T& t() const {
337 return y; 337 return y;
338 } 338 }
339 constexpr const T& q() const { 339 [[nodiscard]] constexpr const T& q() const {
340 return z; 340 return z;
341 } 341 }
342 342
@@ -345,7 +345,7 @@ public:
345// _DEFINE_SWIZZLER2 defines a single such function, DEFINE_SWIZZLER2 defines all of them for all 345// _DEFINE_SWIZZLER2 defines a single such function, DEFINE_SWIZZLER2 defines all of them for all
346// component names (x<->r) and permutations (xy<->yx) 346// component names (x<->r) and permutations (xy<->yx)
347#define _DEFINE_SWIZZLER2(a, b, name) \ 347#define _DEFINE_SWIZZLER2(a, b, name) \
348 constexpr Vec2<T> name() const { \ 348 [[nodiscard]] constexpr Vec2<T> name() const { \
349 return Vec2<T>(a, b); \ 349 return Vec2<T>(a, b); \
350 } 350 }
351#define DEFINE_SWIZZLER2(a, b, a2, b2, a3, b3, a4, b4) \ 351#define DEFINE_SWIZZLER2(a, b, a2, b2, a3, b3, a4, b4) \
@@ -366,7 +366,7 @@ public:
366}; 366};
367 367
368template <typename T, typename V> 368template <typename T, typename V>
369constexpr Vec3<T> operator*(const V& f, const Vec3<T>& vec) { 369[[nodiscard]] constexpr Vec3<T> operator*(const V& f, const Vec3<T>& vec) {
370 return Vec3<T>(f * vec.x, f * vec.y, f * vec.z); 370 return Vec3<T>(f * vec.x, f * vec.y, f * vec.z);
371} 371}
372 372
@@ -402,16 +402,16 @@ public:
402 : x(x_), y(y_), z(z_), w(w_) {} 402 : x(x_), y(y_), z(z_), w(w_) {}
403 403
404 template <typename T2> 404 template <typename T2>
405 constexpr Vec4<T2> Cast() const { 405 [[nodiscard]] constexpr Vec4<T2> Cast() const {
406 return Vec4<T2>(static_cast<T2>(x), static_cast<T2>(y), static_cast<T2>(z), 406 return Vec4<T2>(static_cast<T2>(x), static_cast<T2>(y), static_cast<T2>(z),
407 static_cast<T2>(w)); 407 static_cast<T2>(w));
408 } 408 }
409 409
410 static constexpr Vec4 AssignToAll(const T& f) { 410 [[nodiscard]] static constexpr Vec4 AssignToAll(const T& f) {
411 return Vec4(f, f, f, f); 411 return Vec4(f, f, f, f);
412 } 412 }
413 413
414 constexpr Vec4<decltype(T{} + T{})> operator+(const Vec4& other) const { 414 [[nodiscard]] constexpr Vec4<decltype(T{} + T{})> operator+(const Vec4& other) const {
415 return {x + other.x, y + other.y, z + other.z, w + other.w}; 415 return {x + other.x, y + other.y, z + other.z, w + other.w};
416 } 416 }
417 417
@@ -423,7 +423,7 @@ public:
423 return *this; 423 return *this;
424 } 424 }
425 425
426 constexpr Vec4<decltype(T{} - T{})> operator-(const Vec4& other) const { 426 [[nodiscard]] constexpr Vec4<decltype(T{} - T{})> operator-(const Vec4& other) const {
427 return {x - other.x, y - other.y, z - other.z, w - other.w}; 427 return {x - other.x, y - other.y, z - other.z, w - other.w};
428 } 428 }
429 429
@@ -436,16 +436,16 @@ public:
436 } 436 }
437 437
438 template <typename U = T> 438 template <typename U = T>
439 constexpr Vec4<std::enable_if_t<std::is_signed_v<U>, U>> operator-() const { 439 [[nodiscard]] constexpr Vec4<std::enable_if_t<std::is_signed_v<U>, U>> operator-() const {
440 return {-x, -y, -z, -w}; 440 return {-x, -y, -z, -w};
441 } 441 }
442 442
443 constexpr Vec4<decltype(T{} * T{})> operator*(const Vec4& other) const { 443 [[nodiscard]] constexpr Vec4<decltype(T{} * T{})> operator*(const Vec4& other) const {
444 return {x * other.x, y * other.y, z * other.z, w * other.w}; 444 return {x * other.x, y * other.y, z * other.z, w * other.w};
445 } 445 }
446 446
447 template <typename V> 447 template <typename V>
448 constexpr Vec4<decltype(T{} * V{})> operator*(const V& f) const { 448 [[nodiscard]] constexpr Vec4<decltype(T{} * V{})> operator*(const V& f) const {
449 return {x * f, y * f, z * f, w * f}; 449 return {x * f, y * f, z * f, w * f};
450 } 450 }
451 451
@@ -456,7 +456,7 @@ public:
456 } 456 }
457 457
458 template <typename V> 458 template <typename V>
459 constexpr Vec4<decltype(T{} / V{})> operator/(const V& f) const { 459 [[nodiscard]] constexpr Vec4<decltype(T{} / V{})> operator/(const V& f) const {
460 return {x / f, y / f, z / f, w / f}; 460 return {x / f, y / f, z / f, w / f};
461 } 461 }
462 462
@@ -466,15 +466,15 @@ public:
466 return *this; 466 return *this;
467 } 467 }
468 468
469 constexpr T Length2() const { 469 [[nodiscard]] constexpr T Length2() const {
470 return x * x + y * y + z * z + w * w; 470 return x * x + y * y + z * z + w * w;
471 } 471 }
472 472
473 constexpr T& operator[](std::size_t i) { 473 [[nodiscard]] constexpr T& operator[](std::size_t i) {
474 return *((&x) + i); 474 return *((&x) + i);
475 } 475 }
476 476
477 constexpr const T& operator[](std::size_t i) const { 477 [[nodiscard]] constexpr const T& operator[](std::size_t i) const {
478 return *((&x) + i); 478 return *((&x) + i);
479 } 479 }
480 480
@@ -486,29 +486,29 @@ public:
486 } 486 }
487 487
488 // Common alias: RGBA (colors) 488 // Common alias: RGBA (colors)
489 constexpr T& r() { 489 [[nodiscard]] constexpr T& r() {
490 return x; 490 return x;
491 } 491 }
492 constexpr T& g() { 492 [[nodiscard]] constexpr T& g() {
493 return y; 493 return y;
494 } 494 }
495 constexpr T& b() { 495 [[nodiscard]] constexpr T& b() {
496 return z; 496 return z;
497 } 497 }
498 constexpr T& a() { 498 [[nodiscard]] constexpr T& a() {
499 return w; 499 return w;
500 } 500 }
501 501
502 constexpr const T& r() const { 502 [[nodiscard]] constexpr const T& r() const {
503 return x; 503 return x;
504 } 504 }
505 constexpr const T& g() const { 505 [[nodiscard]] constexpr const T& g() const {
506 return y; 506 return y;
507 } 507 }
508 constexpr const T& b() const { 508 [[nodiscard]] constexpr const T& b() const {
509 return z; 509 return z;
510 } 510 }
511 constexpr const T& a() const { 511 [[nodiscard]] constexpr const T& a() const {
512 return w; 512 return w;
513 } 513 }
514 514
@@ -520,7 +520,7 @@ public:
520// DEFINE_SWIZZLER2_COMP2 defines two component functions for all component names (x<->r) and 520// DEFINE_SWIZZLER2_COMP2 defines two component functions for all component names (x<->r) and
521// permutations (xy<->yx) 521// permutations (xy<->yx)
522#define _DEFINE_SWIZZLER2(a, b, name) \ 522#define _DEFINE_SWIZZLER2(a, b, name) \
523 constexpr Vec2<T> name() const { \ 523 [[nodiscard]] constexpr Vec2<T> name() const { \
524 return Vec2<T>(a, b); \ 524 return Vec2<T>(a, b); \
525 } 525 }
526#define DEFINE_SWIZZLER2_COMP1(a, a2) \ 526#define DEFINE_SWIZZLER2_COMP1(a, a2) \
@@ -547,7 +547,7 @@ public:
547#undef _DEFINE_SWIZZLER2 547#undef _DEFINE_SWIZZLER2
548 548
549#define _DEFINE_SWIZZLER3(a, b, c, name) \ 549#define _DEFINE_SWIZZLER3(a, b, c, name) \
550 constexpr Vec3<T> name() const { \ 550 [[nodiscard]] constexpr Vec3<T> name() const { \
551 return Vec3<T>(a, b, c); \ 551 return Vec3<T>(a, b, c); \
552 } 552 }
553#define DEFINE_SWIZZLER3_COMP1(a, a2) \ 553#define DEFINE_SWIZZLER3_COMP1(a, a2) \
@@ -581,7 +581,7 @@ public:
581}; 581};
582 582
583template <typename T, typename V> 583template <typename T, typename V>
584constexpr Vec4<decltype(V{} * T{})> operator*(const V& f, const Vec4<T>& vec) { 584[[nodiscard]] constexpr Vec4<decltype(V{} * T{})> operator*(const V& f, const Vec4<T>& vec) {
585 return {f * vec.x, f * vec.y, f * vec.z, f * vec.w}; 585 return {f * vec.x, f * vec.y, f * vec.z, f * vec.w};
586} 586}
587 587
@@ -593,39 +593,41 @@ constexpr decltype(T{} * T{} + T{} * T{}) Dot(const Vec2<T>& a, const Vec2<T>& b
593} 593}
594 594
595template <typename T> 595template <typename T>
596constexpr decltype(T{} * T{} + T{} * T{}) Dot(const Vec3<T>& a, const Vec3<T>& b) { 596[[nodiscard]] constexpr decltype(T{} * T{} + T{} * T{}) Dot(const Vec3<T>& a, const Vec3<T>& b) {
597 return a.x * b.x + a.y * b.y + a.z * b.z; 597 return a.x * b.x + a.y * b.y + a.z * b.z;
598} 598}
599 599
600template <typename T> 600template <typename T>
601constexpr decltype(T{} * T{} + T{} * T{}) Dot(const Vec4<T>& a, const Vec4<T>& b) { 601[[nodiscard]] constexpr decltype(T{} * T{} + T{} * T{}) Dot(const Vec4<T>& a, const Vec4<T>& b) {
602 return a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w; 602 return a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w;
603} 603}
604 604
605template <typename T> 605template <typename T>
606constexpr Vec3<decltype(T{} * T{} - T{} * T{})> Cross(const Vec3<T>& a, const Vec3<T>& b) { 606[[nodiscard]] constexpr Vec3<decltype(T{} * T{} - T{} * T{})> Cross(const Vec3<T>& a,
607 const Vec3<T>& b) {
607 return {a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x}; 608 return {a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x};
608} 609}
609 610
610// linear interpolation via float: 0.0=begin, 1.0=end 611// linear interpolation via float: 0.0=begin, 1.0=end
611template <typename X> 612template <typename X>
612constexpr decltype(X{} * float{} + X{} * float{}) Lerp(const X& begin, const X& end, 613[[nodiscard]] constexpr decltype(X{} * float{} + X{} * float{}) Lerp(const X& begin, const X& end,
613 const float t) { 614 const float t) {
614 return begin * (1.f - t) + end * t; 615 return begin * (1.f - t) + end * t;
615} 616}
616 617
617// linear interpolation via int: 0=begin, base=end 618// linear interpolation via int: 0=begin, base=end
618template <typename X, int base> 619template <typename X, int base>
619constexpr decltype((X{} * int{} + X{} * int{}) / base) LerpInt(const X& begin, const X& end, 620[[nodiscard]] constexpr decltype((X{} * int{} + X{} * int{}) / base) LerpInt(const X& begin,
620 const int t) { 621 const X& end,
622 const int t) {
621 return (begin * (base - t) + end * t) / base; 623 return (begin * (base - t) + end * t) / base;
622} 624}
623 625
624// bilinear interpolation. s is for interpolating x00-x01 and x10-x11, and t is for the second 626// bilinear interpolation. s is for interpolating x00-x01 and x10-x11, and t is for the second
625// interpolation. 627// interpolation.
626template <typename X> 628template <typename X>
627constexpr auto BilinearInterp(const X& x00, const X& x01, const X& x10, const X& x11, const float s, 629[[nodiscard]] constexpr auto BilinearInterp(const X& x00, const X& x01, const X& x10, const X& x11,
628 const float t) { 630 const float s, const float t) {
629 auto y0 = Lerp(x00, x01, s); 631 auto y0 = Lerp(x00, x01, s);
630 auto y1 = Lerp(x10, x11, s); 632 auto y1 = Lerp(x10, x11, s);
631 return Lerp(y0, y1, t); 633 return Lerp(y0, y1, t);
@@ -633,42 +635,42 @@ constexpr auto BilinearInterp(const X& x00, const X& x01, const X& x10, const X&
633 635
634// Utility vector factories 636// Utility vector factories
635template <typename T> 637template <typename T>
636constexpr Vec2<T> MakeVec(const T& x, const T& y) { 638[[nodiscard]] constexpr Vec2<T> MakeVec(const T& x, const T& y) {
637 return Vec2<T>{x, y}; 639 return Vec2<T>{x, y};
638} 640}
639 641
640template <typename T> 642template <typename T>
641constexpr Vec3<T> MakeVec(const T& x, const T& y, const T& z) { 643[[nodiscard]] constexpr Vec3<T> MakeVec(const T& x, const T& y, const T& z) {
642 return Vec3<T>{x, y, z}; 644 return Vec3<T>{x, y, z};
643} 645}
644 646
645template <typename T> 647template <typename T>
646constexpr Vec4<T> MakeVec(const T& x, const T& y, const Vec2<T>& zw) { 648[[nodiscard]] constexpr Vec4<T> MakeVec(const T& x, const T& y, const Vec2<T>& zw) {
647 return MakeVec(x, y, zw[0], zw[1]); 649 return MakeVec(x, y, zw[0], zw[1]);
648} 650}
649 651
650template <typename T> 652template <typename T>
651constexpr Vec3<T> MakeVec(const Vec2<T>& xy, const T& z) { 653[[nodiscard]] constexpr Vec3<T> MakeVec(const Vec2<T>& xy, const T& z) {
652 return MakeVec(xy[0], xy[1], z); 654 return MakeVec(xy[0], xy[1], z);
653} 655}
654 656
655template <typename T> 657template <typename T>
656constexpr Vec3<T> MakeVec(const T& x, const Vec2<T>& yz) { 658[[nodiscard]] constexpr Vec3<T> MakeVec(const T& x, const Vec2<T>& yz) {
657 return MakeVec(x, yz[0], yz[1]); 659 return MakeVec(x, yz[0], yz[1]);
658} 660}
659 661
660template <typename T> 662template <typename T>
661constexpr Vec4<T> MakeVec(const T& x, const T& y, const T& z, const T& w) { 663[[nodiscard]] constexpr Vec4<T> MakeVec(const T& x, const T& y, const T& z, const T& w) {
662 return Vec4<T>{x, y, z, w}; 664 return Vec4<T>{x, y, z, w};
663} 665}
664 666
665template <typename T> 667template <typename T>
666constexpr Vec4<T> MakeVec(const Vec2<T>& xy, const T& z, const T& w) { 668[[nodiscard]] constexpr Vec4<T> MakeVec(const Vec2<T>& xy, const T& z, const T& w) {
667 return MakeVec(xy[0], xy[1], z, w); 669 return MakeVec(xy[0], xy[1], z, w);
668} 670}
669 671
670template <typename T> 672template <typename T>
671constexpr Vec4<T> MakeVec(const T& x, const Vec2<T>& yz, const T& w) { 673[[nodiscard]] constexpr Vec4<T> MakeVec(const T& x, const Vec2<T>& yz, const T& w) {
672 return MakeVec(x, yz[0], yz[1], w); 674 return MakeVec(x, yz[0], yz[1], w);
673} 675}
674 676
@@ -676,17 +678,17 @@ constexpr Vec4<T> MakeVec(const T& x, const Vec2<T>& yz, const T& w) {
676// Even if someone wanted to use an odd object like Vec2<Vec2<T>>, the compiler would error 678// Even if someone wanted to use an odd object like Vec2<Vec2<T>>, the compiler would error
677// out soon enough due to misuse of the returned structure. 679// out soon enough due to misuse of the returned structure.
678template <typename T> 680template <typename T>
679constexpr Vec4<T> MakeVec(const Vec2<T>& xy, const Vec2<T>& zw) { 681[[nodiscard]] constexpr Vec4<T> MakeVec(const Vec2<T>& xy, const Vec2<T>& zw) {
680 return MakeVec(xy[0], xy[1], zw[0], zw[1]); 682 return MakeVec(xy[0], xy[1], zw[0], zw[1]);
681} 683}
682 684
683template <typename T> 685template <typename T>
684constexpr Vec4<T> MakeVec(const Vec3<T>& xyz, const T& w) { 686[[nodiscard]] constexpr Vec4<T> MakeVec(const Vec3<T>& xyz, const T& w) {
685 return MakeVec(xyz[0], xyz[1], xyz[2], w); 687 return MakeVec(xyz[0], xyz[1], xyz[2], w);
686} 688}
687 689
688template <typename T> 690template <typename T>
689constexpr Vec4<T> MakeVec(const T& x, const Vec3<T>& yzw) { 691[[nodiscard]] constexpr Vec4<T> MakeVec(const T& x, const Vec3<T>& yzw) {
690 return MakeVec(x, yzw[0], yzw[1], yzw[2]); 692 return MakeVec(x, yzw[0], yzw[1], yzw[2]);
691} 693}
692 694
diff --git a/src/common/virtual_buffer.cpp b/src/common/virtual_buffer.cpp
index be5b67752..b009cb500 100644
--- a/src/common/virtual_buffer.cpp
+++ b/src/common/virtual_buffer.cpp
@@ -5,16 +5,7 @@
5#ifdef _WIN32 5#ifdef _WIN32
6#include <windows.h> 6#include <windows.h>
7#else 7#else
8#include <stdio.h>
9#include <sys/mman.h> 8#include <sys/mman.h>
10#include <sys/types.h>
11#if defined __APPLE__ || defined __FreeBSD__ || defined __OpenBSD__
12#include <sys/sysctl.h>
13#elif defined __HAIKU__
14#include <OS.h>
15#else
16#include <sys/sysinfo.h>
17#endif
18#endif 9#endif
19 10
20#include "common/assert.h" 11#include "common/assert.h"
diff --git a/src/common/virtual_buffer.h b/src/common/virtual_buffer.h
index da064e59e..125cb42f0 100644
--- a/src/common/virtual_buffer.h
+++ b/src/common/virtual_buffer.h
@@ -30,23 +30,23 @@ public:
30 base_ptr = reinterpret_cast<T*>(AllocateMemoryPages(alloc_size)); 30 base_ptr = reinterpret_cast<T*>(AllocateMemoryPages(alloc_size));
31 } 31 }
32 32
33 constexpr const T& operator[](std::size_t index) const { 33 [[nodiscard]] constexpr const T& operator[](std::size_t index) const {
34 return base_ptr[index]; 34 return base_ptr[index];
35 } 35 }
36 36
37 constexpr T& operator[](std::size_t index) { 37 [[nodiscard]] constexpr T& operator[](std::size_t index) {
38 return base_ptr[index]; 38 return base_ptr[index];
39 } 39 }
40 40
41 constexpr T* data() { 41 [[nodiscard]] constexpr T* data() {
42 return base_ptr; 42 return base_ptr;
43 } 43 }
44 44
45 constexpr const T* data() const { 45 [[nodiscard]] constexpr const T* data() const {
46 return base_ptr; 46 return base_ptr;
47 } 47 }
48 48
49 constexpr std::size_t size() const { 49 [[nodiscard]] constexpr std::size_t size() const {
50 return alloc_size / sizeof(T); 50 return alloc_size / sizeof(T);
51 } 51 }
52 52
diff --git a/src/common/wall_clock.h b/src/common/wall_clock.h
index 367d72134..5db30083d 100644
--- a/src/common/wall_clock.h
+++ b/src/common/wall_clock.h
@@ -14,24 +14,24 @@ namespace Common {
14class WallClock { 14class WallClock {
15public: 15public:
16 /// Returns current wall time in nanoseconds 16 /// Returns current wall time in nanoseconds
17 virtual std::chrono::nanoseconds GetTimeNS() = 0; 17 [[nodiscard]] virtual std::chrono::nanoseconds GetTimeNS() = 0;
18 18
19 /// Returns current wall time in microseconds 19 /// Returns current wall time in microseconds
20 virtual std::chrono::microseconds GetTimeUS() = 0; 20 [[nodiscard]] virtual std::chrono::microseconds GetTimeUS() = 0;
21 21
22 /// Returns current wall time in milliseconds 22 /// Returns current wall time in milliseconds
23 virtual std::chrono::milliseconds GetTimeMS() = 0; 23 [[nodiscard]] virtual std::chrono::milliseconds GetTimeMS() = 0;
24 24
25 /// Returns current wall time in emulated clock cycles 25 /// Returns current wall time in emulated clock cycles
26 virtual u64 GetClockCycles() = 0; 26 [[nodiscard]] virtual u64 GetClockCycles() = 0;
27 27
28 /// Returns current wall time in emulated cpu cycles 28 /// Returns current wall time in emulated cpu cycles
29 virtual u64 GetCPUCycles() = 0; 29 [[nodiscard]] virtual u64 GetCPUCycles() = 0;
30 30
31 virtual void Pause(bool is_paused) = 0; 31 virtual void Pause(bool is_paused) = 0;
32 32
33 /// Tells if the wall clock, uses the host CPU's hardware clock 33 /// Tells if the wall clock, uses the host CPU's hardware clock
34 bool IsNative() const { 34 [[nodiscard]] bool IsNative() const {
35 return is_native; 35 return is_native;
36 } 36 }
37 37
@@ -47,7 +47,7 @@ private:
47 bool is_native; 47 bool is_native;
48}; 48};
49 49
50std::unique_ptr<WallClock> CreateBestMatchingClock(u32 emulated_cpu_frequency, 50[[nodiscard]] std::unique_ptr<WallClock> CreateBestMatchingClock(u32 emulated_cpu_frequency,
51 u32 emulated_clock_frequency); 51 u32 emulated_clock_frequency);
52 52
53} // namespace Common 53} // namespace Common
diff --git a/src/common/zstd_compression.cpp b/src/common/zstd_compression.cpp
index 978526492..5f45459da 100644
--- a/src/common/zstd_compression.cpp
+++ b/src/common/zstd_compression.cpp
@@ -5,7 +5,6 @@
5#include <algorithm> 5#include <algorithm>
6#include <zstd.h> 6#include <zstd.h>
7 7
8#include "common/assert.h"
9#include "common/zstd_compression.h" 8#include "common/zstd_compression.h"
10 9
11namespace Common::Compression { 10namespace Common::Compression {
diff --git a/src/common/zstd_compression.h b/src/common/zstd_compression.h
index e9de941c8..c26a30ab9 100644
--- a/src/common/zstd_compression.h
+++ b/src/common/zstd_compression.h
@@ -13,24 +13,25 @@ namespace Common::Compression {
13/** 13/**
14 * Compresses a source memory region with Zstandard and returns the compressed data in a vector. 14 * Compresses a source memory region with Zstandard and returns the compressed data in a vector.
15 * 15 *
16 * @param source the uncompressed source memory region. 16 * @param source The uncompressed source memory region.
17 * @param source_size the size in bytes of the uncompressed source memory region. 17 * @param source_size The size of the uncompressed source memory region.
18 * @param compression_level the used compression level. Should be between 1 and 22. 18 * @param compression_level The used compression level. Should be between 1 and 22.
19 * 19 *
20 * @return the compressed data. 20 * @return the compressed data.
21 */ 21 */
22std::vector<u8> CompressDataZSTD(const u8* source, std::size_t source_size, s32 compression_level); 22[[nodiscard]] std::vector<u8> CompressDataZSTD(const u8* source, std::size_t source_size,
23 s32 compression_level);
23 24
24/** 25/**
25 * Compresses a source memory region with Zstandard with the default compression level and returns 26 * Compresses a source memory region with Zstandard with the default compression level and returns
26 * the compressed data in a vector. 27 * the compressed data in a vector.
27 * 28 *
28 * @param source the uncompressed source memory region. 29 * @param source The uncompressed source memory region.
29 * @param source_size the size in bytes of the uncompressed source memory region. 30 * @param source_size The size of the uncompressed source memory region.
30 * 31 *
31 * @return the compressed data. 32 * @return the compressed data.
32 */ 33 */
33std::vector<u8> CompressDataZSTDDefault(const u8* source, std::size_t source_size); 34[[nodiscard]] std::vector<u8> CompressDataZSTDDefault(const u8* source, std::size_t source_size);
34 35
35/** 36/**
36 * Decompresses a source memory region with Zstandard and returns the uncompressed data in a vector. 37 * Decompresses a source memory region with Zstandard and returns the uncompressed data in a vector.
@@ -39,6 +40,6 @@ std::vector<u8> CompressDataZSTDDefault(const u8* source, std::size_t source_siz
39 * 40 *
40 * @return the decompressed data. 41 * @return the decompressed data.
41 */ 42 */
42std::vector<u8> DecompressDataZSTD(const std::vector<u8>& compressed); 43[[nodiscard]] std::vector<u8> DecompressDataZSTD(const std::vector<u8>& compressed);
43 44
44} // namespace Common::Compression \ No newline at end of file 45} // namespace Common::Compression \ No newline at end of file
diff --git a/src/core/crypto/key_manager.cpp b/src/core/crypto/key_manager.cpp
index f87fe0abc..c09f7ad41 100644
--- a/src/core/crypto/key_manager.cpp
+++ b/src/core/crypto/key_manager.cpp
@@ -40,12 +40,14 @@ namespace Core::Crypto {
40constexpr u64 CURRENT_CRYPTO_REVISION = 0x5; 40constexpr u64 CURRENT_CRYPTO_REVISION = 0x5;
41constexpr u64 FULL_TICKET_SIZE = 0x400; 41constexpr u64 FULL_TICKET_SIZE = 0x400;
42 42
43using namespace Common; 43using Common::AsArray;
44 44
45const std::array<SHA256Hash, 2> eticket_source_hashes{ 45// clang-format off
46 "B71DB271DC338DF380AA2C4335EF8873B1AFD408E80B3582D8719FC81C5E511C"_array32, // eticket_rsa_kek_source 46constexpr std::array eticket_source_hashes{
47 "E8965A187D30E57869F562D04383C996DE487BBA5761363D2D4D32391866A85C"_array32, // eticket_rsa_kekek_source 47 AsArray("B71DB271DC338DF380AA2C4335EF8873B1AFD408E80B3582D8719FC81C5E511C"), // eticket_rsa_kek_source
48 AsArray("E8965A187D30E57869F562D04383C996DE487BBA5761363D2D4D32391866A85C"), // eticket_rsa_kekek_source
48}; 49};
50// clang-format on
49 51
50const std::map<std::pair<S128KeyType, u64>, std::string> KEYS_VARIABLE_LENGTH{ 52const std::map<std::pair<S128KeyType, u64>, std::string> KEYS_VARIABLE_LENGTH{
51 {{S128KeyType::Master, 0}, "master_key_"}, 53 {{S128KeyType::Master, 0}, "master_key_"},
diff --git a/src/core/crypto/partition_data_manager.cpp b/src/core/crypto/partition_data_manager.cpp
index c5c073e70..46136d04a 100644
--- a/src/core/crypto/partition_data_manager.cpp
+++ b/src/core/crypto/partition_data_manager.cpp
@@ -27,7 +27,7 @@
27#include "core/file_sys/vfs_offset.h" 27#include "core/file_sys/vfs_offset.h"
28#include "core/file_sys/vfs_vector.h" 28#include "core/file_sys/vfs_vector.h"
29 29
30using namespace Common; 30using Common::AsArray;
31 31
32namespace Core::Crypto { 32namespace Core::Crypto {
33 33
@@ -47,105 +47,123 @@ struct Package2Header {
47}; 47};
48static_assert(sizeof(Package2Header) == 0x200, "Package2Header has incorrect size."); 48static_assert(sizeof(Package2Header) == 0x200, "Package2Header has incorrect size.");
49 49
50const std::array<SHA256Hash, 0x10> source_hashes{ 50// clang-format off
51 "B24BD293259DBC7AC5D63F88E60C59792498E6FC5443402C7FFE87EE8B61A3F0"_array32, // keyblob_mac_key_source 51constexpr std::array source_hashes{
52 "7944862A3A5C31C6720595EFD302245ABD1B54CCDCF33000557681E65C5664A4"_array32, // master_key_source 52 AsArray("B24BD293259DBC7AC5D63F88E60C59792498E6FC5443402C7FFE87EE8B61A3F0"), // keyblob_mac_key_source
53 "21E2DF100FC9E094DB51B47B9B1D6E94ED379DB8B547955BEF8FE08D8DD35603"_array32, // package2_key_source 53 AsArray("7944862A3A5C31C6720595EFD302245ABD1B54CCDCF33000557681E65C5664A4"), // master_key_source
54 "FC02B9D37B42D7A1452E71444F1F700311D1132E301A83B16062E72A78175085"_array32, // aes_kek_generation_source 54 AsArray("21E2DF100FC9E094DB51B47B9B1D6E94ED379DB8B547955BEF8FE08D8DD35603"), // package2_key_source
55 "FBD10056999EDC7ACDB96098E47E2C3606230270D23281E671F0F389FC5BC585"_array32, // aes_key_generation_source 55 AsArray("FC02B9D37B42D7A1452E71444F1F700311D1132E301A83B16062E72A78175085"), // aes_kek_generation_source
56 "C48B619827986C7F4E3081D59DB2B460C84312650E9A8E6B458E53E8CBCA4E87"_array32, // titlekek_source 56 AsArray("FBD10056999EDC7ACDB96098E47E2C3606230270D23281E671F0F389FC5BC585"), // aes_key_generation_source
57 "04AD66143C726B2A139FB6B21128B46F56C553B2B3887110304298D8D0092D9E"_array32, // key_area_key_application_source 57 AsArray("C48B619827986C7F4E3081D59DB2B460C84312650E9A8E6B458E53E8CBCA4E87"), // titlekek_source
58 "FD434000C8FF2B26F8E9A9D2D2C12F6BE5773CBB9DC86300E1BD99F8EA33A417"_array32, // key_area_key_ocean_source 58 AsArray("04AD66143C726B2A139FB6B21128B46F56C553B2B3887110304298D8D0092D9E"), // key_area_key_application_source
59 "1F17B1FD51AD1C2379B58F152CA4912EC2106441E51722F38700D5937A1162F7"_array32, // key_area_key_system_source 59 AsArray("FD434000C8FF2B26F8E9A9D2D2C12F6BE5773CBB9DC86300E1BD99F8EA33A417"), // key_area_key_ocean_source
60 "6B2ED877C2C52334AC51E59ABFA7EC457F4A7D01E46291E9F2EAA45F011D24B7"_array32, // sd_card_kek_source 60 AsArray("1F17B1FD51AD1C2379B58F152CA4912EC2106441E51722F38700D5937A1162F7"), // key_area_key_system_source
61 "D482743563D3EA5DCDC3B74E97C9AC8A342164FA041A1DC80F17F6D31E4BC01C"_array32, // sd_card_save_key_source 61 AsArray("6B2ED877C2C52334AC51E59ABFA7EC457F4A7D01E46291E9F2EAA45F011D24B7"), // sd_card_kek_source
62 "2E751CECF7D93A2B957BD5FFCB082FD038CC2853219DD3092C6DAB9838F5A7CC"_array32, // sd_card_nca_key_source 62 AsArray("D482743563D3EA5DCDC3B74E97C9AC8A342164FA041A1DC80F17F6D31E4BC01C"), // sd_card_save_key_source
63 "1888CAED5551B3EDE01499E87CE0D86827F80820EFB275921055AA4E2ABDFFC2"_array32, // header_kek_source 63 AsArray("2E751CECF7D93A2B957BD5FFCB082FD038CC2853219DD3092C6DAB9838F5A7CC"), // sd_card_nca_key_source
64 "8F783E46852DF6BE0BA4E19273C4ADBAEE16380043E1B8C418C4089A8BD64AA6"_array32, // header_key_source 64 AsArray("1888CAED5551B3EDE01499E87CE0D86827F80820EFB275921055AA4E2ABDFFC2"), // header_kek_source
65 "D1757E52F1AE55FA882EC690BC6F954AC46A83DC22F277F8806BD55577C6EED7"_array32, // rsa_kek_seed3 65 AsArray("8F783E46852DF6BE0BA4E19273C4ADBAEE16380043E1B8C418C4089A8BD64AA6"), // header_key_source
66 "FC02B9D37B42D7A1452E71444F1F700311D1132E301A83B16062E72A78175085"_array32, // rsa_kek_mask0 66 AsArray("D1757E52F1AE55FA882EC690BC6F954AC46A83DC22F277F8806BD55577C6EED7"), // rsa_kek_seed3
67 AsArray("FC02B9D37B42D7A1452E71444F1F700311D1132E301A83B16062E72A78175085"), // rsa_kek_mask0
67}; 68};
68 69// clang-format on
69const std::array<SHA256Hash, 0x20> keyblob_source_hashes{ 70
70 "8A06FE274AC491436791FDB388BCDD3AB9943BD4DEF8094418CDAC150FD73786"_array32, // keyblob_key_source_00 71// clang-format off
71 "2D5CAEB2521FEF70B47E17D6D0F11F8CE2C1E442A979AD8035832C4E9FBCCC4B"_array32, // keyblob_key_source_01 72constexpr std::array keyblob_source_hashes{
72 "61C5005E713BAE780641683AF43E5F5C0E03671117F702F401282847D2FC6064"_array32, // keyblob_key_source_02 73 AsArray("8A06FE274AC491436791FDB388BCDD3AB9943BD4DEF8094418CDAC150FD73786"), // keyblob_key_source_00
73 "8E9795928E1C4428E1B78F0BE724D7294D6934689C11B190943923B9D5B85903"_array32, // keyblob_key_source_03 74 AsArray("2D5CAEB2521FEF70B47E17D6D0F11F8CE2C1E442A979AD8035832C4E9FBCCC4B"), // keyblob_key_source_01
74 "95FA33AF95AFF9D9B61D164655B32710ED8D615D46C7D6CC3CC70481B686B402"_array32, // keyblob_key_source_04 75 AsArray("61C5005E713BAE780641683AF43E5F5C0E03671117F702F401282847D2FC6064"), // keyblob_key_source_02
75 "3F5BE7B3C8B1ABD8C10B4B703D44766BA08730562C172A4FE0D6B866B3E2DB3E"_array32, // keyblob_key_source_05 76 AsArray("8E9795928E1C4428E1B78F0BE724D7294D6934689C11B190943923B9D5B85903"), // keyblob_key_source_03
76 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_06 77 AsArray("95FA33AF95AFF9D9B61D164655B32710ED8D615D46C7D6CC3CC70481B686B402"), // keyblob_key_source_04
77 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_07 78 AsArray("3F5BE7B3C8B1ABD8C10B4B703D44766BA08730562C172A4FE0D6B866B3E2DB3E"), // keyblob_key_source_05
78 79 AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_06
79 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_08 80 AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_07
80 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_09 81
81 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_0A 82 AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_08
82 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_0B 83 AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_09
83 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_0C 84 AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_0A
84 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_0D 85 AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_0B
85 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_0E 86 AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_0C
86 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_0F 87 AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_0D
87 88 AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_0E
88 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_10 89 AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_0F
89 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_11 90
90 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_12 91 AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_10
91 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_13 92 AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_11
92 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_14 93 AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_12
93 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_15 94 AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_13
94 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_16 95 AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_14
95 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_17 96 AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_15
96 97 AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_16
97 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_18 98 AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_17
98 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_19 99
99 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_1A 100 AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_18
100 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_1B 101 AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_19
101 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_1C 102 AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_1A
102 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_1D 103 AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_1B
103 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_1E 104 AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_1C
104 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_1F 105 AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_1D
106 AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_1E
107 AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_1F
105}; 108};
106 109// clang-format on
107const std::array<SHA256Hash, 0x20> master_key_hashes{ 110
108 "0EE359BE3C864BB0782E1D70A718A0342C551EED28C369754F9C4F691BECF7CA"_array32, // master_key_00 111// clang-format off
109 "4FE707B7E4ABDAF727C894AAF13B1351BFE2AC90D875F73B2E20FA94B9CC661E"_array32, // master_key_01 112constexpr std::array master_key_hashes{
110 "79277C0237A2252EC3DFAC1F7C359C2B3D121E9DB15BB9AB4C2B4408D2F3AE09"_array32, // master_key_02 113 AsArray("0EE359BE3C864BB0782E1D70A718A0342C551EED28C369754F9C4F691BECF7CA"), // master_key_00
111 "4F36C565D13325F65EE134073C6A578FFCB0008E02D69400836844EAB7432754"_array32, // master_key_03 114 AsArray("4FE707B7E4ABDAF727C894AAF13B1351BFE2AC90D875F73B2E20FA94B9CC661E"), // master_key_01
112 "75FF1D95D26113550EE6FCC20ACB58E97EDEB3A2FF52543ED5AEC63BDCC3DA50"_array32, // master_key_04 115 AsArray("79277C0237A2252EC3DFAC1F7C359C2B3D121E9DB15BB9AB4C2B4408D2F3AE09"), // master_key_02
113 "EBE2BCD6704673EC0F88A187BB2AD9F1CC82B718C389425941BDC194DC46B0DD"_array32, // master_key_05 116 AsArray("4F36C565D13325F65EE134073C6A578FFCB0008E02D69400836844EAB7432754"), // master_key_03
114 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_06 117 AsArray("75FF1D95D26113550EE6FCC20ACB58E97EDEB3A2FF52543ED5AEC63BDCC3DA50"), // master_key_04
115 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_07 118 AsArray("EBE2BCD6704673EC0F88A187BB2AD9F1CC82B718C389425941BDC194DC46B0DD"), // master_key_05
116 119 AsArray("9497E6779F5D840F2BBA1DE4E95BA1D6F21EFC94717D5AE5CA37D7EC5BD37A19"), // master_key_06
117 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_08 120 AsArray("4EC96B8CB01B8DCE382149443430B2B6EBCB2983348AFA04A25E53609DABEDF6"), // master_key_07
118 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_09 121
119 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_0A 122 AsArray("2998E2E23609BC2675FF062A2D64AF5B1B78DFF463B24119D64A1B64F01B2D51"), // master_key_08
120 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_0B 123 AsArray("9D486A98067C44B37CF173D3BF577891EB6081FF6B4A166347D9DBBF7025076B"), // master_key_09
121 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_0C 124 AsArray("4EC5A237A75A083A9C5F6CF615601522A7F822D06BD4BA32612C9CEBBB29BD45"), // master_key_0A
122 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_0D 125 AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // master_key_0B
123 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_0E 126 AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // master_key_0C
124 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_0F 127 AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // master_key_0D
125 128 AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // master_key_0E
126 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_10 129 AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // master_key_0F
127 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_11 130
128 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_12 131 AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // master_key_10
129 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_13 132 AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // master_key_11
130 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_14 133 AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // master_key_12
131 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_15 134 AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // master_key_13
132 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_16 135 AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // master_key_14
133 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_17 136 AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // master_key_15
134 137 AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // master_key_16
135 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_18 138 AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // master_key_17
136 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_19 139
137 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_1A 140 AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // master_key_18
138 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_1B 141 AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // master_key_19
139 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_1C 142 AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // master_key_1A
140 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_1D 143 AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // master_key_1B
141 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_1E 144 AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // master_key_1C
142 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_1F 145 AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // master_key_1D
146 AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // master_key_1E
147 AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // master_key_1F
143}; 148};
149// clang-format on
150
151static constexpr u8 CalculateMaxKeyblobSourceHash() {
152 const auto is_zero = [](const auto& data) {
153 // TODO: Replace with std::all_of whenever mingw decides to update their
154 // libraries to include the constexpr variant of it.
155 for (const auto element : data) {
156 if (element != 0) {
157 return false;
158 }
159 }
160 return true;
161 };
144 162
145static u8 CalculateMaxKeyblobSourceHash() {
146 for (s8 i = 0x1F; i >= 0; --i) { 163 for (s8 i = 0x1F; i >= 0; --i) {
147 if (keyblob_source_hashes[i] != SHA256Hash{}) 164 if (!is_zero(keyblob_source_hashes[i])) {
148 return static_cast<u8>(i + 1); 165 return static_cast<u8>(i + 1);
166 }
149 } 167 }
150 168
151 return 0; 169 return 0;
diff --git a/src/core/file_sys/registered_cache.h b/src/core/file_sys/registered_cache.h
index ec1d54f27..5b414b0f0 100644
--- a/src/core/file_sys/registered_cache.h
+++ b/src/core/file_sys/registered_cache.h
@@ -133,9 +133,9 @@ public:
133 // Parsing function defines the conversion from raw file to NCA. If there are other steps 133 // Parsing function defines the conversion from raw file to NCA. If there are other steps
134 // besides creating the NCA from the file (e.g. NAX0 on SD Card), that should go in a custom 134 // besides creating the NCA from the file (e.g. NAX0 on SD Card), that should go in a custom
135 // parsing function. 135 // parsing function.
136 explicit RegisteredCache(VirtualDir dir, 136 explicit RegisteredCache(
137 ContentProviderParsingFunction parsing_function = 137 VirtualDir dir, ContentProviderParsingFunction parsing_function =
138 [](const VirtualFile& file, const NcaID& id) { return file; }); 138 [](const VirtualFile& file, const NcaID& id) { return file; });
139 ~RegisteredCache() override; 139 ~RegisteredCache() override;
140 140
141 void Refresh() override; 141 void Refresh() override;
diff --git a/src/core/file_sys/system_archive/mii_model.cpp b/src/core/file_sys/system_archive/mii_model.cpp
index 61bb67945..d65c7d234 100644
--- a/src/core/file_sys/system_archive/mii_model.cpp
+++ b/src/core/file_sys/system_archive/mii_model.cpp
@@ -27,18 +27,12 @@ VirtualDir MiiModel() {
27 auto out = std::make_shared<VectorVfsDirectory>(std::vector<VirtualFile>{}, 27 auto out = std::make_shared<VectorVfsDirectory>(std::vector<VirtualFile>{},
28 std::vector<VirtualDir>{}, "data"); 28 std::vector<VirtualDir>{}, "data");
29 29
30 out->AddFile(std::make_shared<ArrayVfsFile<MiiModelData::TEXTURE_LOW_LINEAR.size()>>( 30 out->AddFile(MakeArrayFile(MiiModelData::TEXTURE_LOW_LINEAR, "NXTextureLowLinear.dat"));
31 MiiModelData::TEXTURE_LOW_LINEAR, "NXTextureLowLinear.dat")); 31 out->AddFile(MakeArrayFile(MiiModelData::TEXTURE_LOW_SRGB, "NXTextureLowSRGB.dat"));
32 out->AddFile(std::make_shared<ArrayVfsFile<MiiModelData::TEXTURE_LOW_SRGB.size()>>( 32 out->AddFile(MakeArrayFile(MiiModelData::TEXTURE_MID_LINEAR, "NXTextureMidLinear.dat"));
33 MiiModelData::TEXTURE_LOW_SRGB, "NXTextureLowSRGB.dat")); 33 out->AddFile(MakeArrayFile(MiiModelData::TEXTURE_MID_SRGB, "NXTextureMidSRGB.dat"));
34 out->AddFile(std::make_shared<ArrayVfsFile<MiiModelData::TEXTURE_MID_LINEAR.size()>>( 34 out->AddFile(MakeArrayFile(MiiModelData::SHAPE_HIGH, "ShapeHigh.dat"));
35 MiiModelData::TEXTURE_MID_LINEAR, "NXTextureMidLinear.dat")); 35 out->AddFile(MakeArrayFile(MiiModelData::SHAPE_MID, "ShapeMid.dat"));
36 out->AddFile(std::make_shared<ArrayVfsFile<MiiModelData::TEXTURE_MID_SRGB.size()>>(
37 MiiModelData::TEXTURE_MID_SRGB, "NXTextureMidSRGB.dat"));
38 out->AddFile(std::make_shared<ArrayVfsFile<MiiModelData::SHAPE_HIGH.size()>>(
39 MiiModelData::SHAPE_HIGH, "ShapeHigh.dat"));
40 out->AddFile(std::make_shared<ArrayVfsFile<MiiModelData::SHAPE_MID.size()>>(
41 MiiModelData::SHAPE_MID, "ShapeMid.dat"));
42 36
43 return out; 37 return out;
44} 38}
diff --git a/src/core/file_sys/system_archive/ng_word.cpp b/src/core/file_sys/system_archive/ng_word.cpp
index f4443784d..100d3c5db 100644
--- a/src/core/file_sys/system_archive/ng_word.cpp
+++ b/src/core/file_sys/system_archive/ng_word.cpp
@@ -24,19 +24,18 @@ constexpr std::array<u8, 30> WORD_TXT{
24} // namespace NgWord1Data 24} // namespace NgWord1Data
25 25
26VirtualDir NgWord1() { 26VirtualDir NgWord1() {
27 std::vector<VirtualFile> files(NgWord1Data::NUMBER_WORD_TXT_FILES); 27 std::vector<VirtualFile> files;
28 files.reserve(NgWord1Data::NUMBER_WORD_TXT_FILES);
28 29
29 for (std::size_t i = 0; i < files.size(); ++i) { 30 for (std::size_t i = 0; i < files.size(); ++i) {
30 files[i] = std::make_shared<ArrayVfsFile<NgWord1Data::WORD_TXT.size()>>( 31 files.push_back(MakeArrayFile(NgWord1Data::WORD_TXT, fmt::format("{}.txt", i)));
31 NgWord1Data::WORD_TXT, fmt::format("{}.txt", i));
32 } 32 }
33 33
34 files.push_back(std::make_shared<ArrayVfsFile<NgWord1Data::WORD_TXT.size()>>( 34 files.push_back(MakeArrayFile(NgWord1Data::WORD_TXT, "common.txt"));
35 NgWord1Data::WORD_TXT, "common.txt")); 35 files.push_back(MakeArrayFile(NgWord1Data::VERSION_DAT, "version.dat"));
36 files.push_back(std::make_shared<ArrayVfsFile<NgWord1Data::VERSION_DAT.size()>>(
37 NgWord1Data::VERSION_DAT, "version.dat"));
38 36
39 return std::make_shared<VectorVfsDirectory>(files, std::vector<VirtualDir>{}, "data"); 37 return std::make_shared<VectorVfsDirectory>(std::move(files), std::vector<VirtualDir>{},
38 "data");
40} 39}
41 40
42namespace NgWord2Data { 41namespace NgWord2Data {
@@ -55,27 +54,22 @@ constexpr std::array<u8, 0x2C> AC_NX_DATA{
55} // namespace NgWord2Data 54} // namespace NgWord2Data
56 55
57VirtualDir NgWord2() { 56VirtualDir NgWord2() {
58 std::vector<VirtualFile> files(NgWord2Data::NUMBER_AC_NX_FILES * 3); 57 std::vector<VirtualFile> files;
58 files.reserve(NgWord2Data::NUMBER_AC_NX_FILES * 3);
59 59
60 for (std::size_t i = 0; i < NgWord2Data::NUMBER_AC_NX_FILES; ++i) { 60 for (std::size_t i = 0; i < NgWord2Data::NUMBER_AC_NX_FILES; ++i) {
61 files[3 * i] = std::make_shared<ArrayVfsFile<NgWord2Data::AC_NX_DATA.size()>>( 61 files.push_back(MakeArrayFile(NgWord2Data::AC_NX_DATA, fmt::format("ac_{}_b1_nx", i)));
62 NgWord2Data::AC_NX_DATA, fmt::format("ac_{}_b1_nx", i)); 62 files.push_back(MakeArrayFile(NgWord2Data::AC_NX_DATA, fmt::format("ac_{}_b2_nx", i)));
63 files[3 * i + 1] = std::make_shared<ArrayVfsFile<NgWord2Data::AC_NX_DATA.size()>>( 63 files.push_back(MakeArrayFile(NgWord2Data::AC_NX_DATA, fmt::format("ac_{}_not_b_nx", i)));
64 NgWord2Data::AC_NX_DATA, fmt::format("ac_{}_b2_nx", i));
65 files[3 * i + 2] = std::make_shared<ArrayVfsFile<NgWord2Data::AC_NX_DATA.size()>>(
66 NgWord2Data::AC_NX_DATA, fmt::format("ac_{}_not_b_nx", i));
67 } 64 }
68 65
69 files.push_back(std::make_shared<ArrayVfsFile<NgWord2Data::AC_NX_DATA.size()>>( 66 files.push_back(MakeArrayFile(NgWord2Data::AC_NX_DATA, "ac_common_b1_nx"));
70 NgWord2Data::AC_NX_DATA, "ac_common_b1_nx")); 67 files.push_back(MakeArrayFile(NgWord2Data::AC_NX_DATA, "ac_common_b2_nx"));
71 files.push_back(std::make_shared<ArrayVfsFile<NgWord2Data::AC_NX_DATA.size()>>( 68 files.push_back(MakeArrayFile(NgWord2Data::AC_NX_DATA, "ac_common_not_b_nx"));
72 NgWord2Data::AC_NX_DATA, "ac_common_b2_nx")); 69 files.push_back(MakeArrayFile(NgWord2Data::VERSION_DAT, "version.dat"));
73 files.push_back(std::make_shared<ArrayVfsFile<NgWord2Data::AC_NX_DATA.size()>>(
74 NgWord2Data::AC_NX_DATA, "ac_common_not_b_nx"));
75 files.push_back(std::make_shared<ArrayVfsFile<NgWord2Data::VERSION_DAT.size()>>(
76 NgWord2Data::VERSION_DAT, "version.dat"));
77 70
78 return std::make_shared<VectorVfsDirectory>(files, std::vector<VirtualDir>{}, "data"); 71 return std::make_shared<VectorVfsDirectory>(std::move(files), std::vector<VirtualDir>{},
72 "data");
79} 73}
80 74
81} // namespace FileSys::SystemArchive 75} // namespace FileSys::SystemArchive
diff --git a/src/core/file_sys/system_archive/time_zone_binary.cpp b/src/core/file_sys/system_archive/time_zone_binary.cpp
index d1de63f20..8fd005012 100644
--- a/src/core/file_sys/system_archive/time_zone_binary.cpp
+++ b/src/core/file_sys/system_archive/time_zone_binary.cpp
@@ -654,12 +654,13 @@ static VirtualFile GenerateDefaultTimeZoneFile() {
654} 654}
655 655
656VirtualDir TimeZoneBinary() { 656VirtualDir TimeZoneBinary() {
657 const std::vector<VirtualDir> root_dirs{std::make_shared<VectorVfsDirectory>( 657 std::vector<VirtualDir> root_dirs{std::make_shared<VectorVfsDirectory>(
658 std::vector<VirtualFile>{GenerateDefaultTimeZoneFile()}, std::vector<VirtualDir>{}, 658 std::vector<VirtualFile>{GenerateDefaultTimeZoneFile()}, std::vector<VirtualDir>{},
659 "zoneinfo")}; 659 "zoneinfo")};
660 const std::vector<VirtualFile> root_files{ 660 std::vector<VirtualFile> root_files{MakeArrayFile(LOCATION_NAMES, "binaryList.txt")};
661 std::make_shared<ArrayVfsFile<LOCATION_NAMES.size()>>(LOCATION_NAMES, "binaryList.txt")}; 661
662 return std::make_shared<VectorVfsDirectory>(root_files, root_dirs, "data"); 662 return std::make_shared<VectorVfsDirectory>(std::move(root_files), std::move(root_dirs),
663 "data");
663} 664}
664 665
665} // namespace FileSys::SystemArchive 666} // namespace FileSys::SystemArchive
diff --git a/src/core/file_sys/vfs_vector.h b/src/core/file_sys/vfs_vector.h
index ac36cb2ee..95d3da2f2 100644
--- a/src/core/file_sys/vfs_vector.h
+++ b/src/core/file_sys/vfs_vector.h
@@ -4,7 +4,11 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <array>
7#include <cstring> 8#include <cstring>
9#include <memory>
10#include <string>
11#include <vector>
8#include "core/file_sys/vfs.h" 12#include "core/file_sys/vfs.h"
9 13
10namespace FileSys { 14namespace FileSys {
@@ -13,7 +17,8 @@ namespace FileSys {
13template <std::size_t size> 17template <std::size_t size>
14class ArrayVfsFile : public VfsFile { 18class ArrayVfsFile : public VfsFile {
15public: 19public:
16 ArrayVfsFile(std::array<u8, size> data, std::string name = "", VirtualDir parent = nullptr) 20 explicit ArrayVfsFile(const std::array<u8, size>& data, std::string name = "",
21 VirtualDir parent = nullptr)
17 : data(data), name(std::move(name)), parent(std::move(parent)) {} 22 : data(data), name(std::move(name)), parent(std::move(parent)) {}
18 23
19 std::string GetName() const override { 24 std::string GetName() const override {
@@ -61,6 +66,12 @@ private:
61 VirtualDir parent; 66 VirtualDir parent;
62}; 67};
63 68
69template <std::size_t Size, typename... Args>
70std::shared_ptr<ArrayVfsFile<Size>> MakeArrayFile(const std::array<u8, Size>& data,
71 Args&&... args) {
72 return std::make_shared<ArrayVfsFile<Size>>(data, std::forward<Args>(args)...);
73}
74
64// An implementation of VfsFile that is backed by a vector optionally supplied upon construction 75// An implementation of VfsFile that is backed by a vector optionally supplied upon construction
65class VectorVfsFile : public VfsFile { 76class VectorVfsFile : public VfsFile {
66public: 77public:
diff --git a/src/core/frontend/emu_window.h b/src/core/frontend/emu_window.h
index 13aa14934..3e8780243 100644
--- a/src/core/frontend/emu_window.h
+++ b/src/core/frontend/emu_window.h
@@ -39,7 +39,7 @@ public:
39 39
40 class Scoped { 40 class Scoped {
41 public: 41 public:
42 explicit Scoped(GraphicsContext& context_) : context(context_) { 42 [[nodiscard]] explicit Scoped(GraphicsContext& context_) : context(context_) {
43 context.MakeCurrent(); 43 context.MakeCurrent();
44 } 44 }
45 ~Scoped() { 45 ~Scoped() {
@@ -52,7 +52,7 @@ public:
52 52
53 /// Calls MakeCurrent on the context and calls DoneCurrent when the scope for the returned value 53 /// Calls MakeCurrent on the context and calls DoneCurrent when the scope for the returned value
54 /// ends 54 /// ends
55 Scoped Acquire() { 55 [[nodiscard]] Scoped Acquire() {
56 return Scoped{*this}; 56 return Scoped{*this};
57 } 57 }
58}; 58};
diff --git a/src/core/hle/kernel/address_arbiter.cpp b/src/core/hle/kernel/address_arbiter.cpp
index df0debe1b..b882eaa0f 100644
--- a/src/core/hle/kernel/address_arbiter.cpp
+++ b/src/core/hle/kernel/address_arbiter.cpp
@@ -81,7 +81,7 @@ ResultCode AddressArbiter::IncrementAndSignalToAddressIfEqual(VAddr address, s32
81 do { 81 do {
82 current_value = monitor.ExclusiveRead32(current_core, address); 82 current_value = monitor.ExclusiveRead32(current_core, address);
83 83
84 if (current_value != value) { 84 if (current_value != static_cast<u32>(value)) {
85 return ERR_INVALID_STATE; 85 return ERR_INVALID_STATE;
86 } 86 }
87 current_value++; 87 current_value++;
diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp
index 9277b5d08..81f85643b 100644
--- a/src/core/hle/kernel/hle_ipc.cpp
+++ b/src/core/hle/kernel/hle_ipc.cpp
@@ -293,13 +293,15 @@ std::vector<u8> HLERequestContext::ReadBuffer(std::size_t buffer_index) const {
293 BufferDescriptorA()[buffer_index].Size()}; 293 BufferDescriptorA()[buffer_index].Size()};
294 294
295 if (is_buffer_a) { 295 if (is_buffer_a) {
296 ASSERT_OR_EXECUTE_MSG(BufferDescriptorA().size() > buffer_index, { return buffer; }, 296 ASSERT_OR_EXECUTE_MSG(
297 "BufferDescriptorA invalid buffer_index {}", buffer_index); 297 BufferDescriptorA().size() > buffer_index, { return buffer; },
298 "BufferDescriptorA invalid buffer_index {}", buffer_index);
298 buffer.resize(BufferDescriptorA()[buffer_index].Size()); 299 buffer.resize(BufferDescriptorA()[buffer_index].Size());
299 memory.ReadBlock(BufferDescriptorA()[buffer_index].Address(), buffer.data(), buffer.size()); 300 memory.ReadBlock(BufferDescriptorA()[buffer_index].Address(), buffer.data(), buffer.size());
300 } else { 301 } else {
301 ASSERT_OR_EXECUTE_MSG(BufferDescriptorX().size() > buffer_index, { return buffer; }, 302 ASSERT_OR_EXECUTE_MSG(
302 "BufferDescriptorX invalid buffer_index {}", buffer_index); 303 BufferDescriptorX().size() > buffer_index, { return buffer; },
304 "BufferDescriptorX invalid buffer_index {}", buffer_index);
303 buffer.resize(BufferDescriptorX()[buffer_index].Size()); 305 buffer.resize(BufferDescriptorX()[buffer_index].Size());
304 memory.ReadBlock(BufferDescriptorX()[buffer_index].Address(), buffer.data(), buffer.size()); 306 memory.ReadBlock(BufferDescriptorX()[buffer_index].Address(), buffer.data(), buffer.size());
305 } 307 }
@@ -324,16 +326,16 @@ std::size_t HLERequestContext::WriteBuffer(const void* buffer, std::size_t size,
324 } 326 }
325 327
326 if (is_buffer_b) { 328 if (is_buffer_b) {
327 ASSERT_OR_EXECUTE_MSG(BufferDescriptorB().size() > buffer_index && 329 ASSERT_OR_EXECUTE_MSG(
328 BufferDescriptorB()[buffer_index].Size() >= size, 330 BufferDescriptorB().size() > buffer_index &&
329 { return 0; }, "BufferDescriptorB is invalid, index={}, size={}", 331 BufferDescriptorB()[buffer_index].Size() >= size,
330 buffer_index, size); 332 { return 0; }, "BufferDescriptorB is invalid, index={}, size={}", buffer_index, size);
331 memory.WriteBlock(BufferDescriptorB()[buffer_index].Address(), buffer, size); 333 memory.WriteBlock(BufferDescriptorB()[buffer_index].Address(), buffer, size);
332 } else { 334 } else {
333 ASSERT_OR_EXECUTE_MSG(BufferDescriptorC().size() > buffer_index && 335 ASSERT_OR_EXECUTE_MSG(
334 BufferDescriptorC()[buffer_index].Size() >= size, 336 BufferDescriptorC().size() > buffer_index &&
335 { return 0; }, "BufferDescriptorC is invalid, index={}, size={}", 337 BufferDescriptorC()[buffer_index].Size() >= size,
336 buffer_index, size); 338 { return 0; }, "BufferDescriptorC is invalid, index={}, size={}", buffer_index, size);
337 memory.WriteBlock(BufferDescriptorC()[buffer_index].Address(), buffer, size); 339 memory.WriteBlock(BufferDescriptorC()[buffer_index].Address(), buffer, size);
338 } 340 }
339 341
@@ -344,12 +346,14 @@ std::size_t HLERequestContext::GetReadBufferSize(std::size_t buffer_index) const
344 const bool is_buffer_a{BufferDescriptorA().size() > buffer_index && 346 const bool is_buffer_a{BufferDescriptorA().size() > buffer_index &&
345 BufferDescriptorA()[buffer_index].Size()}; 347 BufferDescriptorA()[buffer_index].Size()};
346 if (is_buffer_a) { 348 if (is_buffer_a) {
347 ASSERT_OR_EXECUTE_MSG(BufferDescriptorA().size() > buffer_index, { return 0; }, 349 ASSERT_OR_EXECUTE_MSG(
348 "BufferDescriptorA invalid buffer_index {}", buffer_index); 350 BufferDescriptorA().size() > buffer_index, { return 0; },
351 "BufferDescriptorA invalid buffer_index {}", buffer_index);
349 return BufferDescriptorA()[buffer_index].Size(); 352 return BufferDescriptorA()[buffer_index].Size();
350 } else { 353 } else {
351 ASSERT_OR_EXECUTE_MSG(BufferDescriptorX().size() > buffer_index, { return 0; }, 354 ASSERT_OR_EXECUTE_MSG(
352 "BufferDescriptorX invalid buffer_index {}", buffer_index); 355 BufferDescriptorX().size() > buffer_index, { return 0; },
356 "BufferDescriptorX invalid buffer_index {}", buffer_index);
353 return BufferDescriptorX()[buffer_index].Size(); 357 return BufferDescriptorX()[buffer_index].Size();
354 } 358 }
355} 359}
@@ -358,12 +362,14 @@ std::size_t HLERequestContext::GetWriteBufferSize(std::size_t buffer_index) cons
358 const bool is_buffer_b{BufferDescriptorB().size() > buffer_index && 362 const bool is_buffer_b{BufferDescriptorB().size() > buffer_index &&
359 BufferDescriptorB()[buffer_index].Size()}; 363 BufferDescriptorB()[buffer_index].Size()};
360 if (is_buffer_b) { 364 if (is_buffer_b) {
361 ASSERT_OR_EXECUTE_MSG(BufferDescriptorB().size() > buffer_index, { return 0; }, 365 ASSERT_OR_EXECUTE_MSG(
362 "BufferDescriptorB invalid buffer_index {}", buffer_index); 366 BufferDescriptorB().size() > buffer_index, { return 0; },
367 "BufferDescriptorB invalid buffer_index {}", buffer_index);
363 return BufferDescriptorB()[buffer_index].Size(); 368 return BufferDescriptorB()[buffer_index].Size();
364 } else { 369 } else {
365 ASSERT_OR_EXECUTE_MSG(BufferDescriptorC().size() > buffer_index, { return 0; }, 370 ASSERT_OR_EXECUTE_MSG(
366 "BufferDescriptorC invalid buffer_index {}", buffer_index); 371 BufferDescriptorC().size() > buffer_index, { return 0; },
372 "BufferDescriptorC invalid buffer_index {}", buffer_index);
367 return BufferDescriptorC()[buffer_index].Size(); 373 return BufferDescriptorC()[buffer_index].Size();
368 } 374 }
369 return 0; 375 return 0;
diff --git a/src/core/hle/kernel/memory/page_table.cpp b/src/core/hle/kernel/memory/page_table.cpp
index 5d6aac00f..a3fadb533 100644
--- a/src/core/hle/kernel/memory/page_table.cpp
+++ b/src/core/hle/kernel/memory/page_table.cpp
@@ -604,7 +604,6 @@ ResultCode PageTable::MapPages(VAddr addr, const PageLinkedList& page_linked_lis
604 if (const auto result{ 604 if (const auto result{
605 Operate(cur_addr, node.GetNumPages(), perm, OperationType::Map, node.GetAddress())}; 605 Operate(cur_addr, node.GetNumPages(), perm, OperationType::Map, node.GetAddress())};
606 result.IsError()) { 606 result.IsError()) {
607 const MemoryInfo info{block_manager->FindBlock(cur_addr).GetMemoryInfo()};
608 const std::size_t num_pages{(addr - cur_addr) / PageSize}; 607 const std::size_t num_pages{(addr - cur_addr) / PageSize};
609 608
610 ASSERT( 609 ASSERT(
@@ -852,11 +851,12 @@ ResultCode PageTable::LockForDeviceAddressSpace(VAddr addr, std::size_t size) {
852 return result; 851 return result;
853 } 852 }
854 853
855 block_manager->UpdateLock(addr, size / PageSize, 854 block_manager->UpdateLock(
856 [](MemoryBlockManager::iterator block, MemoryPermission perm) { 855 addr, size / PageSize,
857 block->ShareToDevice(perm); 856 [](MemoryBlockManager::iterator block, MemoryPermission perm) {
858 }, 857 block->ShareToDevice(perm);
859 perm); 858 },
859 perm);
860 860
861 return RESULT_SUCCESS; 861 return RESULT_SUCCESS;
862} 862}
@@ -874,11 +874,12 @@ ResultCode PageTable::UnlockForDeviceAddressSpace(VAddr addr, std::size_t size)
874 return result; 874 return result;
875 } 875 }
876 876
877 block_manager->UpdateLock(addr, size / PageSize, 877 block_manager->UpdateLock(
878 [](MemoryBlockManager::iterator block, MemoryPermission perm) { 878 addr, size / PageSize,
879 block->UnshareToDevice(perm); 879 [](MemoryBlockManager::iterator block, MemoryPermission perm) {
880 }, 880 block->UnshareToDevice(perm);
881 perm); 881 },
882 perm);
882 883
883 return RESULT_SUCCESS; 884 return RESULT_SUCCESS;
884} 885}
diff --git a/src/core/hle/kernel/memory/system_control.cpp b/src/core/hle/kernel/memory/system_control.cpp
index 2f98e9c4c..11d204bc2 100644
--- a/src/core/hle/kernel/memory/system_control.cpp
+++ b/src/core/hle/kernel/memory/system_control.cpp
@@ -7,22 +7,15 @@
7#include "core/hle/kernel/memory/system_control.h" 7#include "core/hle/kernel/memory/system_control.h"
8 8
9namespace Kernel::Memory::SystemControl { 9namespace Kernel::Memory::SystemControl {
10 10namespace {
11u64 GenerateRandomU64ForInit() {
12 static std::random_device device;
13 static std::mt19937 gen(device());
14 static std::uniform_int_distribution<u64> distribution(1, std::numeric_limits<u64>::max());
15 return distribution(gen);
16}
17
18template <typename F> 11template <typename F>
19u64 GenerateUniformRange(u64 min, u64 max, F f) { 12u64 GenerateUniformRange(u64 min, u64 max, F f) {
20 /* Handle the case where the difference is too large to represent. */ 13 // Handle the case where the difference is too large to represent.
21 if (max == std::numeric_limits<u64>::max() && min == std::numeric_limits<u64>::min()) { 14 if (max == std::numeric_limits<u64>::max() && min == std::numeric_limits<u64>::min()) {
22 return f(); 15 return f();
23 } 16 }
24 17
25 /* Iterate until we get a value in range. */ 18 // Iterate until we get a value in range.
26 const u64 range_size = ((max + 1) - min); 19 const u64 range_size = ((max + 1) - min);
27 const u64 effective_max = (std::numeric_limits<u64>::max() / range_size) * range_size; 20 const u64 effective_max = (std::numeric_limits<u64>::max() / range_size) * range_size;
28 while (true) { 21 while (true) {
@@ -32,6 +25,14 @@ u64 GenerateUniformRange(u64 min, u64 max, F f) {
32 } 25 }
33} 26}
34 27
28u64 GenerateRandomU64ForInit() {
29 static std::random_device device;
30 static std::mt19937 gen(device());
31 static std::uniform_int_distribution<u64> distribution(1, std::numeric_limits<u64>::max());
32 return distribution(gen);
33}
34} // Anonymous namespace
35
35u64 GenerateRandomRange(u64 min, u64 max) { 36u64 GenerateRandomRange(u64 min, u64 max) {
36 return GenerateUniformRange(min, max, GenerateRandomU64ForInit); 37 return GenerateUniformRange(min, max, GenerateRandomU64ForInit);
37} 38}
diff --git a/src/core/hle/kernel/memory/system_control.h b/src/core/hle/kernel/memory/system_control.h
index 3fa93111d..19cab8cbc 100644
--- a/src/core/hle/kernel/memory/system_control.h
+++ b/src/core/hle/kernel/memory/system_control.h
@@ -8,11 +8,6 @@
8 8
9namespace Kernel::Memory::SystemControl { 9namespace Kernel::Memory::SystemControl {
10 10
11u64 GenerateRandomU64ForInit();
12
13template <typename F>
14u64 GenerateUniformRange(u64 min, u64 max, F f);
15
16u64 GenerateRandomRange(u64 min, u64 max); 11u64 GenerateRandomRange(u64 min, u64 max);
17 12
18} // namespace Kernel::Memory::SystemControl 13} // namespace Kernel::Memory::SystemControl
diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp
index f93e5e4b0..a4b234424 100644
--- a/src/core/hle/kernel/scheduler.cpp
+++ b/src/core/hle/kernel/scheduler.cpp
@@ -131,7 +131,8 @@ u32 GlobalScheduler::SelectThreads() {
131 u32 cores_needing_context_switch{}; 131 u32 cores_needing_context_switch{};
132 for (u32 core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) { 132 for (u32 core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) {
133 Scheduler& sched = kernel.Scheduler(core); 133 Scheduler& sched = kernel.Scheduler(core);
134 ASSERT(top_threads[core] == nullptr || top_threads[core]->GetProcessorID() == core); 134 ASSERT(top_threads[core] == nullptr ||
135 static_cast<u32>(top_threads[core]->GetProcessorID()) == core);
135 if (update_thread(top_threads[core], sched)) { 136 if (update_thread(top_threads[core], sched)) {
136 cores_needing_context_switch |= (1ul << core); 137 cores_needing_context_switch |= (1ul << core);
137 } 138 }
@@ -663,32 +664,26 @@ void Scheduler::Reload() {
663} 664}
664 665
665void Scheduler::SwitchContextStep2() { 666void Scheduler::SwitchContextStep2() {
666 Thread* previous_thread = current_thread_prev.get();
667 Thread* new_thread = selected_thread.get();
668
669 // Load context of new thread 667 // Load context of new thread
670 Process* const previous_process = 668 if (selected_thread) {
671 previous_thread != nullptr ? previous_thread->GetOwnerProcess() : nullptr; 669 ASSERT_MSG(selected_thread->GetSchedulingStatus() == ThreadSchedStatus::Runnable,
672
673 if (new_thread) {
674 ASSERT_MSG(new_thread->GetSchedulingStatus() == ThreadSchedStatus::Runnable,
675 "Thread must be runnable."); 670 "Thread must be runnable.");
676 671
677 // Cancel any outstanding wakeup events for this thread 672 // Cancel any outstanding wakeup events for this thread
678 new_thread->SetIsRunning(true); 673 selected_thread->SetIsRunning(true);
679 new_thread->last_running_ticks = system.CoreTiming().GetCPUTicks(); 674 selected_thread->last_running_ticks = system.CoreTiming().GetCPUTicks();
680 new_thread->SetWasRunning(false); 675 selected_thread->SetWasRunning(false);
681 676
682 auto* const thread_owner_process = current_thread->GetOwnerProcess(); 677 auto* const thread_owner_process = current_thread->GetOwnerProcess();
683 if (thread_owner_process != nullptr) { 678 if (thread_owner_process != nullptr) {
684 system.Kernel().MakeCurrentProcess(thread_owner_process); 679 system.Kernel().MakeCurrentProcess(thread_owner_process);
685 } 680 }
686 if (!new_thread->IsHLEThread()) { 681 if (!selected_thread->IsHLEThread()) {
687 Core::ARM_Interface& cpu_core = new_thread->ArmInterface(); 682 Core::ARM_Interface& cpu_core = selected_thread->ArmInterface();
688 cpu_core.LoadContext(new_thread->GetContext32()); 683 cpu_core.LoadContext(selected_thread->GetContext32());
689 cpu_core.LoadContext(new_thread->GetContext64()); 684 cpu_core.LoadContext(selected_thread->GetContext64());
690 cpu_core.SetTlsAddress(new_thread->GetTLSAddress()); 685 cpu_core.SetTlsAddress(selected_thread->GetTLSAddress());
691 cpu_core.SetTPIDR_EL0(new_thread->GetTPIDR_EL0()); 686 cpu_core.SetTPIDR_EL0(selected_thread->GetTPIDR_EL0());
692 cpu_core.ChangeProcessorID(this->core_id); 687 cpu_core.ChangeProcessorID(this->core_id);
693 cpu_core.ClearExclusiveState(); 688 cpu_core.ClearExclusiveState();
694 } 689 }
diff --git a/src/core/hle/kernel/scheduler.h b/src/core/hle/kernel/scheduler.h
index b3b4b5169..36e3c26fb 100644
--- a/src/core/hle/kernel/scheduler.h
+++ b/src/core/hle/kernel/scheduler.h
@@ -289,7 +289,7 @@ private:
289 289
290class SchedulerLock { 290class SchedulerLock {
291public: 291public:
292 explicit SchedulerLock(KernelCore& kernel); 292 [[nodiscard]] explicit SchedulerLock(KernelCore& kernel);
293 ~SchedulerLock(); 293 ~SchedulerLock();
294 294
295protected: 295protected:
diff --git a/src/core/hle/result.h b/src/core/hle/result.h
index 450f61fea..b6bdbd988 100644
--- a/src/core/hle/result.h
+++ b/src/core/hle/result.h
@@ -342,8 +342,9 @@ ResultVal<std::remove_reference_t<Arg>> MakeResult(Arg&& arg) {
342 */ 342 */
343#define CASCADE_RESULT(target, source) \ 343#define CASCADE_RESULT(target, source) \
344 auto CONCAT2(check_result_L, __LINE__) = source; \ 344 auto CONCAT2(check_result_L, __LINE__) = source; \
345 if (CONCAT2(check_result_L, __LINE__).Failed()) \ 345 if (CONCAT2(check_result_L, __LINE__).Failed()) { \
346 return CONCAT2(check_result_L, __LINE__).Code(); \ 346 return CONCAT2(check_result_L, __LINE__).Code(); \
347 } \
347 target = std::move(*CONCAT2(check_result_L, __LINE__)) 348 target = std::move(*CONCAT2(check_result_L, __LINE__))
348 349
349/** 350/**
@@ -351,6 +352,9 @@ ResultVal<std::remove_reference_t<Arg>> MakeResult(Arg&& arg) {
351 * non-success, or discarded otherwise. 352 * non-success, or discarded otherwise.
352 */ 353 */
353#define CASCADE_CODE(source) \ 354#define CASCADE_CODE(source) \
354 auto CONCAT2(check_result_L, __LINE__) = source; \ 355 do { \
355 if (CONCAT2(check_result_L, __LINE__).IsError()) \ 356 auto CONCAT2(check_result_L, __LINE__) = source; \
356 return CONCAT2(check_result_L, __LINE__); 357 if (CONCAT2(check_result_L, __LINE__).IsError()) { \
358 return CONCAT2(check_result_L, __LINE__); \
359 } \
360 } while (false)
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp
index 55a1edf1a..7d92b25a3 100644
--- a/src/core/hle/service/am/am.cpp
+++ b/src/core/hle/service/am/am.cpp
@@ -378,7 +378,11 @@ void ISelfController::GetLibraryAppletLaunchableEvent(Kernel::HLERequestContext&
378} 378}
379 379
380void ISelfController::SetScreenShotPermission(Kernel::HLERequestContext& ctx) { 380void ISelfController::SetScreenShotPermission(Kernel::HLERequestContext& ctx) {
381 LOG_WARNING(Service_AM, "(STUBBED) called"); 381 IPC::RequestParser rp{ctx};
382 const auto permission = rp.PopEnum<ScreenshotPermission>();
383 LOG_DEBUG(Service_AM, "called, permission={}", permission);
384
385 screenshot_permission = permission;
382 386
383 IPC::ResponseBuilder rb{ctx, 2}; 387 IPC::ResponseBuilder rb{ctx, 2};
384 rb.Push(RESULT_SUCCESS); 388 rb.Push(RESULT_SUCCESS);
diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h
index 6cfb11b48..6e69796ec 100644
--- a/src/core/hle/service/am/am.h
+++ b/src/core/hle/service/am/am.h
@@ -149,6 +149,12 @@ private:
149 void GetAccumulatedSuspendedTickValue(Kernel::HLERequestContext& ctx); 149 void GetAccumulatedSuspendedTickValue(Kernel::HLERequestContext& ctx);
150 void GetAccumulatedSuspendedTickChangedEvent(Kernel::HLERequestContext& ctx); 150 void GetAccumulatedSuspendedTickChangedEvent(Kernel::HLERequestContext& ctx);
151 151
152 enum class ScreenshotPermission : u32 {
153 Inherit = 0,
154 Enable = 1,
155 Disable = 2,
156 };
157
152 Core::System& system; 158 Core::System& system;
153 std::shared_ptr<NVFlinger::NVFlinger> nvflinger; 159 std::shared_ptr<NVFlinger::NVFlinger> nvflinger;
154 Kernel::EventPair launchable_event; 160 Kernel::EventPair launchable_event;
@@ -157,6 +163,7 @@ private:
157 u32 idle_time_detection_extension = 0; 163 u32 idle_time_detection_extension = 0;
158 u64 num_fatal_sections_entered = 0; 164 u64 num_fatal_sections_entered = 0;
159 bool is_auto_sleep_disabled = false; 165 bool is_auto_sleep_disabled = false;
166 ScreenshotPermission screenshot_permission = ScreenshotPermission::Inherit;
160}; 167};
161 168
162class ICommonStateGetter final : public ServiceFramework<ICommonStateGetter> { 169class ICommonStateGetter final : public ServiceFramework<ICommonStateGetter> {
diff --git a/src/core/hle/service/am/applets/software_keyboard.cpp b/src/core/hle/service/am/applets/software_keyboard.cpp
index 289da2619..bdeb0737a 100644
--- a/src/core/hle/service/am/applets/software_keyboard.cpp
+++ b/src/core/hle/service/am/applets/software_keyboard.cpp
@@ -122,8 +122,7 @@ void SoftwareKeyboard::ExecuteInteractive() {
122 122
123 switch (request) { 123 switch (request) {
124 case Request::Calc: { 124 case Request::Calc: {
125 broker.PushNormalDataFromApplet( 125 broker.PushNormalDataFromApplet(std::make_shared<IStorage>(std::vector<u8>{1}));
126 std::make_shared<IStorage>(std::move(std::vector<u8>{1})));
127 broker.SignalStateChanged(); 126 broker.SignalStateChanged();
128 break; 127 break;
129 } 128 }
diff --git a/src/core/hle/service/am/applets/web_browser.cpp b/src/core/hle/service/am/applets/web_browser.cpp
index 9f30e167d..4157fbf39 100644
--- a/src/core/hle/service/am/applets/web_browser.cpp
+++ b/src/core/hle/service/am/applets/web_browser.cpp
@@ -551,7 +551,8 @@ void WebBrowser::ExecuteShop() {
551} 551}
552 552
553void WebBrowser::ExecuteOffline() { 553void WebBrowser::ExecuteOffline() {
554 frontend.OpenPageLocal(filename, [this] { UnpackRomFS(); }, [this] { Finalize(); }); 554 frontend.OpenPageLocal(
555 filename, [this] { UnpackRomFS(); }, [this] { Finalize(); });
555} 556}
556 557
557} // namespace Service::AM::Applets 558} // namespace Service::AM::Applets
diff --git a/src/core/hle/service/audio/audout_u.cpp b/src/core/hle/service/audio/audout_u.cpp
index dd80dd1dc..9b4910e53 100644
--- a/src/core/hle/service/audio/audout_u.cpp
+++ b/src/core/hle/service/audio/audout_u.cpp
@@ -206,7 +206,7 @@ private:
206 AudioCore::StreamPtr stream; 206 AudioCore::StreamPtr stream;
207 std::string device_name; 207 std::string device_name;
208 208
209 [[maybe_unused]] AudoutParams audio_params {}; 209 [[maybe_unused]] AudoutParams audio_params{};
210 210
211 /// This is the event handle used to check if the audio buffer was released 211 /// This is the event handle used to check if the audio buffer was released
212 Kernel::EventPair buffer_event; 212 Kernel::EventPair buffer_event;
diff --git a/src/core/hle/service/bcat/backend/boxcat.cpp b/src/core/hle/service/bcat/backend/boxcat.cpp
index d29e78d7e..51c2ba964 100644
--- a/src/core/hle/service/bcat/backend/boxcat.cpp
+++ b/src/core/hle/service/bcat/backend/boxcat.cpp
@@ -365,8 +365,7 @@ bool Boxcat::Synchronize(TitleIDVersion title, ProgressServiceBackend& progress)
365 365
366 std::thread([this, title, &progress] { 366 std::thread([this, title, &progress] {
367 SynchronizeInternal(applet_manager, dir_getter, title, progress); 367 SynchronizeInternal(applet_manager, dir_getter, title, progress);
368 }) 368 }).detach();
369 .detach();
370 369
371 return true; 370 return true;
372} 371}
@@ -377,8 +376,7 @@ bool Boxcat::SynchronizeDirectory(TitleIDVersion title, std::string name,
377 376
378 std::thread([this, title, name, &progress] { 377 std::thread([this, title, name, &progress] {
379 SynchronizeInternal(applet_manager, dir_getter, title, progress, name); 378 SynchronizeInternal(applet_manager, dir_getter, title, progress, name);
380 }) 379 }).detach();
381 .detach();
382 380
383 return true; 381 return true;
384} 382}
diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp
index ef67ad690..0e7794dc7 100644
--- a/src/core/hle/service/hid/controllers/npad.cpp
+++ b/src/core/hle/service/hid/controllers/npad.cpp
@@ -90,7 +90,7 @@ u32 Controller_NPad::IndexToNPad(std::size_t index) {
90 default: 90 default:
91 UNIMPLEMENTED_MSG("Unknown npad index {}", index); 91 UNIMPLEMENTED_MSG("Unknown npad index {}", index);
92 return 0; 92 return 0;
93 }; 93 }
94} 94}
95 95
96Controller_NPad::Controller_NPad(Core::System& system) : ControllerBase(system), system(system) {} 96Controller_NPad::Controller_NPad(Core::System& system) : ControllerBase(system), system(system) {}
@@ -630,7 +630,7 @@ Controller_NPad::LedPattern Controller_NPad::GetLedPattern(u32 npad_id) {
630 default: 630 default:
631 UNIMPLEMENTED_MSG("Unhandled npad_id {}", npad_id); 631 UNIMPLEMENTED_MSG("Unhandled npad_id {}", npad_id);
632 return LedPattern{0, 0, 0, 0}; 632 return LedPattern{0, 0, 0, 0};
633 }; 633 }
634} 634}
635 635
636void Controller_NPad::SetVibrationEnabled(bool can_vibrate) { 636void Controller_NPad::SetVibrationEnabled(bool can_vibrate) {
diff --git a/src/core/hle/service/nvdrv/devices/nvdevice.h b/src/core/hle/service/nvdrv/devices/nvdevice.h
index 1b52511a5..0240d6643 100644
--- a/src/core/hle/service/nvdrv/devices/nvdevice.h
+++ b/src/core/hle/service/nvdrv/devices/nvdevice.h
@@ -21,8 +21,9 @@ namespace Service::Nvidia::Devices {
21/// implement the ioctl interface. 21/// implement the ioctl interface.
22class nvdevice { 22class nvdevice {
23public: 23public:
24 explicit nvdevice(Core::System& system) : system{system} {}; 24 explicit nvdevice(Core::System& system) : system{system} {}
25 virtual ~nvdevice() = default; 25 virtual ~nvdevice() = default;
26
26 union Ioctl { 27 union Ioctl {
27 u32_le raw; 28 u32_le raw;
28 BitField<0, 8, u32> cmd; 29 BitField<0, 8, u32> cmd;
diff --git a/src/core/hle/service/nvflinger/nvflinger.h b/src/core/hle/service/nvflinger/nvflinger.h
index ff85cbba6..1ebe949c0 100644
--- a/src/core/hle/service/nvflinger/nvflinger.h
+++ b/src/core/hle/service/nvflinger/nvflinger.h
@@ -86,11 +86,13 @@ public:
86 86
87 [[nodiscard]] s64 GetNextTicks() const; 87 [[nodiscard]] s64 GetNextTicks() const;
88 88
89 [[nodiscard]] std::unique_lock<std::mutex> Lock() const { return std::unique_lock{*guard}; } 89 [[nodiscard]] std::unique_lock<std::mutex> Lock() const {
90 return std::unique_lock{*guard};
91 }
90 92
91 private : 93private:
92 /// Finds the display identified by the specified ID. 94 /// Finds the display identified by the specified ID.
93 [[nodiscard]] VI::Display* FindDisplay(u64 display_id); 95 [[nodiscard]] VI::Display* FindDisplay(u64 display_id);
94 96
95 /// Finds the display identified by the specified ID. 97 /// Finds the display identified by the specified ID.
96 [[nodiscard]] const VI::Display* FindDisplay(u64 display_id) const; 98 [[nodiscard]] const VI::Display* FindDisplay(u64 display_id) const;
diff --git a/src/core/hle/service/sm/sm.h b/src/core/hle/service/sm/sm.h
index b526a94fe..aabf166b7 100644
--- a/src/core/hle/service/sm/sm.h
+++ b/src/core/hle/service/sm/sm.h
@@ -57,7 +57,7 @@ public:
57 ResultVal<std::shared_ptr<Kernel::ClientPort>> GetServicePort(const std::string& name); 57 ResultVal<std::shared_ptr<Kernel::ClientPort>> GetServicePort(const std::string& name);
58 ResultVal<std::shared_ptr<Kernel::ClientSession>> ConnectToService(const std::string& name); 58 ResultVal<std::shared_ptr<Kernel::ClientSession>> ConnectToService(const std::string& name);
59 59
60 template <Common::IsBaseOf<Kernel::SessionRequestHandler> T> 60 template <Common::DerivedFrom<Kernel::SessionRequestHandler> T>
61 std::shared_ptr<T> GetService(const std::string& service_name) const { 61 std::shared_ptr<T> GetService(const std::string& service_name) const {
62 auto service = registered_services.find(service_name); 62 auto service = registered_services.find(service_name);
63 if (service == registered_services.end()) { 63 if (service == registered_services.end()) {
diff --git a/src/core/hle/service/time/time_zone_content_manager.cpp b/src/core/hle/service/time/time_zone_content_manager.cpp
index c070d6e97..320672add 100644
--- a/src/core/hle/service/time/time_zone_content_manager.cpp
+++ b/src/core/hle/service/time/time_zone_content_manager.cpp
@@ -73,10 +73,8 @@ TimeZoneContentManager::TimeZoneContentManager(TimeManager& time_manager, Core::
73 73
74 std::string location_name; 74 std::string location_name;
75 const auto timezone_setting = Settings::GetTimeZoneString(); 75 const auto timezone_setting = Settings::GetTimeZoneString();
76 if (timezone_setting == "auto") { 76 if (timezone_setting == "auto" || timezone_setting == "default") {
77 location_name = Common::TimeZone::GetDefaultTimeZone(); 77 location_name = Common::TimeZone::GetDefaultTimeZone();
78 } else if (timezone_setting == "default") {
79 location_name = location_name;
80 } else { 78 } else {
81 location_name = timezone_setting; 79 location_name = timezone_setting;
82 } 80 }
diff --git a/src/core/loader/loader.cpp b/src/core/loader/loader.cpp
index b8f8f1448..7c48e55e1 100644
--- a/src/core/loader/loader.cpp
+++ b/src/core/loader/loader.cpp
@@ -25,7 +25,7 @@ namespace Loader {
25 25
26namespace { 26namespace {
27 27
28template <Common::IsBaseOf<AppLoader> T> 28template <Common::DerivedFrom<AppLoader> T>
29std::optional<FileType> IdentifyFileLoader(FileSys::VirtualFile file) { 29std::optional<FileType> IdentifyFileLoader(FileSys::VirtualFile file) {
30 const auto file_type = T::IdentifyType(file); 30 const auto file_type = T::IdentifyType(file);
31 if (file_type != FileType::Error) { 31 if (file_type != FileType::Error) {
diff --git a/src/core/memory/cheat_engine.cpp b/src/core/memory/cheat_engine.cpp
index eeebdf02e..e503118dd 100644
--- a/src/core/memory/cheat_engine.cpp
+++ b/src/core/memory/cheat_engine.cpp
@@ -42,7 +42,7 @@ u64 StandardVmCallbacks::HidKeysDown() {
42 if (applet_resource == nullptr) { 42 if (applet_resource == nullptr) {
43 LOG_WARNING(CheatEngine, 43 LOG_WARNING(CheatEngine,
44 "Attempted to read input state, but applet resource is not initialized!"); 44 "Attempted to read input state, but applet resource is not initialized!");
45 return false; 45 return 0;
46 } 46 }
47 47
48 const auto press_state = 48 const auto press_state =
@@ -199,17 +199,29 @@ void CheatEngine::Initialize() {
199 metadata.title_id = system.CurrentProcess()->GetTitleID(); 199 metadata.title_id = system.CurrentProcess()->GetTitleID();
200 200
201 const auto& page_table = system.CurrentProcess()->PageTable(); 201 const auto& page_table = system.CurrentProcess()->PageTable();
202 metadata.heap_extents = {page_table.GetHeapRegionStart(), page_table.GetHeapRegionSize()}; 202 metadata.heap_extents = {
203 metadata.address_space_extents = {page_table.GetAddressSpaceStart(), 203 .base = page_table.GetHeapRegionStart(),
204 page_table.GetAddressSpaceSize()}; 204 .size = page_table.GetHeapRegionSize(),
205 metadata.alias_extents = {page_table.GetAliasCodeRegionStart(), 205 };
206 page_table.GetAliasCodeRegionSize()}; 206
207 metadata.address_space_extents = {
208 .base = page_table.GetAddressSpaceStart(),
209 .size = page_table.GetAddressSpaceSize(),
210 };
211
212 metadata.alias_extents = {
213 .base = page_table.GetAliasCodeRegionStart(),
214 .size = page_table.GetAliasCodeRegionSize(),
215 };
207 216
208 is_pending_reload.exchange(true); 217 is_pending_reload.exchange(true);
209} 218}
210 219
211void CheatEngine::SetMainMemoryParameters(VAddr main_region_begin, u64 main_region_size) { 220void CheatEngine::SetMainMemoryParameters(VAddr main_region_begin, u64 main_region_size) {
212 metadata.main_nso_extents = {main_region_begin, main_region_size}; 221 metadata.main_nso_extents = {
222 .base = main_region_begin,
223 .size = main_region_size,
224 };
213} 225}
214 226
215void CheatEngine::Reload(std::vector<CheatEntry> cheats) { 227void CheatEngine::Reload(std::vector<CheatEntry> cheats) {
diff --git a/src/core/tools/freezer.cpp b/src/core/tools/freezer.cpp
index 2003e096f..5c674a099 100644
--- a/src/core/tools/freezer.cpp
+++ b/src/core/tools/freezer.cpp
@@ -107,28 +107,21 @@ void Freezer::Unfreeze(VAddr address) {
107 107
108 LOG_DEBUG(Common_Memory, "Unfreezing memory for address={:016X}", address); 108 LOG_DEBUG(Common_Memory, "Unfreezing memory for address={:016X}", address);
109 109
110 entries.erase( 110 std::erase_if(entries, [address](const Entry& entry) { return entry.address == address; });
111 std::remove_if(entries.begin(), entries.end(),
112 [&address](const Entry& entry) { return entry.address == address; }),
113 entries.end());
114} 111}
115 112
116bool Freezer::IsFrozen(VAddr address) const { 113bool Freezer::IsFrozen(VAddr address) const {
117 std::lock_guard lock{entries_mutex}; 114 std::lock_guard lock{entries_mutex};
118 115
119 return std::find_if(entries.begin(), entries.end(), [&address](const Entry& entry) { 116 return FindEntry(address) != entries.cend();
120 return entry.address == address;
121 }) != entries.end();
122} 117}
123 118
124void Freezer::SetFrozenValue(VAddr address, u64 value) { 119void Freezer::SetFrozenValue(VAddr address, u64 value) {
125 std::lock_guard lock{entries_mutex}; 120 std::lock_guard lock{entries_mutex};
126 121
127 const auto iter = std::find_if(entries.begin(), entries.end(), [&address](const Entry& entry) { 122 const auto iter = FindEntry(address);
128 return entry.address == address;
129 });
130 123
131 if (iter == entries.end()) { 124 if (iter == entries.cend()) {
132 LOG_ERROR(Common_Memory, 125 LOG_ERROR(Common_Memory,
133 "Tried to set freeze value for address={:016X} that is not frozen!", address); 126 "Tried to set freeze value for address={:016X} that is not frozen!", address);
134 return; 127 return;
@@ -143,11 +136,9 @@ void Freezer::SetFrozenValue(VAddr address, u64 value) {
143std::optional<Freezer::Entry> Freezer::GetEntry(VAddr address) const { 136std::optional<Freezer::Entry> Freezer::GetEntry(VAddr address) const {
144 std::lock_guard lock{entries_mutex}; 137 std::lock_guard lock{entries_mutex};
145 138
146 const auto iter = std::find_if(entries.begin(), entries.end(), [&address](const Entry& entry) { 139 const auto iter = FindEntry(address);
147 return entry.address == address;
148 });
149 140
150 if (iter == entries.end()) { 141 if (iter == entries.cend()) {
151 return std::nullopt; 142 return std::nullopt;
152 } 143 }
153 144
@@ -160,6 +151,16 @@ std::vector<Freezer::Entry> Freezer::GetEntries() const {
160 return entries; 151 return entries;
161} 152}
162 153
154Freezer::Entries::iterator Freezer::FindEntry(VAddr address) {
155 return std::find_if(entries.begin(), entries.end(),
156 [address](const Entry& entry) { return entry.address == address; });
157}
158
159Freezer::Entries::const_iterator Freezer::FindEntry(VAddr address) const {
160 return std::find_if(entries.begin(), entries.end(),
161 [address](const Entry& entry) { return entry.address == address; });
162}
163
163void Freezer::FrameCallback(std::uintptr_t, std::chrono::nanoseconds ns_late) { 164void Freezer::FrameCallback(std::uintptr_t, std::chrono::nanoseconds ns_late) {
164 if (!IsActive()) { 165 if (!IsActive()) {
165 LOG_DEBUG(Common_Memory, "Memory freezer has been deactivated, ending callback events."); 166 LOG_DEBUG(Common_Memory, "Memory freezer has been deactivated, ending callback events.");
diff --git a/src/core/tools/freezer.h b/src/core/tools/freezer.h
index 2b2326bc4..0fdb701a7 100644
--- a/src/core/tools/freezer.h
+++ b/src/core/tools/freezer.h
@@ -73,13 +73,18 @@ public:
73 std::vector<Entry> GetEntries() const; 73 std::vector<Entry> GetEntries() const;
74 74
75private: 75private:
76 using Entries = std::vector<Entry>;
77
78 Entries::iterator FindEntry(VAddr address);
79 Entries::const_iterator FindEntry(VAddr address) const;
80
76 void FrameCallback(std::uintptr_t user_data, std::chrono::nanoseconds ns_late); 81 void FrameCallback(std::uintptr_t user_data, std::chrono::nanoseconds ns_late);
77 void FillEntryReads(); 82 void FillEntryReads();
78 83
79 std::atomic_bool active{false}; 84 std::atomic_bool active{false};
80 85
81 mutable std::mutex entries_mutex; 86 mutable std::mutex entries_mutex;
82 std::vector<Entry> entries; 87 Entries entries;
83 88
84 std::shared_ptr<Core::Timing::EventType> event; 89 std::shared_ptr<Core::Timing::EventType> event;
85 Core::Timing::CoreTiming& core_timing; 90 Core::Timing::CoreTiming& core_timing;
diff --git a/src/input_common/gcadapter/gc_poller.cpp b/src/input_common/gcadapter/gc_poller.cpp
index f45983f3f..b346fdf8e 100644
--- a/src/input_common/gcadapter/gc_poller.cpp
+++ b/src/input_common/gcadapter/gc_poller.cpp
@@ -148,19 +148,17 @@ void GCButtonFactory::EndConfiguration() {
148 148
149class GCAnalog final : public Input::AnalogDevice { 149class GCAnalog final : public Input::AnalogDevice {
150public: 150public:
151 GCAnalog(int port_, int axis_x_, int axis_y_, float deadzone_, GCAdapter::Adapter* adapter) 151 GCAnalog(int port_, int axis_x_, int axis_y_, float deadzone_, GCAdapter::Adapter* adapter,
152 float range_)
152 : port(port_), axis_x(axis_x_), axis_y(axis_y_), deadzone(deadzone_), gcadapter(adapter), 153 : port(port_), axis_x(axis_x_), axis_y(axis_y_), deadzone(deadzone_), gcadapter(adapter),
153 origin_value_x(adapter->GetOriginValue(port_, axis_x_)), 154 origin_value_x(adapter->GetOriginValue(port_, axis_x_)),
154 origin_value_y(adapter->GetOriginValue(port_, axis_y_)) {} 155 origin_value_y(adapter->GetOriginValue(port_, axis_y_)), range(range_) {}
155 156
156 float GetAxis(int axis) const { 157 float GetAxis(int axis) const {
157 if (gcadapter->DeviceConnected(port)) { 158 if (gcadapter->DeviceConnected(port)) {
158 std::lock_guard lock{mutex}; 159 std::lock_guard lock{mutex};
159 const auto origin_value = axis % 2 == 0 ? origin_value_x : origin_value_y; 160 const auto origin_value = axis % 2 == 0 ? origin_value_x : origin_value_y;
160 // division is not by a perfect 128 to account for some variance in center location 161 return (gcadapter->GetPadState()[port].axes.at(axis) - origin_value) / (100.0f * range);
161 // e.g. my device idled at 131 in X, 120 in Y, and full range of motion was in range
162 // [20-230]
163 return (gcadapter->GetPadState()[port].axes.at(axis) - origin_value) / 95.0f;
164 } 162 }
165 return 0.0f; 163 return 0.0f;
166 } 164 }
@@ -215,6 +213,7 @@ private:
215 GCAdapter::Adapter* gcadapter; 213 GCAdapter::Adapter* gcadapter;
216 const float origin_value_x; 214 const float origin_value_x;
217 const float origin_value_y; 215 const float origin_value_y;
216 const float range;
218 mutable std::mutex mutex; 217 mutable std::mutex mutex;
219}; 218};
220 219
@@ -234,8 +233,9 @@ std::unique_ptr<Input::AnalogDevice> GCAnalogFactory::Create(const Common::Param
234 const int axis_x = params.Get("axis_x", 0); 233 const int axis_x = params.Get("axis_x", 0);
235 const int axis_y = params.Get("axis_y", 1); 234 const int axis_y = params.Get("axis_y", 1);
236 const float deadzone = std::clamp(params.Get("deadzone", 0.0f), 0.0f, .99f); 235 const float deadzone = std::clamp(params.Get("deadzone", 0.0f), 0.0f, .99f);
236 const float range = std::clamp(params.Get("range", 1.0f), 0.50f, 1.50f);
237 237
238 return std::make_unique<GCAnalog>(port, axis_x, axis_y, deadzone, adapter.get()); 238 return std::make_unique<GCAnalog>(port, axis_x, axis_y, deadzone, adapter.get(), range);
239} 239}
240 240
241void GCAnalogFactory::BeginConfiguration() { 241void GCAnalogFactory::BeginConfiguration() {
diff --git a/src/input_common/sdl/sdl_impl.cpp b/src/input_common/sdl/sdl_impl.cpp
index 675b477fa..d76c279d3 100644
--- a/src/input_common/sdl/sdl_impl.cpp
+++ b/src/input_common/sdl/sdl_impl.cpp
@@ -66,14 +66,14 @@ public:
66 state.axes.insert_or_assign(axis, value); 66 state.axes.insert_or_assign(axis, value);
67 } 67 }
68 68
69 float GetAxis(int axis) const { 69 float GetAxis(int axis, float range) const {
70 std::lock_guard lock{mutex}; 70 std::lock_guard lock{mutex};
71 return state.axes.at(axis) / 32767.0f; 71 return state.axes.at(axis) / (32767.0f * range);
72 } 72 }
73 73
74 std::tuple<float, float> GetAnalog(int axis_x, int axis_y) const { 74 std::tuple<float, float> GetAnalog(int axis_x, int axis_y, float range) const {
75 float x = GetAxis(axis_x); 75 float x = GetAxis(axis_x, range);
76 float y = GetAxis(axis_y); 76 float y = GetAxis(axis_y, range);
77 y = -y; // 3DS uses an y-axis inverse from SDL 77 y = -y; // 3DS uses an y-axis inverse from SDL
78 78
79 // Make sure the coordinates are in the unit circle, 79 // Make sure the coordinates are in the unit circle,
@@ -313,7 +313,7 @@ public:
313 trigger_if_greater(trigger_if_greater_) {} 313 trigger_if_greater(trigger_if_greater_) {}
314 314
315 bool GetStatus() const override { 315 bool GetStatus() const override {
316 const float axis_value = joystick->GetAxis(axis); 316 const float axis_value = joystick->GetAxis(axis, 1.0f);
317 if (trigger_if_greater) { 317 if (trigger_if_greater) {
318 return axis_value > threshold; 318 return axis_value > threshold;
319 } 319 }
@@ -329,11 +329,13 @@ private:
329 329
330class SDLAnalog final : public Input::AnalogDevice { 330class SDLAnalog final : public Input::AnalogDevice {
331public: 331public:
332 SDLAnalog(std::shared_ptr<SDLJoystick> joystick_, int axis_x_, int axis_y_, float deadzone_) 332 SDLAnalog(std::shared_ptr<SDLJoystick> joystick_, int axis_x_, int axis_y_, float deadzone_,
333 : joystick(std::move(joystick_)), axis_x(axis_x_), axis_y(axis_y_), deadzone(deadzone_) {} 333 float range_)
334 : joystick(std::move(joystick_)), axis_x(axis_x_), axis_y(axis_y_), deadzone(deadzone_),
335 range(range_) {}
334 336
335 std::tuple<float, float> GetStatus() const override { 337 std::tuple<float, float> GetStatus() const override {
336 const auto [x, y] = joystick->GetAnalog(axis_x, axis_y); 338 const auto [x, y] = joystick->GetAnalog(axis_x, axis_y, range);
337 const float r = std::sqrt((x * x) + (y * y)); 339 const float r = std::sqrt((x * x) + (y * y));
338 if (r > deadzone) { 340 if (r > deadzone) {
339 return std::make_tuple(x / r * (r - deadzone) / (1 - deadzone), 341 return std::make_tuple(x / r * (r - deadzone) / (1 - deadzone),
@@ -363,6 +365,7 @@ private:
363 const int axis_x; 365 const int axis_x;
364 const int axis_y; 366 const int axis_y;
365 const float deadzone; 367 const float deadzone;
368 const float range;
366}; 369};
367 370
368/// A button device factory that creates button devices from SDL joystick 371/// A button device factory that creates button devices from SDL joystick
@@ -458,13 +461,13 @@ public:
458 const int axis_x = params.Get("axis_x", 0); 461 const int axis_x = params.Get("axis_x", 0);
459 const int axis_y = params.Get("axis_y", 1); 462 const int axis_y = params.Get("axis_y", 1);
460 const float deadzone = std::clamp(params.Get("deadzone", 0.0f), 0.0f, .99f); 463 const float deadzone = std::clamp(params.Get("deadzone", 0.0f), 0.0f, .99f);
461 464 const float range = std::clamp(params.Get("range", 1.0f), 0.50f, 1.50f);
462 auto joystick = state.GetSDLJoystickByGUID(guid, port); 465 auto joystick = state.GetSDLJoystickByGUID(guid, port);
463 466
464 // This is necessary so accessing GetAxis with axis_x and axis_y won't crash 467 // This is necessary so accessing GetAxis with axis_x and axis_y won't crash
465 joystick->SetAxis(axis_x, 0); 468 joystick->SetAxis(axis_x, 0);
466 joystick->SetAxis(axis_y, 0); 469 joystick->SetAxis(axis_y, 0);
467 return std::make_unique<SDLAnalog>(joystick, axis_x, axis_y, deadzone); 470 return std::make_unique<SDLAnalog>(joystick, axis_x, axis_y, deadzone, range);
468 } 471 }
469 472
470private: 473private:
diff --git a/src/input_common/udp/client.cpp b/src/input_common/udp/client.cpp
index 6c95a8b42..3f4eaf448 100644
--- a/src/input_common/udp/client.cpp
+++ b/src/input_common/udp/client.cpp
@@ -224,8 +224,7 @@ void TestCommunication(const std::string& host, u16 port, u8 pad_index, u32 clie
224 } else { 224 } else {
225 failure_callback(); 225 failure_callback();
226 } 226 }
227 }) 227 }).detach();
228 .detach();
229} 228}
230 229
231CalibrationConfigurationJob::CalibrationConfigurationJob( 230CalibrationConfigurationJob::CalibrationConfigurationJob(
@@ -279,8 +278,7 @@ CalibrationConfigurationJob::CalibrationConfigurationJob(
279 complete_event.Wait(); 278 complete_event.Wait();
280 socket.Stop(); 279 socket.Stop();
281 worker_thread.join(); 280 worker_thread.join();
282 }) 281 }).detach();
283 .detach();
284} 282}
285 283
286CalibrationConfigurationJob::~CalibrationConfigurationJob() { 284CalibrationConfigurationJob::~CalibrationConfigurationJob() {
diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h
index ef1618990..c97eeb792 100644
--- a/src/video_core/engines/maxwell_3d.h
+++ b/src/video_core/engines/maxwell_3d.h
@@ -647,7 +647,7 @@ public:
647 GetX() + GetWidth(), // right 647 GetX() + GetWidth(), // right
648 GetY() // bottom 648 GetY() // bottom
649 }; 649 };
650 }; 650 }
651 651
652 f32 GetX() const { 652 f32 GetX() const {
653 return std::max(0.0f, translate_x - std::fabs(scale_x)); 653 return std::max(0.0f, translate_x - std::fabs(scale_x));
diff --git a/src/video_core/engines/maxwell_dma.cpp b/src/video_core/engines/maxwell_dma.cpp
index a2d3d7823..e88290754 100644
--- a/src/video_core/engines/maxwell_dma.cpp
+++ b/src/video_core/engines/maxwell_dma.cpp
@@ -94,7 +94,8 @@ void MaxwellDMA::CopyPitchToPitch() {
94} 94}
95 95
96void MaxwellDMA::CopyBlockLinearToPitch() { 96void MaxwellDMA::CopyBlockLinearToPitch() {
97 ASSERT(regs.src_params.block_size.depth == 0); 97 UNIMPLEMENTED_IF(regs.src_params.block_size.depth != 0);
98 UNIMPLEMENTED_IF(regs.src_params.layer != 0);
98 99
99 // Optimized path for micro copies. 100 // Optimized path for micro copies.
100 const size_t dst_size = static_cast<size_t>(regs.pitch_out) * regs.line_count; 101 const size_t dst_size = static_cast<size_t>(regs.pitch_out) * regs.line_count;
@@ -123,17 +124,12 @@ void MaxwellDMA::CopyBlockLinearToPitch() {
123 write_buffer.resize(dst_size); 124 write_buffer.resize(dst_size);
124 } 125 }
125 126
126 if (Settings::IsGPULevelExtreme()) { 127 memory_manager.ReadBlock(regs.offset_in, read_buffer.data(), src_size);
127 memory_manager.ReadBlock(regs.offset_in, read_buffer.data(), src_size); 128 memory_manager.ReadBlock(regs.offset_out, write_buffer.data(), dst_size);
128 memory_manager.ReadBlock(regs.offset_out, write_buffer.data(), dst_size);
129 } else {
130 memory_manager.ReadBlockUnsafe(regs.offset_in, read_buffer.data(), src_size);
131 memory_manager.ReadBlockUnsafe(regs.offset_out, write_buffer.data(), dst_size);
132 }
133 129
134 UnswizzleSubrect(regs.line_length_in, regs.line_count, regs.pitch_out, width, bytes_per_pixel, 130 UnswizzleSubrect(regs.line_length_in, regs.line_count, regs.pitch_out, width, bytes_per_pixel,
135 read_buffer.data() + src_layer_size * src_params.layer, write_buffer.data(), 131 block_height, src_params.origin.x, src_params.origin.y, write_buffer.data(),
136 block_height, src_params.origin.x, src_params.origin.y); 132 read_buffer.data());
137 133
138 memory_manager.WriteBlock(regs.offset_out, write_buffer.data(), dst_size); 134 memory_manager.WriteBlock(regs.offset_out, write_buffer.data(), dst_size);
139} 135}
@@ -198,7 +194,6 @@ void MaxwellDMA::FastCopyBlockLinearToPitch() {
198 if (read_buffer.size() < src_size) { 194 if (read_buffer.size() < src_size) {
199 read_buffer.resize(src_size); 195 read_buffer.resize(src_size);
200 } 196 }
201
202 if (write_buffer.size() < dst_size) { 197 if (write_buffer.size() < dst_size) {
203 write_buffer.resize(dst_size); 198 write_buffer.resize(dst_size);
204 } 199 }
@@ -212,8 +207,8 @@ void MaxwellDMA::FastCopyBlockLinearToPitch() {
212 } 207 }
213 208
214 UnswizzleSubrect(regs.line_length_in, regs.line_count, regs.pitch_out, regs.src_params.width, 209 UnswizzleSubrect(regs.line_length_in, regs.line_count, regs.pitch_out, regs.src_params.width,
215 bytes_per_pixel, read_buffer.data(), write_buffer.data(), 210 bytes_per_pixel, regs.src_params.block_size.height, pos_x, pos_y,
216 regs.src_params.block_size.height, pos_x, pos_y); 211 write_buffer.data(), read_buffer.data());
217 212
218 memory_manager.WriteBlock(regs.offset_out, write_buffer.data(), dst_size); 213 memory_manager.WriteBlock(regs.offset_out, write_buffer.data(), dst_size);
219} 214}
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index cb284db77..4af5824cd 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -177,15 +177,7 @@ RasterizerOpenGL::RasterizerOpenGL(Core::System& system, Core::Frontend::EmuWind
177 } 177 }
178 178
179 if (device.UseAsynchronousShaders()) { 179 if (device.UseAsynchronousShaders()) {
180 // Max worker threads we should allow 180 async_shaders.AllocateWorkers();
181 constexpr u32 MAX_THREADS = 4;
182 // Deduce how many threads we can use
183 const u32 threads_used = std::thread::hardware_concurrency() / 4;
184 // Always allow at least 1 thread regardless of our settings
185 const auto max_worker_count = std::max(1U, threads_used);
186 // Don't use more than MAX_THREADS
187 const auto worker_count = std::min(max_worker_count, MAX_THREADS);
188 async_shaders.AllocateWorkers(worker_count);
189 } 181 }
190} 182}
191 183
diff --git a/src/video_core/renderer_opengl/gl_shader_cache.cpp b/src/video_core/renderer_opengl/gl_shader_cache.cpp
index be71e1733..eb49a36bf 100644
--- a/src/video_core/renderer_opengl/gl_shader_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_cache.cpp
@@ -403,7 +403,7 @@ void ShaderCacheOpenGL::LoadDiskCache(const std::atomic_bool& stop_loading,
403 } 403 }
404 }; 404 };
405 405
406 const auto num_workers{static_cast<std::size_t>(std::thread::hardware_concurrency() + 1ULL)}; 406 const std::size_t num_workers{std::max(1U, std::thread::hardware_concurrency())};
407 const std::size_t bucket_size{transferable->size() / num_workers}; 407 const std::size_t bucket_size{transferable->size() / num_workers};
408 std::vector<std::unique_ptr<Core::Frontend::GraphicsContext>> contexts(num_workers); 408 std::vector<std::unique_ptr<Core::Frontend::GraphicsContext>> contexts(num_workers);
409 std::vector<std::thread> threads(num_workers); 409 std::vector<std::thread> threads(num_workers);
diff --git a/src/video_core/renderer_vulkan/vk_device.cpp b/src/video_core/renderer_vulkan/vk_device.cpp
index 0c03e4d83..ebcfaa0e3 100644
--- a/src/video_core/renderer_vulkan/vk_device.cpp
+++ b/src/video_core/renderer_vulkan/vk_device.cpp
@@ -382,6 +382,8 @@ bool VKDevice::Create() {
382 382
383 graphics_queue = logical.GetQueue(graphics_family); 383 graphics_queue = logical.GetQueue(graphics_family);
384 present_queue = logical.GetQueue(present_family); 384 present_queue = logical.GetQueue(present_family);
385
386 use_asynchronous_shaders = Settings::values.use_asynchronous_shaders.GetValue();
385 return true; 387 return true;
386} 388}
387 389
diff --git a/src/video_core/renderer_vulkan/vk_device.h b/src/video_core/renderer_vulkan/vk_device.h
index 529744f2d..26a233db1 100644
--- a/src/video_core/renderer_vulkan/vk_device.h
+++ b/src/video_core/renderer_vulkan/vk_device.h
@@ -202,6 +202,11 @@ public:
202 return reported_extensions; 202 return reported_extensions;
203 } 203 }
204 204
205 /// Returns true if the setting for async shader compilation is enabled.
206 bool UseAsynchronousShaders() const {
207 return use_asynchronous_shaders;
208 }
209
205 /// Checks if the physical device is suitable. 210 /// Checks if the physical device is suitable.
206 static bool IsSuitable(vk::PhysicalDevice physical, VkSurfaceKHR surface); 211 static bool IsSuitable(vk::PhysicalDevice physical, VkSurfaceKHR surface);
207 212
@@ -252,6 +257,9 @@ private:
252 bool ext_extended_dynamic_state{}; ///< Support for VK_EXT_extended_dynamic_state. 257 bool ext_extended_dynamic_state{}; ///< Support for VK_EXT_extended_dynamic_state.
253 bool nv_device_diagnostics_config{}; ///< Support for VK_NV_device_diagnostics_config. 258 bool nv_device_diagnostics_config{}; ///< Support for VK_NV_device_diagnostics_config.
254 259
260 // Asynchronous Graphics Pipeline setting
261 bool use_asynchronous_shaders{}; ///< Setting to use asynchronous shaders/graphics pipeline
262
255 // Telemetry parameters 263 // Telemetry parameters
256 std::string vendor_name; ///< Device's driver name. 264 std::string vendor_name; ///< Device's driver name.
257 std::vector<std::string> reported_extensions; ///< Reported Vulkan extensions. 265 std::vector<std::string> reported_extensions; ///< Reported Vulkan extensions.
diff --git a/src/video_core/renderer_vulkan/vk_fence_manager.cpp b/src/video_core/renderer_vulkan/vk_fence_manager.cpp
index a02be5487..d7f65d435 100644
--- a/src/video_core/renderer_vulkan/vk_fence_manager.cpp
+++ b/src/video_core/renderer_vulkan/vk_fence_manager.cpp
@@ -29,7 +29,7 @@ void InnerFence::Queue() {
29 } 29 }
30 ASSERT(!event); 30 ASSERT(!event);
31 31
32 event = device.GetLogical().CreateEvent(); 32 event = device.GetLogical().CreateNewEvent();
33 ticks = scheduler.Ticks(); 33 ticks = scheduler.Ticks();
34 34
35 scheduler.RequestOutsideRenderPassOperationContext(); 35 scheduler.RequestOutsideRenderPassOperationContext();
diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp
index aaf930b90..2e46c6278 100644
--- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp
+++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp
@@ -78,15 +78,14 @@ VKGraphicsPipeline::VKGraphicsPipeline(const VKDevice& device, VKScheduler& sche
78 const GraphicsPipelineCacheKey& key, 78 const GraphicsPipelineCacheKey& key,
79 vk::Span<VkDescriptorSetLayoutBinding> bindings, 79 vk::Span<VkDescriptorSetLayoutBinding> bindings,
80 const SPIRVProgram& program) 80 const SPIRVProgram& program)
81 : device{device}, scheduler{scheduler}, fixed_state{key.fixed_state}, hash{key.Hash()}, 81 : device{device}, scheduler{scheduler}, cache_key{key}, hash{cache_key.Hash()},
82 descriptor_set_layout{CreateDescriptorSetLayout(bindings)}, 82 descriptor_set_layout{CreateDescriptorSetLayout(bindings)},
83 descriptor_allocator{descriptor_pool, *descriptor_set_layout}, 83 descriptor_allocator{descriptor_pool, *descriptor_set_layout},
84 update_descriptor_queue{update_descriptor_queue}, layout{CreatePipelineLayout()}, 84 update_descriptor_queue{update_descriptor_queue}, layout{CreatePipelineLayout()},
85 descriptor_template{CreateDescriptorUpdateTemplate(program)}, modules{CreateShaderModules( 85 descriptor_template{CreateDescriptorUpdateTemplate(program)}, modules{CreateShaderModules(
86 program)}, 86 program)},
87 renderpass{renderpass_cache.GetRenderPass(key.renderpass_params)}, pipeline{CreatePipeline( 87 renderpass{renderpass_cache.GetRenderPass(cache_key.renderpass_params)},
88 key.renderpass_params, 88 pipeline{CreatePipeline(cache_key.renderpass_params, program)} {}
89 program)} {}
90 89
91VKGraphicsPipeline::~VKGraphicsPipeline() = default; 90VKGraphicsPipeline::~VKGraphicsPipeline() = default;
92 91
@@ -181,7 +180,7 @@ std::vector<vk::ShaderModule> VKGraphicsPipeline::CreateShaderModules(
181 180
182vk::Pipeline VKGraphicsPipeline::CreatePipeline(const RenderPassParams& renderpass_params, 181vk::Pipeline VKGraphicsPipeline::CreatePipeline(const RenderPassParams& renderpass_params,
183 const SPIRVProgram& program) const { 182 const SPIRVProgram& program) const {
184 const auto& state = fixed_state; 183 const auto& state = cache_key.fixed_state;
185 const auto& viewport_swizzles = state.viewport_swizzles; 184 const auto& viewport_swizzles = state.viewport_swizzles;
186 185
187 FixedPipelineState::DynamicState dynamic; 186 FixedPipelineState::DynamicState dynamic;
diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.h b/src/video_core/renderer_vulkan/vk_graphics_pipeline.h
index a1d699a6c..58aa35efd 100644
--- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.h
+++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.h
@@ -19,7 +19,27 @@ namespace Vulkan {
19 19
20using Maxwell = Tegra::Engines::Maxwell3D::Regs; 20using Maxwell = Tegra::Engines::Maxwell3D::Regs;
21 21
22struct GraphicsPipelineCacheKey; 22struct GraphicsPipelineCacheKey {
23 RenderPassParams renderpass_params;
24 u32 padding;
25 std::array<GPUVAddr, Maxwell::MaxShaderProgram> shaders;
26 FixedPipelineState fixed_state;
27
28 std::size_t Hash() const noexcept;
29
30 bool operator==(const GraphicsPipelineCacheKey& rhs) const noexcept;
31
32 bool operator!=(const GraphicsPipelineCacheKey& rhs) const noexcept {
33 return !operator==(rhs);
34 }
35
36 std::size_t Size() const noexcept {
37 return sizeof(renderpass_params) + sizeof(padding) + sizeof(shaders) + fixed_state.Size();
38 }
39};
40static_assert(std::has_unique_object_representations_v<GraphicsPipelineCacheKey>);
41static_assert(std::is_trivially_copyable_v<GraphicsPipelineCacheKey>);
42static_assert(std::is_trivially_constructible_v<GraphicsPipelineCacheKey>);
23 43
24class VKDescriptorPool; 44class VKDescriptorPool;
25class VKDevice; 45class VKDevice;
@@ -54,6 +74,10 @@ public:
54 return renderpass; 74 return renderpass;
55 } 75 }
56 76
77 GraphicsPipelineCacheKey GetCacheKey() const {
78 return cache_key;
79 }
80
57private: 81private:
58 vk::DescriptorSetLayout CreateDescriptorSetLayout( 82 vk::DescriptorSetLayout CreateDescriptorSetLayout(
59 vk::Span<VkDescriptorSetLayoutBinding> bindings) const; 83 vk::Span<VkDescriptorSetLayoutBinding> bindings) const;
@@ -70,7 +94,7 @@ private:
70 94
71 const VKDevice& device; 95 const VKDevice& device;
72 VKScheduler& scheduler; 96 VKScheduler& scheduler;
73 const FixedPipelineState fixed_state; 97 const GraphicsPipelineCacheKey cache_key;
74 const u64 hash; 98 const u64 hash;
75 99
76 vk::DescriptorSetLayout descriptor_set_layout; 100 vk::DescriptorSetLayout descriptor_set_layout;
diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
index 418c62bc4..cfdcdd6ab 100644
--- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
@@ -28,6 +28,7 @@
28#include "video_core/shader/compiler_settings.h" 28#include "video_core/shader/compiler_settings.h"
29#include "video_core/shader/memory_util.h" 29#include "video_core/shader/memory_util.h"
30#include "video_core/shader_cache.h" 30#include "video_core/shader_cache.h"
31#include "video_core/shader_notify.h"
31 32
32namespace Vulkan { 33namespace Vulkan {
33 34
@@ -205,24 +206,43 @@ std::array<Shader*, Maxwell::MaxShaderProgram> VKPipelineCache::GetShaders() {
205 return last_shaders = shaders; 206 return last_shaders = shaders;
206} 207}
207 208
208VKGraphicsPipeline& VKPipelineCache::GetGraphicsPipeline(const GraphicsPipelineCacheKey& key) { 209VKGraphicsPipeline* VKPipelineCache::GetGraphicsPipeline(
210 const GraphicsPipelineCacheKey& key, VideoCommon::Shader::AsyncShaders& async_shaders) {
209 MICROPROFILE_SCOPE(Vulkan_PipelineCache); 211 MICROPROFILE_SCOPE(Vulkan_PipelineCache);
210 212
211 if (last_graphics_pipeline && last_graphics_key == key) { 213 if (last_graphics_pipeline && last_graphics_key == key) {
212 return *last_graphics_pipeline; 214 return last_graphics_pipeline;
213 } 215 }
214 last_graphics_key = key; 216 last_graphics_key = key;
215 217
218 if (device.UseAsynchronousShaders() && async_shaders.IsShaderAsync(system.GPU())) {
219 std::unique_lock lock{pipeline_cache};
220 const auto [pair, is_cache_miss] = graphics_cache.try_emplace(key);
221 if (is_cache_miss) {
222 system.GPU().ShaderNotify().MarkSharderBuilding();
223 LOG_INFO(Render_Vulkan, "Compile 0x{:016X}", key.Hash());
224 const auto [program, bindings] = DecompileShaders(key.fixed_state);
225 async_shaders.QueueVulkanShader(this, device, scheduler, descriptor_pool,
226 update_descriptor_queue, renderpass_cache, bindings,
227 program, key);
228 }
229 last_graphics_pipeline = pair->second.get();
230 return last_graphics_pipeline;
231 }
232
216 const auto [pair, is_cache_miss] = graphics_cache.try_emplace(key); 233 const auto [pair, is_cache_miss] = graphics_cache.try_emplace(key);
217 auto& entry = pair->second; 234 auto& entry = pair->second;
218 if (is_cache_miss) { 235 if (is_cache_miss) {
236 system.GPU().ShaderNotify().MarkSharderBuilding();
219 LOG_INFO(Render_Vulkan, "Compile 0x{:016X}", key.Hash()); 237 LOG_INFO(Render_Vulkan, "Compile 0x{:016X}", key.Hash());
220 const auto [program, bindings] = DecompileShaders(key); 238 const auto [program, bindings] = DecompileShaders(key.fixed_state);
221 entry = std::make_unique<VKGraphicsPipeline>(device, scheduler, descriptor_pool, 239 entry = std::make_unique<VKGraphicsPipeline>(device, scheduler, descriptor_pool,
222 update_descriptor_queue, renderpass_cache, key, 240 update_descriptor_queue, renderpass_cache, key,
223 bindings, program); 241 bindings, program);
242 system.GPU().ShaderNotify().MarkShaderComplete();
224 } 243 }
225 return *(last_graphics_pipeline = entry.get()); 244 last_graphics_pipeline = entry.get();
245 return last_graphics_pipeline;
226} 246}
227 247
228VKComputePipeline& VKPipelineCache::GetComputePipeline(const ComputePipelineCacheKey& key) { 248VKComputePipeline& VKPipelineCache::GetComputePipeline(const ComputePipelineCacheKey& key) {
@@ -277,6 +297,12 @@ VKComputePipeline& VKPipelineCache::GetComputePipeline(const ComputePipelineCach
277 return *entry; 297 return *entry;
278} 298}
279 299
300void VKPipelineCache::EmplacePipeline(std::unique_ptr<VKGraphicsPipeline> pipeline) {
301 system.GPU().ShaderNotify().MarkShaderComplete();
302 std::unique_lock lock{pipeline_cache};
303 graphics_cache.at(pipeline->GetCacheKey()) = std::move(pipeline);
304}
305
280void VKPipelineCache::OnShaderRemoval(Shader* shader) { 306void VKPipelineCache::OnShaderRemoval(Shader* shader) {
281 bool finished = false; 307 bool finished = false;
282 const auto Finish = [&] { 308 const auto Finish = [&] {
@@ -312,8 +338,7 @@ void VKPipelineCache::OnShaderRemoval(Shader* shader) {
312} 338}
313 339
314std::pair<SPIRVProgram, std::vector<VkDescriptorSetLayoutBinding>> 340std::pair<SPIRVProgram, std::vector<VkDescriptorSetLayoutBinding>>
315VKPipelineCache::DecompileShaders(const GraphicsPipelineCacheKey& key) { 341VKPipelineCache::DecompileShaders(const FixedPipelineState& fixed_state) {
316 const auto& fixed_state = key.fixed_state;
317 auto& memory_manager = system.GPU().MemoryManager(); 342 auto& memory_manager = system.GPU().MemoryManager();
318 const auto& gpu = system.GPU().Maxwell3D(); 343 const auto& gpu = system.GPU().Maxwell3D();
319 344
diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.h b/src/video_core/renderer_vulkan/vk_pipeline_cache.h
index 0a3fe65fb..c04829e77 100644
--- a/src/video_core/renderer_vulkan/vk_pipeline_cache.h
+++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.h
@@ -22,6 +22,7 @@
22#include "video_core/renderer_vulkan/vk_renderpass_cache.h" 22#include "video_core/renderer_vulkan/vk_renderpass_cache.h"
23#include "video_core/renderer_vulkan/vk_shader_decompiler.h" 23#include "video_core/renderer_vulkan/vk_shader_decompiler.h"
24#include "video_core/renderer_vulkan/wrapper.h" 24#include "video_core/renderer_vulkan/wrapper.h"
25#include "video_core/shader/async_shaders.h"
25#include "video_core/shader/memory_util.h" 26#include "video_core/shader/memory_util.h"
26#include "video_core/shader/registry.h" 27#include "video_core/shader/registry.h"
27#include "video_core/shader/shader_ir.h" 28#include "video_core/shader/shader_ir.h"
@@ -43,28 +44,6 @@ class VKUpdateDescriptorQueue;
43 44
44using Maxwell = Tegra::Engines::Maxwell3D::Regs; 45using Maxwell = Tegra::Engines::Maxwell3D::Regs;
45 46
46struct GraphicsPipelineCacheKey {
47 RenderPassParams renderpass_params;
48 u32 padding;
49 std::array<GPUVAddr, Maxwell::MaxShaderProgram> shaders;
50 FixedPipelineState fixed_state;
51
52 std::size_t Hash() const noexcept;
53
54 bool operator==(const GraphicsPipelineCacheKey& rhs) const noexcept;
55
56 bool operator!=(const GraphicsPipelineCacheKey& rhs) const noexcept {
57 return !operator==(rhs);
58 }
59
60 std::size_t Size() const noexcept {
61 return sizeof(renderpass_params) + sizeof(padding) + sizeof(shaders) + fixed_state.Size();
62 }
63};
64static_assert(std::has_unique_object_representations_v<GraphicsPipelineCacheKey>);
65static_assert(std::is_trivially_copyable_v<GraphicsPipelineCacheKey>);
66static_assert(std::is_trivially_constructible_v<GraphicsPipelineCacheKey>);
67
68struct ComputePipelineCacheKey { 47struct ComputePipelineCacheKey {
69 GPUVAddr shader; 48 GPUVAddr shader;
70 u32 shared_memory_size; 49 u32 shared_memory_size;
@@ -152,16 +131,19 @@ public:
152 131
153 std::array<Shader*, Maxwell::MaxShaderProgram> GetShaders(); 132 std::array<Shader*, Maxwell::MaxShaderProgram> GetShaders();
154 133
155 VKGraphicsPipeline& GetGraphicsPipeline(const GraphicsPipelineCacheKey& key); 134 VKGraphicsPipeline* GetGraphicsPipeline(const GraphicsPipelineCacheKey& key,
135 VideoCommon::Shader::AsyncShaders& async_shaders);
156 136
157 VKComputePipeline& GetComputePipeline(const ComputePipelineCacheKey& key); 137 VKComputePipeline& GetComputePipeline(const ComputePipelineCacheKey& key);
158 138
139 void EmplacePipeline(std::unique_ptr<VKGraphicsPipeline> pipeline);
140
159protected: 141protected:
160 void OnShaderRemoval(Shader* shader) final; 142 void OnShaderRemoval(Shader* shader) final;
161 143
162private: 144private:
163 std::pair<SPIRVProgram, std::vector<VkDescriptorSetLayoutBinding>> DecompileShaders( 145 std::pair<SPIRVProgram, std::vector<VkDescriptorSetLayoutBinding>> DecompileShaders(
164 const GraphicsPipelineCacheKey& key); 146 const FixedPipelineState& fixed_state);
165 147
166 Core::System& system; 148 Core::System& system;
167 const VKDevice& device; 149 const VKDevice& device;
@@ -178,6 +160,7 @@ private:
178 GraphicsPipelineCacheKey last_graphics_key; 160 GraphicsPipelineCacheKey last_graphics_key;
179 VKGraphicsPipeline* last_graphics_pipeline = nullptr; 161 VKGraphicsPipeline* last_graphics_pipeline = nullptr;
180 162
163 std::mutex pipeline_cache;
181 std::unordered_map<GraphicsPipelineCacheKey, std::unique_ptr<VKGraphicsPipeline>> 164 std::unordered_map<GraphicsPipelineCacheKey, std::unique_ptr<VKGraphicsPipeline>>
182 graphics_cache; 165 graphics_cache;
183 std::unordered_map<ComputePipelineCacheKey, std::unique_ptr<VKComputePipeline>> compute_cache; 166 std::unordered_map<ComputePipelineCacheKey, std::unique_ptr<VKComputePipeline>> compute_cache;
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp
index 7500e8244..936f76195 100644
--- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp
+++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp
@@ -14,6 +14,7 @@
14#include "common/assert.h" 14#include "common/assert.h"
15#include "common/logging/log.h" 15#include "common/logging/log.h"
16#include "common/microprofile.h" 16#include "common/microprofile.h"
17#include "common/scope_exit.h"
17#include "core/core.h" 18#include "core/core.h"
18#include "core/settings.h" 19#include "core/settings.h"
19#include "video_core/engines/kepler_compute.h" 20#include "video_core/engines/kepler_compute.h"
@@ -400,8 +401,12 @@ RasterizerVulkan::RasterizerVulkan(Core::System& system, Core::Frontend::EmuWind
400 buffer_cache(*this, system, device, memory_manager, scheduler, staging_pool), 401 buffer_cache(*this, system, device, memory_manager, scheduler, staging_pool),
401 sampler_cache(device), 402 sampler_cache(device),
402 fence_manager(system, *this, device, scheduler, texture_cache, buffer_cache, query_cache), 403 fence_manager(system, *this, device, scheduler, texture_cache, buffer_cache, query_cache),
403 query_cache(system, *this, device, scheduler), wfi_event{device.GetLogical().CreateEvent()} { 404 query_cache(system, *this, device, scheduler),
405 wfi_event{device.GetLogical().CreateNewEvent()}, async_shaders{renderer} {
404 scheduler.SetQueryCache(query_cache); 406 scheduler.SetQueryCache(query_cache);
407 if (device.UseAsynchronousShaders()) {
408 async_shaders.AllocateWorkers();
409 }
405} 410}
406 411
407RasterizerVulkan::~RasterizerVulkan() = default; 412RasterizerVulkan::~RasterizerVulkan() = default;
@@ -413,6 +418,8 @@ void RasterizerVulkan::Draw(bool is_indexed, bool is_instanced) {
413 418
414 query_cache.UpdateCounters(); 419 query_cache.UpdateCounters();
415 420
421 SCOPE_EXIT({ system.GPU().TickWork(); });
422
416 const auto& gpu = system.GPU().Maxwell3D(); 423 const auto& gpu = system.GPU().Maxwell3D();
417 GraphicsPipelineCacheKey key; 424 GraphicsPipelineCacheKey key;
418 key.fixed_state.Fill(gpu.regs, device.IsExtExtendedDynamicStateSupported()); 425 key.fixed_state.Fill(gpu.regs, device.IsExtExtendedDynamicStateSupported());
@@ -439,10 +446,15 @@ void RasterizerVulkan::Draw(bool is_indexed, bool is_instanced) {
439 key.renderpass_params = GetRenderPassParams(texceptions); 446 key.renderpass_params = GetRenderPassParams(texceptions);
440 key.padding = 0; 447 key.padding = 0;
441 448
442 auto& pipeline = pipeline_cache.GetGraphicsPipeline(key); 449 auto* pipeline = pipeline_cache.GetGraphicsPipeline(key, async_shaders);
443 scheduler.BindGraphicsPipeline(pipeline.GetHandle()); 450 if (pipeline == nullptr || pipeline->GetHandle() == VK_NULL_HANDLE) {
451 // Async graphics pipeline was not ready.
452 return;
453 }
454
455 scheduler.BindGraphicsPipeline(pipeline->GetHandle());
444 456
445 const auto renderpass = pipeline.GetRenderPass(); 457 const auto renderpass = pipeline->GetRenderPass();
446 const auto [framebuffer, render_area] = ConfigureFramebuffers(renderpass); 458 const auto [framebuffer, render_area] = ConfigureFramebuffers(renderpass);
447 scheduler.RequestRenderpass(renderpass, framebuffer, render_area); 459 scheduler.RequestRenderpass(renderpass, framebuffer, render_area);
448 460
@@ -452,8 +464,8 @@ void RasterizerVulkan::Draw(bool is_indexed, bool is_instanced) {
452 464
453 BeginTransformFeedback(); 465 BeginTransformFeedback();
454 466
455 const auto pipeline_layout = pipeline.GetLayout(); 467 const auto pipeline_layout = pipeline->GetLayout();
456 const auto descriptor_set = pipeline.CommitDescriptorSet(); 468 const auto descriptor_set = pipeline->CommitDescriptorSet();
457 scheduler.Record([pipeline_layout, descriptor_set, draw_params](vk::CommandBuffer cmdbuf) { 469 scheduler.Record([pipeline_layout, descriptor_set, draw_params](vk::CommandBuffer cmdbuf) {
458 if (descriptor_set) { 470 if (descriptor_set) {
459 cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 471 cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout,
@@ -463,8 +475,6 @@ void RasterizerVulkan::Draw(bool is_indexed, bool is_instanced) {
463 }); 475 });
464 476
465 EndTransformFeedback(); 477 EndTransformFeedback();
466
467 system.GPU().TickWork();
468} 478}
469 479
470void RasterizerVulkan::Clear() { 480void RasterizerVulkan::Clear() {
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.h b/src/video_core/renderer_vulkan/vk_rasterizer.h
index 923178b0b..f640ba649 100644
--- a/src/video_core/renderer_vulkan/vk_rasterizer.h
+++ b/src/video_core/renderer_vulkan/vk_rasterizer.h
@@ -32,6 +32,7 @@
32#include "video_core/renderer_vulkan/vk_texture_cache.h" 32#include "video_core/renderer_vulkan/vk_texture_cache.h"
33#include "video_core/renderer_vulkan/vk_update_descriptor.h" 33#include "video_core/renderer_vulkan/vk_update_descriptor.h"
34#include "video_core/renderer_vulkan/wrapper.h" 34#include "video_core/renderer_vulkan/wrapper.h"
35#include "video_core/shader/async_shaders.h"
35 36
36namespace Core { 37namespace Core {
37class System; 38class System;
@@ -136,6 +137,14 @@ public:
136 u32 pixel_stride) override; 137 u32 pixel_stride) override;
137 void SetupDirtyFlags() override; 138 void SetupDirtyFlags() override;
138 139
140 VideoCommon::Shader::AsyncShaders& GetAsyncShaders() {
141 return async_shaders;
142 }
143
144 const VideoCommon::Shader::AsyncShaders& GetAsyncShaders() const {
145 return async_shaders;
146 }
147
139 /// Maximum supported size that a constbuffer can have in bytes. 148 /// Maximum supported size that a constbuffer can have in bytes.
140 static constexpr std::size_t MaxConstbufferSize = 0x10000; 149 static constexpr std::size_t MaxConstbufferSize = 0x10000;
141 static_assert(MaxConstbufferSize % (4 * sizeof(float)) == 0, 150 static_assert(MaxConstbufferSize % (4 * sizeof(float)) == 0,
@@ -297,6 +306,7 @@ private:
297 vk::Buffer default_buffer; 306 vk::Buffer default_buffer;
298 VKMemoryCommit default_buffer_commit; 307 VKMemoryCommit default_buffer_commit;
299 vk::Event wfi_event; 308 vk::Event wfi_event;
309 VideoCommon::Shader::AsyncShaders async_shaders;
300 310
301 std::array<View, Maxwell::NumRenderTargets> color_attachments; 311 std::array<View, Maxwell::NumRenderTargets> color_attachments;
302 View zeta_attachment; 312 View zeta_attachment;
diff --git a/src/video_core/renderer_vulkan/wrapper.cpp b/src/video_core/renderer_vulkan/wrapper.cpp
index 14cac38ea..c43d60adf 100644
--- a/src/video_core/renderer_vulkan/wrapper.cpp
+++ b/src/video_core/renderer_vulkan/wrapper.cpp
@@ -644,7 +644,7 @@ ShaderModule Device::CreateShaderModule(const VkShaderModuleCreateInfo& ci) cons
644 return ShaderModule(object, handle, *dld); 644 return ShaderModule(object, handle, *dld);
645} 645}
646 646
647Event Device::CreateEvent() const { 647Event Device::CreateNewEvent() const {
648 static constexpr VkEventCreateInfo ci{ 648 static constexpr VkEventCreateInfo ci{
649 .sType = VK_STRUCTURE_TYPE_EVENT_CREATE_INFO, 649 .sType = VK_STRUCTURE_TYPE_EVENT_CREATE_INFO,
650 .pNext = nullptr, 650 .pNext = nullptr,
diff --git a/src/video_core/renderer_vulkan/wrapper.h b/src/video_core/renderer_vulkan/wrapper.h
index 71daac9d7..b9d3fedc1 100644
--- a/src/video_core/renderer_vulkan/wrapper.h
+++ b/src/video_core/renderer_vulkan/wrapper.h
@@ -721,7 +721,7 @@ public:
721 721
722 ShaderModule CreateShaderModule(const VkShaderModuleCreateInfo& ci) const; 722 ShaderModule CreateShaderModule(const VkShaderModuleCreateInfo& ci) const;
723 723
724 Event CreateEvent() const; 724 Event CreateNewEvent() const;
725 725
726 SwapchainKHR CreateSwapchainKHR(const VkSwapchainCreateInfoKHR& ci) const; 726 SwapchainKHR CreateSwapchainKHR(const VkSwapchainCreateInfoKHR& ci) const;
727 727
@@ -756,8 +756,8 @@ public:
756 } 756 }
757 757
758 VkResult GetQueryResults(VkQueryPool query_pool, u32 first, u32 count, std::size_t data_size, 758 VkResult GetQueryResults(VkQueryPool query_pool, u32 first, u32 count, std::size_t data_size,
759 void* data, VkDeviceSize stride, VkQueryResultFlags flags) const 759 void* data, VkDeviceSize stride,
760 noexcept { 760 VkQueryResultFlags flags) const noexcept {
761 return dld->vkGetQueryPoolResults(handle, query_pool, first, count, data_size, data, stride, 761 return dld->vkGetQueryPoolResults(handle, query_pool, first, count, data_size, data, stride,
762 flags); 762 flags);
763 } 763 }
@@ -849,8 +849,8 @@ public:
849 dld->vkCmdBindPipeline(handle, bind_point, pipeline); 849 dld->vkCmdBindPipeline(handle, bind_point, pipeline);
850 } 850 }
851 851
852 void BindIndexBuffer(VkBuffer buffer, VkDeviceSize offset, VkIndexType index_type) const 852 void BindIndexBuffer(VkBuffer buffer, VkDeviceSize offset,
853 noexcept { 853 VkIndexType index_type) const noexcept {
854 dld->vkCmdBindIndexBuffer(handle, buffer, offset, index_type); 854 dld->vkCmdBindIndexBuffer(handle, buffer, offset, index_type);
855 } 855 }
856 856
@@ -863,8 +863,8 @@ public:
863 BindVertexBuffers(binding, 1, &buffer, &offset); 863 BindVertexBuffers(binding, 1, &buffer, &offset);
864 } 864 }
865 865
866 void Draw(u32 vertex_count, u32 instance_count, u32 first_vertex, u32 first_instance) const 866 void Draw(u32 vertex_count, u32 instance_count, u32 first_vertex,
867 noexcept { 867 u32 first_instance) const noexcept {
868 dld->vkCmdDraw(handle, vertex_count, instance_count, first_vertex, first_instance); 868 dld->vkCmdDraw(handle, vertex_count, instance_count, first_vertex, first_instance);
869 } 869 }
870 870
@@ -874,15 +874,15 @@ public:
874 first_instance); 874 first_instance);
875 } 875 }
876 876
877 void ClearAttachments(Span<VkClearAttachment> attachments, Span<VkClearRect> rects) const 877 void ClearAttachments(Span<VkClearAttachment> attachments,
878 noexcept { 878 Span<VkClearRect> rects) const noexcept {
879 dld->vkCmdClearAttachments(handle, attachments.size(), attachments.data(), rects.size(), 879 dld->vkCmdClearAttachments(handle, attachments.size(), attachments.data(), rects.size(),
880 rects.data()); 880 rects.data());
881 } 881 }
882 882
883 void BlitImage(VkImage src_image, VkImageLayout src_layout, VkImage dst_image, 883 void BlitImage(VkImage src_image, VkImageLayout src_layout, VkImage dst_image,
884 VkImageLayout dst_layout, Span<VkImageBlit> regions, VkFilter filter) const 884 VkImageLayout dst_layout, Span<VkImageBlit> regions,
885 noexcept { 885 VkFilter filter) const noexcept {
886 dld->vkCmdBlitImage(handle, src_image, src_layout, dst_image, dst_layout, regions.size(), 886 dld->vkCmdBlitImage(handle, src_image, src_layout, dst_image, dst_layout, regions.size(),
887 regions.data(), filter); 887 regions.data(), filter);
888 } 888 }
@@ -907,8 +907,8 @@ public:
907 regions.data()); 907 regions.data());
908 } 908 }
909 909
910 void CopyBuffer(VkBuffer src_buffer, VkBuffer dst_buffer, Span<VkBufferCopy> regions) const 910 void CopyBuffer(VkBuffer src_buffer, VkBuffer dst_buffer,
911 noexcept { 911 Span<VkBufferCopy> regions) const noexcept {
912 dld->vkCmdCopyBuffer(handle, src_buffer, dst_buffer, regions.size(), regions.data()); 912 dld->vkCmdCopyBuffer(handle, src_buffer, dst_buffer, regions.size(), regions.data());
913 } 913 }
914 914
@@ -924,8 +924,8 @@ public:
924 regions.data()); 924 regions.data());
925 } 925 }
926 926
927 void FillBuffer(VkBuffer dst_buffer, VkDeviceSize dst_offset, VkDeviceSize size, u32 data) const 927 void FillBuffer(VkBuffer dst_buffer, VkDeviceSize dst_offset, VkDeviceSize size,
928 noexcept { 928 u32 data) const noexcept {
929 dld->vkCmdFillBuffer(handle, dst_buffer, dst_offset, size, data); 929 dld->vkCmdFillBuffer(handle, dst_buffer, dst_offset, size, data);
930 } 930 }
931 931
diff --git a/src/video_core/shader/async_shaders.cpp b/src/video_core/shader/async_shaders.cpp
index b7f66d7ee..f815584f7 100644
--- a/src/video_core/shader/async_shaders.cpp
+++ b/src/video_core/shader/async_shaders.cpp
@@ -2,7 +2,6 @@
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 <chrono>
6#include <condition_variable> 5#include <condition_variable>
7#include <mutex> 6#include <mutex>
8#include <thread> 7#include <thread>
@@ -20,9 +19,18 @@ AsyncShaders::~AsyncShaders() {
20 KillWorkers(); 19 KillWorkers();
21} 20}
22 21
23void AsyncShaders::AllocateWorkers(std::size_t num_workers) { 22void AsyncShaders::AllocateWorkers() {
24 // If we're already have workers queued or don't want to queue workers, ignore 23 // Max worker threads we should allow
25 if (num_workers == worker_threads.size() || num_workers == 0) { 24 constexpr u32 MAX_THREADS = 4;
25 // Deduce how many threads we can use
26 const u32 threads_used = std::thread::hardware_concurrency() / 4;
27 // Always allow at least 1 thread regardless of our settings
28 const auto max_worker_count = std::max(1U, threads_used);
29 // Don't use more than MAX_THREADS
30 const auto num_workers = std::min(max_worker_count, MAX_THREADS);
31
32 // If we already have workers queued, ignore
33 if (num_workers == worker_threads.size()) {
26 return; 34 return;
27 } 35 }
28 36
@@ -34,8 +42,8 @@ void AsyncShaders::AllocateWorkers(std::size_t num_workers) {
34 // Create workers 42 // Create workers
35 for (std::size_t i = 0; i < num_workers; i++) { 43 for (std::size_t i = 0; i < num_workers; i++) {
36 context_list.push_back(emu_window.CreateSharedContext()); 44 context_list.push_back(emu_window.CreateSharedContext());
37 worker_threads.push_back(std::move( 45 worker_threads.push_back(
38 std::thread(&AsyncShaders::ShaderCompilerThread, this, context_list[i].get()))); 46 std::thread(&AsyncShaders::ShaderCompilerThread, this, context_list[i].get()));
39 } 47 }
40} 48}
41 49
@@ -111,24 +119,50 @@ void AsyncShaders::QueueOpenGLShader(const OpenGL::Device& device,
111 VideoCommon::Shader::CompilerSettings compiler_settings, 119 VideoCommon::Shader::CompilerSettings compiler_settings,
112 const VideoCommon::Shader::Registry& registry, 120 const VideoCommon::Shader::Registry& registry,
113 VAddr cpu_addr) { 121 VAddr cpu_addr) {
114 WorkerParams params{device.UseAssemblyShaders() ? AsyncShaders::Backend::GLASM 122 WorkerParams params{
115 : AsyncShaders::Backend::OpenGL, 123 .backend = device.UseAssemblyShaders() ? Backend::GLASM : Backend::OpenGL,
116 device, 124 .device = &device,
117 shader_type, 125 .shader_type = shader_type,
118 uid, 126 .uid = uid,
119 std::move(code), 127 .code = std::move(code),
120 std::move(code_b), 128 .code_b = std::move(code_b),
121 main_offset, 129 .main_offset = main_offset,
122 compiler_settings, 130 .compiler_settings = compiler_settings,
123 registry, 131 .registry = registry,
124 cpu_addr}; 132 .cpu_address = cpu_addr,
133 };
125 std::unique_lock lock(queue_mutex); 134 std::unique_lock lock(queue_mutex);
126 pending_queue.push_back(std::move(params)); 135 pending_queue.push(std::move(params));
136 cv.notify_one();
137}
138
139void AsyncShaders::QueueVulkanShader(Vulkan::VKPipelineCache* pp_cache,
140 const Vulkan::VKDevice& device, Vulkan::VKScheduler& scheduler,
141 Vulkan::VKDescriptorPool& descriptor_pool,
142 Vulkan::VKUpdateDescriptorQueue& update_descriptor_queue,
143 Vulkan::VKRenderPassCache& renderpass_cache,
144 std::vector<VkDescriptorSetLayoutBinding> bindings,
145 Vulkan::SPIRVProgram program,
146 Vulkan::GraphicsPipelineCacheKey key) {
147 WorkerParams params{
148 .backend = Backend::Vulkan,
149 .pp_cache = pp_cache,
150 .vk_device = &device,
151 .scheduler = &scheduler,
152 .descriptor_pool = &descriptor_pool,
153 .update_descriptor_queue = &update_descriptor_queue,
154 .renderpass_cache = &renderpass_cache,
155 .bindings = bindings,
156 .program = program,
157 .key = key,
158 };
159
160 std::unique_lock lock(queue_mutex);
161 pending_queue.push(std::move(params));
127 cv.notify_one(); 162 cv.notify_one();
128} 163}
129 164
130void AsyncShaders::ShaderCompilerThread(Core::Frontend::GraphicsContext* context) { 165void AsyncShaders::ShaderCompilerThread(Core::Frontend::GraphicsContext* context) {
131 using namespace std::chrono_literals;
132 while (!is_thread_exiting.load(std::memory_order_relaxed)) { 166 while (!is_thread_exiting.load(std::memory_order_relaxed)) {
133 std::unique_lock lock{queue_mutex}; 167 std::unique_lock lock{queue_mutex};
134 cv.wait(lock, [this] { return HasWorkQueued() || is_thread_exiting; }); 168 cv.wait(lock, [this] { return HasWorkQueued() || is_thread_exiting; });
@@ -144,18 +178,17 @@ void AsyncShaders::ShaderCompilerThread(Core::Frontend::GraphicsContext* context
144 if (pending_queue.empty()) { 178 if (pending_queue.empty()) {
145 continue; 179 continue;
146 } 180 }
181
147 // Pull work from queue 182 // Pull work from queue
148 WorkerParams work = std::move(pending_queue.front()); 183 WorkerParams work = std::move(pending_queue.front());
149 pending_queue.pop_front(); 184 pending_queue.pop();
150
151 lock.unlock(); 185 lock.unlock();
152 186
153 if (work.backend == AsyncShaders::Backend::OpenGL || 187 if (work.backend == Backend::OpenGL || work.backend == Backend::GLASM) {
154 work.backend == AsyncShaders::Backend::GLASM) { 188 const ShaderIR ir(work.code, work.main_offset, work.compiler_settings, *work.registry);
155 const ShaderIR ir(work.code, work.main_offset, work.compiler_settings, work.registry);
156 const auto scope = context->Acquire(); 189 const auto scope = context->Acquire();
157 auto program = 190 auto program =
158 OpenGL::BuildShader(work.device, work.shader_type, work.uid, ir, work.registry); 191 OpenGL::BuildShader(*work.device, work.shader_type, work.uid, ir, *work.registry);
159 Result result{}; 192 Result result{};
160 result.backend = work.backend; 193 result.backend = work.backend;
161 result.cpu_address = work.cpu_address; 194 result.cpu_address = work.cpu_address;
@@ -164,9 +197,9 @@ void AsyncShaders::ShaderCompilerThread(Core::Frontend::GraphicsContext* context
164 result.code_b = std::move(work.code_b); 197 result.code_b = std::move(work.code_b);
165 result.shader_type = work.shader_type; 198 result.shader_type = work.shader_type;
166 199
167 if (work.backend == AsyncShaders::Backend::OpenGL) { 200 if (work.backend == Backend::OpenGL) {
168 result.program.opengl = std::move(program->source_program); 201 result.program.opengl = std::move(program->source_program);
169 } else if (work.backend == AsyncShaders::Backend::GLASM) { 202 } else if (work.backend == Backend::GLASM) {
170 result.program.glasm = std::move(program->assembly_program); 203 result.program.glasm = std::move(program->assembly_program);
171 } 204 }
172 205
@@ -174,6 +207,13 @@ void AsyncShaders::ShaderCompilerThread(Core::Frontend::GraphicsContext* context
174 std::unique_lock complete_lock(completed_mutex); 207 std::unique_lock complete_lock(completed_mutex);
175 finished_work.push_back(std::move(result)); 208 finished_work.push_back(std::move(result));
176 } 209 }
210 } else if (work.backend == Backend::Vulkan) {
211 auto pipeline = std::make_unique<Vulkan::VKGraphicsPipeline>(
212 *work.vk_device, *work.scheduler, *work.descriptor_pool,
213 *work.update_descriptor_queue, *work.renderpass_cache, work.key, work.bindings,
214 work.program);
215
216 work.pp_cache->EmplacePipeline(std::move(pipeline));
177 } 217 }
178 } 218 }
179} 219}
diff --git a/src/video_core/shader/async_shaders.h b/src/video_core/shader/async_shaders.h
index 2f5ee94ad..d5ae814d5 100644
--- a/src/video_core/shader/async_shaders.h
+++ b/src/video_core/shader/async_shaders.h
@@ -14,6 +14,10 @@
14#include "video_core/renderer_opengl/gl_device.h" 14#include "video_core/renderer_opengl/gl_device.h"
15#include "video_core/renderer_opengl/gl_resource_manager.h" 15#include "video_core/renderer_opengl/gl_resource_manager.h"
16#include "video_core/renderer_opengl/gl_shader_decompiler.h" 16#include "video_core/renderer_opengl/gl_shader_decompiler.h"
17#include "video_core/renderer_vulkan/vk_device.h"
18#include "video_core/renderer_vulkan/vk_pipeline_cache.h"
19#include "video_core/renderer_vulkan/vk_scheduler.h"
20#include "video_core/renderer_vulkan/vk_update_descriptor.h"
17 21
18namespace Core::Frontend { 22namespace Core::Frontend {
19class EmuWindow; 23class EmuWindow;
@@ -24,6 +28,10 @@ namespace Tegra {
24class GPU; 28class GPU;
25} 29}
26 30
31namespace Vulkan {
32class VKPipelineCache;
33}
34
27namespace VideoCommon::Shader { 35namespace VideoCommon::Shader {
28 36
29class AsyncShaders { 37class AsyncShaders {
@@ -31,6 +39,7 @@ public:
31 enum class Backend { 39 enum class Backend {
32 OpenGL, 40 OpenGL,
33 GLASM, 41 GLASM,
42 Vulkan,
34 }; 43 };
35 44
36 struct ResultPrograms { 45 struct ResultPrograms {
@@ -52,7 +61,7 @@ public:
52 ~AsyncShaders(); 61 ~AsyncShaders();
53 62
54 /// Start up shader worker threads 63 /// Start up shader worker threads
55 void AllocateWorkers(std::size_t num_workers); 64 void AllocateWorkers();
56 65
57 /// Clear the shader queue and kill all worker threads 66 /// Clear the shader queue and kill all worker threads
58 void FreeWorkers(); 67 void FreeWorkers();
@@ -76,6 +85,14 @@ public:
76 VideoCommon::Shader::CompilerSettings compiler_settings, 85 VideoCommon::Shader::CompilerSettings compiler_settings,
77 const VideoCommon::Shader::Registry& registry, VAddr cpu_addr); 86 const VideoCommon::Shader::Registry& registry, VAddr cpu_addr);
78 87
88 void QueueVulkanShader(Vulkan::VKPipelineCache* pp_cache, const Vulkan::VKDevice& device,
89 Vulkan::VKScheduler& scheduler,
90 Vulkan::VKDescriptorPool& descriptor_pool,
91 Vulkan::VKUpdateDescriptorQueue& update_descriptor_queue,
92 Vulkan::VKRenderPassCache& renderpass_cache,
93 std::vector<VkDescriptorSetLayoutBinding> bindings,
94 Vulkan::SPIRVProgram program, Vulkan::GraphicsPipelineCacheKey key);
95
79private: 96private:
80 void ShaderCompilerThread(Core::Frontend::GraphicsContext* context); 97 void ShaderCompilerThread(Core::Frontend::GraphicsContext* context);
81 98
@@ -83,16 +100,28 @@ private:
83 bool HasWorkQueued(); 100 bool HasWorkQueued();
84 101
85 struct WorkerParams { 102 struct WorkerParams {
86 AsyncShaders::Backend backend; 103 Backend backend;
87 OpenGL::Device device; 104 // For OGL
105 const OpenGL::Device* device;
88 Tegra::Engines::ShaderType shader_type; 106 Tegra::Engines::ShaderType shader_type;
89 u64 uid; 107 u64 uid;
90 std::vector<u64> code; 108 std::vector<u64> code;
91 std::vector<u64> code_b; 109 std::vector<u64> code_b;
92 u32 main_offset; 110 u32 main_offset;
93 VideoCommon::Shader::CompilerSettings compiler_settings; 111 VideoCommon::Shader::CompilerSettings compiler_settings;
94 VideoCommon::Shader::Registry registry; 112 std::optional<VideoCommon::Shader::Registry> registry;
95 VAddr cpu_address; 113 VAddr cpu_address;
114
115 // For Vulkan
116 Vulkan::VKPipelineCache* pp_cache;
117 const Vulkan::VKDevice* vk_device;
118 Vulkan::VKScheduler* scheduler;
119 Vulkan::VKDescriptorPool* descriptor_pool;
120 Vulkan::VKUpdateDescriptorQueue* update_descriptor_queue;
121 Vulkan::VKRenderPassCache* renderpass_cache;
122 std::vector<VkDescriptorSetLayoutBinding> bindings;
123 Vulkan::SPIRVProgram program;
124 Vulkan::GraphicsPipelineCacheKey key;
96 }; 125 };
97 126
98 std::condition_variable cv; 127 std::condition_variable cv;
@@ -101,7 +130,7 @@ private:
101 std::atomic<bool> is_thread_exiting{}; 130 std::atomic<bool> is_thread_exiting{};
102 std::vector<std::unique_ptr<Core::Frontend::GraphicsContext>> context_list; 131 std::vector<std::unique_ptr<Core::Frontend::GraphicsContext>> context_list;
103 std::vector<std::thread> worker_threads; 132 std::vector<std::thread> worker_threads;
104 std::deque<WorkerParams> pending_queue; 133 std::queue<WorkerParams> pending_queue;
105 std::vector<AsyncShaders::Result> finished_work; 134 std::vector<AsyncShaders::Result> finished_work;
106 Core::Frontend::EmuWindow& emu_window; 135 Core::Frontend::EmuWindow& emu_window;
107}; 136};
diff --git a/src/video_core/shader/control_flow.cpp b/src/video_core/shader/control_flow.cpp
index 8d86020f6..336397cdb 100644
--- a/src/video_core/shader/control_flow.cpp
+++ b/src/video_core/shader/control_flow.cpp
@@ -187,24 +187,26 @@ std::optional<std::pair<BufferInfo, u64>> TrackLDC(const CFGRebuildState& state,
187 187
188std::optional<u64> TrackSHLRegister(const CFGRebuildState& state, u32& pos, 188std::optional<u64> TrackSHLRegister(const CFGRebuildState& state, u32& pos,
189 u64 ldc_tracked_register) { 189 u64 ldc_tracked_register) {
190 return TrackInstruction<u64>(state, pos, 190 return TrackInstruction<u64>(
191 [ldc_tracked_register](auto instr, const auto& opcode) { 191 state, pos,
192 return opcode.GetId() == OpCode::Id::SHL_IMM && 192 [ldc_tracked_register](auto instr, const auto& opcode) {
193 instr.gpr0.Value() == ldc_tracked_register; 193 return opcode.GetId() == OpCode::Id::SHL_IMM &&
194 }, 194 instr.gpr0.Value() == ldc_tracked_register;
195 [](auto instr, const auto&) { return instr.gpr8.Value(); }); 195 },
196 [](auto instr, const auto&) { return instr.gpr8.Value(); });
196} 197}
197 198
198std::optional<u32> TrackIMNMXValue(const CFGRebuildState& state, u32& pos, 199std::optional<u32> TrackIMNMXValue(const CFGRebuildState& state, u32& pos,
199 u64 shl_tracked_register) { 200 u64 shl_tracked_register) {
200 return TrackInstruction<u32>(state, pos, 201 return TrackInstruction<u32>(
201 [shl_tracked_register](auto instr, const auto& opcode) { 202 state, pos,
202 return opcode.GetId() == OpCode::Id::IMNMX_IMM && 203 [shl_tracked_register](auto instr, const auto& opcode) {
203 instr.gpr0.Value() == shl_tracked_register; 204 return opcode.GetId() == OpCode::Id::IMNMX_IMM &&
204 }, 205 instr.gpr0.Value() == shl_tracked_register;
205 [](auto instr, const auto&) { 206 },
206 return static_cast<u32>(instr.alu.GetSignedImm20_20() + 1); 207 [](auto instr, const auto&) {
207 }); 208 return static_cast<u32>(instr.alu.GetSignedImm20_20() + 1);
209 });
208} 210}
209 211
210std::optional<BranchIndirectInfo> TrackBranchIndirectInfo(const CFGRebuildState& state, u32 pos) { 212std::optional<BranchIndirectInfo> TrackBranchIndirectInfo(const CFGRebuildState& state, u32 pos) {
diff --git a/src/video_core/shader/decode/memory.cpp b/src/video_core/shader/decode/memory.cpp
index 63adbc4a3..e4739394d 100644
--- a/src/video_core/shader/decode/memory.cpp
+++ b/src/video_core/shader/decode/memory.cpp
@@ -471,9 +471,9 @@ std::tuple<Node, Node, GlobalMemoryBase> ShaderIR::TrackGlobalMemory(NodeBlock&
471 471
472 const auto [base_address, index, offset] = 472 const auto [base_address, index, offset] =
473 TrackCbuf(addr_register, global_code, static_cast<s64>(global_code.size())); 473 TrackCbuf(addr_register, global_code, static_cast<s64>(global_code.size()));
474 ASSERT_OR_EXECUTE_MSG(base_address != nullptr, 474 ASSERT_OR_EXECUTE_MSG(
475 { return std::make_tuple(nullptr, nullptr, GlobalMemoryBase{}); }, 475 base_address != nullptr, { return std::make_tuple(nullptr, nullptr, GlobalMemoryBase{}); },
476 "Global memory tracking failed"); 476 "Global memory tracking failed");
477 477
478 bb.push_back(Comment(fmt::format("Base address is c[0x{:x}][0x{:x}]", index, offset))); 478 bb.push_back(Comment(fmt::format("Base address is c[0x{:x}][0x{:x}]", index, offset)));
479 479
diff --git a/src/video_core/texture_cache/surface_params.cpp b/src/video_core/texture_cache/surface_params.cpp
index 9a98f0e98..e614a92df 100644
--- a/src/video_core/texture_cache/surface_params.cpp
+++ b/src/video_core/texture_cache/surface_params.cpp
@@ -96,7 +96,6 @@ SurfaceParams SurfaceParams::CreateForTexture(const FormatLookupTable& lookup_ta
96 } 96 }
97 params.type = GetFormatType(params.pixel_format); 97 params.type = GetFormatType(params.pixel_format);
98 } 98 }
99 params.type = GetFormatType(params.pixel_format);
100 // TODO: on 1DBuffer we should use the tic info. 99 // TODO: on 1DBuffer we should use the tic info.
101 if (tic.IsBuffer()) { 100 if (tic.IsBuffer()) {
102 params.target = SurfaceTarget::TextureBuffer; 101 params.target = SurfaceTarget::TextureBuffer;
diff --git a/src/video_core/textures/decoders.cpp b/src/video_core/textures/decoders.cpp
index 474ae620a..16d46a018 100644
--- a/src/video_core/textures/decoders.cpp
+++ b/src/video_core/textures/decoders.cpp
@@ -228,24 +228,30 @@ void SwizzleSubrect(u32 subrect_width, u32 subrect_height, u32 source_pitch, u32
228 } 228 }
229} 229}
230 230
231void UnswizzleSubrect(u32 subrect_width, u32 subrect_height, u32 dest_pitch, u32 swizzled_width, 231void UnswizzleSubrect(u32 line_length_in, u32 line_count, u32 pitch, u32 width, u32 bytes_per_pixel,
232 u32 bytes_per_pixel, u8* swizzled_data, u8* unswizzled_data, 232 u32 block_height, u32 origin_x, u32 origin_y, u8* output, const u8* input) {
233 u32 block_height_bit, u32 offset_x, u32 offset_y) { 233 const u32 stride = width * bytes_per_pixel;
234 const u32 block_height = 1U << block_height_bit; 234 const u32 gobs_in_x = (stride + GOB_SIZE_X - 1) / GOB_SIZE_X;
235 for (u32 line = 0; line < subrect_height; ++line) { 235 const u32 block_size = gobs_in_x << (GOB_SIZE_SHIFT + block_height);
236 const u32 y2 = line + offset_y; 236
237 const u32 gob_address_y = (y2 / (GOB_SIZE_Y * block_height)) * GOB_SIZE * block_height + 237 const u32 block_height_mask = (1U << block_height) - 1;
238 ((y2 % (GOB_SIZE_Y * block_height)) / GOB_SIZE_Y) * GOB_SIZE; 238 const u32 x_shift = static_cast<u32>(GOB_SIZE_SHIFT) + block_height;
239 const auto& table = LEGACY_SWIZZLE_TABLE[y2 % GOB_SIZE_Y]; 239
240 for (u32 x = 0; x < subrect_width; ++x) { 240 for (u32 line = 0; line < line_count; ++line) {
241 const u32 x2 = (x + offset_x) * bytes_per_pixel; 241 const u32 src_y = line + origin_y;
242 const u32 gob_address = gob_address_y + (x2 / GOB_SIZE_X) * GOB_SIZE * block_height; 242 const auto& table = LEGACY_SWIZZLE_TABLE[src_y % GOB_SIZE_Y];
243 const u32 swizzled_offset = gob_address + table[x2 % GOB_SIZE_X]; 243
244 const u32 unswizzled_offset = line * dest_pitch + x * bytes_per_pixel; 244 const u32 block_y = src_y >> GOB_SIZE_Y_SHIFT;
245 u8* dest_line = unswizzled_data + unswizzled_offset; 245 const u32 src_offset_y = (block_y >> block_height) * block_size +
246 u8* source_addr = swizzled_data + swizzled_offset; 246 ((block_y & block_height_mask) << GOB_SIZE_SHIFT);
247 for (u32 column = 0; column < line_length_in; ++column) {
248 const u32 src_x = (column + origin_x) * bytes_per_pixel;
249 const u32 src_offset_x = (src_x >> GOB_SIZE_X_SHIFT) << x_shift;
250
251 const u32 swizzled_offset = src_offset_y + src_offset_x + table[src_x % GOB_SIZE_X];
252 const u32 unswizzled_offset = line * pitch + column * bytes_per_pixel;
247 253
248 std::memcpy(dest_line, source_addr, bytes_per_pixel); 254 std::memcpy(output + unswizzled_offset, input + swizzled_offset, bytes_per_pixel);
249 } 255 }
250 } 256 }
251} 257}
@@ -261,7 +267,7 @@ void SwizzleSliceToVoxel(u32 line_length_in, u32 line_count, u32 pitch, u32 widt
261 const u32 block_size = gobs_in_x << (GOB_SIZE_SHIFT + block_height + block_depth); 267 const u32 block_size = gobs_in_x << (GOB_SIZE_SHIFT + block_height + block_depth);
262 268
263 const u32 block_height_mask = (1U << block_height) - 1; 269 const u32 block_height_mask = (1U << block_height) - 1;
264 const u32 x_shift = Common::CountTrailingZeroes32(GOB_SIZE << (block_height + block_depth)); 270 const u32 x_shift = static_cast<u32>(GOB_SIZE_SHIFT) + block_height + block_depth;
265 271
266 for (u32 line = 0; line < line_count; ++line) { 272 for (u32 line = 0; line < line_count; ++line) {
267 const auto& table = LEGACY_SWIZZLE_TABLE[line % GOB_SIZE_Y]; 273 const auto& table = LEGACY_SWIZZLE_TABLE[line % GOB_SIZE_Y];
diff --git a/src/video_core/textures/decoders.h b/src/video_core/textures/decoders.h
index d6fe35d37..01e156bc8 100644
--- a/src/video_core/textures/decoders.h
+++ b/src/video_core/textures/decoders.h
@@ -48,9 +48,8 @@ void SwizzleSubrect(u32 subrect_width, u32 subrect_height, u32 source_pitch, u32
48 u32 block_height_bit, u32 offset_x, u32 offset_y); 48 u32 block_height_bit, u32 offset_x, u32 offset_y);
49 49
50/// Copies a tiled subrectangle into a linear surface. 50/// Copies a tiled subrectangle into a linear surface.
51void UnswizzleSubrect(u32 subrect_width, u32 subrect_height, u32 dest_pitch, u32 swizzled_width, 51void UnswizzleSubrect(u32 line_length_in, u32 line_count, u32 pitch, u32 width, u32 bytes_per_pixel,
52 u32 bytes_per_pixel, u8* swizzled_data, u8* unswizzled_data, u32 block_height, 52 u32 block_height, u32 origin_x, u32 origin_y, u8* output, const u8* input);
53 u32 offset_x, u32 offset_y);
54 53
55/// @brief Swizzles a 2D array of pixels into a 3D texture 54/// @brief Swizzles a 2D array of pixels into a 3D texture
56/// @param line_length_in Number of pixels per line 55/// @param line_length_in Number of pixels per line
diff --git a/src/yuzu/configuration/configure_graphics_advanced.ui b/src/yuzu/configuration/configure_graphics_advanced.ui
index a793c803d..846a30586 100644
--- a/src/yuzu/configuration/configure_graphics_advanced.ui
+++ b/src/yuzu/configuration/configure_graphics_advanced.ui
@@ -92,7 +92,7 @@
92 <string>Enables asynchronous shader compilation, which may reduce shader stutter. This feature is experimental.</string> 92 <string>Enables asynchronous shader compilation, which may reduce shader stutter. This feature is experimental.</string>
93 </property> 93 </property>
94 <property name="text"> 94 <property name="text">
95 <string>Use asynchronous shader building (experimental, OpenGL or Assembly shaders only)</string> 95 <string>Use asynchronous shader building (experimental)</string>
96 </property> 96 </property>
97 </widget> 97 </widget>
98 </item> 98 </item>
diff --git a/src/yuzu/configuration/configure_input_player.cpp b/src/yuzu/configuration/configure_input_player.cpp
index b1850bc95..597defe8c 100644
--- a/src/yuzu/configuration/configure_input_player.cpp
+++ b/src/yuzu/configuration/configure_input_player.cpp
@@ -281,24 +281,25 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
281 281
282 button->setContextMenuPolicy(Qt::CustomContextMenu); 282 button->setContextMenuPolicy(Qt::CustomContextMenu);
283 connect(button, &QPushButton::clicked, [=, this] { 283 connect(button, &QPushButton::clicked, [=, this] {
284 HandleClick(button_map[button_id], 284 HandleClick(
285 [=, this](Common::ParamPackage params) { 285 button_map[button_id],
286 // Workaround for ZL & ZR for analog triggers like on XBOX controllors. 286 [=, this](Common::ParamPackage params) {
287 // Analog triggers (from controllers like the XBOX controller) would not 287 // Workaround for ZL & ZR for analog triggers like on XBOX controllors.
288 // work due to a different range of their signals (from 0 to 255 on 288 // Analog triggers (from controllers like the XBOX controller) would not
289 // analog triggers instead of -32768 to 32768 on analog joysticks). The 289 // work due to a different range of their signals (from 0 to 255 on
290 // SDL driver misinterprets analog triggers as analog joysticks. 290 // analog triggers instead of -32768 to 32768 on analog joysticks). The
291 // TODO: reinterpret the signal range for analog triggers to map the 291 // SDL driver misinterprets analog triggers as analog joysticks.
292 // values correctly. This is required for the correct emulation of the 292 // TODO: reinterpret the signal range for analog triggers to map the
293 // analog triggers of the GameCube controller. 293 // values correctly. This is required for the correct emulation of the
294 if (button_id == Settings::NativeButton::ZL || 294 // analog triggers of the GameCube controller.
295 button_id == Settings::NativeButton::ZR) { 295 if (button_id == Settings::NativeButton::ZL ||
296 params.Set("direction", "+"); 296 button_id == Settings::NativeButton::ZR) {
297 params.Set("threshold", "0.5"); 297 params.Set("direction", "+");
298 } 298 params.Set("threshold", "0.5");
299 buttons_param[button_id] = std::move(params); 299 }
300 }, 300 buttons_param[button_id] = std::move(params);
301 InputCommon::Polling::DeviceType::Button); 301 },
302 InputCommon::Polling::DeviceType::Button);
302 }); 303 });
303 connect(button, &QPushButton::customContextMenuRequested, 304 connect(button, &QPushButton::customContextMenuRequested,
304 [=, this](const QPoint& menu_location) { 305 [=, this](const QPoint& menu_location) {
@@ -325,12 +326,13 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
325 326
326 analog_button->setContextMenuPolicy(Qt::CustomContextMenu); 327 analog_button->setContextMenuPolicy(Qt::CustomContextMenu);
327 connect(analog_button, &QPushButton::clicked, [=, this] { 328 connect(analog_button, &QPushButton::clicked, [=, this] {
328 HandleClick(analog_map_buttons[analog_id][sub_button_id], 329 HandleClick(
329 [=, this](const Common::ParamPackage& params) { 330 analog_map_buttons[analog_id][sub_button_id],
330 SetAnalogButton(params, analogs_param[analog_id], 331 [=, this](const Common::ParamPackage& params) {
331 analog_sub_buttons[sub_button_id]); 332 SetAnalogButton(params, analogs_param[analog_id],
332 }, 333 analog_sub_buttons[sub_button_id]);
333 InputCommon::Polling::DeviceType::Button); 334 },
335 InputCommon::Polling::DeviceType::Button);
334 }); 336 });
335 connect(analog_button, &QPushButton::customContextMenuRequested, 337 connect(analog_button, &QPushButton::customContextMenuRequested,
336 [=, this](const QPoint& menu_location) { 338 [=, this](const QPoint& menu_location) {
@@ -357,11 +359,12 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
357 tr("After pressing OK, first move your joystick horizontally, " 359 tr("After pressing OK, first move your joystick horizontally, "
358 "and then vertically."), 360 "and then vertically."),
359 QMessageBox::Ok | QMessageBox::Cancel) == QMessageBox::Ok) { 361 QMessageBox::Ok | QMessageBox::Cancel) == QMessageBox::Ok) {
360 HandleClick(analog_map_stick[analog_id], 362 HandleClick(
361 [=, this](const Common::ParamPackage& params) { 363 analog_map_stick[analog_id],
362 analogs_param[analog_id] = params; 364 [=, this](const Common::ParamPackage& params) {
363 }, 365 analogs_param[analog_id] = params;
364 InputCommon::Polling::DeviceType::Analog); 366 },
367 InputCommon::Polling::DeviceType::Analog);
365 } 368 }
366 }); 369 });
367 370
diff --git a/src/yuzu/configuration/configure_mouse_advanced.cpp b/src/yuzu/configuration/configure_mouse_advanced.cpp
index ea2549363..5bcf5ffa8 100644
--- a/src/yuzu/configuration/configure_mouse_advanced.cpp
+++ b/src/yuzu/configuration/configure_mouse_advanced.cpp
@@ -84,11 +84,12 @@ ConfigureMouseAdvanced::ConfigureMouseAdvanced(QWidget* parent)
84 84
85 button->setContextMenuPolicy(Qt::CustomContextMenu); 85 button->setContextMenuPolicy(Qt::CustomContextMenu);
86 connect(button, &QPushButton::clicked, [=, this] { 86 connect(button, &QPushButton::clicked, [=, this] {
87 HandleClick(button_map[button_id], 87 HandleClick(
88 [=, this](const Common::ParamPackage& params) { 88 button_map[button_id],
89 buttons_param[button_id] = params; 89 [=, this](const Common::ParamPackage& params) {
90 }, 90 buttons_param[button_id] = params;
91 InputCommon::Polling::DeviceType::Button); 91 },
92 InputCommon::Polling::DeviceType::Button);
92 }); 93 });
93 connect(button, &QPushButton::customContextMenuRequested, 94 connect(button, &QPushButton::customContextMenuRequested,
94 [=, this](const QPoint& menu_location) { 95 [=, this](const QPoint& menu_location) {
diff --git a/src/yuzu/debugger/profiler.cpp b/src/yuzu/debugger/profiler.cpp
index 53049ffd6..0e26f765b 100644
--- a/src/yuzu/debugger/profiler.cpp
+++ b/src/yuzu/debugger/profiler.cpp
@@ -109,8 +109,7 @@ MicroProfileWidget::MicroProfileWidget(QWidget* parent) : QWidget(parent) {
109 MicroProfileSetDisplayMode(1); // Timers screen 109 MicroProfileSetDisplayMode(1); // Timers screen
110 MicroProfileInitUI(); 110 MicroProfileInitUI();
111 111
112 connect(&update_timer, &QTimer::timeout, this, 112 connect(&update_timer, &QTimer::timeout, this, qOverload<>(&MicroProfileWidget::update));
113 static_cast<void (MicroProfileWidget::*)()>(&MicroProfileWidget::update));
114} 113}
115 114
116void MicroProfileWidget::paintEvent(QPaintEvent* ev) { 115void MicroProfileWidget::paintEvent(QPaintEvent* ev) {
diff --git a/src/yuzu/game_list.cpp b/src/yuzu/game_list.cpp
index 62acc3720..967ef4a21 100644
--- a/src/yuzu/game_list.cpp
+++ b/src/yuzu/game_list.cpp
@@ -406,7 +406,7 @@ bool GameList::isEmpty() const {
406 type == GameListItemType::SysNandDir)) { 406 type == GameListItemType::SysNandDir)) {
407 item_model->invisibleRootItem()->removeRow(child->row()); 407 item_model->invisibleRootItem()->removeRow(child->row());
408 i--; 408 i--;
409 }; 409 }
410 } 410 }
411 return !item_model->invisibleRootItem()->hasChildren(); 411 return !item_model->invisibleRootItem()->hasChildren();
412} 412}
diff --git a/src/yuzu/game_list_worker.cpp b/src/yuzu/game_list_worker.cpp
index 239016b94..c9a395222 100644
--- a/src/yuzu/game_list_worker.cpp
+++ b/src/yuzu/game_list_worker.cpp
@@ -350,6 +350,7 @@ void GameListWorker::ScanFileSystem(ScanTarget target, const std::string& dir_pa
350 350
351void GameListWorker::run() { 351void GameListWorker::run() {
352 stop_processing = false; 352 stop_processing = false;
353 provider->ClearAllEntries();
353 354
354 for (UISettings::GameDir& game_dir : game_dirs) { 355 for (UISettings::GameDir& game_dir : game_dirs) {
355 if (game_dir.path == QStringLiteral("SDMC")) { 356 if (game_dir.path == QStringLiteral("SDMC")) {
@@ -368,13 +369,12 @@ void GameListWorker::run() {
368 watch_list.append(game_dir.path); 369 watch_list.append(game_dir.path);
369 auto* const game_list_dir = new GameListDir(game_dir); 370 auto* const game_list_dir = new GameListDir(game_dir);
370 emit DirEntryReady(game_list_dir); 371 emit DirEntryReady(game_list_dir);
371 provider->ClearAllEntries();
372 ScanFileSystem(ScanTarget::FillManualContentProvider, game_dir.path.toStdString(), 372 ScanFileSystem(ScanTarget::FillManualContentProvider, game_dir.path.toStdString(),
373 game_dir.deep_scan ? 256 : 0, game_list_dir); 373 game_dir.deep_scan ? 256 : 0, game_list_dir);
374 ScanFileSystem(ScanTarget::PopulateGameList, game_dir.path.toStdString(), 374 ScanFileSystem(ScanTarget::PopulateGameList, game_dir.path.toStdString(),
375 game_dir.deep_scan ? 256 : 0, game_list_dir); 375 game_dir.deep_scan ? 256 : 0, game_list_dir);
376 } 376 }
377 }; 377 }
378 378
379 emit Finished(watch_list); 379 emit Finished(watch_list);
380} 380}
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index 592993c36..3ef59fbad 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -894,6 +894,8 @@ void GMainWindow::ConnectMenuEvents() {
894 connect(ui.action_Open_FAQ, &QAction::triggered, this, &GMainWindow::OnOpenFAQ); 894 connect(ui.action_Open_FAQ, &QAction::triggered, this, &GMainWindow::OnOpenFAQ);
895 connect(ui.action_Restart, &QAction::triggered, this, [this] { BootGame(QString(game_path)); }); 895 connect(ui.action_Restart, &QAction::triggered, this, [this] { BootGame(QString(game_path)); });
896 connect(ui.action_Configure, &QAction::triggered, this, &GMainWindow::OnConfigure); 896 connect(ui.action_Configure, &QAction::triggered, this, &GMainWindow::OnConfigure);
897 connect(ui.action_Configure_Current_Game, &QAction::triggered, this,
898 &GMainWindow::OnConfigurePerGame);
897 899
898 // View 900 // View
899 connect(ui.action_Single_Window_Mode, &QAction::triggered, this, 901 connect(ui.action_Single_Window_Mode, &QAction::triggered, this,
@@ -1167,6 +1169,7 @@ void GMainWindow::ShutdownGame() {
1167 ui.action_Pause->setEnabled(false); 1169 ui.action_Pause->setEnabled(false);
1168 ui.action_Stop->setEnabled(false); 1170 ui.action_Stop->setEnabled(false);
1169 ui.action_Restart->setEnabled(false); 1171 ui.action_Restart->setEnabled(false);
1172 ui.action_Configure_Current_Game->setEnabled(false);
1170 ui.action_Report_Compatibility->setEnabled(false); 1173 ui.action_Report_Compatibility->setEnabled(false);
1171 ui.action_Load_Amiibo->setEnabled(false); 1174 ui.action_Load_Amiibo->setEnabled(false);
1172 ui.action_Capture_Screenshot->setEnabled(false); 1175 ui.action_Capture_Screenshot->setEnabled(false);
@@ -1718,26 +1721,7 @@ void GMainWindow::OnGameListOpenPerGameProperties(const std::string& file) {
1718 return; 1721 return;
1719 } 1722 }
1720 1723
1721 ConfigurePerGame dialog(this, title_id); 1724 OpenPerGameConfiguration(title_id, file);
1722 dialog.LoadFromFile(v_file);
1723 auto result = dialog.exec();
1724 if (result == QDialog::Accepted) {
1725 dialog.ApplyConfiguration();
1726
1727 const auto reload = UISettings::values.is_game_list_reload_pending.exchange(false);
1728 if (reload) {
1729 game_list->PopulateAsync(UISettings::values.game_dirs);
1730 }
1731
1732 // Do not cause the global config to write local settings into the config file
1733 Settings::RestoreGlobalState();
1734
1735 if (!Core::System::GetInstance().IsPoweredOn()) {
1736 config->Save();
1737 }
1738 } else {
1739 Settings::RestoreGlobalState();
1740 }
1741} 1725}
1742 1726
1743void GMainWindow::OnMenuLoadFile() { 1727void GMainWindow::OnMenuLoadFile() {
@@ -2066,6 +2050,7 @@ void GMainWindow::OnStartGame() {
2066 ui.action_Pause->setEnabled(true); 2050 ui.action_Pause->setEnabled(true);
2067 ui.action_Stop->setEnabled(true); 2051 ui.action_Stop->setEnabled(true);
2068 ui.action_Restart->setEnabled(true); 2052 ui.action_Restart->setEnabled(true);
2053 ui.action_Configure_Current_Game->setEnabled(true);
2069 ui.action_Report_Compatibility->setEnabled(true); 2054 ui.action_Report_Compatibility->setEnabled(true);
2070 2055
2071 discord_rpc->Update(); 2056 discord_rpc->Update();
@@ -2255,6 +2240,36 @@ void GMainWindow::OnConfigure() {
2255 UpdateStatusButtons(); 2240 UpdateStatusButtons();
2256} 2241}
2257 2242
2243void GMainWindow::OnConfigurePerGame() {
2244 const u64 title_id = Core::System::GetInstance().CurrentProcess()->GetTitleID();
2245 OpenPerGameConfiguration(title_id, game_path.toStdString());
2246}
2247
2248void GMainWindow::OpenPerGameConfiguration(u64 title_id, const std::string& file_name) {
2249 const auto v_file = Core::GetGameFileFromPath(vfs, file_name);
2250
2251 ConfigurePerGame dialog(this, title_id);
2252 dialog.LoadFromFile(v_file);
2253 auto result = dialog.exec();
2254 if (result == QDialog::Accepted) {
2255 dialog.ApplyConfiguration();
2256
2257 const auto reload = UISettings::values.is_game_list_reload_pending.exchange(false);
2258 if (reload) {
2259 game_list->PopulateAsync(UISettings::values.game_dirs);
2260 }
2261
2262 // Do not cause the global config to write local settings into the config file
2263 Settings::RestoreGlobalState();
2264
2265 if (!Core::System::GetInstance().IsPoweredOn()) {
2266 config->Save();
2267 }
2268 } else {
2269 Settings::RestoreGlobalState();
2270 }
2271}
2272
2258void GMainWindow::OnLoadAmiibo() { 2273void GMainWindow::OnLoadAmiibo() {
2259 const QString extensions{QStringLiteral("*.bin")}; 2274 const QString extensions{QStringLiteral("*.bin")};
2260 const QString file_filter = tr("Amiibo File (%1);; All Files (*.*)").arg(extensions); 2275 const QString file_filter = tr("Amiibo File (%1);; All Files (*.*)").arg(extensions);
diff --git a/src/yuzu/main.h b/src/yuzu/main.h
index 73a44a3bf..64c33830d 100644
--- a/src/yuzu/main.h
+++ b/src/yuzu/main.h
@@ -216,6 +216,7 @@ private slots:
216 void OnMenuInstallToNAND(); 216 void OnMenuInstallToNAND();
217 void OnMenuRecentFile(); 217 void OnMenuRecentFile();
218 void OnConfigure(); 218 void OnConfigure();
219 void OnConfigurePerGame();
219 void OnLoadAmiibo(); 220 void OnLoadAmiibo();
220 void OnOpenYuzuFolder(); 221 void OnOpenYuzuFolder();
221 void OnAbout(); 222 void OnAbout();
@@ -249,6 +250,7 @@ private:
249 void ShowMouseCursor(); 250 void ShowMouseCursor();
250 void OpenURL(const QUrl& url); 251 void OpenURL(const QUrl& url);
251 void LoadTranslation(); 252 void LoadTranslation();
253 void OpenPerGameConfiguration(u64 title_id, const std::string& file_name);
252 254
253 Ui::MainWindow ui; 255 Ui::MainWindow ui;
254 256
diff --git a/src/yuzu/main.ui b/src/yuzu/main.ui
index c3a1d715e..87ea985d8 100644
--- a/src/yuzu/main.ui
+++ b/src/yuzu/main.ui
@@ -81,6 +81,7 @@
81 <addaction name="action_Restart"/> 81 <addaction name="action_Restart"/>
82 <addaction name="separator"/> 82 <addaction name="separator"/>
83 <addaction name="action_Configure"/> 83 <addaction name="action_Configure"/>
84 <addaction name="action_Configure_Current_Game"/>
84 </widget> 85 </widget>
85 <widget class="QMenu" name="menu_View"> 86 <widget class="QMenu" name="menu_View">
86 <property name="title"> 87 <property name="title">
@@ -287,6 +288,14 @@
287 <string>Capture Screenshot</string> 288 <string>Capture Screenshot</string>
288 </property> 289 </property>
289 </action> 290 </action>
291 <action name="action_Configure_Current_Game">
292 <property name="enabled">
293 <bool>false</bool>
294 </property>
295 <property name="text">
296 <string>Configure Current Game..</string>
297 </property>
298 </action>
290 </widget> 299 </widget>
291 <resources/> 300 <resources/>
292 <connections/> 301 <connections/>
diff --git a/src/yuzu/uisettings.h b/src/yuzu/uisettings.h
index bbfeafc55..2d2e82f15 100644
--- a/src/yuzu/uisettings.h
+++ b/src/yuzu/uisettings.h
@@ -29,14 +29,14 @@ extern const Themes themes;
29 29
30struct GameDir { 30struct GameDir {
31 QString path; 31 QString path;
32 bool deep_scan; 32 bool deep_scan = false;
33 bool expanded; 33 bool expanded = false;
34 bool operator==(const GameDir& rhs) const { 34 bool operator==(const GameDir& rhs) const {
35 return path == rhs.path; 35 return path == rhs.path;
36 }; 36 }
37 bool operator!=(const GameDir& rhs) const { 37 bool operator!=(const GameDir& rhs) const {
38 return !operator==(rhs); 38 return !operator==(rhs);
39 }; 39 }
40}; 40};
41 41
42struct Values { 42struct Values {